ამ პოსტში განვიხილავთ Flux.1-Dev მოდელს ტექსტი-გამოსახულებაზე გენერაციისთვის, მისი ფართო პოპულარობისა და მიღების გამო, და იმას, თუ როგორ შეიძლება მისი ინფერენციის სიჩქარის ოპტიმიზაცია LoRAs-ის (~2.3x) გამოყენებისას. მასთან ერთად 30 ათასზე მეტი ადაპტერია გაწვრთნილი (როგორც Hugging Face Hub პლატფორმაზეა აღნიშნული). შესაბამისად, მისი მნიშვნელობა საზოგადოებისთვის დიდია. აღსანიშნავია, რომ მიუხედავად იმისა, რომ ჩვენ ვაჩვენებთ სიჩქარის ზრდას Flux-ით, გვჯერა, რომ ჩვენი რეცეპტი საკმარისად უნივერსალურია სხვა მოდელებზეც გამოსაყენებლად. თუ ვერ მოითმენთ კოდის გამოყენებას, გთხოვთ, იხილოთ თანდართული კოდის რეპოზიტორიუმი. LoRAs-ის სერვისისას, ჩვეულებრივია მათი ცხელად ცვლა (hotswap) – სხვადასხვა LoRAs-ის მონაცვლეობით ჩატვირთვა და ამოტვირთვა. LoRA ცვლის საბაზისო მოდელის არქიტექტურას. გარდა ამისა, LoRAs შეიძლება ერთმანეთისგან განსხვავდებოდეს – თითოეულ მათგანს შეიძლება ჰქონდეს სხვადასხვა რანგი და განსხვავებული ფენები, რომლებსაც ის ადაპტაციისთვის მიზნად ისახავს. LoRAs-ის ამ დინამიური თვისებების გათვალისწინებით, ჩვენ უნდა მივიღოთ აუცილებელი ზომები, რათა უზრუნველვყოთ ჩვენ მიერ გამოყენებული ოპტიმიზაციების მდგრადობა. მაგალითად, ჩვენ შეგვიძლია გამოვიყენოთ `torch.compile` კონკრეტული LoRA-ით ჩატვირთულ მოდელზე, რათა მივიღოთ ინფერენციის შეყოვნების დაჩქარება. თუმცა, როგორც კი LoRA-ს სხვა (პოტენციურად განსხვავებული კონფიგურაციის) LoRA-თი შევცვლით, გადაკომპილაციის პრობლემები შეგვხვდება, რაც ინფერენციის შენელებას გამოიწვევს. ასევე შესაძლებელია LoRA პარამეტრების გაერთიანება საბაზისო მოდელის პარამეტრებთან, კომპილაციის გაშვება და LoRA პარამეტრების გათიშვა ახლების ჩატვირთვისას. თუმცა, ეს მიდგომა კვლავ გადაკომპილაციის პრობლემას შეეჯახება ყოველ ჯერზე, როდესაც ინფერენცია გაეშვება, არქიტექტურული დონის პოტენციური ცვლილებების გამო. ჩვენი ოპტიმიზაციის რეცეპტი ითვალისწინებს ზემოაღნიშნულ სიტუაციებს, რათა იყოს მაქსიმალურად რეალისტური. ქვემოთ მოცემულია ჩვენი ოპტიმიზაციის რეცეპტის ძირითადი კომპონენტები: აღსანიშნავია, რომ ზემოთ ხსენებულთაგან, FP8 კვანტიზაცია დანაკარგებიანია, მაგრამ ხშირად უზრუნველყოფს სიჩქარე-მეხსიერების ყველაზე შთამბეჭდავ კომპრომისს. მიუხედავად იმისა, რომ ჩვენ რეცეპტი ძირითადად NVIDIA GPU-ებზე გამოვცადეთ, ის AMD GPU-ებზეც უნდა იმუშაოს. ჩვენს წინა ბლოგ პოსტებში (პოსტი 1 და პოსტი 2) უკვე განვიხილეთ ჩვენი ოპტიმიზაციის რეცეპტის პირველი სამი კომპონენტის გამოყენების უპირატესობები. მათი სათითაოდ გამოყენება მხოლოდ რამდენიმე ხაზი კოდია: FA3 პროცესორი აქედან მოდის. პრობლემები მაშინ იწყება, როდესაც ვცდილობთ LoRAs-ის ჩატვირთვას და ამოტვირთვას უკვე კომპილირებულ დიფუზიურ ტრანსფორმერში (`pipe.transformer`) გადაკომპილაციის გამოწვევის გარეშე. ჩვეულებრივ, LoRAs-ის ჩატვირთვა და ამოტვირთვა საჭიროებს გადაკომპილაციას, რაც ანადგურებს კომპილაციისგან მიღებულ ნებისმიერ სიჩქარის უპირატესობას. საბედნიეროდ, არსებობს გადაკომპილაციის საჭიროების თავიდან აცილების გზა. `hotswap=True`-ის გადაცემით, `diffusers` მოდელის არქიტექტურას უცვლელს დატოვებს და მხოლოდ LoRA ადაპტერის წონებს გაცვლის, რაც გადაკომპილაციას არ საჭიროებს. (შეგახსენებთ, რომ `pipe`-ზე პირველი გამოძახება ნელი იქნება, რადგან `torch.compile` არის `just-in-time` კომპილატორი. თუმცა, შემდგომი გამოძახებები მნიშვნელოვნად სწრაფი უნდა იყოს.) ეს ზოგადად იძლევა LoRAs-ის გადაკომპილაციის გარეშე ცვლის საშუალებას, მაგრამ არსებობს შეზღუდვები: `Diffusers`-ში `hotswapping`-ის და მისი შეზღუდვების შესახებ დამატებითი ინფორმაციისთვის, ეწვიეთ დოკუმენტაციის `hotswapping` განყოფილებას. ამ სამუშაო პროცესის სარგებელი აშკარა ხდება, როდესაც ვუყურებთ ინფერენციის შეყოვნებას კომპილაციის გარეშე, `hotswapping`-ის გამოყენებით. ძირითადი დასკვნები: ოპტიმიზაციის რეცეპტი, რომელიც აქამდე განვიხილეთ, ვარაუდობს ისეთ მძლავრ GPU-ზე წვდომას, როგორიცაა H100. თუმცა, რა შეგვიძლია გავაკეთოთ, როდესაც შეზღუდულნი ვართ სამომხმარებლო GPU-ების, მაგალითად RTX 4090-ის გამოყენებით? მოდით გავარკვიოთ. Flux.1-Dev (ნებისმიერი LoRA-ს გარეშე), Bfloat16 მონაცემთა ტიპის გამოყენებით, დაახლოებით 33 GB მეხსიერებას მოითხოვს გასაშვებად. LoRA მოდულის ზომიდან გამომდინარე და ყოველგვარი ოპტიმიზაციის გარეშე, ეს მეხსიერების მოხმარება შეიძლება კიდევ უფრო გაიზარდოს. ბევრ სამომხმარებლო GPU-ს, როგორიცაა RTX 4090, მხოლოდ 24 GB აქვს. ამ სექციის დანარჩენ ნაწილში, RTX 4090 აპარატს განვიხილავთ, როგორც ჩვენს საცდელ პლატფორმას. პირველ რიგში, Flux.1-Dev-ის სრულად გასაშვებად, შეგვიძლია გამოვიყენოთ CPU offloading, რა დროსაც კომპონენტები, რომლებიც არ არის საჭირო მიმდინარე გამოთვლის შესასრულებლად, გადაიტვირთება CPU-ზე მეტი ამაჩქარებლის მეხსიერების გასათავისუფლებლად. ამის გაკეთება საშუალებას გვაძლევს გავუშვათ მთელი კონვეიერი დაახლოებით 22 GB-ში 35.403 წამში RTX 4090-ზე. კომპილაციის ჩართვას შეუძლია შეყოვნების შემცირება 31.205 წამამდე (1.12x დაჩქარება). კოდის თვალსაზრისით, ეს მხოლოდ რამდენიმე ხაზია: ყურადღება მიაქციეთ, რომ აქ არ გამოგვიყენებია FP8 კვანტიზაცია, რადგან ის არ არის მხარდაჭერილი CPU offloading-თან და კომპილაციასთან ერთად (მხარდამჭერი საკითხის თემა). ამიტომ, მხოლოდ FP8 კვანტიზაციის გამოყენება Flux ტრანსფორმერზე არ არის საკმარისი მეხსიერების ამოწურვის პრობლემის შესამსუბუქებლად. ამ შემთხვევაში, გადავწყვიტეთ მისი ამოღება. შესაბამისად, FP8 კვანტიზაციის სქემის უპირატესობების გამოსაყენებლად, უნდა ვიპოვოთ გზა მისი CPU offloading-ის გარეშე გასაკეთებლად. Flux.1-Dev-ისთვის, თუ დამატებით გამოვიყენებთ კვანტიზაციას T5 ტექსტურ ენკოდერზე, შევძლებთ მთლიანი კონვეიერის ჩატვირთვას და გაშვებას 24GB-ში. ქვემოთ მოცემულია შედეგების შედარება T5 ტექსტური ენკოდერის კვანტიზაციითა და მის გარეშე (NF4 კვანტიზაცია bitsandbytes-დან). როგორც ზემოთ მოცემულ ფიგურაში ვხედავთ, T5 ტექსტური ენკოდერის კვანტიზაცია უზრუნველყოფს ოპტიმალურ მეხსიერების მოხმარებას.