Zephyrnet-logotyp

Förstå Overfitting i ConvNets

Datum:

Beskrivning

Överanpassning i ConvNets är en utmaning i djupinlärning och neurala nätverk, där en modell lär sig för mycket från träningsdata, vilket leder till dålig prestanda på ny data. Detta fenomen är särskilt utbrett i komplexa neurala arkitekturer, som kan modellera intrikata relationer. Att åtgärda överanpassning i convnet är avgörande för att bygga tillförlitliga neurala nätverksmodeller. Den här artikeln ger en guide för att förstå och mildra överanpassning, undersöka grundorsaker som modellkomplexitet, begränsad träningsdata och bullriga funktioner. Den diskuterar också tekniker för att förhindra överanpassning, såsom dataförstärkningsstrategier och regleringsmetoder.

Jag skulle rekommendera att läsa dessa artiklar för grundläggande förståelse overfitting, underfitting och bias varians kompromiss.

Lär mål

  • Förstå orsakerna, konsekvenserna och scenarierna för överanpassning ConvNets.
  • Tolka inlärningskurvor för att upptäcka över- och underanpassning i neurala nätverksmodeller.
  • Lär dig olika tekniker för att mildra överanpassning, såsom tidig stopp, avhopp, batchnormalisering, regularisering och dataökning.
  • Implementera dessa tekniker med hjälp av TensorFlow och Keras för att träna ConvNets på CIFAR-10-datauppsättningen.
  • Analysera effekten av olika tekniker på modellprestanda och generalisering.

Innehållsförteckning

Vanliga scenarier för övermontering i ConvNet

Låt oss titta på några vanliga scenarier för överanpassning i ConvNet:

Scenario 1: Mycket komplex modell med otillräcklig data

Att använda en mycket komplex modell, som ett djupt neuralt nätverk, på en liten datauppsättning kan leda till överanpassning. Modellen kan memorera träningsexemplen istället för att lära sig det allmänna mönstret. Att träna ett djupt neuralt nätverk med bara några hundra bilder för en komplex uppgift som bildigenkänning kan till exempel leda till överanpassning.

Konsekvens

Modellen kan prestera mycket bra på träningsdata men misslyckas med att generalisera till nya, osynliga data, vilket resulterar i dålig prestanda i verkliga tillämpningar.

Hur löser man det här problemet?

Få mer träningsdata, Gör bildförstoring för att generalisera vår datauppsättning. Börja med en mindre komplex modell och om kapaciteten är mindre, öka komplexiteten. 

Scenario 2: Överdriven träning

Att kontinuerligt träna en modell under för många epoker kan leda till överanpassning. Eftersom modellen ser träningsdata upprepade gånger kan den börja memorera det snarare än att lära sig de underliggande mönstren.

Konsekvens

Modellens prestanda kan platåa eller till och med försämras på osynliga data när den blir allt mer specialiserad för träningsuppsättningen.

Hur löser man det här problemet?

Använd tidig stopp för att undvika att modellen överpassar och spara den bästa modellen. 

Scenario 3: Ignorera regularisering

Regulariseringstekniker, såsom L1- eller L2-regularisering, används för att förhindra överanpassning genom att straffa komplexa modeller. Att ignorera eller felaktigt inställa regleringsparametrar kan leda till överanpassning.

Konsekvens

Modellen kan bli alltför komplex och misslyckas med att generalisera bra till nya data, vilket resulterar i dålig prestation utanför träningsuppsättningen.

Hur löser man det här problemet?

Implementera regularisering, korsvalidering, hyperparameterjustering. 

Vad är modellens kapacitet?

En modells kapacitet avser storleken och komplexiteten hos de mönster den kan lära sig. För neurala nätverk kommer detta till stor del att bestämmas av hur många neuroner det har och hur de är sammankopplade. Om det verkar som att ditt nätverk underpassar data, bör du försöka öka dess kapacitet.

Du kan öka kapaciteten för ett nätverk antingen genom att göra det bredare (fler enheter till befintliga lager) eller genom att göra det djupare (lägga till fler lager). Bredare nätverk har lättare att lära sig mer linjära relationer, medan djupare nätverk föredrar mer olinjära. Vilket som är bättre beror bara på datasetet.

Tolkning av inlärningskurvor

Keras ger möjligheten att registrera återuppringningar när du tränar en modell för djupinlärning. En av de standardåteruppringningar som registreras när man tränar alla modeller för djupinlärning är Historikåteruppringningen. Den registrerar träningsmått för varje epok. Detta inkluderar förlusten och noggrannheten (för klassificeringsproblem) och förlusten och noggrannheten för valideringsdatauppsättningen om en sådan är inställd.

