მიუხედავად იმისა, რომ GPU მეხსიერების სისრულის დანახვა მარტივია, იმის გაგება, თუ რატომ ხდება ეს და როგორ გამოვასწოროთ, უფრო რთული შეიძლება იყოს. ამ გაკვეთილში, ჩვენ ეტაპობრივად განვიხილავთ, თუ როგორ მოვახდინოთ GPU მეხსიერების გამოყენების ვიზუალიზაცია და გაგება PyTorch-ში ტრენინგის დროს. ასევე ვნახავთ, როგორ შევაფასოთ მეხსიერების მოთხოვნები და მოვახდინოთ GPU მეხსიერების გამოყენების ოპტიმიზაცია. PyTorch გთავაზობთ მოსახერხებელ ინსტრუმენტს GPU მეხსიერების გამოყენების ვიზუალიზაციისთვის: ამ კოდის გაშვება წარმოქმნის profile.pkl ფაილს, რომელიც შეიცავს GPU მეხსიერების გამოყენების ისტორიას შესრულების დროს. ამ ისტორიის ვიზუალიზაცია შეგიძლიათ შემდეგ მისამართზე: https://pytorch.org/memory_viz. თქვენი profile.pkl ფაილის გადათრევით და ჩაგდებით, ნახავთ მსგავს გრაფიკს: მოდით, ეს გრაფიკი ძირითად ნაწილებად დავყოთ: **მოდელის შექმნა (Model Creation):** მეხსიერება იზრდება 2 GB-ით, რაც შეესაბამება მოდელის ზომას: 10,000×50,000 წონა (weights) + 50,000 გადახრა (biases) float32 ფორმატში (4 ბაიტი) ⟹ (5×10^8)×4 ბაიტი = 2 GB. ეს მეხსიერება (ლურჯ ფერში) ნარჩუნდება შესრულების მთელი პერიოდის განმავლობაში. **შეყვანის ტენზორის შექმნა (1-ლი ციკლი) (Input Tensor Creation (1st Loop)):** მეხსიერება იზრდება 200 MB-ით, რაც შეესაბამება შეყვანის ტენზორის ზომას: 5,000×10,000 ელემენტი float32 ფორმატში (4 ბაიტი) ⟹ (5×10^7)×4 ბაიტი = 0.2 GB. **Forward Pass (1-ლი ციკლი):** მეხსიერება იზრდება 1 GB-ით გამომავალი ტენზორისთვის: 5,000×50,000 ელემენტი float32 ფორმატში (4 ბაიტი) ⟹ (25×10^7)×4 ბაიტი = 1 GB. **შეყვანის ტენზორის შექმნა (მე-2 ციკლი) (Input Tensor Creation (2nd Loop)):** მეხსიერება იზრდება 200 MB-ით ახალი შეყვანის ტენზორისთვის. ამ ეტაპზე, შეიძლება მოელოდეთ, რომ მე-2 ნაბიჯიდან შეყვანის ტენზორი გათავისუფლდება. თუმცა, ასე არ ხდება: მოდელი ინარჩუნებს თავის აქტივაციას, ამიტომ, მაშინაც კი, თუ ტენზორი აღარ არის მინიჭებული 'inputs' ცვლადისთვის, ის მაინც მიეთითება მოდელის forward pass გამოთვლის მიერ. მოდელი ინარჩუნებს თავის აქტივაციებს, რადგან ეს ტენზორები საჭიროა ნერვულ ქსელებში backpropagation პროცესისთვის. სცადეთ torch.no_grad()-ით, რომ განსხვავება დაინახოთ. **Forward Pass (მე-2 ციკლი):** მეხსიერება იზრდება 1 GB-ით ახალი გამომავალი ტენზორისთვის, გამოთვლილია მე-3 ნაბიჯის მსგავსად. **1-ლი ციკლის აქტივაციის გათავისუფლება (Release 1st Loop Activation):** მეორე ციკლის forward pass-ის შემდეგ, პირველი ციკლის (მე-2 ნაბიჯი) შეყვანის ტენზორი შეიძლება გათავისუფლდეს. მოდელის აქტივაციები, რომლებიც პირველ შეყვანის ტენზორს შეიცავდნენ, გადაიწერება მეორე ციკლის შეყვანით. როგორც კი მეორე ციკლი დასრულდება, პირველი ტენზორი აღარ არის მითითებული და მისი მეხსიერება შეიძლება გათავისუფლდეს. **გამოსავლის განახლება (Update output):** მე-3 ნაბიჯიდან გამომავალი ტენზორი ხელახლა ენიჭება 'output' ცვლადს. წინა ტენზორი აღარ არის მითითებული და იშლება, რის შედეგადაც მისი მეხსიერება თავისუფლდება. **შეყვანის ტენზორის შექმნა (მე-3 ციკლი) (Input Tensor Creation (3rd Loop)):** მე-4 ნაბიჯის მსგავსად. **Forward Pass (მე-3 ციკლი):** მე-5 ნაბიჯის მსგავსად. **მე-2 ციკლის აქტივაციის გათავისუფლება (Release 2nd Loop Activation):** მე-4 ნაბიჯიდან შეყვანის ტენზორი თავისუფლდება. **გამოსავლის ხელახლა განახლება (Update output Again):** მე-5 ნაბიჯიდან გამომავალი ტენზორი ხელახლა ენიჭება 'output' ცვლადს, რის შედეგადაც წინა ტენზორი თავისუფლდება. **კოდის შესრულების დასასრული (End of Code Execution):** მთელი მეხსიერება თავისუფლდება. წინა მაგალითი გამარტივებული იყო. რეალურ სცენარებში, ჩვენ ხშირად ვავარჯიშებთ კომპლექსურ მოდელებს, ვიდრე ერთ ხაზოვან ფენას. გარდა ამისა, ადრინდელი მაგალითი არ მოიცავდა ტრენინგის პროცესს. აქ, ჩვენ განვიხილავთ, თუ როგორ იქცევა GPU მეხსიერება რეალური დიდი ენობრივი მოდელის (LLM) სრული ტრენინგის ციკლის განმავლობაში. 💡 **რჩევა:** პროფაილინგის დროს შეზღუდეთ ნაბიჯების რაოდენობა. GPU მეხსიერების ყოველი მოვლენა იწერება და ფაილი შეიძლება ძალიან დიდი გახდეს. მაგალითად, ზემოთ მოცემული კოდი წარმოქმნის 8 MB ზომის ფაილს. აი, ამ მაგალითის მეხსიერების პროფილი: ეს გრაფიკი უფრო კომპლექსურია, ვიდრე წინა მაგალითი, მაგრამ მაინც შეგვიძლია მისი ეტაპობრივად დაშლა. შეამჩნიეთ სამი პიკი, თითოეული შეესაბამება ტრენინგის ციკლის ერთ იტერაციას. მოდით, გავამარტივოთ გრაფიკი, რათა მისი ინტერპრეტაცია უფრო ადვილი იყოს: **მოდელის ინიციალიზაცია (Model Initialization) (model = AutoModelForCausalLM.from_pretrained("Qwen/Qwen2.5-1.5B").to("cuda")):** პირველი ნაბიჯი გულისხმობს მოდელის GPU-ზე ჩატვირთვას. მოდელის პარამეტრები (ლურჯ ფერში) იკავებს მეხსიერებას და რჩება იქ ტრენინგის დასრულებამდე. **Forward Pass (model(inputs)):** Forward pass-ის დროს, აქტივაციები (თითოეული ფენის შუალედური გამოსავლები) გამოითვლება და ინახება მეხსიერებაში backpropagation-ისთვის. ეს აქტივაციები, წარმოდგენილი ნარინჯისფერ ფერში, იზრდება ფენა-ფენად საბოლოო ფენამდე. დანაკარგი (loss) გამოითვლება ნარინჯისფერი ზონის პიკზე. **Backward Pass (loss.backward()):** ამ ფაზაში გამოითვლება და ინახება გრადიენტები (gradiens) (ყვითელ ფერში). ამავდროულად, აქტივაციები უგულებელყოფილია, რადგან ისინი აღარ არის საჭირო, რაც იწვევს ნარინჯისფერი ზონის შემცირებას. ყვითელი ზონა წარმოადგენს მეხსიერების გამოყენებას გრადიენტების გამოთვლებისთვის. **ოპტიმიზატორის ნაბიჯი (Optimizer Step) (optimizer.step()):** გრადიენტები გამოიყენება მოდელის პარამეტრების განახლებისთვის. თავდაპირველად, ოპტ...