„ნუ გაიმეორებ საკუთარ თავს“ (Don't repeat yourself), ანუ DRY, პროგრამული უზრუნველყოფის შემუშავების კარგად ცნობილი პრინციპია. ეს პრინციპი მომდინარეობს წიგნიდან „პრაგმატული პროგრამისტი“, რომელიც კოდის დიზაინის შესახებ ერთ-ერთი ყველაზე წაკითხვადი წიგნია. პრინციპის მარტივი გზავნილი აშკარაა: ნუ გადაწერ იმ ლოგიკას, რომელიც უკვე არსებობს სხვაგან. ეს უზრუნველყოფს კოდის სინქრონულობას, რაც აადვილებს მის შენარჩუნებას და ხდის მას უფრო მდგრადს. ამ ლოგიკურ შაბლონში ნებისმიერი ცვლილება ერთნაირად იმოქმედებს მის ყველა დამოკიდებულებაზე. ერთი შეხედვით, Hugging Face-ის Transformers ბიბლიოთეკის დიზაინი, შესაძლოა, DRY პრინციპის სრულ საპირისპიროდ მოგვეჩვენოს. ყურადღების მექანიზმის კოდი, მეტ-ნაკლებად, 50-ჯერ მაინც არის გადაკოპირებული სხვადასხვა მოდელის ფაილებში. ზოგჯერ მთელი BERT მოდელის კოდი კოპირდება სხვა მოდელის ფაილებში. ხშირად ვაიძულებთ ახალი მოდელის კონტრიბუტორებს – არსებულ მოდელებთან იდენტურ შემთხვევაში, მცირე ლოგიკური ცვლილებების გარდა – გადააკოპირონ მთელი არსებული კოდი. რატომ ვაკეთებთ ამას? ვართ თუ არა უბრალოდ ზარმაცები ან გადატვირთულები, რომ არ მოვახდინოთ ყველა ლოგიკური ნაწილის ცენტრალიზება ერთ ადგილას? არა, ჩვენ ზარმაცები არ ვართ – ეს არის შეგნებული გადაწყვეტილება, რომ არ გამოვიყენოთ DRY დიზაინის პრინციპი Transformers ბიბლიოთეკაში. ამის ნაცვლად, ჩვენ გადავწყვიტეთ სხვა დიზაინის პრინციპის მიღება, რომელსაც „ერთი მოდელის ფაილის პოლიტიკას“ ვუწოდებთ. ეს პოლიტიკა აცხადებს, რომ მოდელის „წინა გადაცემისთვის“ (forward pass) აუცილებელი მთელი კოდი მოთავსებულია ერთადერთ ფაილში – ე.წ. მოდელის ფაილში. თუ მკითხველს სურს გაიგოს, როგორ მუშაობს BERT დასკვნისთვის (inference), მას მხოლოდ BERT-ის `modeling_bert.py` ფაილში უნდა ჩაიხედოს. ჩვენ, როგორც წესი, უარვყოფთ სხვადასხვა მოდელის იდენტური ქვე-კომპონენტების ახალ ცენტრალიზებულ ადგილას აბსტრაქციის ნებისმიერ მცდელობას. არ გვსურს გვქონდეს `attention_layer.py` ფაილი, რომელიც მოიცავს ყველა შესაძლო ყურადღების მექანიზმს. კვლავაც, რატომ ვაკეთებთ ამას? მოკლედ, მიზეზები შემდეგია: Transformers შექმნილია იმისთვის, რომ აქტიურად წაახალისოს გარე კონტრიბუციები. კონტრიბუცია ხშირად არის ან შეცდომის გამოსწორება, ან ახალი მოდელის დამატება. თუ შეცდომა აღმოჩენილია ერთ-ერთ მოდელის ფაილში, გვსურს, რომ მისი გამოსწორება აღმომჩენისთვის მაქსიმალურად მარტივი იყოს. არაფერია იმაზე მეტად დემოტივირებული, ვიდრე შეცდომის გამოსწორება და შემდეგ იმის აღმოჩენა, რომ მან 100 სხვა მოდელის გაუმართაობა გამოიწვია. ვინაიდან მოდელის კოდი დამოუკიდებელია ყველა სხვა მოდელისგან, საკმაოდ მარტივია იმ ადამიანისთვის, ვინც მხოლოდ იმ ერთ მოდელს იცნობს, რომელზეც მუშაობს, მისი გამოსწორება. ანალოგიურად, უფრო ადვილია ახალი მოდელირების კოდის დამატება და შესაბამისი Pull Request-ის (PR) განხილვა, თუ მხოლოდ ერთი ახალი მოდელის ფაილია დამატებული. კონტრიბუტორს არ უწევს იმის გარკვევა, თუ როგორ დაამატოს ახალი ფუნქციონალობა ცენტრალიზებულ ყურადღების მექანიზმს არსებული მოდელების დაზიანების გარეშე. რევიუერს შეუძლია მარტივად გადაამოწმოს, რომ არცერთი არსებული მოდელი არ არის გაუმართავი. ჩვენ ვვარაუდობთ, რომ Transformers ბიბლიოთეკის მომხმარებელთა მნიშვნელოვანი ნაწილი არა მხოლოდ კითხულობს დოკუმენტაციას, არამედ ათვალიერებს რეალურ მოდელირების კოდს და პოტენციურად ცვლის მას. ეს ჰიპოთეზა გამყარებულია იმით, რომ Transformers ბიბლიოთეკა 10 000-ზე მეტჯერაა ფორკირებული (forked) და Transformers-ის სტატია ათასზე მეტჯერაა ციტირებული. ამიტომ, უაღრესად მნიშვნელოვანია, რომ Transformers-ის მოდელირების კოდის პირველად წამკითხველმა ადვილად გაიგოს და პოტენციურად მოარგოს ის თავის საჭიროებებს. ყველა საჭირო ლოგიკური კომპონენტის მოწესრიგებულად, ერთ მოდელირების ფაილში მოწოდება, მნიშვნელოვნად უწყობს ხელს წაკითხვადობისა და ადაპტირების გაუმჯობესებას. გარდა ამისა, ჩვენ დიდ ყურადღებას ვაქცევთ ცვლადების/მეთოდების გონივრულ დასახელებას და უპირატესობას ვანიჭებთ ექსპრესიულ/წაკითხვად კოდს სიმბოლოების ეფექტურ კოდთან შედარებით. მანქანური სწავლების, განსაკუთრებით კი ნერვული ქსელების სფეროში კვლევა, უკიდურესად სწრაფად ვითარდება. მოდელი, რომელიც ერთი წლის წინ უახლესი იყო, შესაძლოა დღეს მოძველებული იყოს. ჩვენ არ ვიცით, რომელი ყურადღების მექანიზმი, პოზიციური ჩანართი თუ არქიტექტურა იქნება საუკეთესო ერთ წელიწადში. ამიტომ, ჩვენ ვერ განვსაზღვრავთ სტანდარტულ ლოგიკურ შაბლონებს, რომლებიც ყველა მოდელზე ვრცელდება. მაგალითად, ორი წლის წინ, შესაძლოა, BERT-ის თვითყურადღების შრე განგვესაზღვრა, როგორც სტანდარტული ყურადღების შრე, რომელსაც ყველა Transformers მოდელი გამოიყენებდა. ლოგიკურად, „სტანდარტული“ ყურადღების ფუნქცია შესაძლოა გადატანილიყო ცენტრალურ `attention.py` ფაილში. მაგრამ შემდეგ გამოჩნდა ყურადღების შრეები, რომლებმაც დაამატეს შედარებითი პოზიციური ჩანართები თითოეულ ყურადღების შრეში (T5), „დაყოფილი ყურადღების“ (chunked attention) მრავალი განსხვავებული ფორმა (Reformer, Longformer, BigBird) და ცალკეული ყურადღების მექანიზმი პოზიციისა და სიტყვის ჩანართებისთვის (DeBERTa) და ა.შ. ყოველ ჯერზე მოგვიწევდა გვკითხა საკუთარი თავისთვის, უნდა ადაპტირებულიყო თუ არა „სტანდარტული“ ყურადღების ფუნქცია, თუ უკეთესი იქნებოდა ახალი ყურადღების ფუნქციის დამატება `attention.py` ფაილში. მაგრამ შემდეგ როგორ დაგვერქმია მისთვის? `attention_with_positional_embd`, `reformer_attention`, `deberta_attention`? საშიშია მანქანური სწავლების მოდელების ლოგიკური კომპონენტებისთვის ზოგადი სახელების მინიჭება, რადგან ამ კომპონენტის აღქმა, რასაც ის წარმოადგენს, შეიძლება ძალიან სწრაფად შეიცვალოს ან მოძველდეს. მაგალითად, შეესაბამება თუ არა „დაყოფილი ყურადღება“ GPTNeo-ს, Reformer-ის თუ BigBird-ის დაყოფილ ყურადღებას? არის თუ არა ყურადღების შრე თვითყურადღების შრე, ჯვარედინი ყურადღების შრე, თუ ორივეს მოიცავს? თუმცა, თუ ყურადღების შრეებს მათი მოდელის სახელით დავარქმევთ, უშუალოდ უნდა მოვათავსოთ