Historikobjektet returneras från anrop till funktionen fit() som används för att träna modellen. Mätvärden lagras i en ordbok i historikmedlemmen för det returnerade objektet.

Du kan till exempel lista mätvärdena som samlats in i ett historikobjekt med hjälp av följande kodavsnitt efter att en modell har tränats:

# list all data in history
print(history.history.keys())

Produktion:

['precision', 'loss', 'val_accuracy', 'val_loss']

Informationstyp

Du kan tänka dig att informationen i träningsdata är av två slag:

  • signal: Signalen är den del som generaliserar, den del som kan hjälpa vår modell att göra förutsägelser från ny data.
  • Buller: Bruset är den del som bara är sant för träningsdata; bruset är alla slumpmässiga fluktuationer som kommer från data i den verkliga världen eller alla tillfälliga, icke-informativa mönster som faktiskt inte kan hjälpa modellen att göra förutsägelser. Bruset är att delen kan se användbar ut men är det verkligen inte.

När vi tränar en modell har vi ritat in förlusten på träningssetet epok för epok. Till detta kommer vi också att lägga till en plot av valideringsdata. Dessa plotter kallar vi inlärningskurvorna. För att träna modeller för djupinlärning effektivt måste vi kunna tolka dem.

Inlärningskurvor

I figuren ovan kan vi se att träningsförlusten minskar när epokerna ökar, men valideringsförlusten minskar till en början och ökar när modellen börjar fånga upp brus som finns i datasetet. Nu ska vi se hur man undviker överanpassning i ConvNets genom olika tekniker. 

Metoder för att undvika övermontering

Nu när vi har sett några scenarier och hur man tolkar inlärningskurvor för att upptäcka överanpassning. låt oss kolla in några metoder för att undvika överanpassning i ett neuralt nätverk:

Metod 1: Använd mer data

Att öka storleken på din datauppsättning kan hjälpa modellen att generalisera bättre eftersom den har fler olika exempel att lära av. Modellen kommer att hitta viktiga mönster som finns i datasetet och ignorera brus eftersom modellen inser att de specifika mönstren (brus) inte finns i hela datamängden.

Metod 2: Tidig stopp

Tidig stopp är en teknik som används för att förhindra överanpassning genom att övervaka modellens prestanda på ett valideringsset under träning. Träningen stoppas när prestandan på valideringssetet börjar försämras, vilket indikerar att modellen börjar överanpassas. Vanligtvis används en separat valideringsuppsättning för att övervaka prestanda, och träningen stoppas när prestandan inte har förbättrats under ett specificerat antal epoker.

Underpassning och övermontering

Metod 3: Avhopp

Vi vet att överanpassning orsakas av att nätverket lär sig falska mönster (brus) i träningsdata. För att känna igen dessa falska mönster kommer ett nätverk ofta att förlita sig på mycket specifika kombinationer av vikt, en sorts "konspiration" av vikter. Eftersom de är så specifika tenderar de att vara ömtåliga: ta bort en och konspirationen faller isär.

Detta är tanken bakom avhopp. För att bryta upp dessa konspirationer tappar vi slumpmässigt en del av ett lagers indataenheter varje steg i träningen, vilket gör det mycket svårare för nätverket att lära sig de falska mönstren i träningsdatan. Istället måste den söka efter breda, allmänna mönster, vars viktmönster tenderar att vara mer robusta. 

Man kan också tänka på avhopp som att skapa en sorts ensemble av nätverk. Förutsägelserna kommer inte längre att göras av ett stort nätverk, utan istället av en kommitté av mindre nätverk. Individer i kommittén tenderar att göra olika typer av misstag, men ha rätt samtidigt, vilket gör kommittén som helhet bättre än någon individ. (Om du är bekant med slumpmässiga skogar som en ensemble av beslutsträd, är det samma idé.)

Överanpassning i ConvNets

Metod 4: Batchnormalisering

Nästa speciella metod vi ska titta på utför "batch-normalisering" (eller "batchnorm"), vilket kan hjälpa till att rätta till träning som är långsam eller instabil.

Med neurala nätverk är det i allmänhet en bra idé att placera all din data på en gemensam skala, kanske med något som scikit-learns StandardScaler eller MinMaxScaler. Anledningen är att SGD kommer att flytta nätverksvikterna i proportion till hur stor aktivering data producerar. Funktioner som tenderar att producera aktiveringar av väldigt olika storlekar kan ge instabilt träningsbeteende.

