مدل های زبانی بزرگ (LLM) از نظر حجم هم واقعا بسیار بزرگ هستند. این مدل ها معمولاً بین 7 تا 70 میلیارد پارامتر دارند که برای بارگذاری یک مدل پارامتر 70 میلیاردی با دقت کامل، به 280 گیگابایت حافظه GPU نیاز است. برای آموزش این مدلها، باید میلیاردها توکن را در میلیون ها یا میلیاردها متن به روز کرد که محاسبات مورد نیاز برای بهروزرسانی پارامترهای آن حایز اهمیت است. آموزش self-supervised این مدل ها گران است و برای سازمانها تا 100 میلیون دلار هزینه در بر دارد.
ما معمولا به دنبال این هستیم داده هایمان را با این مدل ها تطبیق دهیم. اما با مجموعه دادههای محدود و بدون داشتن قدرت محاسباتی، چگونه میتوان مدلهایی ایجاد کرد که با هزینهای کم، مدلهای اصلی را بهبود داد؟
اینجاست که حوزه تحقیقاتی Parameter-Efficient Fine-Tuning (PEFT) وارد عمل می شود. از طریق تکنیکهای مختلف که به زودی به تفصیل آنها را بررسی خواهیم کرد، میتوان بخشهای کوچکی از این مدلها را تقویت کرد تا برای کارهای خودمان، مناسبتر باشند. هدف PEFT تنظیم دقیق تنها زیر مجموعه کوچکی از پارامترهای مدل، جهت دستیابی به عملکرد قابل مقایسه با تنظیم دقیق کامل و در عین حال کاهش قابل توجه نیازهای محاسباتی است.
تنظیم دقیق مدلهای زبانی بزرگ (LLM) میتواند برای سازمانها خطرناک باشد، چرا که این مدلها میتوانند بخش قابل توجهی (حداقل 1%) از دادههای آموزشی را به خاطر بسپارند. این امر در مورد دادههای تکراری، نگرانی بیشتری ایجاد میکند. اگر LLM شما توسط افراد خارج از سازمان مورد استفاده قرار گیرد، به اشتراک گذاشتن دادههای آموزشی با آنها میتواند ریسکهای امنیتی را به همراه داشته باشد، مانند حملات تزریق پرامپت.
در این شرایط، راهحلهایی مانند استفاده از "مشاهده پویا" با ICL میتواند مفید باشد. این روش به شما امکان میدهد تا بدون به اشتراک گذاشتن دادههای آموزشی، از LLM خود در یک محیط کنترلشده استفاده کنید.
علاوه بر این، کیفیت دادههای آموزشی برای عملکرد LLM شما حیاتی است. اگر سازمان شما به جمعآوری و برچسبگذاری دادههای باکیفیت تعهد ندارد، بهتر است از تنظیم دقیق LLM خودداری کنید. مدلهای زبانی با دادههای باکیفیت عملکرد بهتری دارند و عدم وجود چنین تعهدی میتواند منجر به ناامیدی ذینفعان شود.
تنظیم دقیق و تنظیم دقیق بهینه پارامتر دو رویکردی هستند که در یادگیری ماشین برای بهبود عملکرد مدلهای از پیش آموزش دیده در یک کار خاص استفاده میشوند.
تنظیم دقیق یک مدل از پیش آموزش دیده، آموزش بیشتر آن مدل در حوزهای جدید با داده های جدید است. معمولاً کل مدل آموزش دیده در این روش آموزش داده می شود و شامل تمام لایه ها و پارامترهای آن میشود. این فرآیند می تواند از نظر محاسباتی گران و وقت گیر باشد، به خصوص برای مدل های بزرگ.
از سوی دیگر، تنظیم دقیق پارامتر کارآمد PEFT، روشی برای تنظیم دقیق است که تنها بر آموزش زیرمجموعه ای از پارامترهای مدل تمرکز دارد. این رویکرد شامل شناسایی مهم ترین پارامترها برای حوزه جدید و تنها به روز رسانی آن پارامترها در طول آموزش است. با انجام این کار، PEFT می تواند محاسبات مورد نیاز را به میزان قابل توجهی کاهش دهد.
در این مقاله نگاهی میاندازیم به تکنیک های که در Hugging Face PEFT در زمان نگارش در دسترس هستند.
فرض می کنیم که خوانندگان با معماری ترانسفورمر آشنا هستند و نیازی به جزئیات self-attention یا کامپوننت دیگری ندارید، اما بهتر است نگاهی به این مقاله بیندازید و شاید نیاز به توضیحی درباره The Annotated Transformer داشته باشیم.
قصد داریم از این شبه کد برای بلوک ترانسفورماتور استفاده کنیم:
def self_attention(x): k = x @ W_k q = x @ W_q v = x @ W_v return softmax(q @ k.T) @ v def transformer_block(x): """ Pseudo code by author based on [2] """ residual = x x = self_attention(x) x = layer_norm(x + residual) residual = x x = FFN(x) x = layer_norm(x + residual) return x
FFN یک شبکه Feed Forward است که متناسب با هدف ما در اینجا 2 لایه است. بسیاری از تکنیکهای PEFT که در ادامه میآیند، تغییراتی را در بلوک ترانسفورمر یا self-attention ایجاد میکنند، بنابراین در مقاله چندین بار به این شبه کد اشاره میکنیم و آن را تغییر میدهیم.
متدهای Additive از سادهترین متدها هستند. هدف متدهای Additive اضافه کردن مجموعهای از پارامترها یا لایههای شبکه برای تقویت مدل است. هنگام تنظیم دقیق داده ها، وزن این پارامترهای تازه اضافه شده را به روز می کنید. این امر آموزش را از نظر محاسباتی آسانتر میکند و همچنین با مجموعه دادههای کوچکتر سازگار میشود (برای شروع، 100 تا 500 را در نظر بگیرید، با سقفی نزدیک به 100000).
اداپترها به طور همزمان یک متد و یک کلاس هستند. این تکنیک توسط Houlsby و همکاران معرفی شد. هدف اداپترها اضافه کردن شبکههای کوچک Feed Forward بعد از لایههای فرعی Transformer و یادگیری آن پارامترها است. پس اداپترها فقط لایههای Feed Forward را به شبکه اضافه میکنند.
یک به روز رسانی ساده برای بلوک ترانسفورمر همانطور که در این شبه کد نشان داده شده است لایه های Feed Forward در دو مکان اضافه میشوند.
def transformer_block_adapter(x): """Pseudo code from [2] """ residual = x x = self_attention(x) x = FFN(x) # adapter x = layer_norm(x + residual) residual = x x = FFN(x) x = FFN(x) # adapter x = layer_norm(x + residual) return x
تنظیم دقیق با استفاده از اداپتر چگونه کار می کند؟
ماژول اداپتر شامل دو لایه feed forward است که با یک لایه فعالسازی غیرخطی متصل شدهاند. همچنین یک skip connection وجود دارد که لایههای fully connected را دور میزند.
اگر اداپتر را درست بعد از لایه multi-head attention قرار دهیم، ورودی لایه اداپتر ، نمایش پنهان h است که توسط لایه multi-head attention محاسبه می شود. در اینجا، h دو مسیر مختلف را در لایه آداپتور طی می کند. یکی skip-connection است که ورودی را بدون تغییر میگذارد و راه دیگر شامل لایههای feed-forward است.
در ابتدا، اولین لایه feed-forward، مقدار h را به فضایی با ابعاد پایین تبدیل میکند. این فضا ابعادی کمتر از h دارد. پس از آن، ورودی از طریق یک تابع فعالسازی غیر خطی عبور داده میشود و دومین لایه feed-forward آن را به ابعاد h برمیگرداند. نتایج به دست آمده از دو روش با هم جمع می شوند تا خروجی نهایی ماژول اداپتر به دست آید.
skip-connection ورودی اصلی h اداپتر را حفظ می کند، در حالی که مسیر feed-forward یک تغییر افزایشی ایجاد می کند که به صورت Δh نشان داده می شود. با اضافه کردن تغییر افزایشی Δh، به دست آمده از لایه feed-forward با h اصلی از لایه قبل، اداپتر نمایش پنهان محاسبه شده توسط مدل از پیش آموزش دیده را تغییر می دهد. این به اداپتر اجازه می دهد تا نمایش پنهان مدل از پیش آموزش دیده را تغییر دهد و در نتیجه خروجی آن را برای یک کار خاص تغییر دهد.
سازگاری با رتبه پایین (LoRA)Low-Rank Adaptation در مدلهای زبانی بزرگ، رویکرد دیگری در تنظیم دقیق مدلها برای وظایف یا حوزههای خاص است. مشابه اداپترها، LoRA نیز یک زیر ماژول کوچک قابل آموزش است که می تواند در معماری ترانسفورمرها وارد شود که شامل فریز کردن وزنهای مدل از پیش آموزشدیده و تزریق ماتریسهای تجزیه-رتبه rank-decomposition قابل آموزش به هر لایه از معماری ترانسفورمر است که تعداد پارامترهای قابل آموزش را کاهش میدهد. این روش میتواند تعداد پارامترهای قابل آموزش را تا 10000 برابر و نیاز به حافظه GPU را تا 3 برابر کاهش دهد، در حالی که همچنان در کارهای مختلف، با کیفیت مدل مشابه یا بهتر از تنظیم دقیق عمل میکند. LoRA همچنین امکان سوئیچینگ کارآمدتر را فراهم می کند، موانع سخت افزاری برای ورود را کاهش می دهد و در مقایسه با روش های دیگر، تاخیر برای استنتاج اضافی را ندارد.با استفاده از LoRA از huggingface PEFT ، می توانیم تعداد پارامترهای قابل آموزش در مدل را به 0.77 درصد از نسخه اصلی کاهش دهیم.
LoRA به موازات ماژول ها در مدل ترانسفورمر از پیش آموزش دیده قرار می گیرد، به ویژه به موازات لایه های feed-forward. یک لایه feed-forward دارای دو لایه و یک لایه غیرخطی در بین آنها است، که در آن بردار ورودی با استفاده از تبدیل افین affine به یک بردار خروجی با ابعاد متفاوت نمایش داده میشود. لایههای LoRA در کنار هر یک از دو لایه feed-forward قرار میگیرند.
حال، اجازه دهید لایه فید فوروارد up-project و LoRA را در کنار آن در نظر بگیریم. پارامترهای اصلی لایه feed-forward خروجی از لایه قبلی با ابعاد dmodel گرفته و آن را به dFFW میفرستند. در اینجا، FFW مخفف feed-forward است. ماژول LoRA که در کنار آن قرار گرفته است از دو لایه feed-forward تشکیل شده است. اولین لایه فید فوروارد LoRA همان ورودی لایه feed-forward up-project را می گیرد و آن را در یک بردارr بعدی که به مراتب کمتر از dmodel است، تبدیل می کند. سپس، لایه دوم feed-forward، بردار را به بردار دیگری با ابعاد dFFW تبدیل می کند. در نهایت، دو بردار با هم جمع می شوند تا نمایش نهایی را تشکیل دهند.
همانطور که قبلاً بحث کردیم، تنظیم دقیق نمایش پنهان h محاسبه شده توسط مدل اصلی ترانسفورمر را تغییر می دهد. از این رو، در این مورد، نمایش پنهان محاسبه شده توسط لایه feed-forward up-project ترانسفورمر اصلی h است. در همین حال، بردار محاسبه شده توسط LoRA، تغییر افزایشی Δh است که برای اصلاح h اصلی استفاده می شود. بنابراین، مجموع نمایش اصلی و تغییر افزایشی، نمایش پنهان به روز شده ’h است.
با قرار دادن ماژولهای LoRA در کنار لایههای feed-forward و یک classifier head در بالای مدل از پیش آموزشدیده، پارامترها برای وظیفه خاص هر کار به حداقل میرسد.
Prefix tuning
متد Prefix tuning یک جایگزین سبک برای تنظیم دقیق مدل های زبانی بزرگ از پیش آموزش دیده برای وظایف خاص است. Prefix tuning پارامترهای مدل زبان را ثابت نگه میدارد و یک بردار کوچک پیوسته task-specific به نام prefix را بهینه میکند. در Prefix tuning، بردار prefix مجموعه ای از پارامترهای آزاد است که همراه با مدل زبانی آموزش داده می شود. هدف از prefix tuning یافتن زمینه ای است که مدل زبان را به سمت تولید متنی هدایت شود که یک کار خاص را حل می کند.
متد Prefix tuning یک روش additive است که در آن دنبالهای از بردارهای پیوسته مخصوص تسک خاص به ابتدای ورودی یا پیشوند (prefix) متصل می شود. فقط پارامترهای پیشوند بهینه شده و به حالت های پنهان hidden state در هر لایه از مدل اضافه می شوند. توکن های جملات ورودی همچنین می توانند به عنوان توکنهای مجازی به پیشوند توجه کنند. در نتیجه، تنظیم پیشوند 1000 برابر پارامترهای کمتری نسبت به یک مدل کاملاً تنظیم شده ذخیره می کند، به این معنی که می توانید از یک مدل زبان بزرگ برای بسیاری از کارها استفاده کنید.
متد prefix را می توان دنباله ای از 'توکن های مجازی' virtual tokens دانست که توکن های بعدی می توانند به آن توجه کنند. با یادگیری تنها 0.1٪ از پارامترها، prefix عملکردی قابل مقایسه با تنظیم دقیق در تنظیمات کامل داده را به دست می آورد، از تنظیم دقیق در تنظیمات با داده کم بهتر عمل می کند و به نمونه هایی با موضوعاتی که در طول آموزش دیده نمی شوند، بهتر عمل می کند.
مشابه تمام تکنیکهای PEFT که قبلاً ذکر شد، هدف نهایی تنظیم prefix رسیدن به h است. تنظیم prefix از پیشوندها برای اصلاح نمایش های پنهان استخراج شده توسط مدل های زبان اصلی از پیش آموزش داده شده استفاده می کند. هنگامی که تغییر افزایشی Δh به نمایش پنهان اصلی h اضافه می شود، نمایش اصلاح شده را دریافت می کنیم، یعنی ’h.
هنگام استفاده از Prefix tuning، فقط prefix ها به روز می شوند، در حالی که بقیه لایه ها ثابت هستند و به روز نمی شوند.
Prompt tuning یکی دیگر از تکنیک های PEFT برای تطبیق مدل های زبان از پیش آموزش دیده با وظایف خاص پایین دست است. تنظیم پرامپت شامل یادگیری soft prompts از طریق پس انتشار خطا (backpropagation) است که میتواند برای کارهای خاص با استفاده از نمونههای برچسبگذاری شده تنظیم دقیق شود. Prompt tuning از یادگیری few-shot در GPT-3 بهتر عمل می کند و با افزایش اندازه مدل رقابتی تر می شود. همچنین در انتقال دامنه (domain transfer) استحکام (robustness) بیشتری دارد. این کار نیاز به ذخیره یک prompt کوچک مختص هر کار دارد، که استفاده مجدد از یک مدل ثابت را برای کار پاییندستی آسانتر میکند.
چگونه کار می کند؟
Prompt tuning یک نوع ساده تر از Prefix tuning است. در آن، برخی از بردارها در ابتدای دنباله در لایه ورودی قرار می گیرند. هنگامی که یک جمله ورودی ارائه می شود، لایه embedding، هر توکن را به بردار embedding متناظر خود تبدیل می کند و prefix embeddings به دنباله ی token embeddings اضافه می شوند. در مرحله بعد، لایههای ترانسفورمر از قبل آموزش داده شده، دنباله جاسازی را مانند مدل ترانسفورمر با یک دنباله عادی پردازش میکنند. فقط prefix embeddings در طول فرآیند تنظیم دقیق تنظیم میشوند، در حالی که بقیه مدل ترانسفورمر ثابت و بدون تغییر نگه داشته میشوند.
این تکنیک چندین مزیت نسبت به روشهای تنظیم دقیق سنتی دارد، از جمله بهبود کارایی و کاهش سربار محاسباتی. علاوه بر این، این واقعیت که فقط prefix embedding تنظیم دقیق شده به این معنی است که خطر کمتری برای تطبیق بیش از حد با دادههای آموزشی وجود دارد و در نتیجه مدلهای قویتر و قابل تعمیمتری تولید میشود.