반응형
1. eval() 함수의 개념과 필요성
PyTorch에서 eval()
함수는 모델을 평가(evaluation) 모드로 전환하는데 사용된다.
모델에 Dropout 레이어나 Batch Normalization 계층이 있는 경우 훈련 모드와 평가 모드에서 모델의 동작이 달라지는 경우가 있기 때문에, eval()
함수를 사용해 모델이 평가 단계에서 적절한 동작을 하도록 설정한다.
2. eval() 함수를 사용할 때 모델의 주요 변화
- Dropout 비활성화:
모델에eval()
함수를 먹여서 평가 모드로 전환하면, Dropout 계층이 무작위로 뉴런을 끄는 것을 막아 학습을 방해하지 않고 모든 뉴런을 사용한다. - Batch Normalization 고정:
평가 모드에서는 배치 정규화(BatchNorm
) 계층이 새로운 배치 통계를 사용하지 않고, 학습 중 계산된 이동 평균과 분산을 사용한다.
3. 사용 방법
# 모델을 평가 모드로 전환
model.eval()
# 모델을 학습 모드로 전환
model.train()
4. 예제
Dropout
과 BatchNorm
레이어가 포함된 간단한 모델을 만들어, 훈련 모드와 평가 모드에서 차이점을 확인해보자.
import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader, TensorDataset
import numpy as np
# 간단한 데이터셋 생성 (예: 2D 분류 데이터)
X_train = torch.rand(500, 2)
y_train = (X_train[:, 0] + X_train[:, 1] > 1).long() # 임의의 이진 분류 라벨 생성
train_loader = DataLoader(TensorDataset(X_train, y_train), batch_size=32, shuffle=True)
# 모델 정의 (드롭아웃과 배치 정규화 포함)
class SimpleModel(nn.Module):
def __init__(self):
super(SimpleModel, self).__init__()
self.fc1 = nn.Linear(2, 64)
self.bn1 = nn.BatchNorm1d(64)
self.fc2 = nn.Linear(64, 32)
self.bn2 = nn.BatchNorm1d(32)
self.fc3 = nn.Linear(32, 2)
self.dropout = nn.Dropout(p=0.5) # 드롭아웃 확률 50%
def forward(self, x):
x = self.bn1(torch.relu(self.fc1(x)))
x = self.dropout(x)
x = self.bn2(torch.relu(self.fc2(x)))
x = self.fc3(x)
return x
# 모델과 손실 함수, 옵티마이저 정의
model = SimpleModel()
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)
# 훈련 루프
epochs = 10
for epoch in range(epochs):
model.train() # 모델을 학습 모드로 설정
train_loss = 0.0
correct = 0
total = 0
for inputs, labels in train_loader:
optimizer.zero_grad()
outputs = model(inputs)
loss = criterion(outputs, labels)
loss.backward()
optimizer.step()
train_loss += loss.item()
_, predicted = torch.max(outputs, 1)
total += labels.size(0)
correct += (predicted == labels).sum().item()
# 중간 결과 출력 (학습 정확도)
train_acc = 100 * correct / total
print(f"Epoch {epoch+1}/{epochs}, Loss: {train_loss / len(train_loader):.4f}, Accuracy: {train_acc:.2f}%")
# 평가 모드에서 정확도 확인
model.eval() # 모델을 평가 모드로 전환
eval_loss = 0.0
correct = 0
total = 0
with torch.no_grad(): # 평가에서는 그래디언트 계산을 하지 않음
for inputs, labels in train_loader:
outputs = model(inputs)
loss = criterion(outputs, labels)
eval_loss += loss.item()
_, predicted = torch.max(outputs, 1)
total += labels.size(0)
correct += (predicted == labels).sum().item()
eval_acc = 100 * correct / total
print(f" Validation Accuracy: {eval_acc:.2f}%")
# 최종 모델 평가
print("Training completed.")
위 코드의 트레이닝 루프에서 주요한 라인들을 알아보자.
for epoch in range(epochs):
model.train() # 모델을 학습 모드로 설정
train_loss = 0.0
correct = 0
total = 0
- model.train(): 모델을 학습 모드로 전환한다.
이러면Dropout
과BatchNorm
레이어가 학습 모드로 설정되어 각각 오버피팅을 방지하고 미니배치마다 새로운 평균과 분산을 계산하여 정규화한다.
model.eval() # 모델을 평가 모드로 전환
eval_loss = 0.0
correct = 0
total = 0
with torch.no_grad(): # 평가에서는 그래디언트 계산을 하지 않음
for inputs, labels in train_loader:
outputs = ...
- model.eval(): 모델을 평가 모드로 전환한다.
여기서는Dropout
과BatchNorm
이 비활성화되어 모델이 모든 뉴런을 사용하고 배치 정규화가 훈련 중 계산된 평균과 분산 값을 사용해 데이터를 정규화한다.
코드는 여기까지이고 eval()과 train()함수에서 모델의 입출력이 다른지 한번 확인해보자.
아래 코드를 통해 확인해보자.
참고로 torch.equal은 두 텐서가 동일한지 비교하는 함수이다.
완전히 동일하면 True을 뱉고 하나라도 다르면 False을 뱉는다.
# 동일한 입력 데이터로 두 모드에서의 출력을 비교해보기 위해 랜덤한 입력 생성
sample_input = torch.rand(5, 2) # (batch_size=5, input_dim=2)
# 학습 모드에서의 출력
model.train() # 학습 모드로 전환
train_output = model(sample_input)
print("Train mode output:", train_output)
# 평가 모드에서의 출력
model.eval() # 평가 모드로 전환
eval_output = model(sample_input)
print("Eval mode output:", eval_output)
# 출력 비교
print("\nComparison:")
print("Are the outputs equal? ", torch.equal(train_output, eval_output)) # 동일한지 확인
print("Difference between outputs:\n", train_output - eval_output) # 차이점 출력
코드 설명
- 샘플 입력 생성: 랜덤한 데이터를 생성하여 모델에 넣는다. 같은 입력 데이터를 두 모드에서 사용해야 정확한 차이를 확인할 수 있다.
- 학습 모드 출력:
model.train()
을 호출하여 모델을 학습 모드로 전환한 후, 출력(train_output
)을 계산한다. - 평가 모드 출력:
model.eval()
을 호출하여 모델을 평가 모드로 전환한 후, 동일한 입력 데이터에 대한 출력(eval_output
)을 계산한다. - 출력 비교:
torch.equal(train_output, eval_output)
을 통해 두 출력이 완전히 같은지 확인한다. 드롭아웃이나 배치 정규화가 있다면 대부분 다르게 나온다.train_output - eval_output
을 통해 출력의 차이를 확인한다.
이 코드를 통해 eval()
와 train()
에서 Dropout과 Batch Normalization의 차이가 모델의 출력에 어떻게 영향을 미치는지 확인할 수 있다.
결과는 아래처럼 나온다.
물론 결과는 돌릴 때마다 다르게 나올 수 있지만 두 값은 다를 것이다.
반응형
'코딩 환경 > PyTorch' 카테고리의 다른 글
[PyTorch] 파이토치 모델 저장 및 불러오기 (0) | 2024.09.03 |
---|---|
[PyTorch] 파이토치에서 특정 GPU 선택, 지정하는 방법 (0) | 2023.05.27 |
[PyTorch] 파이토치에서 .to('cuda'), .cuda() 차이점 (2) | 2023.05.27 |
[PyTorch] 파이토치 코드 실행 속도 높이기 / .cuda()와 device=torch.device('cuda')의 차이 + 애플 m1, m2 칩 (0) | 2023.05.27 |
[PyTorch] num_workers 설명과 빠른 트레이닝을 위한 값 최적화 (0) | 2023.05.24 |