Nu, om det är bra att normalisera data innan den går in i nätverket, kanske också normalisering inuti nätverket skulle vara bättre! Faktum är att vi har en speciell sorts lager som kan göra detta, batchnormaliseringslagret. Ett batchnormaliseringslager tittar på varje batch när det kommer in, först normaliserar batchen med sitt eget medelvärde och standardavvikelse, och lägger sedan även data på en ny skala med två träningsbara omskalningsparametrar. Batchnorm utför i själva verket en sorts koordinerad omskalning av sina ingångar.

Oftast läggs batchnorm till som ett hjälpmedel i optimeringsprocessen (även om det ibland också kan hjälpa till att förutsäga prestanda). Modeller med batchnorm tenderar att behöva färre epoker för att slutföra utbildning. Dessutom kan batchnorm också fixa olika problem som kan göra att träningen "fastnar". Överväg att lägga till batchnormalisering till dina modeller, särskilt om du har problem under träningen.

Metod5: L1 och L2 Regularisering

L1- och L2-regularisering är tekniker som används för att förhindra överanpassning genom att straffa stora vikter i det neurala nätverket. L1-regularisering lägger till en straffterm till förlustfunktionen proportionell mot vikternas absoluta värde. Det uppmuntrar gleshet i vikterna och kan leda till funktionsval. L2-regularisering, även känd som viktnedgång, lägger till en straffterm som är proportionell mot kvadraten på vikterna till förlustfunktionen. Det förhindrar att vikterna blir för stora och uppmuntrar till att viktfördelningen fördelas jämnare.

Valet mellan L1- och L2-regularisering beror ofta på det specifika problemet och de önskade egenskaperna hos modellen.

Att ha höga värden för L1/L2-regularisering kommer att göra att modellen inte lär sig snabbt och når en platå i inlärningen vilket gör att modellen underpassas. 

Metod 6: Dataökning

Det bästa sättet att förbättra prestandan för en maskininlärningsmodell är att träna den på mer data. Ju fler exempel modellen har att lära av, desto bättre kommer den att kunna känna igen vilka skillnader i bilder som spelar roll och vilka som inte gör det. Mer data hjälper modellen att generalisera bättre.

Ett enkelt sätt att få mer data är att använda den data du redan har. Om vi ​​kan transformera bilderna i vår datauppsättning på sätt som bevarar klassen (exempel: MNIST-sifferklassificering om vi försöker augment 6 blir det svårt att skilja mellan 6 och 9), kan vi lära vår klassificerare att ignorera den typen av transformationer. Om en bil till exempel är vänd åt vänster eller höger på ett foto ändrar inte det faktum att det är en bil och inte en lastbil. Så om vi utökar vår träningsdata med vända bilder kommer vår klassificerare att lära sig att "vänster eller höger" är en skillnad som den bör ignorera.

Och det är hela idén bakom dataökning: lägg till lite extra falska data som ser rimligt ut som den verkliga datan så kommer din klassificerare att förbättras. 

Kom ihåg att nyckeln till att undvika övermontering är att se till att din modell generaliserar väl. Kontrollera alltid din modells prestanda på ett valideringsset, inte bara träningssetet.

Implementering av ovanstående metoder med data

Låt oss utforska implementeringsstegen för ovanstående metoder:

Steg 1: Laddar nödvändiga bibliotek

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import tensorflow as tf
from tensorflow.keras import datasets, layers, models
from tensorflow.keras.preprocessing.image import ImageDataGenerator
from tensorflow.keras.callbacks import ModelCheckpoint
import keras
from keras.preprocessing import image
from keras import models, layers, regularizers
from tqdm import tqdm
import warnings
warnings.filterwarnings(action='ignore')

Steg 2: Ladda datauppsättning och förbearbetning

#Here all the images are in the form of a numpy array
cifar10 = tf.keras.datasets.cifar10
(x_train, y_train), (x_test, y_test) = cifar10.load_data()
x_train = x_train / 255.0
x_test = x_test / 255.0

Steg 3: Lär dig datauppsättning

x_train.shape, y_train.shape, x_test.shape, y_test.shape 

Produktion:

Produktion
np.unique(y_train)

Produktion:

Produktion
#These labels are in the order and taken from the documentaion
class_names = ['airplane', 'automobile', 'bird', 'cat', 'deer',
               'dog', 'frog', 'horse', 'ship', 'truck']

Steg 4: Visualisera bild från Dataset

def show_image(IMG_INDEX):
    plt.imshow(x_train[20] ,cmap=plt.cm.binary)
    plt.xlabel(class_names[y_train[IMG_INDEX][0]])
    plt.show()
