Dropout در عمل
در بسیاری از معماریها لازم نیست dropout را در همه لایهها اعمال کنیم؛ اغلب اعمال آن فقط روی نورونهای یک تا سه لایه بالایی، بهجز لایه خروجی، کافی است.
یک جزئیات فنی مهم وجود دارد. فرض کنید نرخ dropout برابر p=75% باشد؛ در هر گام آموزش بهطور متوسط فقط ۲۵٪ نورونها فعالاند. پس هنگام inference که همه نورونها فعال هستند، هر نورون عملاً چهار برابر ورودی بیشتری نسبت به آموزش میبیند. برای جبران، در زمان آموزش activationهای باقیمانده بر 1−p تقسیم میشوند؛ این همان روش inverted dropout است که Keras بهصورت خودکار انجام میدهد.
لایه tf.keras.layers.Dropout هنگام آموزش بخشی از ورودیها را تصادفی صفر میکند و بقیه را بر keep probability تقسیم میکند. پس از آموزش هیچ تغییری روی ورودی نمیدهد:
model = tf.keras.Sequential([
tf.keras.layers.Flatten(input_shape=[28, 28]),
tf.keras.layers.Dropout(rate=0.2),
tf.keras.layers.Dense(100, activation="relu",
kernel_initializer="he_normal"),
tf.keras.layers.Dropout(rate=0.2),
tf.keras.layers.Dense(100, activation="relu",
kernel_initializer="he_normal"),
tf.keras.layers.Dropout(rate=0.2),
tf.keras.layers.Dense(10, activation="softmax")
])
# compile and train the model
اگر overfitting مشاهده شد، dropout rate را افزایش دهید؛ اگر مدل underfit است آن را کاهش دهید. برای لایههای بزرگ میتوان نرخ بیشتری و برای لایههای کوچک نرخ کمتری به کار برد. بسیاری از معماریهای پیشرفته فقط پس از آخرین لایه پنهان dropout دارند؛ اگر dropout در همه لایهها بیش از حد قوی است، این گزینه را امتحان کنید.
Dropout معمولاً همگرایی را کند میکند، اما اگر درست تنظیم شود اغلب مدل نهایی بهتری میدهد و مخصوصاً برای مدلهای بزرگ ارزش زمان اضافه را دارد. در شبکههای self-normalizing مبتنی بر SELU باید از AlphaDropout استفاده شود، زیرا dropout معمولی میانگین و انحراف معیار activationها را به هم میزند و self-normalization را میشکند.
Monte Carlo (MC) Dropout
پژوهش Yarin Gal و Zoubin Ghahramani در سال ۲۰۱۶ دو نکته مهم را درباره dropout برجسته کرد. نخست، رابطه ریاضی عمیقی بین شبکههای دارای Dropout و استنباط تقریبی بیزی وجود دارد. دوم، تکنیک MC Dropout میتواند بدون retrain کردن مدل dropout، هم عملکرد پیشبینی را بهتر کند و هم برآوردی مفیدتر از عدمقطعیت مدل بدهد.
کل ایده در چند خط پیاده میشود: هنگام inference، dropout را عمداً فعال نگه میداریم، چندین پیشبینی تصادفی میگیریم و میانگین آنها را محاسبه میکنیم:
import numpy as np
y_probas = np.stack([
model(X_test, training=True)
for sample in range(100)
])
y_proba = y_probas.mean(axis=0)
model(X) شبیه model.predict(X) است، اما tensor برمیگرداند و آرگومان training را میپذیرد. با training=True هر بار mask متفاوتی از dropout نمونهبرداری میشود، پس پیشبینیها کمی متفاوت خواهند بود. اگر test set دارای ۱۰٬۰۰۰ نمونه و ۱۰ کلاس باشد، هر پیشبینی شکل [10000, 10] دارد؛ با ۱۰۰ بار اجرا، y_probas شکل [100, 10000, 10] میگیرد. میانگین روی محور اول دوباره ماتریسی [10000, 10] میدهد.
برای نمونه اول Fashion MNIST، پیشبینی معمولی مدل چنین بود:
model.predict(X_test[:1]).round(3)
# array([[0. , 0. , 0. , 0. , 0. , 0.024, 0. , 0.132, 0. ,
# 0.844]], dtype=float32)
مدل با اطمینان ۸۴٫۴٪ کلاس ۹، یعنی ankle boot، را انتخاب میکرد. میانگین MC dropout اما چنین بود:
y_proba[0].round(3)
# array([0. , 0. , 0. , 0. , 0. , 0.067, 0. , 0.209, 0.001,
# 0.723], dtype=float32)
هنوز کلاس ۹ محتملترین است، اما اطمینان به ۷۲٫۳٪ کاهش یافته و احتمال کلاسهای ۵ و ۷، که آنها هم کفش هستند، بیشتر شده است. این برآورد محافظهکارانهتر میتواند در سیستمهای حساس به ریسک بسیار مهم باشد.
انحراف معیار پیشبینیهای Monte Carlo نیز مستقیماً عدمقطعیت را نشان میدهد:
y_std = y_probas.std(axis=0)
y_std[0].round(3)
# array([0. , 0. , 0. , 0.001, 0. , 0.096, 0. , 0.162, 0.001,
# 0.183], dtype=float32)
برای کلاس ۹، انحراف معیار ۰٫۱۸۳ در برابر احتمال میانگین ۰٫۷۲۳ قابل توجه است؛ در کاربرد پزشکی یا مالی چنین پیشبینیای باید با احتیاط بیشتری نسبت به یک «اطمینان ۸۴٫۴٪» ساده تفسیر شود. در مثال کتاب، accuracy نیز اندکی از ۸۷٫۰٪ به حدود ۸۷٫۲٪ افزایش یافت:
y_pred = y_proba.argmax(axis=1)
accuracy = (y_pred == y_test).sum() / len(y_test)
# 0.8717
تعداد نمونههای Monte Carlo یک ابرپارامتر است. افزایش آن برآورد احتمال و عدمقطعیت را دقیقتر میکند، اما زمان inference تقریباً به همان نسبت زیاد میشود و بعد از نقطهای سود اضافه بسیار کم است. بنابراین باید بین latency و دقت تعادل برقرار کرد.
MC Dropout در حضور لایههایی مثل BatchNormalization
اگر مدل لایههایی دارد که در training رفتار خاصی دارند، مانند BatchNormalization، فعالکردن training=True برای کل مدل مناسب نیست، چون BN نیز به حالت training میرود. در این حالت بهتر است Dropoutها را با کلاسی جایگزین کنیم که فقط خود dropout را همیشه فعال نگه دارد:
class MCDropout(tf.keras.layers.Dropout):
def call(self, inputs, training=False):
return super().call(inputs, training=True)
این کلاس از Dropout ارثبری میکند و در call() همیشه training=True را به parent میفرستد. برای AlphaDropout نیز میتوان کلاس مشابهی ساخت. اگر مدل از ابتدا ساخته میشود، کافی است بهجای Dropout از MCDropout استفاده شود؛ اگر مدل از قبل با Dropout آموزش دیده، باید معماری معادل با MCDropout ساخته و وزنهای مدل قبلی در آن کپی شوند.
در مجموع MC dropout هم میتواند خروجی مدلهای dropout را کمی بهبود دهد و هم تخمین احتمال و uncertainty قابل اتکاتری تولید کند؛ در زمان training نیز همان regularization معمول dropout را دارد.
Max-Norm Regularization
در max-norm regularization، برای هر نورون norm نوع ℓ2 بردار وزنهای ورودی محدود میشود:
||w||₂ ≤ r
r ابرپارامتر max-norm است. برخلاف ℓ1 و ℓ2 regularization، این روش term جدیدی به loss اضافه نمیکند. پس از هر training step، norm وزنها محاسبه میشود و اگر از r بیشتر باشد، وزنها rescale میشوند:
w ← w × r / ||w||₂
کاهش r regularization را قویتر میکند و میتواند overfitting و حتی ناپایداری گرادیان را کاهش دهد، بهخصوص اگر Batch Normalization استفاده نشده باشد.
dense = tf.keras.layers.Dense(
100, activation="relu", kernel_initializer="he_normal",
kernel_constraint=tf.keras.constraints.max_norm(1.))
بعد از هر iteration، fit() constraint را روی وزنها اعمال و وزن rescaleشده را جایگزین میکند. میتوان constraint سفارشی ساخت و برای bias نیز bias_constraint تعیین کرد. آرگومان axis در max_norm() بهطور پیشفرض ۰ است. چون وزن Dense معمولاً شکل [number of inputs, number of neurons] دارد، این مقدار constraint را برای بردار وزن هر نورون جداگانه اعمال میکند. در Conv layerها معمولاً باید axis مناسب، مثلاً [0, 1, 2]، انتخاب شود.
جمعبندی و راهنمای عملی
هیچ پیکربندی واحدی برای همه مسائل وجود ندارد، اما تنظیمات زیر در بسیاری از موارد بدون نیاز به tuning زیاد نقطه شروع خوبی هستند؛ اینها قانون قطعی نیستند.
جدول ۱۱-۳ - پیکربندی پیشفرض پیشنهادی برای DNN
| ابرپارامتر | مقدار پیشنهادی |
| Kernel initializer | He initialization |
| Activation | ReLU برای شبکه کمعمق؛ Swish برای شبکه عمیق |
| Normalization | برای کمعمق هیچ؛ برای عمیق Batch Normalization |
| Regularization | Early stopping؛ در صورت نیاز weight decay |
| Optimizer | Nesterov Accelerated Gradient یا AdamW |
| Learning-rate schedule | Performance scheduling یا 1cycle |
اگر شبکه فقط یک پشته ساده از Denseهاست و میتوان شرایط self-normalization را رعایت کرد، تنظیمات زیر مناسبترند:
جدول ۱۱-۴ - پیکربندی شبکه self-normalizing
| ابرپارامتر | مقدار پیشنهادی |
| Kernel initializer | LeCun initialization |
| Activation | SELU |
| Normalization | هیچ - self-normalization |
| Regularization | در صورت نیاز AlphaDropout |
| Optimizer | Nesterov Accelerated Gradient |
| Learning-rate schedule | Performance scheduling یا 1cycle |
ویژگیهای ورودی را فراموش نکنید که normalize شوند. اگر مدل pretrained مشابهی وجود دارد، reuse کردن آن را در اولویت قرار دهید؛ اگر داده بدون برچسب فراوان دارید، unsupervised pretraining را امتحان کنید؛ و اگر برای وظیفه مشابه داده برچسبخورده زیاد دارید، pretraining روی auxiliary task مفید است.
استثناهای مهم:
- برای مدل sparse، ℓ1 و در صورت نیاز TF-MOT pruning مفیدند؛ اما این کار self-normalization را میشکند.
- برای latency بسیار پایین، تعداد لایهها را کم کنید، activation سریع مثل ReLU یا Leaky ReLU به کار ببرید، BN را پس از آموزش با لایه قبلی fuse کنید، sparsity را افزایش دهید و در صورت نیاز precision را از float32 به ۱۶ یا ۸ بیت کاهش دهید.
- برای کاربرد حساس به ریسک، یا جایی که latency مهم نیست، MC dropout میتواند هم performance را بالا ببرد و هم probability و uncertainty قابل اتکاتری بدهد.
با این ابزارها آماده آموزش شبکههای بسیار عمیق هستیم. Keras برای طیف بزرگی از نیازها کافی است؛ اما گاهی کنترل بیشتری مانند loss سفارشی یا تغییر training algorithm لازم میشود. فصل بعد به API سطح پایین TensorFlow میرود.
تمرینها
- Glorot initialization و He initialization دقیقاً برای حل چه مشکلی طراحی شدهاند؟
- آیا اگر یک مقدار با He initialization تصادفی انتخاب شود، میتوان تمام وزنها را با همان مقدار یکسان مقداردهی کرد؟
- آیا مقداردهی biasها با صفر مجاز و منطقی است؟
- در چه شرایطی هرکدام از توابع فعالسازی بررسیشده در این فصل را انتخاب میکنید؟
- اگر هنگام استفاده از SGD مقدار momentum بیش از حد به ۱ نزدیک باشد، مثلاً ۰٫۹۹۹۹۹، چه اتفاقی ممکن است بیفتد؟
- سه روش برای تولید مدل sparse نام ببرید.
- آیا dropout آموزش را کند میکند؟ inference چطور؟ MC dropout چه اثری دارد؟
- روی dataset تصویری CIFAR-10 تمرین کنید:
- DNNای با ۲۰ لایه پنهان و ۱۰۰ نورون در هر لایه بسازید؛ عمداً بزرگ است. از He initialization و Swish استفاده کنید.
- با Nadam و early stopping شبکه را آموزش دهید. CIFAR-10 شامل ۶۰٬۰۰۰ تصویر رنگی ۳۲×۳۲ در ۱۰ کلاس است؛ ۵۰٬۰۰۰ آموزش و ۱۰٬۰۰۰ آزمون. خروجی softmax با ۱۰ نورون لازم است. پس از هر تغییر معماری یا ابرپارامتر، learning rate مناسب را دوباره پیدا کنید.
- Batch Normalization اضافه کنید و learning curveها، سرعت همگرایی، کیفیت مدل و سرعت هر epoch را با قبل مقایسه کنید.
- BN را با SELU جایگزین کنید و شرایط self-normalization را رعایت کنید: استانداردسازی ورودی، LeCun normal، فقط زنجیره Dense و سایر محدودیتها.
- مدل را با AlphaDropout regularize کنید؛ سپس بدون retrain بررسی کنید MC dropout دقت بهتری میدهد یا نه.
- مدل را با 1cycle scheduling دوباره آموزش دهید و اثر آن بر سرعت و accuracy را بسنجید.
راهحل تمرینها در notebook فصل کتاب ارائه شده است.
این ترجمه برای استفادهٔ آموزشی تهیه شده است. انتشار عمومی، فروش یا بازنشر آن باید با رعایت حقوق مؤلف و ناشر و اخذ مجوزهای لازم انجام شود.