ვინაიდან მოდელს სჭირდება 352GB bf16 (bfloat16) წონები (176*2), ყველაზე ეფექტური კონფიგურაციაა 8x80GB A100 GPU-ები. ასევე შესაძლებელია 2x8x40GB A100-ების ან 2x8x48GB A6000-ების გამოყენება. ამ GPU-ების გამოყენების მთავარი მიზეზი ის არის, რომ ამ სტატიის დაწერის მომენტისთვის ისინი უზრუნველყოფენ ყველაზე დიდ GPU მეხსიერებას, თუმცა სხვა GPU-ების გამოყენებაც შესაძლებელია. მაგალითად, შეიძლება გამოყენებულ იქნას 24x32GB V100-ები. ერთჯერადი კვანძის (node) გამოყენება, როგორც წესი, უზრუნველყოფს უსწრაფეს გამტარუნარიანობას (throughput), ვინაიდან უმეტეს შემთხვევაში კვანძშიდა GPU დამაკავშირებელი აპარატურა უფრო სწრაფია, ვიდრე კვანძთაშორისი, მაგრამ ეს ყოველთვის ასე არ არის. თუ არ გაქვთ ამდენი აპარატურა, BLOOM ინფერენსის გაშვება მცირე ზომის GPU-ებზე მაინც შესაძლებელია CPU-ის ან NVMe offload-ის გამოყენებით, თუმცა, რა თქმა უნდა, გენერაციის დრო გაცილებით ნელი იქნება. ჩვენ ასევე განვიხილავთ 8-ბიტიან კვანტიზებულ გადაწყვეტებს, რომლებიც მოითხოვს GPU მეხსიერების ნახევარს, ოდნავ ნელი გამტარუნარიანობის ხარჯზე. ამ კონტექსტში განვიხილავთ BitsAndBytes და Deepspeed-Inference ბიბლიოთეკებს. ყოველგვარი შეფერხების გარეშე, წარმოგიდგენთ ციფრებს. თანმიმდევრულობისთვის, თუ სხვაგვარად არ არის მითითებული, ამ სტატიაში მოცემული ყველა ბენჩმარკინგი შესრულდა იმავე 8x80GB A100 კვანძზე, 512GB CPU მეხსიერებით, Jean Zay HPC-ზე. JeanZay HPC-ის მომხმარებლებს აქვთ ძალიან სწრაფი IO, დაახლოებით 3GB/წმ წაკითხვის სიჩქარით (GPFS). ეს მნიშვნელოვანია checkpoint-ის ჩატვირთვის დროისთვის. ნელი დისკი გამოიწვევს ჩატვირთვის ნელ დროს, განსაკუთრებით იმის გათვალისწინებით, რომ IO-ს ერთდროულად ვასრულებთ მრავალ პროცესში. ყველა ბენჩმარკინგი აკეთებს 100 ტოკენის გამომავალი მონაცემების "greedy" გენერაციას: შეყვანის მოთხოვნა (input prompt) მხოლოდ რამდენიმე ტოკენისგან შედგება. წინა ტოკენების ქეშირებაც ჩართულია, რადგან მათი მუდმივი გადაანგარიშება საკმაოდ ნელი იქნებოდა. პირველ რიგში, სწრაფად გადავხედოთ, რამდენი დრო დასჭირდა მოდელის გენერაციისთვის მომზადებას – ანუ, რამდენი დრო დასჭირდა მოდელის ჩატვირთვასა და მომზადებას: Deepspeed-Inference მოყვება წინასწარ დაყოფილი (pre-sharded) წონების რეპოზიტორებს და იქ ჩატვირთვას დაახლოებით 1 წუთი სჭირდება. Accelerate-ის ჩატვირთვის დრო ასევე შესანიშნავია – დაახლოებით 2 წუთი. სხვა გადაწყვეტები აქ ბევრად ნელია. ჩატვირთვის დროს შეიძლება ჰქონდეს ან არ ჰქონდეს მნიშვნელობა, რადგან ერთხელ ჩატვირთვის შემდეგ შეგიძლიათ მუდმივად გენერირება ტოკენების დამატებითი ჩატვირთვის დანახარჯების გარეშე. შემდეგი არის ტოკენების გენერაციის გამტარუნარიანობის (throughput) ყველაზე მნიშვნელოვანი ბენჩმარკინგი. გამტარუნარიანობის მეტრიკა აქ მარტივია – რამდენი დრო დასჭირდა 100 ახალი ტოკენის გენერირებას გაყოფილი 100-ზე და batch ზომაზე (ანუ გაყოფილი გენერირებული ტოკენების საერთო რაოდენობაზე). აქ მოცემულია გამტარუნარიანობა მილიწამებში 8x80GB GPU-ებზე: სადაც OOM == Out of Memory მდგომარეობაა, როდესაც batch ზომა ძალიან დიდი იყო GPU მეხსიერებაში მოსათავსებლად. 1 მილიწამზე ნაკლები გამტარუნარიანობის მიღწევა Deepspeed-Inference-ის Tensor Parallelism (TP) და მორგებული "fused" CUDA kernel-ების გამოყენებით! ეს აბსოლუტურად გასაოცარია! თუმცა, ამ გადაწყვეტის გამოყენებამ სხვა მოდელებისთვის, რომლებზეც ის არ გამოუცდიათ, შესაძლოა მოითხოვოს დეველოპერების დრო მის გასამართად. Accelerate ასევე სუპერ სწრაფია. ის იყენებს მარტივ მიდგომას, "naive" Pipeline Parallelism (PP)-ს და მისი სიმარტივის გამო ის უნდა მუშაობდეს ყოველგვარი დამატებითი კონფიგურაციის გარეშე ნებისმიერ მოდელთან. ვინაიდან Deepspeed-ZeRO-ს შეუძლია მრავალი გენერირების ნაკადის პარალელურად დამუშავება, მისი გამტარუნარიანობა შეიძლება კიდევ გაიყოს 8-ზე ან 16-ზე, იმის მიხედვით, 8 თუ 16 GPU იყო გამოყენებული გენერაციის გამოძახების დროს. და, რა თქმა უნდა, ეს ნიშნავს, რომ მას შეუძლია დაამუშაოს 64-ის batch ზომა 8x80 A100-ის შემთხვევაში (ზემოთ მოცემული ცხრილი) და ამგვარად გამტარუნარიანობა დაახლოებით 4ms-ია – ასე რომ, ყველა 3 გადაწყვეტა ერთმანეთთან ძალიან ახლოსაა. მოდით, კიდევ ერთხელ გადავხედოთ, როგორ გამოითვალა ეს ციფრები. 100 ახალი ტოკენის გენერირებას 128-ის batch ზომისთვის დასჭირდა 8832 მილიწამი რეალურ დროში Deepspeed-Inference-ის fp16 რეჟიმში გამოყენებისას. ასე რომ, გამტარუნარიანობის გამოსათვლელად ჩვენ გავაკეთეთ: walltime/(batch_size*new_tokens) ან 8832/(128*100) = 0.69. ახლა კი გადავხედოთ კვანტიზებული int8-ზე დაფუძნებული მოდელების ძალას, რომლებსაც გვთავაზობენ Deepspeed-Inference და BitsAndBytes, ვინაიდან მათ სჭირდებათ bfloat16 ან float16 ინფერენსისთვის საჭირო GPU მეხსიერების მხოლოდ ნახევარი. გამტარუნარიანობა მილიწამებში 4x80GB A100-ზე: ბენჩმარკინგის შედეგების რეპროდუცირებისთვის, უბრალოდ დაამატეთ --benchmark ქვემოთ განხილულ ნებისმიერ 3 სკრიპტს. პირველ რიგში, შეამოწმეთ დემო რეპოზიტორიუმი: ამ სტატიაში ჩვენ გამოვიყენებთ 3 სკრიპტს, რომლებიც მდებარეობს bloom-inference-scripts/ საქაღალდეში. ფრეიმვორკის სპეციფიკური გადაწყვეტები წარმოდგენილია ანბანური თანმიმდევრობით: Accelerate Accelerate დიდ მოდელებს ინფერენსისთვის შემდეგნაირად ამუშავებს: ის უზრუნველყოფს მოდელის სწორად მუშაობას "hooks"-ის მეშვეობით, რომელიც გადასცემს შეყვანის და გამომავალ მონაცემებს სწორ მოწყობილობაზე და რომ CPU-ზე (ან თუნდაც დისკზე) გადატვირთული მოდელის წონები ჩაიტვირთება GPU-ზე ზუსტად "forward pass"-ის წინ, სანამ ისევ გადაიტვირთება "forward pass"-ის დასრულების შემდეგ. სიტუაციაში, როდესაც არსებობს მრავალი GPU საკმარისი სივრცით მთელი მოდელის მოსათავსებლად, ის აკონტროლებს პროცესს ერთი GPU-დან მეორეზე გადასვლით, სანამ ყველა ფენა არ შესრულდება. დროის ნებისმიერ მომენტში მხოლოდ ერთი GPU მუშაობს, რაც ძალიან არაეფექტურად ჟღერს, მაგრამ ის მაინც უზრუნველყოფს ღირსეულ გამტარუნარიანობას GPU-ების უმოქმედობის მიუხედავად. ის ასევე ძალიან მოქნილია, რადგან იგივე კოდი შეიძლება გაშვებული იყოს ნებისმიერ კონფიგურაციაზე. Accelerate ჯერ გამოიყენებს ყველა ხელმისაწვდომ GPU-ს, შემდეგ გადატვირთავს CPU-ზე RAM-ის სრულად შევსებამდე, და ბოლოს დისკზე გადატვირთავს.