show_image(20)
Överanpassning i ConvNets
model = models.Sequential()
model.add(layers.Conv2D(32, (3, 3), activation='relu', input_shape=(32, 32, 3)))
model.add(layers.AveragePooling2D((2, 2)))
model.add(layers.Conv2D(64, (3, 3), activation='relu'))
model.add(layers.AveragePooling2D((2, 2)))
model.add(layers.Conv2D(64, (3, 3), activation='relu'))
model.add(layers.Flatten())
model.add(layers.Dense(64, activation='relu'))
model.add(layers.Dense(10))
model.summary()

Låt oss nu initiera hyperparametrar och kompilera modell med optimerare, förlustfunktion och utvärderingsmått.


train_hyperparameters_config={'optim':keras.optimizers.Adam(learning_rate=0.001),
                             'epochs':20,
                              'batch_size':16
                             }
model.compile(optimizer=train_hyperparameters_config['optim'],
                  loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
                  metrics=['accuracy'])

Steg 6: Träningsmodell

history = model.fit(x_train, y_train, 
                        epochs=train_hyperparameters_config['epochs'], 
                        batch_size=train_hyperparameters_config['batch_size'], 
                        verbose=1,
                        validation_data=(x_test, y_test))

Steg 7: Utvärdera modellen

Dessa kommer att berätta för oss informationen som finns i historieobjektet och vi använder dem för att skapa våra informationskurvor.

print(history.history.keys()) 
def learning_curves(history):
# Plotting Accuracy
    plt.figure(figsize=(14, 5))  # Adjust the figure size as needed
    plt.subplot(1, 2, 1)  # Subplot with 1 row, 2 columns, and index 1
    plt.plot(history.history['accuracy'], label='train_accuracy', marker='s', markersize=4)
    plt.plot(history.history['val_accuracy'], label='val_accuracy', marker='*', markersize=4)
    plt.xlabel('Epoch')
    plt.ylabel('Accuracy')
    plt.legend(loc='lower right')

    # Plotting Loss
    plt.subplot(1, 2, 2)  # Subplot with 1 row, 2 columns, and index 2
    plt.plot(history.history['loss'], label='train_loss', marker='s', markersize=4)
    plt.plot(history.history['val_loss'], label='val_loss', marker='*', markersize=4)
    plt.xlabel('Epoch')
    plt.ylabel('Loss')
    plt.legend(loc='lower right')

    plt.show()
learning_curves(history)
Överanpassning i ConvNets

Från kurvorna kan vi se att valideringsnoggrannheten når en platå efter den 4:e epoken och modellen börjar fånga brus. Därför kommer vi att implementera tidig stopp för att undvika att modellen överpassar och återställa de bästa vikterna baserat på val_loss. Vi kommer att använda val_loss för att övervaka tidigt stopp när vårt neurala nätverk försöker minska förlusten med hjälp av optimerare. Noggrannhet och valideringsnoggrannhet beror på tröskeln (en sannolikhet att separera klasser – vanligtvis 0.5 för binär klassificering), så om vår datauppsättning är obalanserad skulle det vara förlust vi bör oroa oss för i de flesta fall. 

Steg 8: Implementera tidig stopp

Eftersom vi inte är oroliga för att vår modell ska överanpassa, så kommer tidig stopp undvika att vår modell händer. Det är ett bra val att välja ett högre antal epoker och ett lämpligt tålamod. Nu kommer vi att använda samma modellarkitektur och träna med tidig återuppringning. 

model = models.Sequential()
model.add(layers.Conv2D(32, (3, 3), activation='relu', input_shape=(32, 32, 3)))
model.add(layers.AveragePooling2D((2, 2)))
model.add(layers.Conv2D(64, (3, 3), activation='relu'))
model.add(layers.AveragePooling2D((2, 2)))
model.add(layers.Conv2D(64, (3, 3), activation='relu'))
model.add(layers.Flatten())
model.add(layers.Dense(128, activation='relu'))
model.add(layers.Dense(64, activation='relu'))
model.add(layers.Dense(10))
model.summary()

# Here we have used more epochs than needed since we use patience parameter which we stop the model from overfitting
train_hyperparameters_config = {
    'optim': keras.optimizers.Adam(learning_rate=0.001),
    'patience': 5,
    'epochs': 50,
    'batch_size': 32, 
}
print('Setting the callback and early stopping configurations...')
callback = tf.keras.callbacks.EarlyStopping(
    monitor='val_loss', 
    min_delta=0.001, # minimium amount of change to count as an improvement
    patience=train_hyperparameters_config['patience'], 
    restore_best_weights=True)

