overfit و underfit

عرض على TensorFlow.org تشغيل في Google Colab عرض المصدر على جيثب تحميل دفتر

كما هو الحال دائمًا ، ستستخدم الكود في هذا المثال واجهة برمجة تطبيقات tf.keras ، والتي يمكنك معرفة المزيد عنها في دليل TensorFlow Keras .

في كلا المثالين السابقين - تصنيف النص والتنبؤ بكفاءة استهلاك الوقود - رأينا أن دقة نموذجنا في بيانات التحقق من الصحة ستبلغ ذروتها بعد التدريب لعدد من الفترات ، ثم ستظل راكدة أو تبدأ في التناقص.

بعبارة أخرى ، فإن نموذجنا سيتناسب مع بيانات التدريب. تعلم كيفية التعامل مع فرط التجهيز مهم. على الرغم من أنه من الممكن غالبًا تحقيق دقة عالية في مجموعة التدريب ، فإن ما نريده حقًا هو تطوير نماذج تُعمم جيدًا على مجموعة اختبار (أو بيانات لم يروها من قبل).

عكس فرط التجهيز . يحدث النقص في الملاءمة عندما لا يزال هناك مجال لتحسين بيانات القطار. يمكن أن يحدث هذا لعدد من الأسباب: إذا لم يكن النموذج قويًا بما يكفي ، أو مفرط التنظيم ، أو ببساطة لم يتم تدريبه لفترة كافية. هذا يعني أن الشبكة لم تتعلم الأنماط ذات الصلة في بيانات التدريب.

إذا كنت تتدرب لفترة طويلة جدًا ، فسيبدأ النموذج في التجهيز الزائد ويتعلم أنماطًا من بيانات التدريب التي لا يتم تعميمها على بيانات الاختبار. نحن بحاجة إلى تحقيق التوازن. يعد فهم كيفية التدريب لعدد مناسب من الحقب كما سنستكشف أدناه مهارة مفيدة.

لمنع فرط التخصيص ، فإن أفضل حل هو استخدام بيانات تدريب أكثر اكتمالاً. يجب أن تغطي مجموعة البيانات النطاق الكامل للمدخلات التي من المتوقع أن يتعامل معها النموذج. قد تكون البيانات الإضافية مفيدة فقط إذا كانت تغطي حالات جديدة ومثيرة للاهتمام.

النموذج الذي يتم تدريبه على بيانات أكثر اكتمالاً سيعمم بشكل أفضل بشكل طبيعي. عندما لا يكون ذلك ممكنًا ، فإن أفضل حل تالي هو استخدام تقنيات مثل التنظيم. تضع هذه القيود قيودًا على كمية ونوع المعلومات التي يمكن أن يخزنها نموذجك. إذا كانت الشبكة تستطيع فقط حفظ عدد صغير من الأنماط ، فإن عملية التحسين ستجبرها على التركيز على الأنماط الأكثر بروزًا ، والتي لديها فرصة أفضل للتعميم بشكل جيد.

في هذا الكمبيوتر الدفتري ، سوف نستكشف العديد من تقنيات التنظيم الشائعة ، ونستخدمها لتحسين نموذج التصنيف.

يثبت

قبل البدء ، قم باستيراد الحزم الضرورية:

import tensorflow as tf

from tensorflow.keras import layers
from tensorflow.keras import regularizers

print(tf.__version__)
2.8.0-rc1
!pip install git+https://github.com/tensorflow/docs

import tensorflow_docs as tfdocs
import tensorflow_docs.modeling
import tensorflow_docs.plots
from  IPython import display
from matplotlib import pyplot as plt

import numpy as np

import pathlib
import shutil
import tempfile
logdir = pathlib.Path(tempfile.mkdtemp())/"tensorboard_logs"
shutil.rmtree(logdir, ignore_errors=True)

مجموعة بيانات هيجز

الهدف من هذا البرنامج التعليمي ليس القيام بفيزياء الجسيمات ، لذلك لا تسهب في تفاصيل مجموعة البيانات. يحتوي على 11000000 مثال ، لكل منها 28 ميزة ، وتسمية فئة ثنائية.

gz = tf.keras.utils.get_file('HIGGS.csv.gz', 'http://mlphysics.ics.uci.edu/data/higgs/HIGGS.csv.gz')
Downloading data from http://mlphysics.ics.uci.edu/data/higgs/HIGGS.csv.gz
2816409600/2816407858 [==============================] - 123s 0us/step
2816417792/2816407858 [==============================] - 123s 0us/step
FEATURES = 28

يمكن استخدام فئة tf.data.experimental.CsvDataset لقراءة تسجيلات csv مباشرة من ملف gzip بدون خطوة ضغط وسيطة.

ds = tf.data.experimental.CsvDataset(gz,[float(),]*(FEATURES+1), compression_type="GZIP")

تقوم فئة قارئ csv بإرجاع قائمة بالمقاسات لكل سجل. تعيد الوظيفة التالية حزم قائمة الحجميات تلك في زوج (feature_vector ، label).

def pack_row(*row):
  label = row[0]
  features = tf.stack(row[1:],1)
  return features, label

TensorFlow هو الأكثر كفاءة عند العمل على دفعات كبيرة من البيانات.

لذا بدلاً من إعادة حزم كل صف على حدة ، قم بإنشاء مجموعة بيانات جديدة تأخذ دفعات من 10000 مثال ، pack_row Dataset كل دفعة ، ثم قم بتقسيم الدُفعات احتياطيًا إلى سجلات فردية:

packed_ds = ds.batch(10000).map(pack_row).unbatch()

ألق نظرة على بعض السجلات من هذا packed_ds .

لم يتم تطبيع الميزات تمامًا ، لكن هذا يكفي لهذا البرنامج التعليمي.

for features,label in packed_ds.batch(1000).take(1):
  print(features[0])
  plt.hist(features.numpy().flatten(), bins = 101)
