Pakaian berlebih dan pakaian dalam

Lihat di TensorFlow.org Jalankan di Google Colab Lihat sumber di GitHub Unduh buku catatan

Seperti biasa, kode dalam contoh ini akan menggunakan API tf.keras , yang dapat Anda pelajari lebih lanjut di panduan TensorFlow Keras .

Dalam kedua contoh sebelumnya— mengklasifikasikan teks dan memprediksi efisiensi bahan bakar — kami melihat bahwa keakuratan model kami pada data validasi akan mencapai puncaknya setelah pelatihan selama beberapa periode, dan kemudian akan stagnan atau mulai menurun.

Dengan kata lain, model kami akan menyesuaikan dengan data pelatihan. Mempelajari cara menangani overfitting itu penting. Meskipun seringkali mungkin untuk mencapai akurasi tinggi pada set pelatihan , yang sebenarnya kami inginkan adalah mengembangkan model yang digeneralisasikan dengan baik ke set pengujian (atau data yang belum pernah mereka lihat sebelumnya).

Kebalikan dari overfitting adalah underfitting . Underfitting terjadi ketika masih ada ruang untuk perbaikan pada data kereta api. Hal ini dapat terjadi karena beberapa alasan: Jika model tidak cukup kuat, terlalu diatur, atau tidak cukup lama dilatih. Ini berarti jaringan belum mempelajari pola yang relevan dalam data pelatihan.

Jika Anda berlatih terlalu lama, model akan mulai menyesuaikan dan mempelajari pola dari data pelatihan yang tidak digeneralisasi ke data pengujian. Kita perlu mencapai keseimbangan. Memahami cara melatih untuk jumlah epoch yang sesuai seperti yang akan kita jelajahi di bawah ini adalah keterampilan yang berguna.

Untuk mencegah overfitting, solusi terbaik adalah menggunakan data pelatihan yang lebih lengkap. Kumpulan data harus mencakup berbagai input yang diharapkan dapat ditangani oleh model. Data tambahan mungkin hanya berguna jika mencakup kasus-kasus baru dan menarik.

Sebuah model yang dilatih pada data yang lebih lengkap secara alami akan menggeneralisasi lebih baik. Ketika itu tidak mungkin lagi, solusi terbaik berikutnya adalah menggunakan teknik seperti regularisasi. Ini menempatkan batasan pada kuantitas dan jenis informasi yang dapat disimpan oleh model Anda. Jika jaringan hanya mampu menghafal sejumlah kecil pola, proses optimasi akan memaksanya untuk fokus pada pola yang paling menonjol, yang memiliki peluang lebih baik untuk menggeneralisasi dengan baik.

Dalam buku catatan ini, kita akan menjelajahi beberapa teknik regularisasi umum, dan menggunakannya untuk memperbaiki model klasifikasi.

Mempersiapkan

Sebelum memulai, impor paket yang diperlukan:

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)

Kumpulan Data Higgs

Tujuan dari tutorial ini bukan untuk melakukan fisika partikel, jadi jangan terpaku pada detail dataset. Ini berisi 11.000.000 contoh, masing-masing dengan 28 fitur, dan label kelas biner.

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

Kelas tf.data.experimental.CsvDataset dapat digunakan untuk membaca catatan csv langsung dari file gzip tanpa langkah dekompresi perantara.

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

Kelas pembaca csv itu mengembalikan daftar skalar untuk setiap catatan. Fungsi berikut mengemas ulang daftar skalar tersebut menjadi pasangan (feature_vector, label).

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

TensorFlow paling efisien saat beroperasi pada kumpulan data yang besar.

Jadi, alih-alih mengemas ulang setiap baris satu per satu, buat Dataset baru yang mengambil kumpulan 10.000 contoh, terapkan fungsi pack_row ke setiap kumpulan, lalu pisahkan kumpulan kembali menjadi catatan individual:

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

Lihat beberapa catatan packed_ds baru ini.

Fitur-fiturnya tidak dinormalisasi dengan sempurna, tetapi ini cukup untuk tutorial ini.

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)

png

Agar tutorial ini relatif singkat, gunakan hanya 1000 sampel pertama untuk validasi, dan 10.000 berikutnya untuk pelatihan:

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

Metode Dataset.skip dan Dataset.take membuatnya mudah.

Pada saat yang sama, gunakan metode Dataset.cache untuk memastikan bahwa loader tidak perlu membaca ulang data dari file pada setiap epoch:

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))>

Kumpulan data ini mengembalikan contoh individual. Gunakan metode .batch untuk membuat kumpulan dengan ukuran yang sesuai untuk pelatihan. Sebelum batching juga ingat untuk .shuffle dan .repeat set pelatihan.

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

Mendemonstrasikan overfitting

