본문 바로가기
DeepLearning|MachineLearning/연구하며 사소한 실수들

train, validation 과정에서 +=연산과 append, extend

by yongPro 2025. 4. 10.
반응형

딥러닝 학습과 검증 과정을 할 때

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 그대로 한 개를 리스트에 넣기 때문에 그렇다.