tf.Tensor(
[ 0.8692932  -0.6350818   0.22569026  0.32747006 -0.6899932   0.75420225
 -0.24857314 -1.0920639   0.          1.3749921  -0.6536742   0.9303491
  1.1074361   1.1389043  -1.5781983  -1.0469854   0.          0.65792954
 -0.01045457 -0.04576717  3.1019614   1.35376     0.9795631   0.97807616
  0.92000484  0.72165745  0.98875093  0.87667835], shape=(28,), dtype=float32)

بي إن جي

للحفاظ على هذا البرنامج التعليمي قصيرًا نسبيًا ، استخدم فقط أول 1000 عينة للتحقق من صحتها ، و 10000 عينة التالية للتدريب:

N_VALIDATION = int(1e3)
N_TRAIN = int(1e4)
BUFFER_SIZE = int(1e4)
BATCH_SIZE = 500
STEPS_PER_EPOCH = N_TRAIN//BATCH_SIZE

Dataset.skip و Dataset.take هذا الأمر سهلاً.

في الوقت نفسه ، استخدم طريقة Dataset.cache للتأكد من أن المُحمل لا يحتاج إلى إعادة قراءة البيانات من الملف في كل فترة:

validate_ds = packed_ds.take(N_VALIDATION).cache()
train_ds = packed_ds.skip(N_VALIDATION).take(N_TRAIN).cache()
train_ds
<CacheDataset element_spec=(TensorSpec(shape=(28,), dtype=tf.float32, name=None), TensorSpec(shape=(), dtype=tf.float32, name=None))>

مجموعات البيانات هذه تعرض أمثلة فردية. استخدم طريقة .batch لإنشاء مجموعات ذات حجم مناسب للتدريب. قبل التجميع ، تذكر أيضًا .shuffle .repeat التدريب و.

validate_ds = validate_ds.batch(BATCH_SIZE)
train_ds = train_ds.shuffle(BUFFER_SIZE).repeat().batch(BATCH_SIZE)

أظهر التجهيز الزائد

إن أبسط طريقة لمنع فرط التخصيص هي البدء بنموذج صغير: نموذج يحتوي على عدد صغير من المعلمات القابلة للتعلم (والتي يتم تحديدها من خلال عدد الطبقات وعدد الوحدات لكل طبقة). في التعلم العميق ، غالبًا ما يشار إلى عدد المعلمات القابلة للتعلم في نموذج باسم "قدرة" النموذج.

حدسيًا ، سيكون للنموذج الذي يحتوي على المزيد من المعلمات "قدرة حفظ" أكبر وبالتالي سيكون قادرًا على تعلم رسم خرائط مثالي يشبه القاموس بين عينات التدريب وأهدافها ، ورسم خرائط بدون أي قوة تعميم ، ولكن هذا سيكون عديم الفائدة عند عمل التنبؤات على بيانات غير مرئية من قبل.

ضع هذا في اعتبارك دائمًا: تميل نماذج التعلم العميق إلى أن تكون جيدة في ملاءمة بيانات التدريب ، لكن التحدي الحقيقي هو التعميم وليس الملاءمة.

من ناحية أخرى ، إذا كانت الشبكة لديها موارد حفظ محدودة ، فلن تكون قادرة على تعلم التعيين بسهولة. لتقليل فقدها ، سيتعين عليها تعلم التمثيلات المضغوطة التي تتمتع بقدرة أكبر على التنبؤ. في الوقت نفسه ، إذا جعلت نموذجك صغيرًا جدًا ، فسيواجه صعوبة في ملاءمته لبيانات التدريب. هناك توازن بين "السعة الزائدة عن الحد" و "السعة غير الكافية".

لسوء الحظ ، لا توجد صيغة سحرية لتحديد الحجم أو البنية المناسبة للنموذج الخاص بك (من حيث عدد الطبقات ، أو الحجم المناسب لكل طبقة). سيكون عليك تجربة استخدام سلسلة من البنى المختلفة.

للعثور على حجم نموذج مناسب ، من الأفضل البدء بعدد قليل نسبيًا من الطبقات والمعلمات ، ثم البدء في زيادة حجم الطبقات أو إضافة طبقات جديدة حتى ترى عوائد متناقصة على فقدان التحقق من الصحة.

ابدأ بنموذج بسيط باستخدام الطبقات فقط ، ثم layers.Dense كخط أساس ، ثم قم بإنشاء إصدارات أكبر ، وقارن بينها.

إجراءات التدريب

تتدرب العديد من النماذج بشكل أفضل إذا قمت بتقليل معدل التعلم تدريجيًا أثناء التدريب. استخدم optimizers.schedules لتقليل معدل التعلم بمرور الوقت:

lr_schedule = tf.keras.optimizers.schedules.InverseTimeDecay(
  0.001,
  decay_steps=STEPS_PER_EPOCH*1000,
  decay_rate=1,
  staircase=False)

def get_optimizer():
  return tf.keras.optimizers.Adam(lr_schedule)

يحدد الكود أعلاه schedules.InverseTimeDecay . InverseTimeDecay لخفض معدل التعلم بشكل قطعي إلى 1/2 من المعدل الأساسي عند 1000 عصر ، و 1/3 في 2000 عصر وما إلى ذلك.

step = np.linspace(0,100000)
lr = lr_schedule(step)
plt.figure(figsize = (8,6))
plt.plot(step/STEPS_PER_EPOCH, lr)
plt.ylim([0,max(plt.ylim())])
plt.xlabel('Epoch')
_ = plt.ylabel('Learning Rate')

بي إن جي

سيستخدم كل نموذج في هذا البرنامج التعليمي نفس تكوين التدريب. لذا قم بإعداد هذه بطريقة قابلة لإعادة الاستخدام ، بدءًا من قائمة عمليات الاسترجاعات.

