این روزها مدلهای یادگیری عمیق با سرعت هرچه بیشتری نسبت به قبل معرفی میشوند و هر کدام به شکلی تاثیری در پیشرفت این علم دارند؛ اما بیشک یکی از تاثیرگذارترین مدلهایی که تا کنون معرفی شده، مدلهای تبدیلکننده یا Transformer ها هستند. برای آشنایی بیشتر با این مدلها، در این پست ابتدا روند شکلگیری آنها را بررسی کرده و سپس نگاهی به معماری و نحوهی کار آنها میاندازیم.
با توجه به این که مدلهای تبدیلکننده یا Transformer ها در حل مسائل توالی به توالی (Seq2Seq) کاربرد دارند، بهتر است ابتدا این نوع از مسائل را بررسی کنیم.
همانطور که در جلسهی اول مقدمهای بر شبکههای عصبی بازگشتی گفته شد، این شبکهها انواع مختلفی دارند. یکی از آنها، شبکههای many to many هستند که ابتدا کل رشتهی ورودی را پردازش کرده و سپس رشتهی خروجی را تولید میکنند. برای این کار معمولا از شبکههای Encoder-Decoder استفاده میشود. شبکهی کدگذار یا Encoder وظیفه دارد که کل رشتهی ورودی را پردازش کرده و اطلاعات آن را در وکتوری با ابعاد بالاتر ذخیره کند. در مرحلهی بعد، این وکتور به شبکهی کدگشا یا Decoder داده میشود تا رشتهی خروجی تولید شود.
اگر مسئلهی مشخصی مانند ترجمهی ماشینی را در نظر بگیریم، این شبکهها در ترجمهی جملات کوتاه عملکرد قابل قبولی دارند؛ اما با توجه به این که وکتور محتوا یا Context Vector طول ثابتی دارد، برای ترجمهی جملات طولانیتر به مشکل برمیخورند. توجه کنید که مسیری که در این شبکهها برای ترجمهی یک کلمه طی میشود بسیار طولانی است.
برای حل این مشکل، تلاش شد تا روشی پیدا شود که برای تولید هر کلمهی خروجی در هر گام زمانی، علاوه بر مفهوم کل جمله، بتوان بخشهای خاصی از رشتهی ورودی را نیز مد نظر داشت. لازم به ذکر است که انسانها نیز برای ترجمه از یک زبان به زبان دیگر روند مشابهی را طی میکنند؛ یعنی ابتدا کل جمله را خوانده و مفهوم کلی آن را درمییابند، سپس کلماتی از زبان مبدا را در نظر گرفته و آنها را به زبان مقصد ترجمه میکنند. نتیجهی این تلاش، معرفی مکانیزم توجه یا attention بود.
مکانیزم توجه اولین بار در سال ۲۰۱۵ در مقالهای که توسط Bahdanau نوشته شده بود، برای حل مسئلهی ترجمه ماشینی معرفی شد. میتوان گفت استفاده از مکانیزم توجه به ما کمک میکند تا علاوه بر مسئلهی اصلی، یک مسئله از نوع alignment (تعیین این که کدام بخشها از رشتهی ورودی به هر خروجی تولیدشده مرتبط هستند) را هم حل کنیم.
فرض کنید میخواهیم جملهای به طول n را با استفاده از مکانیزم توجه ترجمه کنیم.
روش پیشنهادشده توسط Bahdanau دارای مراحل زیر است:
۱. کدگذاری کلمات ورودی (Encoding)
ابتدا لازم است تا کلمات را به وکتورهای کدگذاریشده تبدیل کنیم. Bahdanau برای این کار از یک شبکهی عصبی بازگشتی دوطرفه استفاده کرد و حافظهی نهان یا hidden state آنها را بعد از ورود هر کلمه به هم الحاق کرد. این وکتورها را با h نمایش میدهیم.
۲. تعیین کلمات مرتبط (Alignment)
بعد از کدگذاری کلمات ورودی، نوبت به کدگشایی یا Decoding میرسد. برای این کار نیاز است تا هنگام تولید هر کلمهی خروجی، ابتدا مشخص شود که کدام کلمات ورودی اهمیت بیشتری دارند. به بیان دیگر، در این مرحله نیاز به تابعی داریم که با درنظر گرفتن کلماتی که تاکنون تولید شدهاند و وکتور هر کلمهی ورودی، امتیازی به آن کلمه نسبت دهد. در رابطه زیر، t گام زمانی در تولید کلمات خروجی، a تابع امتیازدهنده، s حافظهی نهان شبکهی Decoder پس از گام زمانی قبلی و e امتیاز نهایی به ازای هر گام زمانی و هر کلمهی ورودی است.
در روش Bahdanau، تابع a یک شبکهی عصبی بود که همزمان با شبکههای کدگذار و کدگشا آموزش میبیند و وزنهای آن مشخص میشود. در سالهای بعد، روشهای دیگری برای تعیین میزان ارتباط معرفی شدند، مانند معیار شباهتی کسینوسی یا ضرب داخلی دو بردار.
۳. تعیین وزن کلمات (Weighting)
برای تبدیل امتیازهای مشخصشده به وزن هر کلمه، تابع softmax بر روی آنها اعمال میشود.
۴. ایجاد وکتور مخصوص به هر کلمه خروجی (Generate Context Vector)
پس از تعیین وزنها، با ضرب هر وزن در کلمهی ورودی مرتبط به آن، وکتور محتوا به ازای هر کلمهی خروجی تولید میشود.
۵. تعیین کلمات خروجی
شبکهی کدگشا یا decoder که خود یک شبکهی عصبی بازگشتی است، با استفاده از وکتور تولیدشده و حافظهی نهان خود، کلمهی خروجی در گامزمانی t ام را تولید میکند.
برای مرور روند، به ویدئوی زیر از این پست توجه کنید.
این مفهوم برای اولین بار در سال ۲۰۱۶ در این مقاله استفاده شده است. توجه به خود نوع خاصی از دستهبندیهای مکانیزم توجه است که در ادامهی مطلب برای درک بهتر مدلهای تبدیلکننده یا transformer به آن نیاز خواهیم داشت.
هدف Self-Attention این است که ارتباط اجزای موجود در یک دنباله را با یکدیگر بسنجد تا بتواند برداشت درستتری از کل دنباله داشته باشد. تنها تفاوت این مکانیزم با توجه عادی این است که در توجه به خود، دنبالهی ورودی و خروجی یکسانند.
در تصویر زیر که از مقالهی گفتهشده برداشته شده است، ارتباط کلمه قرمز با کلمههای قبلی در جمله بررسی شده و شدت آبی بودن هر کلمه، میزان ارتباط را نشان میدهد.
مدلهای تبدیلکننده یا Transformer ها در سال ۲۰۱۷ در مقالهی «Attention is all you need» معرفی شدند. با معرفی ایدهی مدلهای تبدیلکننده، واحدهای بازگشتی حذف شدند تا بتوان مسائل توالی به توالی را تنها با استفاده از مکانیزم توجه حل کرد. در این صورت، این امکان برای ما فراهم میشود که اجزای مختلف توالی را به صورت همزمان (parallel) پردازش کنیم. برای درک بهتر این مدلها، در ادامه معماری آنها را بررسی خواهیم کرد.
در شکل زیر میتوانید معماری کلی شبکههای تبدیلکننده را مشاهده کنید. با توجه به این که این شبکه در ابتدا برای حل مسئلهی ترجمه ماشینی معرفی شد، در ادامهی این مطلب نیز برای درک بهتر فرض میکنیم که با همین مسئله مواجه هستیم و میخواهیم جملهای از زبان مبدا را به زبان مقصد ترجمه کنیم. حال میتوانیم به بیان جزئیات بیشتر دربارهی هر کدام از بخشهای ورودی شبکه، کدگذار، کدگشا و طبقهبند نهایی بپردازیم.
همانطور که میدانید، برای این که بتوانیم انواع دادههای مختلف را در شبکههای عصبی پردازش کنیم، باید آنها را به اعداد تبدیل کنیم. از این رو ابتدا نیاز است تا تعبیه یا embedding کلمات جمله در زبان مبدا را به دست آوریم.
همانطور که قبلا گفته شد، در مدلهای تبدیلکننده واحد بازگشتی نداریم و پردازش کلمات جملهی ورودی میتواند به صورت موازی انجام شود. از این رو لازم است تا جایگاه کلمه در جمله (Positional Encoding) نیز به عنوان ورودی به شبکه داده شود. برای این کار، وکتورهای جایگاه با استفاده از روابط زیر محاسبه میشوند و به تعبیه یا embedding کلمات اضافه میشوند.
با توجه به توابع فوق، برای محاسبه positional encoding کلماتی که در جایگاه زوج قرار دارند از تابع سینوس، و برای کلماتی که در جایگاه فرد قرار دارند از کسینوس استفاده میشود. میتوان تصور کرد که استفاده از توابع فوق، مانند این است که اعداد را به فرمت باینری در وکتور ذخیره کنیم، با این تفاوت که محدودیت عدد صحیح بودن را برداشتهایم و مجاز به استفاده از اعداد اعشاری نیز هستیم.
در نمودار زیر که از این مطلب برداشته شده است، محور افقی طول وکتور و محور عمودی جایگاههای مختلف را نشان میدهند. به بیان دیگر، هر سطر از این نمودار نشانگر بردار جایگاه به ازای جایگاههای متفاوت است. جهت مطالعه بیشتر در این مورد، میتوانید به همین مطلب مراجعه کنید.
با افزودن وکتورهای جایگاه کلمه به تعبیه یا embedding آنها، به ورودیهای شبکه کدگذار و کدگشا دست یافتهایم. در ادامه عملکرد بخش کدگذار یا Encoder را در شبکههای تبدیلکننده بررسی خواهیم کرد.
هدف شبکه کدگذار یا Encoder درک معنای جمله در زبان مبدا است. همانگونه که در شکل فوق مشاهده میکنید، این ماژول از دو بخش توجه چندسر یا Multi-head Attention و یک شبکهی پیشخور یا Feed Forward تشکیل شده است. در ادامهی مطلب، هر کدام از این المانها را بررسی خواهیم کرد.
توجه چندسر (Multi-Head Attention)
این نوع از مکانیزم توجه را میتوان تعمیمیافتهی نسخه قبلی آن دانست. در توجه چندسر ما با سه موجودیت مختلف به نام کلید (Key)، مقدار (Value) و پرسش (Query) سروکار داریم. در مبحث توجه گفتیم که هدف این کار، تعیین میزان ارتباط بین هر جزء جمله خروجی با تمامی اعضای جمله ورودی است. در نوع تعمیمیافتهی توجه، کلید و مقدار به ازای هر جزء رشته ورودی و پرسش به ازای اجزای جمله خروجی مشخص میشوند. برای درک بهتر، مثال زیر را درنظر بگیرید.
فرض کنید در یک سایت پخش فیلم به دنبال فیلم مشخصی هستید. برای پیدا کردن این فیلم عبارت خاصی را در سایت جستجو میکنید. این عبارت نقشی مانند query یا پرسش در مکانیزم توجه چندسر دارد. سایت برای پیدا کردن ویدیوی مورد نظر شما، عبارتی که جستجو کردهاید را با مواردی مانند عنوان و توضیحات ویدیوهای موجود مقایسه میکند و بعد از پیدا کردن شبیهترین عنوان، فیلم مرتبط به آن را برای شما پخش میکند. عنوان و توضیحات هر فیلم نقشی مانند کلید یا key و خود فیلم نقشی مانند مقدار یا value در مکانیزم توجه چندسر دارند.
اگر به شکل قبل توجه کنید، میبینید که هر سه ورودی این بلوک توجه از یک منبع که همان جملهی ورودی است میآیند، پس از نوع توجه به خود یا Self Attention است و هدف آن تعیین ارتباط و درک بهتر اجزای جملهی زبان مبدا به یکدیگر است. پیش از بررسی ادامهی روند مدل، لازم است تا الگوریتمی که در این نوع از مکانیزم توجه دنبال میشود را بررسی کنیم.
در مرحلهی اول، وکتور کلمات با گذر از سه لایهی پیشخور (feed-forward layer) با وزنهای متفاوت، وکتورهای K، V و Q را میسازند. سپس این وکتورها، وارد بلوک توجه مقیاسشدهی بر پایهی ضرب داخلی (Scaled Dot-Product Attention) میشوند. در این بخش، ابتدا ضرب داخلی وکتورهای Q و K محاسبه میشود تا مشخص شود این دو چقدر به هم شبیهند. سپس، با تقسیم امتیاز حاصل بر جذر طول رشتهی ورودی، امتیاز نرمال میشود تا از بروز مشکل انفجار گرادیان جلوگیری شود. سپس، با اعمال تابع softmax بر روی این مقادیر، وزن هر کدام از کلیدها برای هر پرسش (query) تعیین میشود. در نهایت، وزنهای محاسبهشده در مقدارهای (value) کلمات متفاوت ضرب میشوند تا خروجی مورد نظر تولید شود. این مراحل را میتوانید در تصویر سمت چپ در شکل بالا مشاهده کنید.
یادآوری
مقدار ضرب داخلی دو بردار با مقادیر یکسان ۱، ضرب داخلی دو بردار عمود ۰ و ضرب داخلی دو بردار خلاف جهت هم -۱ است. از این رو میتوان از ضرب داخلی دو وکتور به عنوان معیار شباهت آنها استفاده کرد.
شاید برایتان سوال شده باشد که چرا این مکانیزم توجه چندسر نام گرفته است. اگر به تصویر سمت راست در شکل بالا نگاه کنید، میبینید که تعدادی از بلوکها h بار تکرار شدهاند. در واقع کلمات به چندین لایهی پیشخور و بلوک توجه متفاوت داده میشوند که به مجموعه تمامی اینها یک سر (head) گفته میشود. انتظار میرود که هر سر به نکات متفاوتی توجه کند و مسائل متفاوتی را یاد بگیرد، که باعث افزایش قدرت نهایی ماژول کدگذار یا Encoder میشود. خروجی این بلوکها به هم الحاق میشوند و در نهایت توسط یک لایهی پیشخور (feed forward) پردازش میشوند.
خروجی بلوک توجه چند سر از طریق اتصالات اضافی (residual connection) به وکتورهای کلمات اصلی بعد از مرحلهی positional encoding اضافه میشوند و در نهایت بر روی حاصل این عملیات یک نرمالسازی لایهای اعمال میشود.
شبکهی پیشخور
پس از اتمام مراحل قبل، نتیجه برای پردازش بیشتر به یک شبکهی پیشخور داده میشود که متشکل از چندین لایه با تابع فعالساز ReLU میباشد. همچنین، مراحل استفاده از اتصالات اضافی (residual connection) و نرمالسازی نیز مجدد تکرار میشوند.
دو مرحلهی اصلی که گفته شد، در کنار هم ماژول کدگذار یا Encoder را در شبکههای تبدیلکننده ایجاد میکنند که هدفش کد کردن ورودی و اطلاعات توجه در وکتوری با مقادیر پیوسته است که به ماژول کدگشا یا decoder کمک میکند تا برای تولید هر کلمهی خروجی، به بخشهای درستی از جملهی ورودی نگاه کند. برای اثربخشی بیشتر، میتوان این ماژول را چندین مرحله تکرار کرد تا قدرت کدگذاری بیشتری پیدا کند.
هدف ماژول کدگشا یا Decoder تولید جملهی خروجی است. در هر گام زمانی، ماژول از خروجیهای قبلی کدگذار و کلماتی که در مراحل قبلی تولید شدهاند استفاده میکند تا کلمهی جدیدی تولید کند. این کار تا زمانی ادامه پیدا میکند که کلمهی <end> تولید شود که به معنای پایان جمله است.
المانهای تشکیلدهندهی این ماژول تقریبا مشابه ماژول کدگذار هستند ولی روند آن تفاوتهای اندکی دارد. ابتدا تعبیهی (embedding) کلماتی که قبلا تولید شدهاند استخراج میشود و مانند قبل وکتورهای جایگاه به آنها افزوده میشوند. سپس، ماژول کدگشا کار خود را آغاز میکند که مراحل آن به شرح زیر هستند.
توجه چند سر پوششی (Masked Multi-Head Attention)
در گام اول، مانند ماژول کدگذار یا encoder از یک بلوک توجه به خود (self-attention) استفاده میشود تا مدل بتواند تحلیل دقیقتری از جملهای که تاکنون تولید کرده است داشته باشد؛ اما روند کار آن تفاوت اندکی با دیگر توجههای چند سر در شبکههای تبدیلکننده دارد. با توجه به این که کدگشا یا decoder رشتهی خروجی را کلمه به کلمه تولید میکند، باید درنظر داشته باشیم که وزنهای توجه به گونهای نباشند که کلمات به واژههای بعد از خود توجه داشته باشند. به بیان دیگر، اگر مثال ابتدای مطلب را درنظر بگیریم، فرض کنید کلمات «گربه»، «موش» و «را» تولید شدهاند. توجه به خود یا Self-Attention باید درنظر داشته باشد که وزنهای توجه (attention weights) واژهی «موش» نباید به کلمهی «را» وابسته باشد.
برای این کار، در روند توجه مقیاسشدهی بر پایهی ضرب داخلی (Scaled Dot-Product Attention)، بعد از نرمال شدن امتیازها و قبل از اعمال تابع softmax، آن را با یک ماتریس اکیدا بالا مثلثی که مقادیر بالای قطر اصلی آن منفی بینهایت هستند جمع میکنیم. این کار باعث میشود که بعد از اعمال تابع softmax، مقدار وزن توجه هر کلمه به کلمههای بعد از خودش صفر شود. در شکل سمت چپ تصویر توجه چندسر، واحد Mask با این هدف گذاشته شده است.
توجه چندسر
پس از بلوک توجه به خود، لازم است که برای ترجمهی دقیقتر، مدل بخشهایی از جملهی ورودی را نیز مورد توجه قرار دهد. از این رو، در بلوک توجه بعدی، کلیدها و مقادیر (Keys & Values) به جای توجه چندسر قبلی، از خروجی ماژول کدگذار یا encoder میآیند.
شبکهی پیشخور
در نهایت، نتیجهی تمامی این مراحل جهت پردازش بیشتر به یک شبکهی پیشخور (feed-forward) داده میشود. توجه کنید که اتصالات اضافی (residual connection) و نرمالسازی لایهها در تمامی این مراحل نیز وجود دارند.
ماژول کدگشا یا decoder نیز میتوانند جهت افزایش قدرت مدل تبدیلکننده یا transformer، چندین مرحله تکرار شود. در این صورت، هر ماژول در روند خود از خروجی کدگشای قبلی و نتیجه نهایی ماژول کدگذار یا encoder استفاده میکند.
پس از از اتمام پردازشها در ماژول کدگشا یا decoder، خروجی به یک لایهی پیشخور یا feed-forward با تابع فعالساز softmax داده میشود تا کلمهی بعدی از رشتهی خروجی را پیشبینی کند. تعداد نورونهای این لایه به اندازهی تعداد کلمات موجود در دایره لغات یا vocabulary مدل است. همانطور که قبلا گفته شد، کلمهای که در هر گام زمانی تولید میشود به همراه کلمات قبلی مجدد به ماژول کدگشا یا decoder داده میشوند که از آنها برای تولید واژهی بعدی استفاده کند. این روند تا زمانی که کلمه <end> (که به معنای پایان جمله است) تولید شود ادامه پیدا میکند.
با توجه به تاثیرگذاری و اهمیت مدلهای تبدیلکننده یا transformer، در این پست به بررسی معماری و روند کار آنها پرداختیم. همچنین، جهت درک بهتر این مدلها، دربارهی مکانیزم توجه و نوع خاصی از آن به نام توجه به خود (Self-Attention) نیز بحث کردیم. مدلهای تبدیلکننده در حوزههای مختلفی کاربرد دارند و باعث پیشرفتهای چشمگیری در بسیاری از مسائل شدند. در پستهای بعدی، تلاش میکنیم تا کاربرد این مدلها را در حوزههای مختلف بررسی کنیم.
نویسنده: بهار برادران افتخاری
منابع: