본문 바로가기

명사 美 비격식 (무리 중에서) 아주 뛰어난[눈에 띄는] 사람[것]

이론

모델이 학습이 덜됬거나 과하게 됬거나: Underfitting (언더피팅), Overfitting (오버피팅)과 해결방법 - 데이터증강 ImageDataGenerator, 드롭아웃 nn.Dropout() , 조기종료 EarlyStoping(), 가중치 감쇠 weight_decay, 모델을 단순화, 배치 정규화 BatchNorm2d, BatchNorm1d, 데이터 추가, 전이학습, 교차검증 KFold(), 라벨스무딩 CrossEntropyLoss()


Underfitting (언더피팅)

모델이 충분히 학습되지않은 상태,아직 덜 배운상태.

모델이 너무 단순하거나 학습이 부족하거나 특징이 부족할 수있다. 

학습이 부족해서 발생한 언더피팅 → 더 학습하면 개선되고

모델 자체가 너무 단순하면 한계가 있다 .

 

Overfitting (오버피팅)
어느순간부터 안좋아지기 시작하는.

훈련데이터에서는 매주 좋은 결과가 나오지만 새로운데이터에서 성능이 떨어지는 것. 

훈련데이터에 너무 맞춰져서 일반화 능력이 떨어진 상태

암기한 상태

 

직선/평면으로 경계하는 선형모델 로지스틱 회귀에서와 다르게

신경망은 선형 + 비선형을 여러층 쌓은 모델이다 .

https://standout.tistory.com/1535

 

선형모형: 다중선형회귀모형, 선형 로지스틱 회귀모형, 다항회귀모형, 일반화 가법모형

선형모형 주택 가격 예측, 수치 예측 등의 문제최소제곱법(Least Squares) 등을 사용하여 입력 변수의 계수(coefficient)를 추정입력 변수와 출력 변수 간의 직선적인 관계, 모델이 단순하고

standout.tistory.com

 

피팅관련해서 확인하면신경망이 항상 더 좋은것이 아니라는것을 이해해볼 수 있다. 

데이터가 적거나 단순할시 파라미터 과다 및 과적합 발생으로 망가질 수있다.

단순한 모델일경우 로지스틱 회귀는 직선평면만 가능해 과하게 외우리가 어려워오버피팅 위험이 낮다. 

 

 

 

 

언더피팅은 학습을 재게하면 된다지만 오버피팅은 좀더 방법이 여러가지로 나뉜다 .

해결방법을 확인해보자.

Underfitting
(언더피팅)
모델이 학습 부족 - 훈련 정확도 낮음
- 검증 정확도도 낮음
모델 복잡도 증가 모델이 데이터 패턴을 충분히 학습하지 못한 상태
      데이터 추가 학습 정보 부족 보완
      학습 시간 증가 epoch 부족 해결
Overfitting
(오버피팅)
훈련 데이터에 과적합 - 훈련 정확도 매우 높음
- 검증 정확도 낮음
Dropout nn.Dropout() 일부 뉴런을 랜덤 제거해 일반화 강화
      Data Augmentation ImageDataGenerator 데이터 다양성 증가
      Early Stopping EarlyStopping() 검증 성능 나빠지면 학습 중단
      Weight Decay (L2 규제) 큰 가중치 패널티 부여
      Batch Normalization BatchNorm1d/2d 학습 안정화 + 일반화 도움
      모델 단순화 파라미터 감소
      데이터 추가 과적합 완화
      전이학습 (Transfer Learning) 사전학습 모델 활용
      교차검증 KFold() 일반화 성능 평가 안정화
      Label Smoothing (CrossEntropyLoss(label_smoothing=)) 정답 확신 줄여 과적합 방지

 

 

 

 

 

데이터를 증강하기

 - 이미지에서 회전, 좌우반전, 확대축소 밝기조절 자르기 노이즈 추가 등으로 모델입장에서 다양한 고양이 사진을 학습하는 효과를 준다 .

from tensorflow.keras.preprocessing.image import ImageDataGenerator
# 이미지 데이터를 학습 중에 다양한 형태로 변형하기 위한 객체 생성
datagen = ImageDataGenerator(
rotation_range=20, # 이미지를 최대 20도까지 회전
width_shift_range=0.1, # 이미지를 좌우 방향으로 10% 이동
height_shift_range=0.1, # 이미지를 상하 방향으로 10% 이동
zoom_range=0.1, # 이미지를 최대 10% 확대 또는 축소
horizontal_flip=True # 이미지를 좌우 반전
)

 

 

 

드롭아웃

 - 학습중에 일부 뉴런을 무작위로 꺼버려 특정 뉴런에 지나치게 의존하는것을 막는다. 

import torch.nn as nn
model = nn.Sequential(
nn.Linear(784, 256), # 입력 784개를 256개 특징으로 변환
nn.ReLU(), # 비선형 활성화 함수 적용
nn.Dropout(0.5), # 학습 중 뉴런의 50%를 무작위로 비활성화
nn.Linear(256, 10) # 최종 10개 클래스 출력
)

 

 

조기종료

 - 오버피팅은 보통 학습을 너무 오래 할때 발생함으로 검증성능이 더이상 좋아지징낳으면 학습을 멈춘다. 

from tensorflow.keras.callbacks import EarlyStopping
early_stop = EarlyStopping(
monitor='val_loss', # 검증 손실을 기준으로 확인
patience=5, # 5번의 epoch 동안 개선이 없으면 중단
restore_best_weights=True # 가장 성능이 좋았던 시점의 가중치 복원
)

 

 

 

 

가중치 감쇠(Weight Decay, L2 Regularization)

모델의 가중치라 너무 커지지않도록 제한한다. 