يمتد التدريب على هذا البرنامج التعليمي لعدة فترات قصيرة. لتقليل ضوضاء التسجيل ، استخدم tfdocs.EpochDots الذي يقوم ببساطة بطباعة ملف . لكل حقبة ، ومجموعة كاملة من المقاييس كل 100 عصر.

بعد ذلك ، قم بتضمين callbacks.EarlyStopping . التوقف المبكر لتجنب أوقات التدريب الطويلة وغير الضرورية. لاحظ أن رد الاتصال هذا مضبوط على مراقبة val_binary_crossentropy ، وليس val_loss . سيكون هذا الاختلاف مهمًا لاحقًا.

استخدم callbacks.TensorBoard . لوحة التنسور لإنشاء سجلات TensorBoard للتدريب.

def get_callbacks(name):
  return [
    tfdocs.modeling.EpochDots(),
    tf.keras.callbacks.EarlyStopping(monitor='val_binary_crossentropy', patience=200),
    tf.keras.callbacks.TensorBoard(logdir/name),
  ]

وبالمثل ، سيستخدم كل نموذج نفس إعدادات Model.compile و Model.fit :

def compile_and_fit(model, name, optimizer=None, max_epochs=10000):
  if optimizer is None:
    optimizer = get_optimizer()
  model.compile(optimizer=optimizer,
                loss=tf.keras.losses.BinaryCrossentropy(from_logits=True),
                metrics=[
                  tf.keras.losses.BinaryCrossentropy(
                      from_logits=True, name='binary_crossentropy'),
                  'accuracy'])

  model.summary()

  history = model.fit(
    train_ds,
    steps_per_epoch = STEPS_PER_EPOCH,
    epochs=max_epochs,
    validation_data=validate_ds,
    callbacks=get_callbacks(name),
    verbose=0)
  return history

نموذج صغير

ابدأ بتدريب نموذج:

tiny_model = tf.keras.Sequential([
    layers.Dense(16, activation='elu', input_shape=(FEATURES,)),
    layers.Dense(1)
])
size_histories = {}
size_histories['Tiny'] = compile_and_fit(tiny_model, 'sizes/Tiny')
Model: "sequential"
_________________________________________________________________
 Layer (type)                Output Shape              Param #   
=================================================================
 dense (Dense)               (None, 16)                464       
                                                                 
 dense_1 (Dense)             (None, 1)                 17        
                                                                 
=================================================================
Total params: 481
Trainable params: 481
Non-trainable params: 0
_________________________________________________________________

Epoch: 0, accuracy:0.4961,  binary_crossentropy:0.7294,  loss:0.7294,  val_accuracy:0.4840,  val_binary_crossentropy:0.7200,  val_loss:0.7200,  
....................................................................................................
Epoch: 100, accuracy:0.5931,  binary_crossentropy:0.6279,  loss:0.6279,  val_accuracy:0.5860,  val_binary_crossentropy:0.6288,  val_loss:0.6288,  
....................................................................................................
Epoch: 200, accuracy:0.6157,  binary_crossentropy:0.6178,  loss:0.6178,  val_accuracy:0.6200,  val_binary_crossentropy:0.6134,  val_loss:0.6134,  
....................................................................................................
Epoch: 300, accuracy:0.6370,  binary_crossentropy:0.6086,  loss:0.6086,  val_accuracy:0.6220,  val_binary_crossentropy:0.6055,  val_loss:0.6055,  
....................................................................................................
Epoch: 400, accuracy:0.6522,  binary_crossentropy:0.6008,  loss:0.6008,  val_accuracy:0.6260,  val_binary_crossentropy:0.5997,  val_loss:0.5997,  
....................................................................................................
Epoch: 500, accuracy:0.6513,  binary_crossentropy:0.5946,  loss:0.5946,  val_accuracy:0.6480,  val_binary_crossentropy:0.5911,  val_loss:0.5911,  
....................................................................................................
Epoch: 600, accuracy:0.6636,  binary_crossentropy:0.5894,  loss:0.5894,  val_accuracy:0.6390,  val_binary_crossentropy:0.5898,  val_loss:0.5898,  
....................................................................................................
Epoch: 700, accuracy:0.6696,  binary_crossentropy:0.5852,  loss:0.5852,  val_accuracy:0.6530,  val_binary_crossentropy:0.5870,  val_loss:0.5870,  
....................................................................................................
Epoch: 800, accuracy:0.6706,  binary_crossentropy:0.5824,  loss:0.5824,  val_accuracy:0.6590,  val_binary_crossentropy:0.5850,  val_loss:0.5850,  
....................................................................................................
Epoch: 900, accuracy:0.6709,  binary_crossentropy:0.5796,  loss:0.5796,  val_accuracy:0.6680,  val_binary_crossentropy:0.5831,  val_loss:0.5831,  
....................................................................................................
Epoch: 1000, accuracy:0.6780,  binary_crossentropy:0.5769,  loss:0.5769,  val_accuracy:0.6530,  val_binary_crossentropy:0.5851,  val_loss:0.5851,  
....................................................................................................
Epoch: 1100, accuracy:0.6735,  binary_crossentropy:0.5752,  loss:0.5752,  val_accuracy:0.6620,  val_binary_crossentropy:0.5807,  val_loss:0.5807,  
....................................................................................................
Epoch: 1200, accuracy:0.6759,  binary_crossentropy:0.5729,  loss:0.5729,  val_accuracy:0.6620,  val_binary_crossentropy:0.5792,  val_loss:0.5792,  
....................................................................................................
Epoch: 1300, accuracy:0.6849,  binary_crossentropy:0.5716,  loss:0.5716,  val_accuracy:0.6450,  val_binary_crossentropy:0.5859,  val_loss:0.5859,  
....................................................................................................
Epoch: 1400, accuracy:0.6790,  binary_crossentropy:0.5695,  loss:0.5695,  val_accuracy:0.6700,  val_binary_crossentropy:0.5776,  val_loss:0.5776,  
....................................................................................................
Epoch: 1500, accuracy:0.6824,  binary_crossentropy:0.5681,  loss:0.5681,  val_accuracy:0.6730,  val_binary_crossentropy:0.5761,  val_loss:0.5761,  
....................................................................................................
Epoch: 1600, accuracy:0.6828,  binary_crossentropy:0.5669,  loss:0.5669,  val_accuracy:0.6690,  val_binary_crossentropy:0.5766,  val_loss:0.5766,  
....................................................................................................
Epoch: 1700, accuracy:0.6874,  binary_crossentropy:0.5657,  loss:0.5657,  val_accuracy:0.6600,  val_binary_crossentropy:0.5774,  val_loss:0.5774,  
....................................................................................................
Epoch: 1800, accuracy:0.6845,  binary_crossentropy:0.5655,  loss:0.5655,  val_accuracy:0.6780,  val_binary_crossentropy:0.5752,  val_loss:0.5752,  
....................................................................................................
Epoch: 1900, accuracy:0.6837,  binary_crossentropy:0.5644,  loss:0.5644,  val_accuracy:0.6790,  val_binary_crossentropy:0.5753,  val_loss:0.5753,  
....................................................................................................
Epoch: 2000, accuracy:0.6853,  binary_crossentropy:0.5632,  loss:0.5632,  val_accuracy:0.6780,  val_binary_crossentropy:0.5753,  val_loss:0.5753,  
....................................................................................................
Epoch: 2100, accuracy:0.6871,  binary_crossentropy:0.5625,  loss:0.5625,  val_accuracy:0.6670,  val_binary_crossentropy:0.5769,  val_loss:0.5769,  
...................................

