احفظ التاريخ! يعود مؤتمر Google I / O من 18 إلى 20 مايو. سجل الآن
ترجمت واجهة Cloud Translation API‏ هذه الصفحة.
Switch to English

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.4.0
!pip install -q 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 [==============================] - 120s 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 هو الأكثر كفاءة عند العمل على دفعات كبيرة من البيانات.

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

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 shapes: ((28,), ()), types: (tf.float32, tf.float32)>

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

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

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

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

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

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

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

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

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

ابدأ بنموذج بسيط باستخدام layers.Dense فقط ، ثم قم 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
_________________________________________________________________
WARNING:tensorflow:Callback method `on_train_batch_end` is slow compared to the batch time (batch time: 0.0027s vs `on_train_batch_end` time: 0.0064s). Check your callbacks.

Epoch: 0, accuracy:0.5142,  binary_crossentropy:0.7823,  loss:0.7823,  val_accuracy:0.5230,  val_binary_crossentropy:0.7322,  val_loss:0.7322,  
....................................................................................................
Epoch: 100, accuracy:0.5933,  binary_crossentropy:0.6284,  loss:0.6284,  val_accuracy:0.5730,  val_binary_crossentropy:0.6271,  val_loss:0.6271,  
....................................................................................................
Epoch: 200, accuracy:0.6176,  binary_crossentropy:0.6135,  loss:0.6135,  val_accuracy:0.5950,  val_binary_crossentropy:0.6167,  val_loss:0.6167,  
....................................................................................................
Epoch: 300, accuracy:0.6411,  binary_crossentropy:0.6011,  loss:0.6011,  val_accuracy:0.6230,  val_binary_crossentropy:0.6052,  val_loss:0.6052,  
....................................................................................................
Epoch: 400, accuracy:0.6542,  binary_crossentropy:0.5943,  loss:0.5943,  val_accuracy:0.6300,  val_binary_crossentropy:0.6003,  val_loss:0.6003,  
....................................................................................................
Epoch: 500, accuracy:0.6569,  binary_crossentropy:0.5903,  loss:0.5903,  val_accuracy:0.6470,  val_binary_crossentropy:0.5949,  val_loss:0.5949,  
....................................................................................................
Epoch: 600, accuracy:0.6631,  binary_crossentropy:0.5872,  loss:0.5872,  val_accuracy:0.6550,  val_binary_crossentropy:0.5927,  val_loss:0.5927,  
....................................................................................................
Epoch: 700, accuracy:0.6673,  binary_crossentropy:0.5846,  loss:0.5846,  val_accuracy:0.6690,  val_binary_crossentropy:0.5905,  val_loss:0.5905,  
....................................................................................................
Epoch: 800, accuracy:0.6743,  binary_crossentropy:0.5824,  loss:0.5824,  val_accuracy:0.6710,  val_binary_crossentropy:0.5890,  val_loss:0.5890,  
....................................................................................................
Epoch: 900, accuracy:0.6739,  binary_crossentropy:0.5815,  loss:0.5815,  val_accuracy:0.6630,  val_binary_crossentropy:0.5888,  val_loss:0.5888,  
....................................................................................................
Epoch: 1000, accuracy:0.6748,  binary_crossentropy:0.5791,  loss:0.5791,  val_accuracy:0.6610,  val_binary_crossentropy:0.5881,  val_loss:0.5881,  
....................................................................................................
Epoch: 1100, accuracy:0.6763,  binary_crossentropy:0.5774,  loss:0.5774,  val_accuracy:0.6710,  val_binary_crossentropy:0.5875,  val_loss:0.5875,  
....................................................................................................
Epoch: 1200, accuracy:0.6767,  binary_crossentropy:0.5763,  loss:0.5763,  val_accuracy:0.6630,  val_binary_crossentropy:0.5869,  val_loss:0.5869,  
....................................................................................................
Epoch: 1300, accuracy:0.6833,  binary_crossentropy:0.5750,  loss:0.5750,  val_accuracy:0.6550,  val_binary_crossentropy:0.5878,  val_loss:0.5878,  
....................................................................................................
Epoch: 1400, accuracy:0.6766,  binary_crossentropy:0.5737,  loss:0.5737,  val_accuracy:0.6710,  val_binary_crossentropy:0.5865,  val_loss:0.5865,  
....................................................................................................
Epoch: 1500, accuracy:0.6806,  binary_crossentropy:0.5727,  loss:0.5727,  val_accuracy:0.6630,  val_binary_crossentropy:0.5864,  val_loss:0.5864,  
....................................................................................................
Epoch: 1600, accuracy:0.6807,  binary_crossentropy:0.5717,  loss:0.5717,  val_accuracy:0.6720,  val_binary_crossentropy:0.5859,  val_loss:0.5859,  
....................................................................................................
Epoch: 1700, accuracy:0.6823,  binary_crossentropy:0.5707,  loss:0.5707,  val_accuracy:0.6570,  val_binary_crossentropy:0.5872,  val_loss:0.5872,  
..........

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

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
_________________________________________________________________
WARNING:tensorflow:Callback method `on_train_batch_end` is slow compared to the batch time (batch time: 0.0028s vs `on_train_batch_end` time: 0.0112s). Check your callbacks.

