시작은 미약하였으나 , 그 끝은 창대하리라

[Pytorch 스크래치 코드] 분류문제 Train, Validation 함수 본문

인공지능/딥러닝 스크래치 코드

[Pytorch 스크래치 코드] 분류문제 Train, Validation 함수

애플파ol 2023. 12. 16. 12:06

✓ pytorch 에서는 Train 과 Validation 과정을 코드를 통해 수행한다.

✓ 이를 위해 스크래치 코드를 작성해보았다. (분류 문제임)

회귀는 train에서 loss, accuracy 처리법이 상이

 

 

❏ 분류 문제 Train, Evaluation 함수

 

→ 주의사항. 분류문제에서 cross entropy를 계산을 위해서는 y값이 LongTensor 여야 함.

                   (Float으로 했다가 고생했던 기억이.. 까먹지 말자)

 

→ 유용한 팁. 만약 학습이 잘되는지 확인을 하고싶다면 tqdm을 사용하면 최소 2번이상은 되어야 학습이 잘되는지 loss값 감소를 통해 확인 할 수 있다. (물론 wandb 사용 안할때)  초반에 학습이 잘되는지 확인하고 싶다면 아래코드에서 tqdm을 빼버리고 주석처리된 부분을 살리면, 설정한 log_interval 간격으로 배치 사이즈 마다 출력이 실시간으로 출력된다. 그렇다보니. 미니배치 마다 loss값이 줄어들고 있다면 알맞게 코드를 작성했다고 1epoch가 끝나기 전에 확인이 가능하다. 

(Figure 1. 아래 코드를 그대로 실행시 나오는 화면. )

(Figure 2 . tqdm을 제거하고, 주석처리된 부분을 살렸을때 출력되는 모습)

## 분류 문제 Train, Evaluation 함수

from tqdm import tqdm



# 에폭마다 손실과 정확도를 저장할 리스트
training_loss_hist = [] # tuple() 로 해도됨
training_acc_hist = []


def train(model_name, train_loader,device,optimizer,loss_func,log_interval=10):
    Train_total_loss=0
    Train_correct_predictions=0

    # train mode로 설정
    model_name.train()
    for batch_idx,(x_train, y_train) in enumerate(tqdm(train_loader)):
        # cross entropy의 y는 LongTensor형이어야 함.
        y_train=y_train.type(torch.LongTensor)
        x_train=x_train.to(device)
        y_train=y_train.to(device)



        y_predict=model_name(x_train)
        
        # loss 계산
        loss=loss_func(y_predict,y_train.squeeze(dim=-1))
        Train_total_loss+=loss.item()

        # 정확도 계산
        values, indices = torch.max(y_predict.data, dim=1,keepdim=True)
        Train_correct_predictions += (indices == y_train).sum().item()  # 정확하게 분류한 샘플 수

        # 그라디언트 0으로 설정후 -> 파라미터 업데이트
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()

        # 한 epoch에서 'log_interval'번의 미니배치마다 loss 출력
        # if batch_idx % log_interval==0:
        #     print('Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format(
        #         1+epoch,batch_idx*len(x_train),len(train_dataloader.dataset),
        #         100.*batch_idx/len(train_dataloader.dataset),loss.item()
        #     ))

    avg_train_loss=Train_total_loss/len(train_loader)
    Train_accuracy = 100. * Train_correct_predictions / len(train_loader.dataset)
    print('Train Epoch: {} Average loss: {:.6f}, Accuracy: {:.2f}%'
          .format(1+epoch, avg_train_loss, Train_accuracy))

    # 학습데이터에서 loss, accuracy 저장
    training_loss_hist.append(avg_train_loss)
    training_acc_hist.append(Train_accuracy)


val_loss_hist = []
val_acc_hist = []

def evaluate(model_name,test_loader,device,loss_func):
    correct=0
    val_loss=0
    
    # evaluation mode로 설정 
    model_name.eval()
    with torch.no_grad():
        for idx,(x_test,y_test) in enumerate(tqdm(test_loader)):
            y_test=y_test.type(torch.LongTensor)
            x_test=x_test.to(device)
            y_test=y_test.to(device)  # torch.Size([64, 1])
            
        
            y_pred=model_name(x_test)
            loss=loss_func(y_pred,y_test.squeeze(dim=-1)).item()


            val_loss+=loss
            # 정확하게 분류한 샘플 수 계산
            values, indices = torch.max(y_pred.data, dim=1,keepdim=True)        
            correct += (indices == y_test).sum().item()


    avg_val_loss=val_loss/len(test_loader)
    accuracy = 100 * correct / len(test_loader.dataset)  # 정확도 계산
    print('Validation set: Average loss: {:.4f}, Accuracy: {:.2f}%'
          .format(avg_val_loss, accuracy))
    print()

    # 검증데이터에서 loss, accuracy 저장
    val_loss_hist.append(avg_val_loss)
    val_acc_hist.append(accuracy)

 

Figure 1. tqdm 실행 모습
Figure2. batch_size=64 마다의 loss 값을 찍어주는 것을 볼수 있다. (where log_interval is one)

 

 

 

❏ 코드 적용 예시.

→ 위에 코드에서 연결됨.

device = torch.device('cuda:2')

# 모델 호출
CNN_LSTM_model=CNN_LSTM(
                input_size=99, 
                output_size=64,
                units=32).to(device)

# optimizer 설정
optimizer = optim.Adam(CNN_LSTM_model.parameters(), lr=0.0001)
# loss 함수
criterion = nn.CrossEntropyLoss()
# epoch 설정
epochs = 5


for epoch in range(epochs):
    
    train(
        model_name=CNN_LSTM_model, 
        train_loader=train_dataloader,
        optimizer=optimizer,
        loss_func=criterion,
        log_interval=1,
        device=device,)

    evaluate(
        model_name=CNN_LSTM_model,
        test_loader=val_dataloader,
        loss_func=criterion,
        device=device)

 

 

❏ Train, Evaluation plot 출력. 

→ 꿀팁 : 범례의 위치를 알아서 최적으로 설정하려면 loc='best' 하면됨.. (처음알았음...)

→ 결과 : figure3,4 참고

import matplotlib.pyplot as plt


# Accuracy history
plt.plot(training_acc_hist)
plt.plot(val_acc_hist)

plt.title("Model Accuracy")
plt.ylabel("Accuracy")
plt.xlabel("Epochs")

plt.legend(["Train", "Validation"], loc="best")
plt.grid()
plt.show()


# loss history
plt.plot(training_loss_hist)
plt.plot(val_loss_hist)

plt.title("Model Loss")
plt.ylabel("Loss")
plt.xlabel("Epochs")

plt.legend(["Train", "Validation"], loc="best")
plt.grid()
plt.show()

 

Figure 3
Figure 4

Comments