تحقق الآن من كيفية عمل النموذج:

plotter = tfdocs.plots.HistoryPlotter(metric = 'binary_crossentropy', smoothing_std=10)
plotter.plot(size_histories)
plt.ylim([0.5, 0.7])
(0.5, 0.7)

بي إن جي

نموذج صغير

لمعرفة ما إذا كان بإمكانك التغلب على أداء النموذج الصغير ، تدرب تدريجيًا على بعض الطرز الأكبر حجمًا.

جرب طبقتين مخفيتين كل منهما 16 وحدة:

small_model = tf.keras.Sequential([
    # `input_shape` is only required here so that `.summary` works.
    layers.Dense(16, activation='elu', input_shape=(FEATURES,)),
    layers.Dense(16, activation='elu'),
    layers.Dense(1)
])
size_histories['Small'] = compile_and_fit(small_model, 'sizes/Small')
Model: "sequential_1"
_________________________________________________________________
 Layer (type)                Output Shape              Param #   
=================================================================
 dense_2 (Dense)             (None, 16)                464       
                                                                 
 dense_3 (Dense)             (None, 16)                272       
                                                                 
 dense_4 (Dense)             (None, 1)                 17        
                                                                 
=================================================================
Total params: 753
Trainable params: 753
Non-trainable params: 0
_________________________________________________________________

Epoch: 0, accuracy:0.4864,  binary_crossentropy:0.7769,  loss:0.7769,  val_accuracy:0.4930,  val_binary_crossentropy:0.7211,  val_loss:0.7211,  
....................................................................................................
Epoch: 100, accuracy:0.6386,  binary_crossentropy:0.6052,  loss:0.6052,  val_accuracy:0.6020,  val_binary_crossentropy:0.6177,  val_loss:0.6177,  
....................................................................................................
Epoch: 200, accuracy:0.6697,  binary_crossentropy:0.5829,  loss:0.5829,  val_accuracy:0.6310,  val_binary_crossentropy:0.6018,  val_loss:0.6018,  
....................................................................................................
Epoch: 300, accuracy:0.6838,  binary_crossentropy:0.5721,  loss:0.5721,  val_accuracy:0.6490,  val_binary_crossentropy:0.5940,  val_loss:0.5940,  
....................................................................................................
Epoch: 400, accuracy:0.6911,  binary_crossentropy:0.5656,  loss:0.5656,  val_accuracy:0.6430,  val_binary_crossentropy:0.5985,  val_loss:0.5985,  
....................................................................................................
Epoch: 500, accuracy:0.6930,  binary_crossentropy:0.5607,  loss:0.5607,  val_accuracy:0.6430,  val_binary_crossentropy:0.6028,  val_loss:0.6028,  
.........................

نموذج متوسط

جرب الآن 3 طبقات مخفية تحتوي كل منها على 64 وحدة:

medium_model = tf.keras.Sequential([
    layers.Dense(64, activation='elu', input_shape=(FEATURES,)),
    layers.Dense(64, activation='elu'),
    layers.Dense(64, activation='elu'),
    layers.Dense(1)
])

وقم بتدريب النموذج باستخدام نفس البيانات:

size_histories['Medium']  = compile_and_fit(medium_model, "sizes/Medium")
Model: "sequential_2"
_________________________________________________________________
 Layer (type)                Output Shape              Param #   
=================================================================
 dense_5 (Dense)             (None, 64)                1856      
                                                                 
 dense_6 (Dense)             (None, 64)                4160      
                                                                 
 dense_7 (Dense)             (None, 64)                4160      
                                                                 
 dense_8 (Dense)             (None, 1)                 65        
                                                                 
=================================================================
Total params: 10,241
Trainable params: 10,241
Non-trainable params: 0
_________________________________________________________________

Epoch: 0, accuracy:0.5017,  binary_crossentropy:0.6840,  loss:0.6840,  val_accuracy:0.4790,  val_binary_crossentropy:0.6723,  val_loss:0.6723,  
....................................................................................................
Epoch: 100, accuracy:0.7173,  binary_crossentropy:0.5221,  loss:0.5221,  val_accuracy:0.6470,  val_binary_crossentropy:0.6111,  val_loss:0.6111,  
....................................................................................................
Epoch: 200, accuracy:0.7884,  binary_crossentropy:0.4270,  loss:0.4270,  val_accuracy:0.6390,  val_binary_crossentropy:0.7045,  val_loss:0.7045,  
..............................................................

