반응형
딥러닝 학습과 검증 과정을 할 때
def validation(model, criterion, val_loader, device):
model.eval()
val_loss = []
preds, true_labels = [], []
with torch.no_grad():
for imgs, labels in tqdm(iter(val_loader)):
imgs = imgs.float().to(device)
labels = labels.to(device)
pred = model(imgs)
loss = criterion(pred, labels)
preds += pred.argmax(1).detach().cpu().numpy().tolist()
true_labels += labels.detach().cpu().numpy().tolist()
val_loss.append(loss.item())
_val_loss = np.mean(val_loss)
_val_score = f1_score(true_labels, preds, average='macro')
return _val_loss, _val_score
def train(model, optimizer, train_loader, val_loader, scheduler, device):
model.to(device)
criterion = nn.CrossEntropyLoss().to(device)
best_score = 0
best_model = None
save_path = "best_model.pth"
for epoch in range(1, CFG['EPOCHS'] + 1):
model.train()
train_loss = []
for imgs, labels in tqdm(iter(train_loader), desc=f"Epoch {epoch}"):
imgs = imgs.float().to(device)
labels = labels.to(device)
optimizer.zero_grad()
output = model(imgs)
loss = criterion(output, labels)
loss.backward()
optimizer.step()
train_loss.append(loss.item())
_val_loss, _val_score = validation(model, criterion, val_loader, device)
_train_loss = np.mean(train_loss)
print(f'Epoch [{epoch}], Train Loss: {_train_loss:.5f}, Val Loss: {_val_loss:.5f}, Val Macro F1: {_val_score:.5f}')
if scheduler is not None:
scheduler.step(_val_score)
if best_score < _val_score:
best_score = _val_score
best_model = model
# 모델 가중치 저장
torch.save(model.state_dict(), save_path)
print(f"Best model saved (epoch {epoch}, F1={_val_score:.4f}) → {save_path}")
return best_model
이와 같은 형식으로 하는데 여기서 갑자기 궁금한것이 생겼다.
validation 함수에서 val_loss, preds, true_labels 전부 [] 형태인데
왜 val_loss는 append를 사용하고, preds, true_labels에는 += 연산을 사용하는지에 대해 궁금해졌다.
그 이유는 다음과 같다.
preds, true_labels += 연산이유
pred = [0,1,2]
preds = []
preds.append(pred)
print(preds)
위의 출력은 [[0,1,2]] 로 나오며 리스트 안에 리스트가 생긴다. 그러면 loss 계산시 에러가 난다.
각 loss 계산마다 맞는 형태로 맞춰줘야하는데 f1_score는 flat한 리스트에 맞기 때문.
참고로 extend() == += 는 동일한 효과.
val_loss의 append 연산이유
loss.item()은 float형식 하나이기 때문.
.append(x)는 x 그대로 한 개를 리스트에 넣기 때문에 그렇다.