In [ ]:
#@title Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

In [ ]:
#@title 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.

Aşırı uyum (overfitting) ve yetersiz uyum (underfitting) nedir ?

Note: Bu dökümanlar TensorFlow gönüllü kullanıcıları tarafından çevirilmiştir. Topluluk tarafından sağlananan çeviriler gönüllülerin ellerinden geldiğince güncellendiği için Resmi İngilizce dökümanlar ile bire bir aynı olmasını garantileyemeyiz. Eğer bu tercümeleri iyileştirmek için önerileriniz var ise lütfen tensorflow/docs havuzuna pull request gönderin. Gönüllü olarak çevirilere katkıda bulunmak için docs-tr@tensorflow.org listesi ile iletişime geçebilirsiniz.

Bu örneğimizde, 'tf.keras' API'sini kullanacağız. Tensorflow 'tf.keras' API'si ile ilgili daha fazla bilgiye Keras guide linki üzerinden ulaşabilirsiniz.

Önceki örneklerimizde (film yorumlarının sınıflandırılması, yakıt verimliliğinin tahminlenmesi) gördüğünüz gibi, doğrulama seti üzerinden ölçtüğümüz model doğruluğu, belirli bir epoch sayısında tepe noktasına ulaşıp, sonrasında azalmaya başlamaktadır.

Diğer bir deyişle, modelimiz eğitim veri setine aşırı uyumlu (overfit) hale gelmektedir. Aşırı uyum ile nasıl baş edeceğimiz önemlidir. Eğitim veri seti ile çok yüksek doğruluk değerine sahip olmamız mümkün olsa bile, asıl amacımız modelin daha önce görmediği veriler ile yani test veri seti ile yüksek doğrulukta sonuç üretebilmesi, bu şekilde genelleştirilmesidir.

Aşırı uyumun tersi yetersiz uyum (underfittig) 'dur. Yetersiz uyum, test verisi ile değerlendirdiğimizde modelde hala belirli bir iyileşme alanının olması durumudur. Yetersiz uyum belirli nedenler sonucunda oluşur: Eğer model yeterince güçlü değil ise, çok fazla regülarize edildi ise, yeterince uzun süre eğitilmedi ise. Bu, ağın eğitim verisinden ilgili çıkarımları gerektiği kadar yapamadığı anlamına gelmektedir.

Bunun yanında eğer modeli çok uzun süre eğitirseniz, moldel eğitim veri setine aşırı uyum sağlayarak, yaptığı çıkarımlar ile test veri setinde iyi şekilde çalışabilmesi için gerekli olan genelleme yeteneğini kaybedecektir. Modelimizin daha iyi performans göstermesi için dengeyi sağlamalıyız. Bu nedenle, aşağıda inceleyeceğimiz gibi, modelin uygun sayıda epoch ile nasıl eğitileceğini anlamak önemli bir beceridir.

Aşırı uyumu engellemek için en iyi çözüm daha fazla eğitim verisinin kullanılmasıdır. Daha fazla veri ile eğitilen modeller doğal olarak daha iyi genelleme yeteneğine sahip olurlar. Bunun mümkün olmadığı durumlarda, ikinci en iyi çözüm regularization tekniklerini kullanmak olur. Bu teknikleri kullandığımızda, modelimizin sahip olacağı bilgi tipi ve miktarını sınırlarız. Model ağımız daha az miktarda çıkarımı hafızasına alırsa, optimizasyon süreci en önemli çıkarımları yapması için modeli zorlayacaktır. Bunun sonucunda modelin genelleme yeteneği artacaktır.

Bu notebook'ta, IMBD film yorumlarının sınıflandırılması modelimizin iyileştirilmesi için en çok kullanılan iki regularizasyon tekniği olan ağırlık regularizasyonu (weigth regularization) ve dropout teknikleri kullanılacaktır.


In [ ]:
# keras.datasets.imdb is broken in 1.13 and 1.14, by np 1.16.3
!pip install tf_nightly