Epoch: 0, accuracy:0.5037,  binary_crossentropy:0.9699,  loss:0.9699,  val_accuracy:0.4950,  val_binary_crossentropy:0.7648,  val_loss:0.7648,  
....................................................................................................
Epoch: 100, accuracy:0.6141,  binary_crossentropy:0.6173,  loss:0.6173,  val_accuracy:0.6000,  val_binary_crossentropy:0.6165,  val_loss:0.6165,  
....................................................................................................
Epoch: 200, accuracy:0.6532,  binary_crossentropy:0.5935,  loss:0.5935,  val_accuracy:0.6430,  val_binary_crossentropy:0.6023,  val_loss:0.6023,  
....................................................................................................
Epoch: 300, accuracy:0.6762,  binary_crossentropy:0.5797,  loss:0.5797,  val_accuracy:0.6540,  val_binary_crossentropy:0.5987,  val_loss:0.5987,  
....................................................................................................
Epoch: 400, accuracy:0.6843,  binary_crossentropy:0.5725,  loss:0.5725,  val_accuracy:0.6570,  val_binary_crossentropy:0.6005,  val_loss:0.6005,  
.............................................................................

نموذج متوسط

جرب الآن 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
_________________________________________________________________
WARNING:tensorflow:Callback method `on_train_batch_end` is slow compared to the batch time (batch time: 0.0026s vs `on_train_batch_end` time: 0.0107s). Check your callbacks.

Epoch: 0, accuracy:0.4897,  binary_crossentropy:0.7502,  loss:0.7502,  val_accuracy:0.4590,  val_binary_crossentropy:0.7012,  val_loss:0.7012,  
....................................................................................................
Epoch: 100, accuracy:0.7040,  binary_crossentropy:0.5396,  loss:0.5396,  val_accuracy:0.6760,  val_binary_crossentropy:0.5956,  val_loss:0.5956,  
....................................................................................................
Epoch: 200, accuracy:0.7784,  binary_crossentropy:0.4380,  loss:0.4380,  val_accuracy:0.6560,  val_binary_crossentropy:0.6714,  val_loss:0.6714,  
.......................................................................

نموذج كبير

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

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
_________________________________________________________________
WARNING:tensorflow:Callback method `on_train_batch_end` is slow compared to the batch time (batch time: 0.0035s vs `on_train_batch_end` time: 0.0129s). Check your callbacks.

Epoch: 0, accuracy:0.4901,  binary_crossentropy:0.8508,  loss:0.8508,  val_accuracy:0.5540,  val_binary_crossentropy:0.6800,  val_loss:0.6800,  
....................................................................................................
Epoch: 100, accuracy:1.0000,  binary_crossentropy:0.0025,  loss:0.0025,  val_accuracy:0.6480,  val_binary_crossentropy:1.7541,  val_loss:1.7541,  
....................................................................................................
Epoch: 200, accuracy:1.0000,  binary_crossentropy:0.0002,  loss:0.0002,  val_accuracy:0.6530,  val_binary_crossentropy:2.4090,  val_loss:2.4090,  
....................

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

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

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

في هذا المثال ، عادةً ما يتمكن النموذج "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 المضمّن داخل دفتر ملاحظات:


# Load the TensorBoard notebook extension
%load_ext tensorboard

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

يمكنك عرض نتائج التشغيل السابق لدفتر الملاحظات هذا على TensorBoard.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/tmpr1cbfjvl/tensorboard_logs/regularizers/Tiny')
regularizer_histories = {}
regularizer_histories['Tiny'] = size_histories['Tiny']

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

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

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

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

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

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

في tf.keras ، تتم إضافة تنظيم الوزن عن طريق تمرير مثيلات tf.keras الوزن إلى طبقات 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
_________________________________________________________________
WARNING:tensorflow:Callback method `on_train_batch_end` is slow compared to the batch time (batch time: 0.0034s vs `on_train_batch_end` time: 0.0134s). Check your callbacks.