نموذج كبير

كتمرين ، يمكنك إنشاء نموذج أكبر ، ومعرفة مدى سرعة بدء التجهيز. بعد ذلك ، دعنا نضيف إلى هذا المعيار شبكة ذات سعة أكبر بكثير مما قد تضمنه المشكلة:

large_model = tf.keras.Sequential([
    layers.Dense(512, activation='elu', input_shape=(FEATURES,)),
    layers.Dense(512, activation='elu'),
    layers.Dense(512, activation='elu'),
    layers.Dense(512, activation='elu'),
    layers.Dense(1)
])

ومرة أخرى ، قم بتدريب النموذج باستخدام نفس البيانات:

size_histories['large'] = compile_and_fit(large_model, "sizes/large")
Model: "sequential_3"
_________________________________________________________________
 Layer (type)                Output Shape              Param #   
=================================================================
 dense_9 (Dense)             (None, 512)               14848     
                                                                 
 dense_10 (Dense)            (None, 512)               262656    
                                                                 
 dense_11 (Dense)            (None, 512)               262656    
                                                                 
 dense_12 (Dense)            (None, 512)               262656    
                                                                 
 dense_13 (Dense)            (None, 1)                 513       
                                                                 
=================================================================
Total params: 803,329
Trainable params: 803,329
Non-trainable params: 0
_________________________________________________________________

Epoch: 0, accuracy:0.5145,  binary_crossentropy:0.7740,  loss:0.7740,  val_accuracy:0.4980,  val_binary_crossentropy:0.6793,  val_loss:0.6793,  
....................................................................................................
Epoch: 100, accuracy:1.0000,  binary_crossentropy:0.0020,  loss:0.0020,  val_accuracy:0.6600,  val_binary_crossentropy:1.8540,  val_loss:1.8540,  
....................................................................................................
Epoch: 200, accuracy:1.0000,  binary_crossentropy:0.0001,  loss:0.0001,  val_accuracy:0.6560,  val_binary_crossentropy:2.5293,  val_loss:2.5293,  
..........................

ارسم خسائر التدريب والتحقق من الصحة

تُظهر الخطوط الصلبة خسارة التدريب ، وتُظهر الخطوط المتقطعة فقدان التحقق من الصحة (تذكر: خسارة التحقق الأقل تشير إلى نموذج أفضل).

أثناء بناء نموذج أكبر يمنحه مزيدًا من القوة ، إذا لم تكن هذه القوة مقيدة بطريقة ما ، فيمكن بسهولة أن تتناسب مع مجموعة التدريب.

في هذا المثال ، عادةً ما يتمكن النموذج "Tiny" فقط من تجنب الإفراط في التجهيز كليًا ، وكل من النماذج الأكبر حجمًا يفرط في البيانات بسرعة أكبر. يصبح هذا شديدًا جدًا بالنسبة للنموذج "large" بحيث تحتاج إلى تبديل الحبكة إلى مقياس لوغاريتمي لترى ما يحدث حقًا.

هذا واضح إذا قمت برسم ومقارنة مقاييس التحقق من الصحة بمقاييس التدريب.

  • من الطبيعي أن يكون هناك فرق بسيط.
  • إذا كان كلا المقياسين يتحركان في نفس الاتجاه ، فكل شيء على ما يرام.
  • إذا بدأ مقياس التحقق من الصحة في الركود بينما يستمر مقياس التدريب في التحسن ، فربما تكون على وشك الإفراط في التجهيز.
  • إذا كان مقياس التحقق من الصحة يسير في الاتجاه الخاطئ ، فمن الواضح أن النموذج زائد.
plotter.plot(size_histories)
a = plt.xscale('log')
plt.xlim([5, max(plt.xlim())])
plt.ylim([0.5, 0.7])
plt.xlabel("Epochs [Log Scale]")
Text(0.5, 0, 'Epochs [Log Scale]')

بي إن جي

عرض في TensorBoard

كل هذه النماذج كتبت سجلات TensorBoard أثناء التدريب.

افتح عارض لوحة TensorBoard المضمّن داخل دفتر ملاحظات:

#docs_infra: no_execute

# Load the TensorBoard notebook extension
%load_ext tensorboard

# Open an embedded TensorBoard viewer
%tensorboard --logdir {logdir}/sizes

يمكنك عرض نتائج التشغيل السابق لدفتر الملاحظات هذا على TensorBboard.dev .

TensorBoard.dev هي تجربة مُدارة لاستضافة وتتبع ومشاركة تجارب ML مع الجميع.

يتم تضمينه أيضًا في <iframe> للراحة:

display.IFrame(
    src="https://tensorboard.dev/experiment/vW7jmmF9TmKmy3rbheMQpw/#scalars&_smoothingWeight=0.97",
    width="100%", height="800px")

إذا كنت ترغب في مشاركة نتائج TensorBoard ، فيمكنك تحميل السجلات إلى TensorBoard.dev عن طريق نسخ ما يلي في خلية التعليمات البرمجية.

tensorboard dev upload --logdir  {logdir}/sizes

استراتيجيات لمنع فرط التجهيز

قبل الدخول في محتوى هذا القسم ، انسخ سجلات التدريب من نموذج "Tiny" أعلاه ، لاستخدامها كخط أساس للمقارنة.

shutil.rmtree(logdir/'regularizers/Tiny', ignore_errors=True)
shutil.copytree(logdir/'sizes/Tiny', logdir/'regularizers/Tiny')
PosixPath('/tmp/tmpn1rdh98q/tensorboard_logs/regularizers/Tiny')
regularizer_histories = {}
regularizer_histories['Tiny'] = size_histories['Tiny']