Cara paling sederhana untuk mencegah overfitting adalah memulai dengan model kecil: Model dengan sejumlah kecil parameter yang dapat dipelajari (yang ditentukan oleh jumlah lapisan dan jumlah unit per lapisan). Dalam pembelajaran mendalam, jumlah parameter yang dapat dipelajari dalam suatu model sering disebut sebagai "kapasitas" model.

Secara intuitif, model dengan lebih banyak parameter akan memiliki lebih banyak "kapasitas menghafal" dan oleh karena itu akan dapat dengan mudah mempelajari pemetaan seperti kamus yang sempurna antara sampel pelatihan dan targetnya, pemetaan tanpa kekuatan generalisasi apa pun, tetapi ini tidak akan berguna saat membuat prediksi pada data yang sebelumnya tidak terlihat.

Ingatlah selalu hal ini: model pembelajaran mendalam cenderung bagus dalam menyesuaikan dengan data pelatihan, tetapi tantangan sebenarnya adalah generalisasi, bukan penyesuaian.

Di sisi lain, jika jaringan memiliki sumber daya memori yang terbatas, ia tidak akan dapat mempelajari pemetaan dengan mudah. Untuk meminimalkan kerugiannya, ia harus mempelajari representasi terkompresi yang memiliki lebih banyak kekuatan prediktif. Pada saat yang sama, jika Anda membuat model Anda terlalu kecil, itu akan mengalami kesulitan untuk menyesuaikan dengan data pelatihan. Ada keseimbangan antara "kapasitas terlalu banyak" dan "kapasitas tidak cukup".

Sayangnya, tidak ada formula ajaib untuk menentukan ukuran atau arsitektur model yang tepat (dalam hal jumlah lapisan, atau ukuran yang tepat untuk setiap lapisan). Anda harus bereksperimen menggunakan serangkaian arsitektur yang berbeda.

Untuk menemukan ukuran model yang sesuai, yang terbaik adalah memulai dengan lapisan dan parameter yang relatif sedikit, kemudian mulai meningkatkan ukuran lapisan atau menambahkan lapisan baru sampai Anda melihat hasil yang semakin berkurang pada hilangnya validasi.

Mulailah dengan model sederhana yang hanya menggunakan lapisan. layers.Dense sebagai dasar, lalu buat versi yang lebih besar, dan bandingkan.

Prosedur pelatihan

Banyak model berlatih lebih baik jika Anda secara bertahap mengurangi kecepatan belajar selama pelatihan. Gunakan optimizers.schedules untuk mengurangi kecepatan pembelajaran dari waktu ke waktu:

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)

Kode di atas menetapkan sebuah schedules.InverseTimeDecay untuk secara hiperbolik menurunkan kecepatan belajar menjadi 1/2 dari kecepatan dasar pada 1000 epoch, 1/3 pada 2000 epoch dan seterusnya.

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')

png

Setiap model dalam tutorial ini akan menggunakan konfigurasi pelatihan yang sama. Jadi atur ini dengan cara yang dapat digunakan kembali, dimulai dengan daftar panggilan balik.

Pelatihan untuk tutorial ini berjalan untuk banyak waktu singkat. Untuk mengurangi kebisingan logging, gunakan tfdocs.EpochDots yang hanya mencetak file . untuk setiap zaman, dan satu set metrik lengkap setiap 100 zaman.

Berikutnya termasuk callbacks.EarlyStopping untuk menghindari waktu pelatihan yang lama dan tidak perlu. Perhatikan bahwa panggilan balik ini diatur untuk memantau val_binary_crossentropy , bukan val_loss . Perbedaan ini akan menjadi penting nantinya.

Gunakan callbacks.TensorBoard untuk membuat log TensorBoard untuk pelatihan.

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

Demikian pula setiap model akan menggunakan pengaturan Model.compile dan Model.fit yang sama:

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

model kecil

Mulailah dengan melatih model:

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,  
...................................

Sekarang periksa bagaimana model melakukannya:

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

png

Model kecil

Untuk melihat apakah Anda dapat mengalahkan performa model kecil, latih beberapa model yang lebih besar secara bertahap.

Coba dua lapisan tersembunyi dengan masing-masing 16 unit:

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,  
.........................

Model sedang

Sekarang coba 3 lapisan tersembunyi dengan masing-masing 64 unit:

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)
])

Dan latih model menggunakan data yang sama:

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,  
..............................................................

Model besar

Sebagai latihan, Anda dapat membuat model yang lebih besar lagi, dan melihat seberapa cepat model itu mulai overfitting. Selanjutnya, mari tambahkan ke tolok ukur ini jaringan yang memiliki kapasitas lebih banyak, jauh lebih banyak daripada yang dijamin oleh masalah:

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)
])

