رفتن به نوشته‌ها

مرتب‌سازی و باکت‌بندی Batchها در یادگیری ماشین

این چند وقت که دارم روی چالش kaggle تشخیص سوالات تکراری در کوئرا کار میکنم به مسائل مختلفی برخوردم  و یکی از آنها طول جملات در دادگان (دیتاست) و تاثیر آن روی دقت و عملکرد مدل است. در این تسک کوئرا، هدف تشخیص شباهت دو جمله است. یعنی دو جمله به ما میدن و میخوان میزان شباهت را حساب کنیم. مشکلی که وجود دارد این است که طول جملات بسیار متفاوت است. در این دادگان طول کمترین جمله ۱ و طول بیشترین جمله ۲۳۷ است. همانطور که می‌بینید اختلاف طول جملات خیلی زیاد است و در صورتی که ما طول جملات را برابر بیشترین طول جمله (یعنی ۲۳۷) در نظر بگیریم و طول جملاتی که کمتر از ۲۳۷ کلمه هستند را با padding پر کنیم از نظر زمان اجرا و حافظه اتلاف خواهیم داشت و از طرفی دیگر اگر طول جملات را در حد ۳۰ یا ۴۰ بگیریم و مابقی کلمات جمله را truncate کنیم ممکن است در جملات بلند اطلاعات مهمی را دور بریزیم.

نه فقط در این دادگان بلکه در خیلی از دادگان، طول جملات (یا به طور کلی متون) بسیار متفاوت است. از طرف دیگر ما اغلب در کارهای مرتبط با شبکه‌های عصبی، برای اینکه به صورت دسته‌ای شبکه را آموزش بدهیم مجبور هستیم یک طول ثابت درنظر میگیریم. مثلا در هنگام استفاده از شبکه‌های مختلف عصبی (بازگشتی، کانوولوشن و…) اینجوری رفتار می‌کنیم که طول جمله رو یک مقدار ثابت ۳۰ یا ۴۰ در نظر میگریم (بستگی به تسک هم دارد مثلا برای کار با سند این عدد رو ۱۰۰۰ میگیرند) و اونوقت اون رو به عنوان ورودی به شبکه میدهند. ثابت در نظر گرفتن طول همه جملات به یک شکل برای تمام جملات از نظر حافظه، زمان اجرا و عملکرد چندان جالب‌انگیز نیست! مثلا تصویر بالا رو نگاه کنید (مستطیل‌های رنگی طول جملات هستند) اگر در حالت عادی بخواهیم رفتار کنیم در هر دسته (batch) جملاتی قرار خواهند گرفت که طول‌های متفاوتی دارند که چندان جالب نیست و بهتر است چاره‌ای پیدا کنیم.

یکی از روش‌های متداول برای حل این مشکل باکت‌بندی است. یعنی چی؟

همانطور که می‌دونید ما معمولا برای آموزش شبکه‌های عصبی دادگان‌مون رو دسته‌بندی (batch) می‌کنیم تا از نظر سرعت و موازی‌سازی راحت‌تر باشند. ما معمولا در هر دسته (batch) چیزی در حدود ۸ الی ۱۰۲۴ تا نمونه قرار می‌دهیم. در حالت عادی ما هیچ کنترلی روی اینکه در هر دسته چه جملات قرار بگیرند نداریم ولی با اندکی پیش‌پردازش می‌تونیم این موضوع را بهتر کنیم. یعنی می‌تونیم جملات‌مون رو بر اساس طول جملات مرتب (sort) کنیم و تمام جملات که هم‌اندازه هستند را در یک دسته قرار بدهیم. بدین ترتیب تا حد زیادی زمان آموزش را کاهش خواهیم داد.

۱) اندازه دسته‌ها در ترجمه ماشین!

امروز به طور اتفاقی مقاله‌ای که اولین بار این موضوع را مطرح کرده است پیدا کردم که در این پست نکات مهم اش رو میگم شاید به کار شما هم آمد. یکی از نویسندگان مقاله آقای Neubig است که از اساتید برجسته در پردازش زبان طبیعی محسوب می‌شوند و بخاطر همین خواندن تمام مقاله خالی از لطف نیست.
An Empirical Study of Mini-Batch Creation Strategies for Neural Machine Translation

 

همانطور که از عنوان مقاله معلوم است این مقاله برای ترجمه ماشین نوشته شده و شاید اعداد و ارقامی که آورده شده است به درد تسک شما نخورد ولی ایده‌ای که مطرح شده است ارزش خوندش را دارد و با اعمال این تکنیک‌ها در کار خودتان عملکرد مدل‌تون را بهبود بدید. معمولا هایپرپارامترهای این شکلی مثل اندازه دسته‌ها (batch) که اغلب نادیده گرفته می‌شوند برای رسیدن به State of the art ضروری هستند و باید به دقت تنظیم می‌شوند.