أضِف تنظيم الوزن

قد تكون على دراية بمبدأ أوكام Razor: بالنظر إلى تفسيران لشيء ما ، فإن التفسير الذي من المرجح أن يكون صحيحًا هو "الأبسط" ، التفسير الذي يقدم أقل قدر من الافتراضات. ينطبق هذا أيضًا على النماذج التي تعلمتها الشبكات العصبية: بالنظر إلى بعض بيانات التدريب وبنية الشبكة ، هناك مجموعات متعددة من قيم الأوزان (نماذج متعددة) يمكن أن تشرح البيانات ، والنماذج الأبسط أقل احتمالية للتغلب عليها من النماذج المعقدة.

"النموذج البسيط" في هذا السياق هو نموذج يكون فيه توزيع قيم المعلمات أقل إنتروبيا (أو نموذج به معلمات أقل تمامًا ، كما رأينا في القسم أعلاه). وبالتالي ، فإن الطريقة الشائعة للتخفيف من فرط التخصيص هي وضع قيود على تعقيد الشبكة عن طريق إجبار أوزانها فقط على أخذ قيم صغيرة ، مما يجعل توزيع قيم الوزن أكثر "انتظامًا". وهذا ما يسمى "تنظيم الوزن" ، ويتم ذلك عن طريق إضافة تكلفة مرتبطة بوجود أوزان كبيرة إلى وظيفة الخسارة في الشبكة. تأتي هذه التكلفة في نكهتين:

  • تسوية L1 ، حيث تكون التكلفة المضافة متناسبة مع القيمة المطلقة لمعاملات الأوزان (أي مع ما يسمى "معيار L1" للأوزان).

  • تسوية L2 ، حيث تكون التكلفة المضافة متناسبة مع مربع قيمة معاملات الأوزان (أي مع ما يسمى بـ "معيار L2" التربيعي للأوزان). يُطلق على تنظيم L2 أيضًا اسم انحلال الوزن في سياق الشبكات العصبية. لا تدع الاسم المختلف يربكك: إن تناقص الوزن هو رياضياً هو نفسه بالضبط تنظيم L2.

يدفع تنظيم L1 الأوزان نحو الصفر تمامًا مما يشجع على استخدام نموذج متفرق. سيؤدي تنظيم L2 إلى معاقبة معلمات الأوزان دون جعلها متفرقة نظرًا لأن العقوبة تذهب إلى الصفر للأوزان الصغيرة - أحد الأسباب التي تجعل L2 أكثر شيوعًا.

في tf.keras ، تتم إضافة تنظيم الوزن عن طريق تمرير مثيلات منظم الوزن إلى طبقات كوسائط للكلمات الرئيسية. دعنا نضيف تنظيم وزن L2 الآن.

l2_model = tf.keras.Sequential([
    layers.Dense(512, activation='elu',
                 kernel_regularizer=regularizers.l2(0.001),
                 input_shape=(FEATURES,)),
    layers.Dense(512, activation='elu',
                 kernel_regularizer=regularizers.l2(0.001)),
    layers.Dense(512, activation='elu',
                 kernel_regularizer=regularizers.l2(0.001)),
    layers.Dense(512, activation='elu',
                 kernel_regularizer=regularizers.l2(0.001)),
    layers.Dense(1)
])

regularizer_histories['l2'] = compile_and_fit(l2_model, "regularizers/l2")
Model: "sequential_4"
_________________________________________________________________
 Layer (type)                Output Shape              Param #   
=================================================================
 dense_14 (Dense)            (None, 512)               14848     
                                                                 
 dense_15 (Dense)            (None, 512)               262656    
                                                                 
 dense_16 (Dense)            (None, 512)               262656    
                                                                 
 dense_17 (Dense)            (None, 512)               262656    
                                                                 
 dense_18 (Dense)            (None, 1)                 513       
                                                                 
=================================================================
Total params: 803,329
Trainable params: 803,329
Non-trainable params: 0
_________________________________________________________________

Epoch: 0, accuracy:0.5126,  binary_crossentropy:0.7481,  loss:2.2415,  val_accuracy:0.4950,  val_binary_crossentropy:0.6707,  val_loss:2.0653,  
....................................................................................................
Epoch: 100, accuracy:0.6625,  binary_crossentropy:0.5945,  loss:0.6173,  val_accuracy:0.6400,  val_binary_crossentropy:0.5871,  val_loss:0.6100,  
....................................................................................................
Epoch: 200, accuracy:0.6690,  binary_crossentropy:0.5864,  loss:0.6079,  val_accuracy:0.6650,  val_binary_crossentropy:0.5856,  val_loss:0.6076,  
....................................................................................................
Epoch: 300, accuracy:0.6790,  binary_crossentropy:0.5762,  loss:0.5976,  val_accuracy:0.6550,  val_binary_crossentropy:0.5881,  val_loss:0.6095,  
....................................................................................................
Epoch: 400, accuracy:0.6843,  binary_crossentropy:0.5697,  loss:0.5920,  val_accuracy:0.6650,  val_binary_crossentropy:0.5878,  val_loss:0.6101,  
....................................................................................................
Epoch: 500, accuracy:0.6897,  binary_crossentropy:0.5651,  loss:0.5907,  val_accuracy:0.6890,  val_binary_crossentropy:0.5798,  val_loss:0.6055,  
....................................................................................................
Epoch: 600, accuracy:0.6945,  binary_crossentropy:0.5610,  loss:0.5864,  val_accuracy:0.6820,  val_binary_crossentropy:0.5772,  val_loss:0.6026,  
..........................................................

l2(0.001) تعني أن كل معامل في مصفوفة الوزن للطبقة سيضيف 0.001 * weight_coefficient_value**2 إلى إجمالي خسارة الشبكة.

هذا هو السبب في أننا نراقب الاتجاه binary_crossentropy مباشرة. لأنه لا يحتوي على مكون التنظيم هذا مختلطًا.