In [ ]:
import tensorflow.compat.v1 as tf

from tensorflow import keras

import numpy as np
import matplotlib.pyplot as plt

print(tf.__version__)

IMDB veri setini indirelim

Önceki notebook'ta yer alan emmbeding işlemi yerine, bu örnekte cümlelere multi-hot encoding işlemi uygulayacağız. Modelimiz hızlı bir şekilde eğitim verisine aşırı uyum gösterecektir. Bu şekilde, aşırı uyumun nasıl oluştuğunu ve nasıl baş edeceğimizi göstermiş olacağız.

Multi-hot-encoding ile listemizi 0'lar ve 1'ler içeren vektöre dönüştürelim. Örnek olarak bu işlem ile [3, 5] dizisi, 3 ve 5 indisleri 1 olan bunun dışındaki tüm değerleri 0 olan 10,000 boyutlu bir vektöre çevrilir.


In [ ]:
NUM_WORDS = 10000

(train_data, train_labels), (test_data, test_labels) = keras.datasets.imdb.load_data(num_words=NUM_WORDS)

def multi_hot_sequences(sequences, dimension):
    # Create an all-zero matrix of shape (len(sequences), dimension)
    results = np.zeros((len(sequences), dimension))
    for i, word_indices in enumerate(sequences):
        results[i, word_indices] = 1.0  # set specific indices of results[i] to 1s
    return results


train_data = multi_hot_sequences(train_data, dimension=NUM_WORDS)
test_data = multi_hot_sequences(test_data, dimension=NUM_WORDS)

Sonuçta oluşan multi-hot vektörlerden birine bakalım. Kelime indisleri frekanslarına göre sıralanmıştır, yani aşağıdaki grafikte görüldüğü gibi 0 indeksine yaklaştıkça daha fazla 1 değeri görürüz:


In [ ]:
plt.plot(train_data[0])

Aşırı uyumu açıklayalım

Aşırı uyumu engellemenin en basit yolu model boyutunun küçültülmesidir. Model boyutunu, modelin katman sayısına ve katmanları içersinde yere alan birim sayısına bağlı olan öğrenebilir parametrelerin sayısı belirler. Derin öğrenmede, modelde yer alan öğrenebilir parametrelerin sayısı modelin "kapasitesi" belirlemektedir. Daha basit haliyle, daha fazla parametreye sahip model, daha fazla "hafıza kapasitesine" sahiptir. Bu nedenle, model kusursuz bir şekilde eğitim verisine uyum sağlayacaktır. Genelleme yeteneğine sahip olmayan bu modelin, daha önce görmediği veriler ile başarılı bir şekilde tahminleme yapması mümkün değildir.

Her zaman aklımızda tutmamız gerekir: derin öğrenme modelleri eğitim verisine uyum sağlama eğilimindedirler, asıl başarılması gereken bu uyum değil modele genelleme yeteneği kazandırabilmektir.

Buna karşın, eğer ağın hafızaya alma kaynakları kısıtlı ise, öğrenmesi kolay olmayacaktır. Eğitim sürecinde kayıp değerini küçültmek ve daha fazla tahminleme gücü kazanmak için, modelin sıkıştırılmış çıkarımlar oluşturması gerekecektir. Bununla birlikte, modeli küçük oluşturusak eğitim veri setine uyum sağlamakta zorluk çekecektir. "Çok fazla kapasite" ile "olması gerektiğinden az kapasite" arasında bir denge oluşturulması gerekmektedir.

Ne yazık ki, doğru büyüklükte bir model yapısını (modeldeki katman sayısı ve katmanların büyüklüğü) belirleyebileceğimiz sihirli bir formül bulunmamaktadır. Farklı model yapılarını deneyerek, problemimizin çözümü için en uygun modeli belirlememiz gerekmektedir.