import torch.optim as optim
optimizer = optim.AdamW(
model.parameters(),
lr=0.001,
weight_decay=0.01 # 가중치가 너무 커지는 것을 방지
)

 

 

 

모델을 단순화한다. 

데이터가 1000개 뿐인데 수백만개의 파라미터를 가졌다면? 분류하기 너무나 쉽다. 외울가능성이 크다는 의미다.

모델이 너무 복잡할때 오버피팅이 쉽게 발생한다.

은닉수층줄이거나 뉴런수를 줄이거나 파라미터수를 줄리고 더 작은 모델을 사용해 모델을 오히려 단순화시켜야할 수 있다.

데이터가 적을수록 모델을 단순하게 설계하는것이 안전함을 이해해자.

# 복잡한 모델
nn.Sequential(
nn.Linear(784, 1024),
nn.ReLU(),
nn.Linear(1024, 512),
nn.ReLU(),
nn.Linear(512, 10)
)
# 단순한 모델
nn.Sequential(
nn.Linear(784, 128),
nn.ReLU(),
nn.Linear(128, 10)
)

 

 

 

 

 

 

 

배치 정규화

학습 중 각 층의 값 분포가 게속 바뀌면 학습이 불안정해질 수 있다. 이때 평균과 분산을 조정해서 

각 층의 입력분포를 일정하게 맞춰춰 학습을 안정적으로 만들어 좋다 .

사실 학습 안정화 목적이 크지만 약한 정규화효과도 있어 오버피팅 완화에 도움이 될수있달까.

이미지의 경우 BatchNorm2d , 외는 BatchNorm1d 를 쓴다. 

model = nn.Sequential(
nn.Linear(784, 256),
nn.BatchNorm1d(256), # 256개 출력값을 정규화
nn.ReLU(),
nn.Linear(256, 10)
)
model = nn.Sequential(
    nn.Conv2d(in_channels=1, out_channels=32, kernel_size=3, padding=1),
    nn.BatchNorm2d(32),   # 32개 채널 정규화
    nn.ReLU(),
    nn.MaxPool2d(2),

    nn.Conv2d(32, 64, kernel_size=3, padding=1),
    nn.BatchNorm2d(64),
    nn.ReLU(),
    nn.MaxPool2d(2),

    nn.Flatten(),

    nn.Linear(64 * 7 * 7, 128),
    nn.ReLU(),

    nn.Linear(128, 10)
)

 

 

 

 

 

 

 

 

데이터 추가

사실 가장 근본적인 해결방법은 데이터를 늘리는 것이다. 

오버피팅은 데이터가 부족할때 자주 발생하는데 모델이 외우지 못하고 일반적인 패턴을 학습할 확률이 높아지기때문이다. 

실제데이터를 추가하는것이 제일 좋고.

공개 데이터셋을 활용하거나

데이터 증강해 기존 데이터를 변현하고

합성 데이터를 생성해 활용하는 것도 좋다. 

 

 

 

 

 

전이학습

이미 대규모로 학습된 모델을 가져와서 다시 학습하는 방법도 좋다. 

이미지분류에서는 ResNet, EfficientNet, VGG 등이 이미 잘 사전학습 되었음으로 무리해 학습시키지말고 가져다 쓰는 것이다 .

데이터가 적을때 처음부터 모델을 학습하면 오버피팅이 쉽게 발생한다. 

전이학습은 예습을 마친 모델과 같아 적은 데이터로도 좋은 성능을 얻기 쉽다 .

import torchvision.models as models
import torch.nn as nn
# ImageNet으로 미리 학습된 ResNet18 모델 불러오기
model = models.resnet18(weights=models.ResNet18_Weights.DEFAULT)
# 기존 출력층을 현재 문제의 클래스 수에 맞게 교체
model.fc = nn.Linear(model.fc.in_features, 2)

 

 

 

 

 

교차검증

데이터를 여러부분으로 나눠 여러번 학습과 검증을 반복하는 방법이다. 

예를들어 K-Fold, 즉 5-Fold는 데이터를 5개로 나누어 5번학습과 검증을 반복해 정확도를 5개 출력해 평균으로 최종성능을 판단한다. 

from sklearn.model_selection import KFold, cross_val_score
from sklearn.linear_model import LogisticRegression
from sklearn.datasets import load_iris

# 데이터
X, y = load_iris(return_X_y=True)

# 모델
model = LogisticRegression(max_iter=1000)

# K-Fold 설정 (5-fold)
kf = KFold(n_splits=5, shuffle=True, random_state=42)

# 교차검증 수행
scores = cross_val_score(model, X, y, cv=kf)

print("각 fold 정확도:", scores)
print("평균 정확도:", scores.mean())

 

 

 

 



라벨스무딩

정답라벨을 너무 확신하지않도록 부드럽게 만드는 방법으로 정답에 약간의 여유를 주면 모델이 학습 데이터 정답을 너무 강하게 외우지 않도록 유도할 수 있다.

정답이 [0, 0, 1, 0] 라면 [0.033, 0.033, 0.9, 0.033] 식으로 조금씩 값을 부드럽게 만든다. 

직접 구현하거나 Crossentroyloss등의 함수를 활용할 수 있다 .

import torch

def label_smoothing(one_hot, epsilon=0.1):
    num_classes = one_hot.size(1)
    
    return one_hot * (1 - epsilon) + (epsilon / num_classes)

# 예시: batch 1개, 4개 클래스
one_hot = torch.tensor([[0, 0, 1, 0]], dtype=torch.float)

smoothed = label_smoothing(one_hot, epsilon=0.1)

print(smoothed)
import torch.nn as nn

criterion = nn.CrossEntropyLoss(label_smoothing=0.1)