U hebt uw eerste machine learning-model getraind. Het presteert briljant op basis van uw trainingsgegevens: 98% nauwkeurigheid! Je test het op nieuwe gegevens en het valt uiteen: 61% nauwkeurigheid. Wat ging er mis?
Het is vrijwel zeker dat uw model overfit heeft. Dit is een van de twee meest voorkomende faalwijzen bij machinaal leren, en het begrijpen ervan – naast het tegenovergestelde, underfitting – is essentieel voor het bouwen van modellen die daadwerkelijk werken in de echte wereld.
Voordat we in de voorbeelden duiken, helpt het om het theoretische raamwerk achter deze concepten te begrijpen: de afweging tussen bias en variantie.
Elk model maakt voorspellingsfouten. Deze fouten kunnen in drie delen worden opgesplitst:
Total Error = Bias² + Variance + Irreducible Noise
Bias is de fout die voortkomt uit verkeerde aannames in het model. Een model met hoge bias is te simpel: het mist systematisch het ware patroon in de gegevens.
Variantie is de fout die voortvloeit uit de gevoeligheid voor kleine fluctuaties in de trainingsgegevens. Een model met hoge variantie is te complex: het onthoudt de trainingsgegevens, inclusief de ruis, in plaats van het onderliggende patroon te leren.
Onherleidbare ruis is de natuurlijke willekeur in de gegevens die geen enkel model kan elimineren.
De wisselwerking: het verminderen van bias heeft de neiging de variantie te vergroten, en vice versa. Jouw taak als beoefenaar van machine learning is om de goede plek te vinden.
Onderfitting treedt op wanneer uw model te eenvoudig is om het ware patroon in de gegevens vast te leggen. Het presteert slecht op zowel trainingsgegevens als nieuwe gegevens.
Stel je voor dat je gegevens hebt die huizenprijzen laten zien op basis van grootte. De werkelijke relatie is grofweg een zachte curve: de prijzen stijgen met de omvang, maar met enige stagnatie aan de bovenkant.
Als u een rechte horizontale lijn op deze gegevens past:
# Underfitting: overly simple model
from sklearn.linear_model import LinearRegression
import numpy as np
# True relationship is quadratic, but we're fitting a simple mean
model = DummyRegressor(strategy='mean')
model.fit(X_train, y_train)
# Training accuracy: 55%
# Test accuracy: 54%
# Both are bad — classic underfitting
Inloggen deelnemen aan de discussie
Het model negeert de feitelijke relatie tussen woninggrootte en prijs. Het maakt niet uit of je trainingsgegevens of nieuwe gegevens laat zien; het is hoe dan ook verkeerd.
Overfitting vindt plaats wanneer uw model de trainingsgegevens te goed leert (inclusief de ruis en willekeurige variatie) en er niet in slaagt te generaliseren naar nieuwe voorbeelden.
Een polynoom van 15 graden gebruiken om in dezelfde huizenprijsgegevens te passen:
# Overfitting: overly complex model
from sklearn.preprocessing import PolynomialFeatures
from sklearn.pipeline import make_pipeline
# Degree-15 polynomial — wildly complex for this problem
model = make_pipeline(PolynomialFeatures(15), LinearRegression())
model.fit(X_train, y_train)
train_score = model.score(X_train, y_train) # 0.99 — looks amazing!
test_score = model.score(X_test, y_test) # 0.43 — terrible on new data
De polynoom heeft zichzelf in knopen gewikkeld om door elk trainingspunt te gaan – inclusief de luidruchtige uitschieters. Het heeft de trainingsset uit het hoofd geleerd in plaats van het onderliggende patroon te leren. Op onzichtbare gegevens is het nutteloos.
Een fundamenteel hulpmiddel voor het detecteren van overfitting is het opsplitsen van uw gegevens in drie sets:
from sklearn.model_selection import train_test_split
# First split: hold out 20% as the final test set
X_train_val, X_test, y_train_val, y_test = train_test_split(
X, y, test_size=0.2, random_state=42
)
# Second split: hold out 20% of remaining as validation set
X_train, X_val, y_train, y_val = train_test_split(
X_train_val, y_train_val, test_size=0.25, random_state=42
)
# Result: 60% train / 20% validation / 20% test
De validatieset is uw systeem voor vroegtijdige waarschuwing. Als de trainingsnauwkeurigheid steeds beter wordt, maar de nauwkeurigheid van de validatie stagneert of daalt, dan is er sprake van overfitting.
Regularisatie voegt een straf toe aan de verliesfunctie die het model ervan weerhoudt al te complexe patronen te leren.
L2 Regularisatie (Ridge) bestraft grote gewichten:
from sklearn.linear_model import Ridge
model = Ridge(alpha=1.0) # alpha controls regularisation strength
model.fit(X_train, y_train)
L1-regularisatie (lasso) kan sommige gewichten helemaal naar nul brengen, waardoor functieselectie wordt uitgevoerd:
from sklearn.linear_model import Lasso
model = Lasso(alpha=0.1)
model.fit(X_train, y_train)
Tijdens de training "valt" willekeurig een deel van de neuronen weg (ingesteld op nul):
import torch.nn as nn
model = nn.Sequential(
nn.Linear(128, 64),
nn.ReLU(),
nn.Dropout(p=0.5), # 50% of neurons randomly deactivated during training
nn.Linear(64, 1)
)
Dit verhindert dat neuronen zich gezamenlijk aanpassen en dwingt het netwerk om robuustere, gedistribueerde representaties te leren.
Controleer het validatieverlies tijdens de training en stop wanneer het begint toe te nemen:
from tensorflow.keras.callbacks import EarlyStopping
early_stop = EarlyStopping(
monitor='val_loss',
patience=5, # stop after 5 epochs without improvement
restore_best_weights=True
)
model.fit(X_train, y_train,
validation_data=(X_val, y_val),
callbacks=[early_stop],
epochs=1000)
Meer gegevens maken het moeilijker voor het model om ruis te onthouden; er is simpelweg te veel om precies te passen. Als het verzamelen van gegevens duur is, kan gegevensvergroting (het maken van gewijzigde kopieën van bestaande voorbeelden) helpen.
Soms is de juiste oplossing eenvoudigweg het kiezen van een minder complex model voor het probleem.
Bij kleine datasets kan een enkele trein/val-splitsing misleidend zijn vanwege willekeur. K-voudige kruisvalidatie geeft een betrouwbaardere schatting:
from sklearn.model_selection import cross_val_score
from sklearn.ensemble import RandomForestClassifier
model = RandomForestClassifier(n_estimators=100)
# 5-fold cross-validation
scores = cross_val_score(model, X, y, cv=5, scoring='accuracy')
print(f"Mean accuracy: {scores.mean():.3f} ± {scores.std():.3f}")
# Mean accuracy: 0.847 ± 0.023
De gegevens zijn in vijf delen opgesplitst; het model traint op 4 en valideert op 1, waarbij het elke keer roteert. De uiteindelijke score is het gemiddelde van alle vijf – veel betrouwbaarder dan een enkele splitsing.
Een model behaalt een nauwkeurigheid van 99% op trainingsgegevens, maar slechts 62% op testgegevens. Wat geeft dit aan?