Uygun model boyutunu belirlemek için, göreceli olarak az katman ve parametreye sahip bir yapıyla başlamak en iyisidir. Doğrulama kayıp değerlerinde azalma görmemeye başladığımız zamana kadar, modelin katman sayısını veya katmanlar içerisindeki birimleri artırabiliriz. Film yorumlarının sınıflandırılmasını sağlayan ağımızda bunu deneyelim:

Referans olarak, sadece Yoğun-Dense katmanlar içeren basit bir modelle başlayacağız. Sonrasında bu modelin daha küçük ve büyük versiyonlarını oluşturarak sonuçları karşılaştıracağız.

Referans modeli oluşturalım


In [ ]:
baseline_model = keras.Sequential([
    # `input_shape` is only required here so that `.summary` works. 
    keras.layers.Dense(16, activation=tf.nn.relu, input_shape=(NUM_WORDS,)),
    keras.layers.Dense(16, activation=tf.nn.relu),
    keras.layers.Dense(1, activation=tf.nn.sigmoid)
])

baseline_model.compile(optimizer='adam',
                       loss='binary_crossentropy',
                       metrics=['accuracy', 'binary_crossentropy'])

baseline_model.summary()

In [ ]:
baseline_history = baseline_model.fit(train_data,
                                      train_labels,
                                      epochs=20,
                                      batch_size=512,
                                      validation_data=(test_data, test_labels),
                                      verbose=2)

Daha küçük bir model oluşturalım

Yukarıda oluşturduğumuz referans modele göre daha az gizli birim içeren modelimizi oluşturalım:


In [ ]:
smaller_model = keras.Sequential([
    keras.layers.Dense(4, activation=tf.nn.relu, input_shape=(NUM_WORDS,)),
    keras.layers.Dense(4, activation=tf.nn.relu),
    keras.layers.Dense(1, activation=tf.nn.sigmoid)
])

smaller_model.compile(optimizer='adam',
                loss='binary_crossentropy',
                metrics=['accuracy', 'binary_crossentropy'])

smaller_model.summary()

Ve modelimizi aynı veriler ile eğitelim:


In [ ]:
smaller_history = smaller_model.fit(train_data,
                                    train_labels,
                                    epochs=20,
                                    batch_size=512,
                                    validation_data=(test_data, test_labels),
                                    verbose=2)

Daha büyük bir model oluşturalım

Daha büyük bir model oluşturabilir ve nasıl hızlı bir şekilde aşırı uyum gösterdiğini görebiliriz. Sonrasında, problem için gereğinden fazla kapasiteye sahip bu modeli, karşılaştıma grubumuza ekleyelim:


In [ ]:
bigger_model = keras.models.Sequential([
    keras.layers.Dense(512, activation=tf.nn.relu, input_shape=(NUM_WORDS,)),
    keras.layers.Dense(512, activation=tf.nn.relu),
    keras.layers.Dense(1, activation=tf.nn.sigmoid)
])

bigger_model.compile(optimizer='adam',
                     loss='binary_crossentropy',
                     metrics=['accuracy','binary_crossentropy'])

bigger_model.summary()

Ve yeniden, aynı veriler ile modeli eğitelim:


In [ ]:
bigger_history = bigger_model.fit(train_data, train_labels,
                                  epochs=20,
                                  batch_size=512,
                                  validation_data=(test_data, test_labels),
                                  verbose=2)

Eğitim ve doğrulama kayıp değerlerini grafikte gösterelim

Grafikteki düz çizgiler eğitim kayıp değerini, kesikli çizgiler ise doğrulama kayıp değerini (düşük kayıp değerlerinin daha iyi modelin göstergesi olduğunu hatırlayalım) göstermektedir. Küçük modelimizin referans modele göre daha geç (4ncü epoch yerine 6ncı epochta) aşırı uyum gösterdiğini görebiliriz. Bunun yanında küçük modelimizin performansı, aşırı uyum sonrasında daha yavaş düşmektedir.