def model_train(model, x_train, y_train, x_test, y_test, train_hyperparameters_config):
    model.compile(optimizer=train_hyperparameters_config['optim'],
                      loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
                      metrics=['accuracy'])
    ht = model.fit(x_train, y_train, 
                            epochs=train_hyperparameters_config['epochs'], 
                            batch_size=train_hyperparameters_config['batch_size'],
                            callbacks=[callback],
                            verbose=1,
                            validation_data=(x_test, y_test))
    return ht

ht=model_train(model, x_train, y_train, x_test, y_test, train_hyperparameters_config)
learning_curves(ht)
Överanpassning i ConvNets

Att veta våra bästa vikter som modellen har tagit. 

print('Testing ..................')
test_loss, test_acc = model.evaluate(x_test,  y_test, verbose=2)
print('test_loss : ', test_loss, 'test_accuracy : ', test_acc)

Steg 9: Öka modellens komplexitet

Eftersom vår modell inte fungerar bra och underpassar eftersom den inte kan fånga tillräckligt med data. Vi bör öka vår modellkomplexitet och utvärdera. 

model = models.Sequential()

model.add(layers.Conv2D(128, (3, 3), activation='relu', input_shape=(32, 32, 3)))
model.add(layers.MaxPooling2D((2, 2)))

model.add(layers.Conv2D(256, (3, 3), activation='relu'))
model.add(layers.MaxPooling2D((2, 2)))

model.add(layers.Conv2D(256, (3, 3), activation='relu'))
model.add(layers.MaxPooling2D((2, 2)))

model.add(layers.Conv2D(512, (3, 3), activation='relu', padding='same'))
model.add(layers.MaxPooling2D((2, 2)))

model.add(layers.Flatten())
model.add(layers.Dense(256, activation='relu'))
model.add(layers.Dense(128, activation='relu'))
model.add(layers.Dense(10, activation='softmax'))
model.summary()
Produktion

Vi kan se att de totala parametrarna ökar. Detta skulle hjälpa till att hitta mer komplexa relationer i vår modell. Obs: Vår datauppsättning består av 32X32 bilder; det är relativt små bilder. Att använda mer komplexa modeller i början kommer därför säkerligen att överpassa modellen och därför tenderar vi att långsamt öka vår modellkomplexitet.

# Here we have used more epochs than needed since we use patience parameter which we stop the model from overfitting
train_hyperparameters_config = {
    'optim': keras.optimizers.Adam(learning_rate=0.001),
    'patience': 5,
    'epochs': 50,
    'batch_size': 32, 
}
print('Setting the callback and early stopping configurations...')
callback = tf.keras.callbacks.EarlyStopping(
    monitor='val_loss', 
    min_delta=0.001, # minimium amount of change to count as an improvement
    patience=train_hyperparameters_config['patience'], 
    restore_best_weights=True)
ht=model_train(model, x_train, y_train, x_test, y_test, train_hyperparameters_config)

learning_curves(ht)
Överanpassning i ConvNets
print('Testing ..................')
test_loss, test_acc = model.evaluate(x_test,  y_test, verbose=2)
print('test_loss : ', test_loss, 'test_accuracy : ', test_acc)

Från ovanstående grafer kan vi tydligt säga att modellen är överanpassad, därför kommer vi att använda en annan metod som heter Drop out normalization och Batch normalization.

Steg 10: Använda bortfallslager och batchnormaliseringslager

model = models.Sequential()

model.add(layers.Conv2D(128, (3, 3), activation='relu', input_shape=(32, 32, 3)))
model.add(layers.BatchNormalization())
model.add(layers.MaxPooling2D((2, 2)))

model.add(layers.Conv2D(256, (3, 3), activation='relu'))
model.add(layers.BatchNormalization())
model.add(layers.MaxPooling2D((2, 2)))

model.add(layers.Conv2D(256, (3, 3), activation='relu'))
model.add(layers.BatchNormalization())
model.add(layers.MaxPooling2D((2, 2)))

model.add(layers.Conv2D(512, (3, 3), activation='relu', padding='same'))
model.add(layers.BatchNormalization())
model.add(layers.MaxPooling2D((2, 2)))

model.add(layers.Flatten())
model.add(layers.Dense(256, activation='relu'))
model.add(layers.BatchNormalization())
model.add(layers.Dropout(0.3))

model.add(layers.Dense(128, activation='relu'))
model.add(layers.BatchNormalization())
model.add(layers.Dropout(0.3))

