چگونه دیتاست های نامتوازن را در یادگیری عمیق مدیریت کنیم؟
چرا ما بیشتر تمایل داریم تا دادههای متوازن داشته باشیم؟
در نگاه اول، به نظر میرسد که متوازنکردن دادهها میتواند نقش سودمندی داشته باشد. اما شاید علاقه چندانی به آن دستههای اقلیت نداشته باشیم. یا شاید هدف اصلیمان این است که بالاترین درصد دقت را رقم بزنیم. در این صورت، متوازن کردن دادهها منطقی نیست زیرا دستههایی که نمونههای آموزشی بیشتری داشته باشند، میزان دقت را بالا خواهند برد.
در ثانی، توابع آنتروپی متقاطع categorical crossentropy losses در شرایطی بهترین عملکردشان را دارند که بالاترین درصد دقت را به دست آورند؛ حتی زمانی که دیتاست های نامتوازن باشد. روی هم رفته، دستههای اقلیتمان نقش قابل توجهی در تحقق هدف اصلیمان ندارد؛ بنابراین، متوازن کردن ضرورت چندانی ندارد. با توجه به همه مطالبی که تا به اینجا ذکر شد، اگر با موردی مواجه شویم که نیاز باشد دادههایمان را متوازن کنیم، میتوانیم از دو روش برای تحقق هدفمان استفاده کنیم.
روش «متوازن کردن وزن» Weight balancing
روش «متوازن کردن وزن» با تغییر وزنهای هر نمونه آموزشی سعی در متوازن کردنِ دادهها دارد. در حالت عادی، هر نمونه و دسته در تابع زیان loss function وزن یکسانی خواهد داشت. اما اگر برخی دستهها یا نمونههای آموزشی اهمیت بیشتری داشته باشند، وزن بیشتری خواهند داشت. بگذارید یک بار دیگر به مثال فوق در رابطه با خرید مسکن اشاره کنیم.
به دلیل اینکه دقتِ دستۀ «خرید» برایمان اهمیت دارد، انتظار میرود نمونههای آموزشیِ آن دسته تاثیر بسزایی بر تابع زیان داشته باشند.
با ضرب زیان هر نمونه به ضریبی معین (بسته به دستهها)، میتوان به دستهها وزن داد. میتوان در Keras اقدام به چنین کاری کرد:
import keras class_weight = {"buy": 0.75, "don't buy": 0.25} model.fit(X_train, https://hooshio.com/%da%86%da%af%d9%88%d9%86%d9%87-%d8%af%db%8c%d8%aa%d8%a7%d8%b3%d8%aa-%d9%87%d8%a7%db%8c-%d9%86%d8%a7%d9%85%d8%aa%d9%88%d8%a7%d8%b2%d9%86-%d8%b1%d8%a7-%d8%af%d8%b1-%db%8c%d8%a7%d8%af%da%af%db%8c%d8%b1/Y_train, epochs=10, batch_size=32, class_weight=class_weight)
در کد بالا در متغیری که تحت عنوان class_weight تعریف کردیم ، دستۀ «خرید» باید 75 درصد از وزنِ تابع زیان را داشته باشد چرا که اهمیت بیشتری دارد. دستۀ «عدم خرید» نیز باید 25 درصد باقیمانده را به خود اختصاص دهد. البته امکان دستکاری و تغییر این مقادیر برای ایجاد مناسبترین شرایط وجود دارد. اگر یکی از دستههایمان نمونههای بیشتری از دیگری داشته باشد، میتوانیم از این روش متوازنسازی استفاده کنیم. به جای اینکه زمان و منابع خود را به جمعآوری بیشتر دستههای اقلیت اختصاص دهیم، میتوانیم شرایطی را رقم بزنیم که طی آن، روش متوازنسازی وزن همه دستهها را وادار کند به میزان یکسان در تابع زیان نقش داشته باشند.
یکی دیگر از روشها برای متوازن کردن وزن نمونههای آموزشی، «زیان کانونی» Focal Loss نام دارد. بیایید جزئیات کار را با هم بررسی کنیم: ما در دیتاستمان چند نمونه آموزشی داریم که دستهبندی راحتتری در مقایسه با بقیه دارند. در طی فرایند آموزش، این نمونهها با 99 درصد دقت دستهبندی خواهند شد، اما شاید نمونههای دیگر عملکرد بسیار ضعیفی داشته باشند. مشکل این است که آن دسته از نمونههای آموزشی که به راحتی دستهبندی شدهاند، کماکان در تابع زیان به ایفای نقش میپردازند. اگر دادههای چالشبرانگیز بسیاری وجود دارد که در صورت دستهبندی درست میتوانند دقت کار را تا حد زیادی بالا ببرند، چرا باید وزن برابری به آنها بدهیم؟
«زیان کانونی» دقیقاً برای حل چنین مسئلهای در نظر گرفته شده است. زیان کانونی به جای اینکه وزن برابری به همه نمونههای آموزشی دهد، وزن نمونههای دستهبندی شده با دقت بالا (داده هایی که دسته بندی شان به راحتی برای شبکه امکان پذیر است) را کاهش میدهد. پس دادههایی که دستهبندی آنها به سختی انجام میشود، مورد تاکید قرار میگیرند.
در عمل، وقتی با عدم توازن دادهها روبرو هستیم، دسته اکثریتمان به سرعت دستهبندی میشود زیرا دادههای زیادی برای آن داریم. بنابراین، برای اینکه مطمئن شویم دقت بالایی در دسته اقلیت حاصل میآید، میتوانیم از تابع زیان استفاده کنیم تا وزن بیشتری به نمونه دستههای اقلیت داده شود. تابع زیان میتواند به راحتی در Keras به اجرا درآید.
import keras from keras import backend as K import tensorflow as tf # Define our custom loss function def focal_loss(y_true, y_pred): gamma = 2.0, alpha = 0.25https://hooshio.com/%da%86%da%af%d9%88%d9%86%d9%87-%d8%af%db%8c%d8%aa%d8%a7%d8%b3%d8%aa-%d9%87%d8%a7%db%8c-%d9%86%d8%a7%d9%85%d8%aa%d9%88%d8%a7%d8%b2%d9%86-%d8%b1%d8%a7-%d8%af%d8%b1-%db%8c%d8%a7%d8%af%da%af%db%8c%d8%b1/ pt_1 = tf.where(tf.equal(y_true, 1), y_pred, tf.ones_like(y_pred)) pt_0 = tf.where(tf.equal(y_true, 0), y_pred, tf.zeros_like(y_pred)) return -K.sum(alpha * K.pow(1. - pt_1, gamma) * K.log(pt_1))-K.sum((1-alpha) * K.pow( pt_0, gamma) * K.log(1. - pt_0)) # Compile our model adam = Adam(lr=0.0001) model.compile(loss=[focal_loss], metrics=["accuracy"], optimizer=adam)
روشهای نمونهگیری Over-sampling و Under-sampling
انتخاب وزن دسته مناسب از جمله کارهای پیچیده است. فرایند «فراوانی معکوس» inverse-frequency همیشه جوابگو نیست. زیان کانونی میتواند مفید واقع شود، اما حتی این راهکار نیز باعث خواهد شد همه نمونههایی که به خوبی دستهبندی شدهاند، با کاهش وزن روبرو شوند. از این رو، یکی دیگر از روشهای برقراری توازن در دادهها، انجام مستقیمِ آن از طریق نمونهگیری است. به تصویر زیر توجه داشته باشید.
در سمت چپ و راست تصویر فوق، دسته آبی نمونههای بیشتری نسبت به دسته نارنجی دارد. در این مورد، دو گزینه پیشپردازش PreProcess وجود دارد که میتواند به آموزش مدلهای یادگیری ماشین کمک کند. روش Under-sampling بدین معناست که تنها بخشی از دادهها را از دسته اکثریت انتخاب میکنیم. این گزینش باید برای حفظ توزیع احتمال دسته انجام شود. چقدر راحت! نمونههای کمتر باعث میشود دیتاست متوازن گردد. روش Oversampling هم به این معناست که نسخههایی از دسته اقلیت ایجاد خواهد شد. هدف از این کار، ایجاد تساویِ تعداد نمونه دستههای اقلیت با اکثریت است. ما موفق شدیم دیتاست های نامتوازن را بدون کسب دادههای بیشتر متوازن کنیم!