Dan, sekali lagi, latih model menggunakan data yang sama:

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,  
..........................

Plot kerugian pelatihan dan validasi

Garis padat menunjukkan kehilangan pelatihan, dan garis putus-putus menunjukkan kehilangan validasi (ingat: kehilangan validasi yang lebih rendah menunjukkan model yang lebih baik).

Sementara membangun model yang lebih besar memberikan lebih banyak kekuatan, jika kekuatan ini tidak dibatasi entah bagaimana dapat dengan mudah overfit ke set pelatihan.

Dalam contoh ini, biasanya, hanya model "Tiny" yang berhasil menghindari overfitting sama sekali, dan setiap model yang lebih besar menyesuaikan data dengan lebih cepat. Ini menjadi sangat parah untuk model "large" sehingga Anda perlu mengubah plot ke skala log untuk benar-benar melihat apa yang terjadi.

Ini terlihat jika Anda memplot dan membandingkan metrik validasi dengan metrik pelatihan.

  • Itu normal jika ada perbedaan kecil.
  • Jika kedua metrik bergerak ke arah yang sama, semuanya baik-baik saja.
  • Jika metrik validasi mulai mandek sementara metrik pelatihan terus meningkat, Anda mungkin mendekati overfitting.
  • Jika metrik validasi berjalan ke arah yang salah, modelnya jelas overfitting.
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]')

png

Lihat di TensorBoard

Semua model ini menulis log TensorBoard selama pelatihan.

Buka penampil TensorBoard yang disematkan di dalam buku catatan:

#docs_infra: no_execute

# Load the TensorBoard notebook extension
%load_ext tensorboard

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

Anda dapat melihat hasil dari menjalankan notebook ini sebelumnya di TensorBoard.dev .

TensorBoard.dev adalah pengalaman terkelola untuk menghosting, melacak, dan berbagi eksperimen ML dengan semua orang.

Itu juga termasuk dalam <iframe> untuk kenyamanan:

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

Jika Anda ingin membagikan hasil TensorBoard, Anda dapat mengunggah log ke TensorBoard.dev dengan menyalin kode berikut ke dalam sel kode.

tensorboard dev upload --logdir  {logdir}/sizes

Strategi untuk mencegah overfitting

Sebelum masuk ke konten bagian ini, salin log pelatihan dari model "Tiny" di atas, untuk digunakan sebagai dasar perbandingan.

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']

Tambahkan regularisasi berat badan

Anda mungkin akrab dengan prinsip Occam's Razor: jika diberikan dua penjelasan untuk sesuatu, penjelasan yang paling mungkin benar adalah yang "paling sederhana", yang membuat asumsi paling sedikit. Ini juga berlaku untuk model yang dipelajari oleh jaringan saraf: mengingat beberapa data pelatihan dan arsitektur jaringan, ada beberapa set nilai bobot (beberapa model) yang dapat menjelaskan data, dan model yang lebih sederhana cenderung tidak terlalu cocok daripada model yang kompleks.

"Model sederhana" dalam konteks ini adalah model di mana distribusi nilai parameter memiliki entropi yang lebih sedikit (atau model dengan parameter yang lebih sedikit, seperti yang kita lihat di bagian di atas). Jadi, cara umum untuk mengurangi overfitting adalah dengan memberikan batasan pada kompleksitas jaringan dengan memaksa bobotnya hanya untuk mengambil nilai kecil, yang membuat distribusi nilai bobot lebih "teratur". Ini disebut "regularisasi bobot", dan ini dilakukan dengan menambahkan fungsi kerugian jaringan dengan biaya yang terkait dengan bobot yang besar. Biaya ini datang dalam dua rasa:

  • Regularisasi L1 , di mana biaya yang ditambahkan sebanding dengan nilai absolut dari koefisien bobot (yaitu dengan apa yang disebut "norma L1" dari bobot).

  • Regularisasi L2 , di mana biaya yang ditambahkan sebanding dengan kuadrat dari nilai koefisien bobot (yaitu dengan apa yang disebut kuadrat "norma L2" bobot). Regularisasi L2 juga disebut peluruhan bobot dalam konteks jaringan saraf. Jangan biarkan nama yang berbeda membingungkan Anda: penurunan berat badan secara matematis sama persis dengan regularisasi L2.

Regularisasi L1 mendorong bobot menuju tepat nol mendorong model yang jarang. Regularisasi L2 akan menghukum parameter bobot tanpa membuatnya jarang karena penalti menjadi nol untuk bobot kecil-salah satu alasan mengapa L2 lebih umum.

Di tf.keras , regularisasi bobot ditambahkan dengan meneruskan instance pengatur bobot ke lapisan sebagai argumen kata kunci. Mari kita tambahkan regularisasi berat L2 sekarang.

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) berarti bahwa setiap koefisien dalam matriks bobot lapisan akan menambah 0.001 * weight_coefficient_value**2 ke total kehilangan jaringan.