model.add(layers.Dense(10, activation='softmax'))
model.summary()
Produktion
# Here we have used more epochs than needed since we use patience parameter which we stop the model from overfitting
train_hyperparameters_config = {
    'optim': keras.optimizers.Adam(learning_rate=0.001),
    'patience': 5,
    'epochs': 50,
    'batch_size': 32, 
}
print('Setting the callback and early stopping configurations...')
callback = tf.keras.callbacks.EarlyStopping(
    monitor='val_loss', 
    min_delta=0.001, # minimium amount of change to count as an improvement
    patience=train_hyperparameters_config['patience'], 
    restore_best_weights=True)
ht=model_train(model, x_train, y_train, x_test, y_test, train_hyperparameters_config)
learning_curves(ht)
Överanpassning i ConvNets
print('Testing ..................')
test_loss, test_acc = model.evaluate(x_test,  y_test, verbose=2)
print('test_loss : ', test_loss, 'test_accuracy : ', test_acc)

Från inlärningsgraferna kan vi se att modellen är överanpassad även med batchnormalisering och bortfallsskikt. Därav istället för att öka komplexiteten utan öka antalet filter. Vi skulle lägga till fler faltningslager för att extrahera fler funktioner.

Steg 11: Öka faltningslager

Minska den träningsbara parametern men öka faltningsskikten för att extrahera fler funktioner.

model = models.Sequential()

model.add(layers.Conv2D(32, (3, 3), activation='relu', padding='same', input_shape=(32, 32, 3)))
model.add(layers.BatchNormalization())
model.add(layers.Conv2D(32, (3, 3), activation='relu', padding='same'))
model.add(layers.BatchNormalization())
model.add(layers.MaxPool2D((2, 2)))
model.add(layers.Dropout(0.2))

model.add(layers.Conv2D(64, (3, 3), activation='relu', padding='same'))
model.add(layers.BatchNormalization())
model.add(layers.Conv2D(64, (3, 3), activation='relu', padding='same'))
model.add(layers.BatchNormalization())
model.add(layers.MaxPool2D((2, 2)))
model.add(layers.Dropout(0.3))

model.add(layers.Conv2D(128, (3, 3), activation='relu', padding='same'))
model.add(layers.BatchNormalization())
model.add(layers.Conv2D(128, (3, 3), activation='relu', padding='same'))
model.add(layers.BatchNormalization())
model.add(layers.MaxPool2D((2, 2)))
model.add(layers.Dropout(0.4))

model.add(layers.Flatten())
model.add(layers.Dense(128, activation='relu'))
model.add(layers.BatchNormalization())
model.add(layers.Dropout(0.5))

model.add(layers.Dense(10, activation='softmax'))

model.summary()
# Here we have used more epochs than needed since we use patience parameter which we stop the model from overfitting
train_hyperparameters_config = {
    'optim': keras.optimizers.Adam(learning_rate=0.001),
    'patience': 5,
    'epochs': 50,
    'batch_size': 32, 
}
print('Setting the callback and early stopping configurations...')
callback = tf.keras.callbacks.EarlyStopping(
    monitor='val_loss', 
    min_delta=0.001, # minimium amount of change to count as an improvement
    patience=train_hyperparameters_config['patience'], 
    restore_best_weights=True)
ht=model_train(model, x_train, y_train, x_test, y_test, train_hyperparameters_config)
produktion
learning_curves(ht)
Överanpassning i ConvNets
print('Testing ..................')
test_loss, test_acc = model.evaluate(x_test,  y_test, verbose=2)
print('test_loss : ', test_loss, 'test_accuracy : ', test_acc)

Från ovanstående output och inlärningskurva kan vi dra slutsatsen att modellen har presterat mycket bra och har undvikit överanpassning. Träningsnoggrannheten och valideringsnoggrannheten är mycket nära. I detta scenario kommer vi inte att behöva fler metoder för att minska övermontering. Ändå kommer vi att utforska L1/L2-regularisering. 

Steg 12: Använd L1/L2-regularisering

from tensorflow.keras import regularizers

model = models.Sequential()

model.add(layers.Conv2D(32, (3, 3), activation='relu', padding='same', input_shape=(32, 32, 3)))
model.add(layers.BatchNormalization())
model.add(layers.Conv2D(32, (3, 3), activation='relu', padding='same', kernel_regularizer=regularizers.l1(0.0005)))
model.add(layers.BatchNormalization())
model.add(layers.MaxPool2D((2, 2)))
model.add(layers.Dropout(0.2))

model.add(layers.Conv2D(64, (3, 3), activation='relu', padding='same'))
model.add(layers.BatchNormalization())
model.add(layers.Conv2D(64, (3, 3), activation='relu', padding='same', kernel_regularizer=regularizers.l2(0.0005)))
model.add(layers.BatchNormalization())
model.add(layers.MaxPool2D((2, 2)))
model.add(layers.Dropout(0.3))

model.add(layers.Conv2D(128, (3, 3), activation='relu', padding='same'))
model.add(layers.BatchNormalization())
model.add(layers.Conv2D(128, (3, 3), activation='relu', padding='same'))
model.add(layers.BatchNormalization())
model.add(layers.MaxPool2D((2, 2)))
model.add(layers.Dropout(0.4))

model.add(layers.Flatten())
model.add(layers.Dense(128, activation='relu', kernel_regularizer=regularizers.l1_l2(0.0005, 0.0005)))
model.add(layers.BatchNormalization())
model.add(layers.Dropout(0.5))
model.add(layers.Dense(10, activation='softmax'))

model.summary()
# Here we have used more epochs than needed since we use patience parameter which we stop the model from overfitting
train_hyperparameters_config = {
    'optim': keras.optimizers.Adam(learning_rate=0.001),
    'patience': 7,
    'epochs': 70,
    'batch_size': 32, 
}
print('Setting the callback and early stopping configurations...')
callback = tf.keras.callbacks.EarlyStopping(
    monitor='val_loss', 
    min_delta=0.001, # minimium amount of change to count as an improvement
    patience=train_hyperparameters_config['patience'], 
    restore_best_weights=True)
ht=model_train(model, x_train, y_train, x_test, y_test, train_hyperparameters_config)
learning_curves(ht)
Överanpassning i ConvNets
print('Testing ..................')
test_loss, test_acc = model.evaluate(x_test,  y_test, verbose=2)
print('test_loss : ', test_loss, 'test_accuracy : ', test_acc)

Nu kan vi se att L1/L2-regularisering även efter att ha använt ett lågt straffvärde på 0.0001, gjorde att vår modell underpassade med 4 %. Därför är det tillrådligt att försiktigt använda alla metoderna tillsammans. Eftersom batchnormalisering och -regularisering påverkar modellen på liknande sätt skulle vi inte behöva L1/L2-regularisering. 

Steg 13: Dataökning

Vi kommer att använda ImageDataGenerator från tensorflow keras.

# creates a data generator object that transforms images
datagen = ImageDataGenerator(
rotation_range=40,
width_shift_range=0.2,
height_shift_range=0.2,
shear_range=0.2,
zoom_range=0.2,
horizontal_flip=True,
fill_mode='nearest')

# pick an image to transform
test_img = x_train[20]
img = image.img_to_array(test_img)  # convert image to numpy arry
img = img.reshape((1,) + img.shape)  # reshape image

i = 0

for batch in datagen.flow(img, save_prefix='test', save_format='jpeg'):  # this loops runs forever until we break, saving images to current directory with specified prefix
    plt.figure(i)
    plot = plt.imshow(image.img_to_array(batch[0]))
    i += 1
    if i > 4:  # show 4 images
        break

plt.show()
Överanpassning i ConvNets

Det här är fyra utökade bilder och en originalbild.

# Create an instance of the ImageDataGenerator
datagen = ImageDataGenerator(
    rotation_range=40,
    width_shift_range=0.2,
    height_shift_range=0.2,
    shear_range=0.2,
    zoom_range=0.2,
    horizontal_flip=True,
    fill_mode='nearest'
)

# Create an iterator for the data generator
data_generator = datagen.flow(x_train, y_train, batch_size=32)

# Create empty lists to store the augmented images and labels
augmented_images = []
augmented_labels = []

# Loop over the data generator and append the augmented data to the lists
num_batches = len(x_train) // 32
progress_bar = tqdm(total=num_batches, desc="Augmenting data", unit="batch")

for i in range(num_batches):
    batch_images, batch_labels = next(data_generator)
    augmented_images.append(batch_images)
    augmented_labels.append(batch_labels)
    progress_bar.update(1)

progress_bar.close()

# Convert the lists to NumPy arrays
augmented_images = np.concatenate(augmented_images, axis=0)
augmented_labels = np.concatenate(augmented_labels, axis=0)

# Combine the original and augmented data
x_train_augmented = np.concatenate((x_train, augmented_images), axis=0)
y_train_augmented = np.concatenate((y_train, augmented_labels), axis=0)
produktion

Vi har använt tqdm-biblioteket för att känna till framstegen med vår förstärkning.

x_train_augmented.shape, y_train_augmented.shape
Produktion

Detta är vår datauppsättning efter förstärkning. Låt oss nu använda denna datauppsättning och träna vår modell.

model = models.Sequential()

model.add(layers.Conv2D(32, (3, 3), activation='relu', padding='same', input_shape=(32, 32, 3)))
model.add(layers.BatchNormalization())
model.add(layers.Conv2D(32, (3, 3), activation='relu', padding='same'))
model.add(layers.BatchNormalization())
model.add(layers.MaxPool2D((2, 2)))
model.add(layers.Dropout(0.2))

model.add(layers.Conv2D(64, (3, 3), activation='relu', padding='same'))
model.add(layers.BatchNormalization())
model.add(layers.Conv2D(64, (3, 3), activation='relu', padding='same'))
model.add(layers.BatchNormalization())
model.add(layers.MaxPool2D((2, 2)))
model.add(layers.Dropout(0.3))

model.add(layers.Conv2D(128, (3, 3), activation='relu', padding='same'))
model.add(layers.BatchNormalization())
model.add(layers.Conv2D(128, (3, 3), activation='relu', padding='same'))
model.add(layers.BatchNormalization())
model.add(layers.MaxPool2D((2, 2)))
model.add(layers.Dropout(0.4))

model.add(layers.Flatten())
model.add(layers.Dense(128, activation='relu'))
model.add(layers.BatchNormalization())
model.add(layers.Dropout(0.5))

model.add(layers.Dense(10, activation='softmax'))

model.summary()

# Here we have used more epochs than needed since we use patience parameter which we stop the model from overfitting
train_hyperparameters_config = {
    'optim': keras.optimizers.Adam(learning_rate=0.001),
    'patience': 10,
    'epochs': 70,
    'batch_size': 32, 
}
print('Setting the callback and early stopping configurations...')
callback = tf.keras.callbacks.EarlyStopping(
    monitor='val_loss', 
    min_delta=0.001, # minimium amount of change to count as an improvement
    patience=train_hyperparameters_config['patience'], 
    restore_best_weights=True)

ht=model_train(model, x_train_augmented, y_train_augmented, x_test, y_test, train_hyperparameters_config)


learning_curves(ht)
Överanpassning i ConvNets
print('Testing ..................')
test_loss, test_acc = model.evaluate(x_test,  y_test, verbose=2)
print('test_loss : ', test_loss, 'test_accuracy : ', test_acc)

Vi kan se att modellen är mer generaliserad och en minskning av förlusten. Vi har också fått bättre valideringsnoggrannhet. Därför har dataökning ökat vår modellnoggrannhet. 

Slutsats

Överanpassning är ett vanligt problem vid djupinlärning, särskilt med komplexa neurala nätverksarkitekturer som ConvNets. Utövare kan förhindra överanpassning i ConvNets genom att förstå dess grundorsaker och känna igen scenarier där det inträffar. Tekniker som tidig stopp, avhopp, batchnormalisering, regularisering och dataförstärkning kan hjälpa till att lindra detta problem. Implementering av dessa tekniker på CIFAR-10-datauppsättningen visade betydande förbättringar i modellgeneralisering och prestanda. Att behärska dessa tekniker och förstå deras principer kan leda till robusta och pålitliga neurala nätverksmodeller.

Vanliga frågor

Q1. Vad är överfitting, och varför är det ett problem i djupinlärning? 

S. Överanpassning inträffar när en modell lär sig träningsdata för väl, inklusive dess brus och irrelevanta mönster, vilket resulterar i dålig prestanda på nya, osynliga data. Det är ett problem eftersom övermonterade modeller misslyckas med att generalisera effektivt, vilket begränsar deras praktiska användbarhet.

Q2. Hur kan jag upptäcka överanpassning i min neurala nätverksmodell?

S. Du kan upptäcka överanpassning i ConvNets genom att tolka inlärningskurvorna, som plottar tränings- och valideringsmåtten (t.ex. förlust, noggrannhet) över epoker. Om valideringsmåtten slutar att förbättras eller börjar försämras medan träningsmåtten fortsätter att förbättras, är det ett tecken på överanpassning.

Q3. Vad är tidig stopp och hur hjälper det till att förhindra överanpassning?

S. Tidig stopp är en teknik som övervakar modellens prestanda på ett valideringsset under träning och stoppar träningsprocessen när prestandan på valideringssetet börjar försämras, vilket indikerar överanpassning. Det hjälper till att förhindra att modellen överanpassar sig genom att avbryta träningen vid rätt tidpunkt.

Q4. Hur hjälper dataökning till att lindra överanpassning? 

S. Dataökning är processen att generera nya, syntetiska träningsdata genom att tillämpa transformationer (t.ex. vända, rotera, skala) på befintliga data. Det hjälper modellen att generalisera bättre genom att exponera den för fler olika exempel, vilket minskar risken att överanpassa ConvNets till begränsad träningsdata.

plats_img

Senaste intelligens

plats_img