In [ ]:
def plot_history(histories, key='binary_crossentropy'):
  plt.figure(figsize=(16,10))
    
  for name, history in histories:
    val = plt.plot(history.epoch, history.history['val_'+key],
                   '--', label=name.title()+' Val')
    plt.plot(history.epoch, history.history[key], color=val[0].get_color(),
             label=name.title()+' Train')

  plt.xlabel('Epochs')
  plt.ylabel(key.replace('_',' ').title())
  plt.legend()

  plt.xlim([0,max(history.epoch)])


plot_history([('baseline', baseline_history),
              ('smaller', smaller_history),
              ('bigger', bigger_history)])

Büyük modelimizin neredeyse hemen, ilk eopch sonrası, aşırı uyum gösterdiğini görüyoruz. Ağımızın kapasitesi arttıkça, modelin uyum gösterme hızı artıyor, bunun sonucunda eğitim kayıpları hızlıca azalıyor. Bunun yanında modelimiz eğitim verisine aşırı uyum göstermeye daha yatkın hale geliyor, bundan dolayı eğitim ve doğrulama kayıpları arasında büyük fark görüyoruz.

Stratejiler

Modelimize ağırlık regülarizasyonu (weigth regularization) ekleyelim

Occam's Razor prensibini biliyor olabilirsiniz: bu prensibe göre bir konuyla ilgili iki farklı açıklamadan doğru olması en olası seçenek, "en basit" açıklamadır yani konuyla ilgili en az varsayım içeren açıklamadır. Bu prensip, sinir ağ modelleri içinde geçerlidir: çeşitli eğitim veri setleri ve model yapıları göz önüne alındığında, veriyi açıklayan farklı ağırlık değer setleri (farklı modeller) mevcuttur ve bunların arasından en basit olanlar kompleks modellere göre daha az aşırı uyum olasılığı taşımaktadır.

Bu bağlamda "basit model", parametre değer dağılımının düzensizliğinin (entropy) az olduğu modeldir (veya yukarıdaki bölümde gördüğümüz gibi tümüyle daha az parametreye sahip modeldir). Bu nedenle aşırı uyumu engellemenin bir yoluda, ağırlıklarının küçük değerler almasına zorlayarak modelin karmaşıklığına sınırlama getirmektir. Bunun sonucunda ağırlık değerlerinin dağılımı daha "düzenli" olur. Buna "ağırlık regülarizasyonu" denir ve uygulamada büyük ağırlık değerleri için modelin kayıp fonksiyonuna ilave bir ceza değeri eklenmesiyle gerçekleştirilir. Bu ceza değerini iki farklı şekilde oluşturabiliriz:

  • L1 regülarizasyonu, bu yöntemde ceza değerleri, ağırlıkların mutlak değerleriyle orantılı olarak eklenir (buna ağırlıkların "L1 normu" denir).

  • L2 regülarizasyonu, bu yöntemde ceza değerleri, ağırlık katsayı değerlerinin karesiyle orantılı şekilde eklenir (buna ağırlıkların "L2 normu" denir). L2 regüarizasyonu aynı zamanda weigth decay olarakta adlandırılır. Farklı adlandırmalar karışıklığa neden olabilir: weigth decay ile L2 regularization aslında matematiksel olarak aynı işlemlerdir.

tf.keras'ta bu işlem, katmanlara ağırlık regülarizasyon parametre değerlerinin girilmesi ile uygulanır. Şimdi, modelimize L2 ağırlık regülarizasyonunu birlikte ekleyelim.


In [ ]:
l2_model = keras.models.Sequential([
    keras.layers.Dense(16, kernel_regularizer=keras.regularizers.l2(0.001),
                       activation=tf.nn.relu, input_shape=(NUM_WORDS,)),
    keras.layers.Dense(16, kernel_regularizer=keras.regularizers.l2(0.001),
                       activation=tf.nn.relu),
    keras.layers.Dense(1, activation=tf.nn.sigmoid)
])

l2_model.compile(optimizer='adam',
                 loss='binary_crossentropy',
                 metrics=['accuracy', 'binary_crossentropy'])

