Meta AI-მ და BigScience-მა ცოტა ხნის წინ საჯაროდ ხელმისაწვდომი გახადეს ძალიან დიდი ენობრივი მოდელები, რომლებიც მომხმარებლის უმეტესი აპარატურის მეხსიერებაში (RAM ან GPU) არ ეტევა. Hugging Face-ში ჩვენი მისიის ნაწილია ამ მასშტაბური მოდელების ხელმისაწვდომობის უზრუნველყოფა, რის გამოც შევიმუშავეთ ინსტრუმენტები, რათა ამ მოდელების გაშვება შეგეძლოთ მაშინაც კი, თუ სუპერკომპიუტერი არ გაქვთ. ამ ბლოგპოსტში მოყვანილი ყველა მაგალითი მუშაობს უფასო Colab-ის ინსტანციაზე (შეზღუდული RAM-ით და დისკის სივრცით). თუ უფრო მეტი დისკის სივრცე გაქვთ, ნუ შეგეშინდებათ უფრო დიდი ჩექპოინტების არჩევის. აი, როგორ შეგვიძლია OPT-6.7B-ის გაშვება: ცოტა ხანში აგიხსნით, რას აკეთებს თითოეული ეს არგუმენტი, მაგრამ თავდაპირველად განვიხილოთ ტრადიციული მოდელის ჩატვირთვის პროცესი PyTorch-ში: ის, როგორც წესი, შედგება: მიუხედავად იმისა, რომ ეს მიდგომა გასულ წლებში საკმაოდ კარგად მუშაობდა, ძალიან დიდი მოდელები ამ მეთოდს გამოწვევად აქცევს. აქ შერჩეულ მოდელს აქვს 6.7 მილიარდი პარამეტრი. ნაგულისხმევი სიზუსტით, ეს ნიშნავს, რომ მხოლოდ პირველი ნაბიჯი (მოდელის შექმნა) დაახლოებით 26.8 GB RAM-ს მოიხმარს (float32-ის ერთი პარამეტრი მეხსიერებაში 4 ბაიტს იკავებს). ეს არც კი ეტევა იმ RAM-ში, რომელსაც Colab-ზე იღებთ. შემდეგ მე-2 ნაბიჯი მეხსიერებაში ჩატვირთავს მოდელის მეორე ასლს (ასე რომ, კიდევ 26.8 GB RAM-ს ნაგულისხმევი სიზუსტით). თუ ყველაზე დიდი მოდელების ჩატვირთვას ცდილობდით, მაგალითად BLOOM-ის ან OPT-176B-ის (რომელთაც ორივეს 176 მილიარდი პარამეტრი აქვთ), ამგვარად, დაგჭირდებოდათ 1.4 ტერაბაიტი CPU RAM. ეს ცოტა გადაჭარბებულია! და ეს ყველაფერი იმისთვის, რომ მოდელი მე-4 ნაბიჯზე უბრალოდ ერთ (ან რამდენიმე) GPU-ზე გადავიტანოთ. ნათელია, რომ უფრო ჭკვიანური გადაწყვეტა გვჭირდება. ამ ბლოგპოსტში განვმარტავთ, თუ როგორ იყენებს Accelerate PyTorch-ის ფუნქციებს ძალიან დიდი მოდელების ჩასატვირთად და ინფერენსის გასაშვებად, მაშინაც კი, თუ ისინი არ ეტევა RAM-ში ან ერთ GPU-ზე. მოკლედ, ის ზემოთ აღნიშნულ პროცესს შემდეგნაირად ცვლის: PyTorch 1.9-მა წარმოადგინა ახალი ტიპის მოწყობილობა, სახელწოდებით „მეტა მოწყობილობა“ (meta device). ეს საშუალებას გვაძლევს შევქმნათ ტენზორი მასზე რაიმე მონაცემების მიბმის გარეშე: მეტა მოწყობილობაზე არსებულ ტენზორს მხოლოდ ფორმა სჭირდება. სანამ მეტა მოწყობილობაზე ხართ, შეგიძლიათ შექმნათ თვითნებურად დიდი ტენზორები CPU (ან GPU) RAM-ზე ფიქრის გარეშე. მაგალითად, შემდეგი კოდი ავარიულად შეწყვეტს მუშაობას Colab-ზე: რადგან ამ დიდ ტენზორს ესაჭიროება 4 * 10^10 ბაიტი (ნაგულისხმევი სიზუსტე არის FP32, ასე რომ, ტენზორის თითოეული ელემენტი 4 ბაიტს იკავებს) ანუ 40 GB RAM. იგივე მეტა მოწყობილობაზე უბრალოდ მშვენივრად მუშაობს: თუ ამ ტენზორის ჩვენებას შეეცდებით, აი, რას დაბეჭდავს PyTorch: როგორც უკვე ვთქვით, ამ ტენზორთან მონაცემები არ არის დაკავშირებული, მხოლოდ ფორმაა. შეგიძლიათ მოდელი პირდაპირ მეტა მოწყობილობაზე ინსტანცირება: მაგრამ არსებული მოდელისთვის, ეს სინტაქსი მოითხოვდა თქვენი მთელი მოდელირების კოდის გადაწერას ისე, რომ თითოეული ქვემოდული მიიღებდა და გადასცემდა device საკვანძო სიტყვის არგუმენტს. ვინაიდან ეს არაპრაქტიკული იყო Transformers ბიბლიოთეკის 150 მოდელისთვის, ჩვენ შევიმუშავეთ კონტექსტის მენეჯერი, რომელიც შექმნის ცარიელ მოდელს თქვენთვის. აი, როგორ შეგიძლიათ BLOOM-ის ცარიელი ვერსიის ინსტანცირება: ეს მუშაობს ნებისმიერ მოდელზე, მაგრამ თქვენ იღებთ გარსს, რომლის პირდაპირ გამოყენება არ შეგიძლიათ: მეტა მოწყობილობისთვის ზოგიერთი ოპერაცია განხორციელებულია, მაგრამ ჯერ არა ყველა. მაგალითად, აქ შეგიძლიათ გამოიყენოთ ზემოთ განსაზღვრული large_model შეყვანით, მაგრამ არა BLOOM მოდელი. მისი გამოყენებისასაც კი, გამომავალი იქნება მეტა მოწყობილობის ტენზორი, ასე რომ, თქვენ მიიღებთ შედეგის ფორმას, მაგრამ მეტს არაფერს. ამ საკითხზე შემდგომი მუშაობის ფარგლებში, PyTorch-ის გუნდი მუშაობს ახალ კლას FakeTensor-ზე, რომელიც მეტა მოწყობილობაზე არსებული ტენზორების მსგავსია, მაგრამ მოწყობილობის ინფორმაციით (ფორმისა და dtype-ის გარდა). ვინაიდან ჩვენ ვიცით თითოეული წონის ფორმა, შეგვიძლია განვსაზღვროთ, თუ რამდენ მეხსიერებას მოიხმარენ ისინი მას შემდეგ, რაც წინასწარ გაწვრთნილ ტენზორებს სრულად ჩავტვირთავთ. ამიტომ, შეგვიძლია მივიღოთ გადაწყვეტილება, თუ როგორ გავანაწილოთ ჩვენი მოდელი CPU-ებსა და GPU-ებზე. სანამ წინასწარ გაწვრთნილი წონების ჩატვირთვას დავიწყებთ, უნდა ვიცოდეთ, სად გვინდა მათი განთავსება. ამ გზით შეგვიძლია გავათავისუფლოთ CPU RAM ყოველ ჯერზე, როცა წონას თავის სწორ ადგილას მოვათავსებთ. ეს შეიძლება გაკეთდეს მეტა მოწყობილობაზე არსებული ცარიელი მოდელით, რადგან მხოლოდ თითოეული ტენზორის ფორმა და მისი dtype გვჭირდება იმის გამოსათვლელად, თუ რამდენ ადგილს დაიკავებს ის მეხსიერებაში. Accelerate გთავაზობთ ფუნქციას, რომელიც ავტომატურად განსაზღვრავს მოწყობილობის რუკას (device map) ცარიელი მოდელიდან. ის შეეცდება მაქსიმალურად გამოიყენოს ყველა ხელმისაწვდომი GPU, შემდეგ CPU RAM და ბოლოს მონიშნავს იმ წონებს, რომლებიც არ ეტევა დისკზე გადმოტვირთვისთვის (disk offload). განვიხილოთ OPT-13b-ის გამოყენებით. ეს დააბრუნებს ლექსიკონს, რომელიც მოდულებს ან წონებს აკავშირებს მოწყობილობასთან. მაგალითად, ერთი Titan RTX-ის მქონე მანქანაზე ვიღებთ შემდეგს: Accelerate-ის შეფასებით, embedding-ები და დეკოდერი მე-9 ბლოკამდე შეიძლება სრულად განთავსდეს GPU-ზე (მოწყობილობა 0), შემდეგ მე-10 ბლოკის ნაწილი უნდა იყოს CPU-ზე, ისევე როგორც შემდეგი წონები მე-17 ფენამდე. შემდეგ მე-18 ფენა გაყოფილია CPU-სა და დისკს შორის და შემდეგი ფენები სრულად უნდა გადმოიტვირთოს დისკზე. სინამდვილეში, ამ მოწყობილობის რუკის შემდგომი გამოყენება არ იმუშავებს, რადგან ამ მოდელის შემადგენელ ფენებს აქვთ რეზიდუალური კავშირები (სადაც ბლოკის შეყვანა ემატება ბლოკის გამოსავალს), ამიტომ მოცემული ფენის ყველა ნაწილი უნდა იყოს ერთსა და იმავე მოწყობილობაზე. ამის მითითება Accelerate-ისთვის შეგვიძლია სიის გადაცემით.