Epoch: 0, accuracy:0.5162,  binary_crossentropy:0.7512,  loss:2.2423,  val_accuracy:0.4830,  val_binary_crossentropy:0.6906,  val_loss:2.0808,  
....................................................................................................
Epoch: 100, accuracy:0.6586,  binary_crossentropy:0.5961,  loss:0.6196,  val_accuracy:0.6590,  val_binary_crossentropy:0.5953,  val_loss:0.6188,  
....................................................................................................
Epoch: 200, accuracy:0.6736,  binary_crossentropy:0.5817,  loss:0.6037,  val_accuracy:0.6610,  val_binary_crossentropy:0.5796,  val_loss:0.6015,  
....................................................................................................
Epoch: 300, accuracy:0.6840,  binary_crossentropy:0.5771,  loss:0.6019,  val_accuracy:0.6770,  val_binary_crossentropy:0.5868,  val_loss:0.6124,  
....................................................................................................
Epoch: 400, accuracy:0.6926,  binary_crossentropy:0.5668,  loss:0.5924,  val_accuracy:0.6670,  val_binary_crossentropy:0.5748,  val_loss:0.6004,  
....................................................................................................
Epoch: 500, accuracy:0.6991,  binary_crossentropy:0.5550,  loss:0.5824,  val_accuracy:0.6890,  val_binary_crossentropy:0.5743,  val_loss:0.6018,  
....................................................................................................
Epoch: 600, accuracy:0.7073,  binary_crossentropy:0.5475,  loss:0.5758,  val_accuracy:0.6800,  val_binary_crossentropy:0.5734,  val_loss:0.6016,  
....................................................................................................
Epoch: 700, accuracy:0.7139,  binary_crossentropy:0.5381,  loss:0.5666,  val_accuracy:0.6770,  val_binary_crossentropy:0.5848,  val_loss:0.6132,  
....................................................................................................
Epoch: 800, accuracy:0.7169,  binary_crossentropy:0.5354,  loss:0.5645,  val_accuracy:0.6920,  val_binary_crossentropy:0.5835,  val_loss:0.6126,  
...........

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
_________________________________________________________________
WARNING:tensorflow:Callback method `on_train_batch_end` is slow compared to the batch time (batch time: 0.0036s vs `on_train_batch_end` time: 0.0141s). Check your callbacks.

Epoch: 0, accuracy:0.4944,  binary_crossentropy:0.8070,  loss:0.8070,  val_accuracy:0.5630,  val_binary_crossentropy:0.6919,  val_loss:0.6919,  
....................................................................................................
Epoch: 100, accuracy:0.6579,  binary_crossentropy:0.5956,  loss:0.5956,  val_accuracy:0.6780,  val_binary_crossentropy:0.5794,  val_loss:0.5794,  
....................................................................................................
Epoch: 200, accuracy:0.6878,  binary_crossentropy:0.5569,  loss:0.5569,  val_accuracy:0.6760,  val_binary_crossentropy:0.5896,  val_loss:0.5896,  
....................................................................................................
Epoch: 300, accuracy:0.7189,  binary_crossentropy:0.5084,  loss:0.5084,  val_accuracy:0.6960,  val_binary_crossentropy:0.6009,  val_loss:0.6009,  
....................
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
_________________________________________________________________
WARNING:tensorflow:Callback method `on_train_batch_end` is slow compared to the batch time (batch time: 0.0040s vs `on_train_batch_end` time: 0.0151s). Check your callbacks.

Epoch: 0, accuracy:0.5052,  binary_crossentropy:0.8050,  loss:0.9634,  val_accuracy:0.4700,  val_binary_crossentropy:0.6965,  val_loss:0.8544,  
....................................................................................................
Epoch: 100, accuracy:0.6432,  binary_crossentropy:0.6061,  loss:0.6349,  val_accuracy:0.6440,  val_binary_crossentropy:0.5868,  val_loss:0.6154,  
....................................................................................................
Epoch: 200, accuracy:0.6633,  binary_crossentropy:0.5916,  loss:0.6159,  val_accuracy:0.6420,  val_binary_crossentropy:0.5788,  val_loss:0.6031,  
....................................................................................................
Epoch: 300, accuracy:0.6685,  binary_crossentropy:0.5828,  loss:0.6107,  val_accuracy:0.6900,  val_binary_crossentropy:0.5632,  val_loss:0.5911,  
....................................................................................................
Epoch: 400, accuracy:0.6719,  binary_crossentropy:0.5808,  loss:0.6102,  val_accuracy:0.6880,  val_binary_crossentropy:0.5620,  val_loss:0.5914,  
....................................................................................................
Epoch: 500, accuracy:0.6776,  binary_crossentropy:0.5739,  loss:0.6050,  val_accuracy:0.6880,  val_binary_crossentropy:0.5539,  val_loss:0.5851,  
....................................................................................................
Epoch: 600, accuracy:0.6856,  binary_crossentropy:0.5669,  loss:0.6006,  val_accuracy:0.6960,  val_binary_crossentropy:0.5493,  val_loss:0.5830,  
....................................................................................................
Epoch: 700, accuracy:0.6833,  binary_crossentropy:0.5648,  loss:0.5996,  val_accuracy:0.6980,  val_binary_crossentropy:0.5430,  val_loss:0.5778,  
....................................................................................................
Epoch: 800, accuracy:0.6943,  binary_crossentropy:0.5594,  loss:0.5955,  val_accuracy:0.6930,  val_binary_crossentropy:0.5412,  val_loss:0.5772,  
....................................................................................................
Epoch: 900, accuracy:0.6966,  binary_crossentropy:0.5558,  loss:0.5932,  val_accuracy:0.7060,  val_binary_crossentropy:0.5419,  val_loss:0.5793,  
.................................................................................................
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.