l2_model_history = l2_model.fit(train_data, train_labels,
                                epochs=20,
                                batch_size=512,
                                validation_data=(test_data, test_labels),
                                verbose=2)

l2(0.001) 'nin anlamı şudur; katmanın ağırlık matrisi içerisindeki her bir katsayı, ağın toplam kayıp değerine 0.001 * weight_coefficient_value**2 ceza değerini ekleyecektir. Bu ceza değeri sadece eğitim sürecinde ekleneceği için, kayıp değerleri eğitim sürecinde test sürecine göre çok daha büyük olacaktır.

L2 regülarizasyon ceza değerinin sonuçlara etkisini aşağıda görebiliriz:


In [ ]:
plot_history([('baseline', baseline_history),
              ('l2', l2_model_history)])

Göreceğiniz gibi, L2 regülarizasyonunun uygulandığı model, referans modelimiz ile aynı sayıda parametreye sahip olmasına karşın, aşırı uyuma çok daha dirençli bir hale geldi.

Modelimize 'dropout' ekleyelim

Dropout, Toronto Üniversitesi'nden Hilton ve öğrencileri tarafından geliştirilmiş olan bir yöntemdir. Sinir ağları için en etkin ve en yaygın kullanılan regülarizasyon yöntemlerinden biridir. Dropout, eğitim sürecinde katmanlara ait rastgele seçilen belirli sayıdaki çıktı özelliğinin "bırakılması" (değerinin sıfıra eşitlenmesiyle) anlamına gelmektedir. Örneğin, ele aldığımız katmanın eğitim sürecinde beslenen girdi değeri ile çıktı olarak [0.2, 0.5, 1.3, 0.8, 1.1] vektörü oluşturduğunu varsayalım; dropout uygulandıktan sonra bu vektör gösterildiği şekliyle rastgele dağılmış olarak çeşitli sıfır değerleri içerecektir; [0, 0.5, 1.3, 0, 1.1]. "Dropout oranı" sıfırlanacak özelliklerin oranıdır; genelde 0.2 ile 0.5 arasında bir değer alır. Test sürecinde, daha fazla aktif birime sahip olmak için hiç bir birim sıfırlanmaz, bunun yerine dengeyi korumak için katmanların çıktı değerleri droput oranı ile aynı oranda küçültülür.

tf.keras API'si Dropout katmanıyla, modelimize dropout işlemini uygulayabiliriz.

Aşırı uyumu ne oranda azalttığını değerlendirebilmek için, IMDB ağına iki adet Dropout katmanı ekleyelim:


In [ ]:
dpt_model = keras.models.Sequential([
    keras.layers.Dense(16, activation=tf.nn.relu, input_shape=(NUM_WORDS,)),
    keras.layers.Dropout(0.5),
    keras.layers.Dense(16, activation=tf.nn.relu),
    keras.layers.Dropout(0.5),
    keras.layers.Dense(1, activation=tf.nn.sigmoid)
])

dpt_model.compile(optimizer='adam',
                  loss='binary_crossentropy',
                  metrics=['accuracy','binary_crossentropy'])

dpt_model_history = dpt_model.fit(train_data, train_labels,
                                  epochs=20,
                                  batch_size=512,
                                  validation_data=(test_data, test_labels),
                                  verbose=2)

In [ ]:
plot_history([('baseline', baseline_history),
              ('dropout', dpt_model_history)])

Droput eklenmesi, referans modele göre açık bir iyileşme sunmaktadır.

Tekrardan özetleyelim: sinir ağlarında aşırı uyumu engellemek için yaygın olarak kullanılan yöntemler aşağıda listelenmiştir:

  • Daha fazla eğitim verisi kullanarak.
  • Ağın kapasitesini düşürerek.
  • Ağırlık regülarizasyonu ekleyerek.
  • Droput ekleyerek.

Ve bu notebook'ta yer almayan diğer iki önemli yöntem ise: data-augmentation ve batch normalization yöntemleridir.