لذلك ، فإن هذا النموذج "Large" نفسه مع عقوبة تسوية المستوى L2 يؤدي بشكل أفضل:

plotter.plot(regularizer_histories)
plt.ylim([0.5, 0.7])
(0.5, 0.7)

بي إن جي

كما ترى ، فإن النموذج "L2" أصبح الآن أكثر قدرة على المنافسة مع الطراز "Tiny" . هذا النموذج "L2" هو أيضًا أكثر مقاومة للتركيب الزائد من النموذج "Large" الذي كان يعتمد عليه على الرغم من وجود نفس العدد من المعلمات.

مزيد من المعلومات

هناك شيئان مهمان يجب ملاحظتهما حول هذا النوع من التنظيم.

أولاً: إذا كنت تكتب حلقة التدريب الخاصة بك ، فأنت بحاجة إلى التأكد من مطالبة النموذج بخسائر تنظيمه.

result = l2_model(features)
regularization_loss=tf.add_n(l2_model.losses)

ثانيًا: يعمل هذا التطبيق على إضافة جزاءات الوزن إلى خسارة النموذج ، ثم تطبيق إجراء التحسين القياسي بعد ذلك.

هناك طريقة ثانية تقوم بدلاً من ذلك بتشغيل المُحسِّن فقط على الخسارة الأولية ، ثم أثناء تطبيق الخطوة المحسوبة ، يطبق المُحسِّن أيضًا بعض تناقص الوزن. يظهر هذا "Decoupled Weight Decay" في مُحسِّنون مثل optimizers.FTRL و optimizers.AdamW .

أضف التسرب

يعد التسرب من أكثر تقنيات التنظيم فعالية والأكثر استخدامًا للشبكات العصبية ، وقد طوره هينتون وطلابه في جامعة تورنتو.

التفسير البديهي للتسرب هو أنه نظرًا لأن العقد الفردية في الشبكة لا يمكنها الاعتماد على مخرجات العُقد الأخرى ، يجب على كل عقدة إخراج ميزات مفيدة بمفردها.

يتكون التسرب ، المطبق على طبقة ، من "إسقاط" عشوائيًا (أي ضبط على الصفر) عدد من ميزات الإخراج للطبقة أثناء التدريب. لنفترض أن طبقة معينة قد أعادت عادةً متجهًا [0.2 ، 0.5 ، 1.3 ، 0.8 ، 1.1] لعينة إدخال معينة أثناء التدريب ؛ بعد تطبيق التسرب ، سيكون لهذا المتجه عدد قليل من المدخلات الصفرية موزعة عشوائيًا ، على سبيل المثال [0 ، 0.5 ، 1.3 ، 0 ، 1.1].

"معدل التسرب" هو جزء الميزات التي يتم استبعادها ؛ عادة ما يتم ضبطه بين 0.2 و 0.5. في وقت الاختبار ، لا يتم إسقاط أي وحدات ، وبدلاً من ذلك يتم تقليص قيم مخرجات الطبقة بواسطة عامل يساوي معدل التسرب ، وذلك لتحقيق التوازن بين حقيقة أن عدد الوحدات النشطة أكثر من وقت التدريب.

في tf.keras يمكنك إدخال التسرب في شبكة عبر طبقة Dropout ، والتي يتم تطبيقها على إخراج الطبقة قبل ذلك مباشرة.

دعنا نضيف طبقتين من Dropout في شبكتنا لنرى مدى نجاحهما في تقليل فرط التخصيص:

dropout_model = tf.keras.Sequential([
    layers.Dense(512, activation='elu', input_shape=(FEATURES,)),
    layers.Dropout(0.5),
    layers.Dense(512, activation='elu'),
    layers.Dropout(0.5),
    layers.Dense(512, activation='elu'),
    layers.Dropout(0.5),
    layers.Dense(512, activation='elu'),
    layers.Dropout(0.5),
    layers.Dense(1)
])

regularizer_histories['dropout'] = compile_and_fit(dropout_model, "regularizers/dropout")
Model: "sequential_5"
_________________________________________________________________
 Layer (type)                Output Shape              Param #   
=================================================================
 dense_19 (Dense)            (None, 512)               14848     
                                                                 
 dropout (Dropout)           (None, 512)               0         
                                                                 
 dense_20 (Dense)            (None, 512)               262656    
                                                                 
 dropout_1 (Dropout)         (None, 512)               0         
                                                                 
 dense_21 (Dense)            (None, 512)               262656    
                                                                 
 dropout_2 (Dropout)         (None, 512)               0         
                                                                 
 dense_22 (Dense)            (None, 512)               262656    
                                                                 
 dropout_3 (Dropout)         (None, 512)               0         
                                                                 
 dense_23 (Dense)            (None, 1)                 513       
                                                                 
=================================================================
Total params: 803,329
Trainable params: 803,329
Non-trainable params: 0
_________________________________________________________________

Epoch: 0, accuracy:0.4961,  binary_crossentropy:0.8110,  loss:0.8110,  val_accuracy:0.5330,  val_binary_crossentropy:0.6900,  val_loss:0.6900,  
....................................................................................................
Epoch: 100, accuracy:0.6557,  binary_crossentropy:0.5961,  loss:0.5961,  val_accuracy:0.6710,  val_binary_crossentropy:0.5788,  val_loss:0.5788,  
....................................................................................................
Epoch: 200, accuracy:0.6871,  binary_crossentropy:0.5622,  loss:0.5622,  val_accuracy:0.6860,  val_binary_crossentropy:0.5856,  val_loss:0.5856,  
....................................................................................................
Epoch: 300, accuracy:0.7246,  binary_crossentropy:0.5121,  loss:0.5121,  val_accuracy:0.6820,  val_binary_crossentropy:0.5927,  val_loss:0.5927,  
............
plotter.plot(regularizer_histories)
plt.ylim([0.5, 0.7])
(0.5, 0.7)

بي إن جي

يتضح من هذه المؤامرة أن كلا من أساليب التنظيم هذه تعمل على تحسين سلوك النموذج "Large" . لكن هذا لا يزال لا يتفوق حتى على خط الأساس "Tiny" .

بعد ذلك ، جربهما معًا ، واكتشف ما إذا كان ذلك أفضل.

مجمع L2 + التسرب

combined_model = tf.keras.Sequential([
    layers.Dense(512, kernel_regularizer=regularizers.l2(0.0001),
                 activation='elu', input_shape=(FEATURES,)),
    layers.Dropout(0.5),
    layers.Dense(512, kernel_regularizer=regularizers.l2(0.0001),
                 activation='elu'),
    layers.Dropout(0.5),
    layers.Dense(512, kernel_regularizer=regularizers.l2(0.0001),
                 activation='elu'),
    layers.Dropout(0.5),
    layers.Dense(512, kernel_regularizer=regularizers.l2(0.0001),
                 activation='elu'),
    layers.Dropout(0.5),
    layers.Dense(1)
])

regularizer_histories['combined'] = compile_and_fit(combined_model, "regularizers/combined")
Model: "sequential_6"
_________________________________________________________________
 Layer (type)                Output Shape              Param #   
=================================================================
 dense_24 (Dense)            (None, 512)               14848     
                                                                 
 dropout_4 (Dropout)         (None, 512)               0         
                                                                 
 dense_25 (Dense)            (None, 512)               262656    
                                                                 
 dropout_5 (Dropout)         (None, 512)               0         
                                                                 
 dense_26 (Dense)            (None, 512)               262656    
                                                                 
 dropout_6 (Dropout)         (None, 512)               0         
                                                                 
 dense_27 (Dense)            (None, 512)               262656    
                                                                 
 dropout_7 (Dropout)         (None, 512)               0         
                                                                 
 dense_28 (Dense)            (None, 1)                 513       
                                                                 
=================================================================
Total params: 803,329
Trainable params: 803,329
Non-trainable params: 0
_________________________________________________________________

Epoch: 0, accuracy:0.5090,  binary_crossentropy:0.8064,  loss:0.9648,  val_accuracy:0.4660,  val_binary_crossentropy:0.6877,  val_loss:0.8454,  
....................................................................................................
Epoch: 100, accuracy:0.6445,  binary_crossentropy:0.6050,  loss:0.6350,  val_accuracy:0.6630,  val_binary_crossentropy:0.5871,  val_loss:0.6169,  
....................................................................................................
Epoch: 200, accuracy:0.6660,  binary_crossentropy:0.5932,  loss:0.6186,  val_accuracy:0.6880,  val_binary_crossentropy:0.5722,  val_loss:0.5975,  
....................................................................................................
Epoch: 300, accuracy:0.6697,  binary_crossentropy:0.5818,  loss:0.6100,  val_accuracy:0.6900,  val_binary_crossentropy:0.5614,  val_loss:0.5895,  
....................................................................................................
Epoch: 400, accuracy:0.6749,  binary_crossentropy:0.5742,  loss:0.6046,  val_accuracy:0.6870,  val_binary_crossentropy:0.5576,  val_loss:0.5881,  
....................................................................................................
Epoch: 500, accuracy:0.6854,  binary_crossentropy:0.5703,  loss:0.6029,  val_accuracy:0.6970,  val_binary_crossentropy:0.5458,  val_loss:0.5784,  
....................................................................................................
Epoch: 600, accuracy:0.6806,  binary_crossentropy:0.5673,  loss:0.6015,  val_accuracy:0.6980,  val_binary_crossentropy:0.5453,  val_loss:0.5795,  
....................................................................................................
Epoch: 700, accuracy:0.6937,  binary_crossentropy:0.5583,  loss:0.5938,  val_accuracy:0.6870,  val_binary_crossentropy:0.5477,  val_loss:0.5832,  
....................................................................................................
Epoch: 800, accuracy:0.6911,  binary_crossentropy:0.5576,  loss:0.5947,  val_accuracy:0.7000,  val_binary_crossentropy:0.5446,  val_loss:0.5817,  
.......................
plotter.plot(regularizer_histories)
plt.ylim([0.5, 0.7])
(0.5, 0.7)

بي إن جي

من الواضح أن هذا النموذج مع التنظيم "Combined" هو الأفضل حتى الآن.

عرض في TensorBoard

سجلت هذه النماذج أيضًا سجلات TensorBoard.

لفتح عارض tensorboard مضمن داخل دفتر ملاحظات ، انسخ ما يلي في خلية التعليمات البرمجية:

%tensorboard --logdir {logdir}/regularizers

يمكنك عرض نتائج التشغيل السابق لدفتر الملاحظات هذا على TensorDoard.dev .

يتم تضمينه أيضًا في <iframe> للراحة:

display.IFrame(
    src="https://tensorboard.dev/experiment/fGInKDo8TXes1z7HQku9mw/#scalars&_smoothingWeight=0.97",
    width = "100%",
    height="800px")

تم تحميل هذا مع:

tensorboard dev upload --logdir  {logdir}/regularizers

الاستنتاجات

للتلخيص: فيما يلي أكثر الطرق شيوعًا لمنع فرط التخصيص في الشبكات العصبية:

  • احصل على المزيد من بيانات التدريب.
  • تقليل سعة الشبكة.
  • أضِف تنظيم الوزن.
  • أضف التسرب.

نهجان مهمان لم يتم تناولهما في هذا الدليل هما:

  • زيادة البيانات
  • تطبيع دفعة

تذكر أن كل طريقة يمكن أن تساعد من تلقاء نفسها ، ولكن غالبًا ما يكون الجمع بينها أكثر فاعلية.

# MIT License
#
# Copyright (c) 2017 François Chollet
#
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.