مقاله ابتدا به توضیح انگیزه آن میپردازد که در بالا به آن اشاره کردیم (افزایش سرعت، موازی‌سازی بهتر). سپس به انواع تکنیک‌های که در ترجمه ماشین برای باکت‌بندی استفاده می‌شود پرداخته است:

  • باکت‌بندی بر اساس جمله مبدا (source)
  • باکت‌بندی بر اساس جمله مقصد (target)
  • باکت‌بندی بر اساس هر دو
  • باکت بندی بر اساس میانگین طول جملات در هر دسته

سپس با یک مثال از مدل معروف seq2seq به توضیح و ایده مقاله می‌پردازد (اگر از نوع شبکه سر در نمیارید هیچ اشکالی نداره). با یک مثال به تاثیر اضافه کردن padding می‌پردازد.فریم ورک انکدر دیکدر

قسمت مهم و اصلی مقاله ارزیابی‌های آن است که استراتژی‌های مختلف برای دسته‌بندی جملات مطرح شده است. ۵ روش مختلف مرتب‌سازی مطرح شده است که زمان اجرای آنها بسیار قابل ملاحظه است. همانطور که مشاهده می‌شود در صورتی که ما باکت‌هامون رو مرتب نکنیم (shuffle) تقریبا ۸ ساعت برای آموزش الگوریتم زمان صرف شده است ولی در صورتی که براساس طول جملات آنها (مبدا و مقصد) مرتب کنیم این زمان تقریبا به نصف کاهش می‌یابد.

همچنین تاثیر اندازه دسته‌ها مورد ارزیابی قرار گرفته است و دسته‌بندیهای مختلف با طول ۸ الی ۶۴ بررسی شده است. یک آزمایش هم با میانگین طول جملات انجام شده است (2055-1742 لغت).

اندازه دسته‌ها در شبکه عصبی

که اگر نتایج مقاله نشان میدهد طول دسته ۸ عملکرد ضعیفی داشته است و زمانی که طول دسته ۳۲ و ۶۴ انتخاب شده است بهترین نتایج به دست آمده است.

جزییات بیشتری در مقاله اشاره شده است که اگر دوست داشتید می‌تونید آن را مطالعه کنید ولی نکته اصلی مقاله که بخواهید ازش برداشت کنید این است که:

اندازه و نوع دسته‌بندی (batching) یک هایپر-پارامتر مهم است و در هنگام آموزش مدل باید به آن توجه کنیم.

 

۲) پیاده‌سازی باکت‌بندی در تنسورفلو

خوشبختانه باکت‌بندی در تنسورفلو وجود دارد و شما به راحتی با استفاده از تابع tf.data.experimental.group_by_window از آن استفاده کنید.

تیکه کد زیر با استفاده از tf.data نوشته شده است و روی یک دادگان ساختگی تست شده است. در این تیکه کد به ترتیب

  • ابتدا یک فایل CSV را با استفاده از کلاس CsvDataset میخونم.
  • بعد ترتیب ستون‌های فایل CSV را جابجا می‌کنم (ستون‌ دوم برچسب و ستون سوم جمله است که من ترتیب آنها را جابجا کردم).
  • برچسب‌ها را به فرمت مناسب (۰-۱) و سپس به تک روشن (one-hot) تبدیل کردم.
  • جملات را بر اساس اسپیس توکنایز کردم و سپس به هر کلمه به یک Id منحصر به فرد نگاشت می‌دهم.
  • طول هر جمله را به دست میارم (tf.size)
  • در نهایت با توجه به طول جملات و تابع group_by_window آن‌ها را باکت‌بندی میکنم.

(برای توضیحات بیشتر راجع tf.data به این آموزش و راجع قسمت پیش‌پردازش به ۳-۱ این آموزش مراجعه کنید).

کد کامل را می‌تونید در اینجا ملاحظه کنید. 

در صورتی که کد بالا اجرا کنید خروجی که بهتون خواهد داد به صورت زیر خواهد بود که ملاحظه می‌کنید در هر دسته جملاتی قرار گرفته‌اند که طول آنها یکسان (یا نزدیک به هم هستند) هستند:

شما هم اگر راجع به باکت‌بندی و اندازه دسته‌ها اطلاعاتی دارید خوشحال میشم از طریق کامنت با من به اشتراک بزارید.

منتشر شده در یادگیری عمیقیادگیری ماشین

اولین باشید که نظر می دهید

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *