Zephyrnet-logo

Forstå overtilpasning i ConvNets

Dato:

Introduksjon

Overtilpasning i ConvNets er en utfordring i dyp læring og nevrale nettverk, der en modell lærer for mye av treningsdata, noe som fører til dårlig ytelse på nye data. Dette fenomenet er spesielt utbredt i komplekse nevrale arkitekturer, som kan modellere intrikate forhold. Å adressere overtilpasning i convnet er avgjørende for å bygge pålitelige nevrale nettverksmodeller. Denne artikkelen gir en veiledning for å forstå og redusere overtilpasning, undersøke grunnleggende årsaker som modellkompleksitet, begrensede treningsdata og støyende funksjoner. Den diskuterer også teknikker for å forhindre overtilpasning, for eksempel strategier for dataforsterkning og regulariseringsmetoder.

Jeg vil anbefale å lese disse artiklene for grunnleggende forståelse av overfitting, underfitting og bias varians avveining.

Lær mål

  • Forstå årsakene, konsekvensene og scenariene for overfitting ConvNets.
  • Tolk læringskurver for å oppdage overtilpasning og undertilpasning i nevrale nettverksmodeller.
  • Lær ulike teknikker for å redusere overtilpasning, for eksempel tidlig stopp, frafall, batchnormalisering, regularisering og dataforsterkning.
  • Implementer disse teknikkene ved hjelp av tensorflow og Keras for å trene ConvNets på CIFAR-10-datasettet.
  • Analyser virkningen av ulike teknikker på modellytelse og generalisering.

Innholdsfortegnelse

Vanlige scenarier for overtilpasning i ConvNet

La oss se på noen vanlige scenarier for overtilpasning i ConvNet:

Scenario 1: Svært kompleks modell med utilstrekkelig data

Å bruke en veldig kompleks modell, for eksempel et dypt nevralt nettverk, på et lite datasett kan føre til overtilpasning. Modellen kan huske treningseksemplene i stedet for å lære det generelle mønsteret. For eksempel kan trening av et dypt nevralt nettverk med bare noen få hundre bilder for en kompleks oppgave som bildegjenkjenning føre til overtilpasning.

Konsekvens

Modellen kan prestere veldig bra på treningsdataene, men klarer ikke å generalisere til nye, usynlige data, noe som resulterer i dårlig ytelse i virkelige applikasjoner.

Hvordan løse dette problemet?

Få mer treningsdata, Gjør bildeforstørrelse for å generalisere datasettet vårt. Start med en mindre kompleks modell, og hvis kapasiteten er mindre, øk kompleksiteten. 

Scenario 2: Overdreven trening

Kontinuerlig opplæring av en modell for mange epoker kan føre til overfitting. Ettersom modellen ser treningsdataene gjentatte ganger, kan den begynne å huske dem i stedet for å lære de underliggende mønstrene.

Konsekvens

Modellens ytelse kan platå eller til og med forringes på usynlige data ettersom den blir stadig mer spesialisert til treningssettet.

Hvordan løse dette problemet?

Bruk tidlig stopp for å unngå at modellen overfiter og lagre den beste modellen. 

Scenario 3: Ignorerer regularisering

Regulariseringsteknikker, som L1- eller L2-regularisering, brukes for å forhindre overtilpasning ved å straffe komplekse modeller. Ignorering eller feiljustering av regulariseringsparametere kan føre til overtilpasning.

Konsekvens

Modellen kan bli for kompleks og mislykkes i å generalisere godt til nye data, noe som resulterer i dårlig ytelse utenfor treningssettet.

Hvordan løse dette problemet?

Implementer regularisering, Kryssvalidering, Hyper parameter tuning. 

Hva er modellens kapasitet?

En modells kapasitet refererer til størrelsen og kompleksiteten til mønstrene den er i stand til å lære. For nevrale nettverk vil dette i stor grad være bestemt av hvor mange nevroner det har og hvordan de er koblet sammen. Hvis det ser ut til at nettverket ditt undertilpasser dataene, bør du prøve å øke kapasiteten.

Du kan øke kapasiteten til et nettverk enten ved å gjøre det bredere (flere enheter til eksisterende lag) eller ved å gjøre det dypere (legge til flere lag). Bredere nettverk har lettere for å lære mer lineære relasjoner, mens dypere nettverk foretrekker mer ikke-lineære. Hva som er bedre avhenger bare av datasettet.

Tolkning av læringskurver

Keras gir muligheten til å registrere tilbakeringinger når du trener en dyp læringsmodell. En av standard tilbakeringinger som er registrert når du trener alle dyplæringsmodeller, er historietilbakekalling. Den registrerer treningsberegninger for hver epoke. Dette inkluderer tapet og nøyaktigheten (for klassifiseringsproblemer) og tapet og nøyaktigheten for valideringsdatasettet hvis et er satt.

Historieobjektet returneres fra kall til fit()-funksjonen som brukes til å trene modellen. Beregninger lagres i en ordbok i historikkmedlemmet til det returnerte objektet.

Du kan for eksempel liste opp beregningene som er samlet inn i et historieobjekt ved å bruke følgende kodebit etter at en modell er trent:

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

Utgang:

['accuracy', 'loss', 'val_accuracy', 'val_loss']

Informasjonstype

Du kan tenke på at informasjonen i treningsdataene er av to typer:

  • signal: Signalet er den delen som generaliserer, den delen som kan hjelpe modellen vår til å lage spådommer fra nye data.
  • Støy: Støyen er den delen som bare gjelder treningsdataene; støyen er alle de tilfeldige svingningene som kommer fra data i den virkelige verden eller alle de tilfeldige, ikke-informative mønstrene som faktisk ikke kan hjelpe modellen med å lage spådommer. Støyen er at delen kan se nyttig ut, men er det egentlig ikke.

Når vi trener en modell, har vi plottet tapet på treningssettet epoke for epoke. Til dette legger vi også et plott av valideringsdataene. Disse plottene kaller vi læringskurvene. For å trene dyplæringsmodeller effektivt, må vi være i stand til å tolke dem.

Læringskurver

I figuren ovenfor kan vi se at treningstapet avtar etter hvert som epokene øker, men valideringstapet avtar først og øker når modellen begynner å fange opp støy som er tilstede i datasettet. Nå skal vi se hvordan du unngår overtilpasning i ConvNets gjennom ulike teknikker. 

Metoder for å unngå overtilpasning

Nå som vi har sett noen scenarier og hvordan tolke læringskurver for å oppdage overtilpasning. la oss sjekke noen metoder for å unngå overtilpasning i et nevralt nettverk:

Metode 1: Bruk mer data

Å øke størrelsen på datasettet ditt kan hjelpe modellen til å generalisere bedre ettersom den har flere forskjellige eksempler å lære av. Modellen vil finne viktige mønstre tilstede i datasettet og ignorere støy ettersom modellen innser at de spesifikke mønstrene (støy) ikke er tilstede i hele datasettet.

Metode 2: Tidlig stopp

Tidlig stopp er en teknikk som brukes for å forhindre overtilpasning ved å overvåke ytelsen til modellen på et valideringssett under trening. Treningen stoppes når ytelsen på valideringssettet begynner å bli dårligere, noe som indikerer at modellen begynner å overfitte. Vanligvis brukes et eget valideringssett for å overvåke ytelsen, og treningen stoppes når ytelsen ikke har forbedret seg i et spesifisert antall epoker.

Undertilpassing og overfitting

Metode 3: Frafall

Vi vet at overtilpasning er forårsaket av at nettverket lærer falske mønstre (støy) i treningsdataene. For å gjenkjenne disse falske mønstrene vil et nettverk ofte stole på svært bestemte kombinasjoner av vekt, en slags "konspirasjon" av vekter. Siden de er så spesifikke, har de en tendens til å være skjøre: fjern en og konspirasjonen faller fra hverandre.

Dette er tanken bak frafall. For å bryte opp disse konspirasjonene, dropper vi tilfeldig ut en brøkdel av et lags input-enheter hvert trinn i treningen, noe som gjør det mye vanskeligere for nettverket å lære de falske mønstrene i treningsdataene. I stedet må den søke etter brede, generelle mønstre, hvis vektmønstre har en tendens til å være mer robuste. 

Du kan også tenke på frafall som å skape et slags ensemble av nettverk. Spådommene vil ikke lenger gjøres av ett stort nettverk, men i stedet av en komité med mindre nettverk. Enkeltpersoner i komiteen har en tendens til å gjøre forskjellige typer feil, men ha rett på samme tid, noe som gjør komiteen som helhet bedre enn noen enkeltperson. (Hvis du er kjent med tilfeldige skoger som et ensemble av beslutningstrær, er det samme ideen.)

Overtilpasning i ConvNets

Metode 4: Batch-normalisering

Den neste spesielle metoden vi skal se på utfører "batch-normalisering" (eller "batchnorm"), som kan hjelpe til med å korrigere trening som er langsom eller ustabil.

Med nevrale nettverk er det generelt en god idé å sette alle dataene dine på en felles skala, kanskje med noe som scikit-learns StandardScaler eller MinMaxScaler. Årsaken er at SGD vil flytte nettverksvektene i forhold til hvor stor aktivering dataene gir. Funksjoner som har en tendens til å produsere aktiveringer av svært forskjellige størrelser kan gi ustabil treningsatferd.

Nå, hvis det er bra å normalisere dataene før de går inn i nettverket, vil kanskje også normalisering inne i nettverket være bedre! Faktisk har vi en spesiell type lag som kan gjøre dette, batch-normaliseringslaget. Et batch-normaliseringslag ser på hver batch etter hvert som den kommer inn, normaliserer først batchen med sitt eget gjennomsnitt og standardavvik, og legger deretter også dataene på en ny skala med to trenbare reskaleringsparametere. Batchnorm utfører faktisk en slags koordinert skalering av inngangene.

Oftest legges batchnorm til som en hjelp til optimaliseringsprosessen (selv om det noen ganger også kan hjelpe til med prediksjonsytelse). Modeller med batchnorm har en tendens til å trenge færre epoker for å fullføre opplæring. Dessuten kan batchnorm også fikse ulike problemer som kan føre til at treningen "blir fast". Vurder å legge til batch-normalisering til modellene dine, spesielt hvis du har problemer under trening.

Metode5: L1 og L2 Regularisering

L1- og L2-regularisering er teknikker som brukes for å forhindre overtilpasning ved å straffe store vekter i det nevrale nettverket. L1-regularisering legger til et straffeledd til tapsfunksjonen proporsjonalt med den absolutte verdien av vektene. Det oppmuntrer til sparsomhet i vektene og kan føre til funksjonsvalg. L2-regularisering, også kjent som vektnedgang, legger til et straffeledd proporsjonalt med kvadratet av vektene til tapsfunksjonen. Det forhindrer at vektene blir for store og oppmuntrer til å fordele vektene jevnere.

Valget mellom L1- og L2-regularisering avhenger ofte av det spesifikke problemet og de ønskede egenskapene til modellen.

Å ha store verdier for L1/L2-regularisering vil føre til at modellen ikke lærer fort og når et platå i læringen som fører til at modellen blir dårligere. 

Metode6: Dataforsterkning

Den beste måten å forbedre ytelsen til en maskinlæringsmodell på er å trene den på mer data. Jo flere eksempler modellen har å lære av, jo bedre vil den kunne gjenkjenne hvilke forskjeller i bilder som betyr noe og hvilke som ikke gjør det. Mer data hjelper modellen til å generalisere bedre.

En enkel måte å få mer data på er å bruke dataene du allerede har. Hvis vi kan transformere bildene i datasettet vårt på måter som bevarer klassen (eksempel: MNIST-sifferklassifisering hvis vi prøver utvidelse 6 vil det være vanskelig å skille mellom 6 og 9), kan vi lære klassifikatoren vår å ignorere den typen transformasjoner. For eksempel, om en bil vender mot venstre eller høyre på et bilde, endrer ikke det faktum at det er en bil og ikke en lastebil. Så hvis vi utvider treningsdataene våre med snudde bilder, vil klassifisereren vår lære at "venstre eller høyre" er en forskjell den bør ignorere.

Og det er hele ideen bak dataforstørrelse: legg til noen ekstra falske data som ser rimelig ut som de virkelige dataene, og klassifisereren din vil forbedres. 

Husk at nøkkelen til å unngå overtilpasning er å sørge for at modellen din generaliserer godt. Sjekk alltid modellens ytelse på et valideringssett, ikke bare treningssettet.

Implementering av ovennevnte metoder med data

La oss utforske implementeringstrinn for metodene ovenfor:

Trinn 1: Laster nødvendige biblioteker

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

Trinn 2: Lasting av datasett og forhåndsbehandling

#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

Trinn 3: Lære datasett

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

Utgang:

Produksjon
np.unique(y_train)

Utgang:

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

Trinn 4: Visualisere bilde fra datasett

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

La oss nå initialisere hyperparametere og kompilere modell med optimizer, tapsfunksjon og evalueringsmetrikk.


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

Trinn 6: Treningsmodell

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

Trinn 7: Evaluer modellen

Disse vil fortelle oss informasjonen i historieobjektet, og vi bruker dem til å lage informasjonskurvene våre.

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)
Overtilpasning i ConvNets

Fra kurvene kan vi se at valideringsnøyaktigheten når et platå etter 4. epoke og modellen begynner å fange opp støy. Derfor vil vi implementere tidlig stopp for å unngå at modellen blir overmontert og gjenopprette de beste vektene basert på val_tap. Vi vil bruke val_loss for å overvåke tidlig stopp ettersom det nevrale nettverket vårt prøver å redusere tap ved hjelp av optimerere. Nøyaktighet og valideringsnøyaktighet avhenger av terskelen (en sannsynlighet for å skille klasser – vanligvis 0.5 for binær klassifisering), så hvis datasettet vårt er ubalansert, vil det være tap vi bør bekymre oss for i de fleste tilfellene. 

Trinn 8: Implementering av tidlig stopp

Siden vi ikke er bekymret for at modellen vår skal overfitte, vil tidlig stopp unngå at modellen vår skjer. Det er et godt valg å velge et høyere antall epoker og en passende tålmodighet. Nå skal vi bruke samme modellarkitektur og trene med tidlig stoppende tilbakeringing. 

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)
Overtilpasning i ConvNets

Å kjenne våre beste vekter som modellen har tatt. 

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

Trinn 9: Økende modellkompleksitet

Siden vår modell ikke gir gode resultater og undertilpasser siden den ikke er i stand til å fange nok data. Vi bør øke modellens kompleksitet og evaluere. 

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

Vi kan se at det er en økning i de totale parameterne. Dette vil bidra til å finne mer komplekse sammenhenger i modellen vår. Merk: Vårt datasett består av 32X32 bilder; dette er relativt små bilder. Derfor vil bruk av mer komplekse modeller i begynnelsen helt sikkert overpasse modellen, og derfor har vi en tendens til å øke modellens kompleksitet sakte.

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

Fra grafene ovenfor kan vi tydelig si at modellen er overtilpasset, derfor vil vi bruke en annen metode som heter Drop out normalization og Batch normalization.

Trinn 10: Bruk avfallslag og batchnormaliseringslag

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()
Produksjon
# 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)
Overtilpasning 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)

Fra læringsgrafene kan vi se at modellen er overtilpasset selv med batchnormalisering og dropout-lag. Derfor i stedet for å øke kompleksiteten, men øke antallet filtre. Vi vil legge til flere konvolusjonslag for å trekke ut flere funksjoner.

Trinn 11: Øke konvolusjonslag

Reduser den trenerbare parameteren, men øk konvolusjonslagene for å trekke ut flere funksjoner.

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)
produksjon
learning_curves(ht)
Overtilpasning 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)

Fra utgangs- og læringskurven ovenfor kan vi slutte at modellen har prestert veldig bra og har unngått overtilpasning. Treningsnøyaktigheten og valideringsnøyaktigheten er veldig nær. I dette scenariet trenger vi ikke flere metoder for å redusere overtilpasning. Likevel vil vi utforske L1/L2-regularisering. 

Trinn 12: Bruke 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)
Overtilpasning 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)

Nå kan vi se at L1/L2-regularisering selv etter å ha brukt en lav straffescore på 0.0001, gjorde at modellen vår underfittet med 4 %. Derfor er det tilrådelig å bruke alle metodene forsiktig sammen. Ettersom batchnormalisering og -regularisering påvirker modellen på lignende måte, trenger vi ikke L1/L2-regularisering. 

Trinn 13: Dataforsterkning

Vi vil bruke ImageDataGenerator fra 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()
Overtilpasning i ConvNets

Dette er fire utvidede bilder og ett originalbilde.

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

Vi har brukt tqdm-biblioteket for å vite fremdriften til utvidelsen vår.

x_train_augmented.shape, y_train_augmented.shape
Produksjon

Dette er datasettet vårt etter utvidelse. La oss nå bruke dette datasettet og trene modellen vår.

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)
Overtilpasning 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 at modellen er mer generalisert og en nedgang i tap. Vi har også fått bedre valideringsnøyaktighet. Derfor har dataforsterkning økt modellnøyaktigheten vår. 

konklusjonen

Overtilpasning er et vanlig problem i dyp læring, spesielt med komplekse nevrale nettverksarkitekturer som ConvNets. Utøvere kan forhindre overtilpasning i ConvNets ved å forstå de grunnleggende årsakene og gjenkjenne scenarier der det oppstår. Teknikker som tidlig stopp, frafall, batchnormalisering, regularisering og dataforsterkning kan bidra til å redusere dette problemet. Implementering av disse teknikkene på CIFAR-10-datasettet viste betydelige forbedringer i modellgeneralisering og ytelse. Å mestre disse teknikkene og forstå prinsippene deres kan føre til robuste og pålitelige nevrale nettverksmodeller.

Ofte Stilte Spørsmål

Q1. Hva er overfitting, og hvorfor er det et problem i dyp læring? 

A. Overtilpasning oppstår når en modell lærer treningsdataene for godt, inkludert støy og irrelevante mønstre, noe som resulterer i dårlig ytelse på nye, usynlige data. Det er et problem fordi overmonterte modeller ikke klarer å generalisere effektivt, noe som begrenser deres praktiske nytte.

Q2. Hvordan kan jeg oppdage overtilpasning i min nevrale nettverksmodell?

A. Du kan oppdage overtilpasning i ConvNets ved å tolke læringskurvene, som plotter trenings- og valideringsberegningene (f.eks. tap, nøyaktighet) over epoker. Hvis valideringsberegningene slutter å forbedre seg eller begynner å bli nedverdigende mens treningsmålene fortsetter å forbedres, er det et tegn på overtilpasning.

Q3. Hva er tidlig stopp, og hvordan bidrar det til å forhindre overtilpasning?

A. Tidlig stopp er en teknikk som overvåker modellens ytelse på et valideringssett under trening og stopper treningsprosessen når ytelsen på valideringssettet begynner å bli dårligere, noe som indikerer overfitting. Det bidrar til å forhindre at modellen overfiter ved å stoppe treningen til rett tid.

Q4. Hvordan hjelper dataforsterkning med å redusere overtilpasning? 

A. Dataforsterkning er prosessen med å generere nye, syntetiske treningsdata ved å bruke transformasjoner (f.eks. bla, rotere, skalere) på eksisterende data. Det hjelper modellen med å generalisere bedre ved å eksponere den for flere forskjellige eksempler, og reduserer risikoen for overtilpasning i ConvNets til de begrensede treningsdataene.

spot_img

Siste etterretning

spot_img