Itulah sebabnya kami memantau binary_crossentropy secara langsung. Karena tidak ada komponen regularisasi ini yang tercampur.

Jadi, model "Large" yang sama dengan penalti regularisasi L2 berkinerja jauh lebih baik:

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

png

Seperti yang Anda lihat, model reguler "L2" sekarang jauh lebih kompetitif dengan model "Tiny" . Model "L2" ini juga jauh lebih tahan terhadap overfitting daripada model "Large" yang menjadi dasarnya meskipun memiliki jumlah parameter yang sama.

Info lebih lanjut

Ada dua hal penting yang perlu diperhatikan tentang regularisasi semacam ini.

Pertama: jika Anda menulis loop pelatihan Anda sendiri, maka Anda harus memastikan untuk menanyakan model kehilangan regularisasinya.

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

Kedua: Implementasi ini bekerja dengan menambahkan penalti bobot pada kerugian model, dan kemudian menerapkan prosedur optimasi standar setelah itu.

Ada pendekatan kedua yang hanya menjalankan pengoptimal pada kerugian mentah, dan kemudian saat menerapkan langkah yang dihitung, pengoptimal juga menerapkan beberapa penurunan bobot. "Pembusukan Bobot Terpisah" ini terlihat di pengoptimal seperti optimizers.FTRL dan optimizers.AdamW .

Tambahkan putus sekolah

Dropout adalah salah satu teknik regularisasi yang paling efektif dan paling umum digunakan untuk jaringan saraf, yang dikembangkan oleh Hinton dan mahasiswanya di University of Toronto.

Penjelasan intuitif untuk dropout adalah karena node individu dalam jaringan tidak dapat bergantung pada output yang lain, setiap node harus menampilkan fitur yang berguna untuk mereka sendiri.

Dropout, diterapkan pada sebuah layer, terdiri dari "keluar" secara acak (yaitu disetel ke nol) sejumlah fitur keluaran dari layer selama pelatihan. Katakanlah lapisan yang diberikan biasanya akan mengembalikan vektor [0.2, 0.5, 1.3, 0.8, 1.1] untuk sampel input yang diberikan selama pelatihan; setelah menerapkan dropout, vektor ini akan memiliki beberapa entri nol yang didistribusikan secara acak, misalnya [0, 0.5, 1.3, 0, 1.1].

"Tingkat putus sekolah" adalah sebagian kecil dari fitur yang di-zero-out; biasanya diatur antara 0,2 dan 0,5. Pada waktu pengujian, tidak ada unit yang dikeluarkan, dan sebaliknya nilai keluaran lapisan diperkecil dengan faktor yang sama dengan tingkat putus sekolah, untuk menyeimbangkan fakta bahwa lebih banyak unit yang aktif daripada pada waktu pelatihan.

Di tf.keras Anda dapat memperkenalkan dropout di jaringan melalui lapisan Dropout, yang diterapkan ke output lapisan tepat sebelumnya.

Mari tambahkan dua layer Dropout di jaringan kita untuk melihat seberapa baik mereka mengurangi overfitting:

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)

png

Jelas dari plot ini bahwa kedua pendekatan regularisasi ini meningkatkan perilaku model "Large" . Tapi ini masih belum mengalahkan baseline "Tiny" .

Selanjutnya coba keduanya, bersama-sama, dan lihat apakah itu lebih baik.

Gabungan L2 + putus sekolah

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)

png

Model dengan regularisasi "Combined" ini jelas yang terbaik sejauh ini.

Lihat di TensorBoard

Model ini juga merekam log TensorBoard.

Untuk membuka penampil tensorboard tersemat di dalam buku catatan, salin kode berikut ke dalam sel kode:

%tensorboard --logdir {logdir}/regularizers

Anda dapat melihat hasil dari menjalankan notebook ini sebelumnya di TensorDoard.dev .

Itu juga termasuk dalam <iframe> untuk kenyamanan:

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

Ini diunggah dengan:

tensorboard dev upload --logdir  {logdir}/regularizers

Kesimpulan

Untuk rekap: berikut adalah cara paling umum untuk mencegah overfitting di jaringan saraf:

  • Dapatkan lebih banyak data pelatihan.
  • Mengurangi kapasitas jaringan.
  • Tambahkan regularisasi berat badan.
  • Tambah putus sekolah.

Dua pendekatan penting yang tidak tercakup dalam panduan ini adalah:

  • data-augmentation
  • normalisasi batch

Ingatlah bahwa setiap metode dapat membantu dengan sendirinya, tetapi sering kali menggabungkannya bisa lebih efektif.

# 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.