관리 메뉴

개발자의 스터디 노트

옐프 리뷰 데이터셋으로 학습 하기 본문

파이썬/파이토치 자연어처리

옐프 리뷰 데이터셋으로 학습 하기

박개발씨 2022. 2. 15. 23:14

먼저 포스팅으로 훈련에 필요한 데이터를 로딩하고 가공하는 준비를 하였습니다. 이제부터는 앞에서 만들어 두었던 부품을 가지고 조립을 해보겠습니다. 주피터 노트북을 사용할 경우 앞서 포스팅의 소스파일에 이어서 작업하여야 합니다.

 

1. 훈련 준비

 - args 매개변수로 훈련할 정보를 받아 데이터셋과 모델을 만듭니다. 그리고 마지막으로 손실 함수와 옵티마이저를 만듭니다.

import torch.optim as optim
import torch

def make_train_state(args):
    return {
        'epoch_index' : 0,
        'train_loss' : [],
        'train_acc' : [],
        'val_loss' : [],
        'val_acc' : [],
        'test_loss' : -1,
        'test_acc' : -1
    }
train_state = make_train_state(args)

if not torch.cuda.is_available():
    args.cuda = False
args.device = torch.device("cuda" if args.cuda else "cpu")

#데이터셋과 Vectorizer
dataset = ReviewDataset.load_dataset_and_make_vectorizer(args.review_csv)
vectorizer = dataset.get_vectorizer()

#모델
classifier = ReviewClassifier(num_features=len(vectorizer.review_vocab))
classifier = classifier.to(args.device)

# 손실 함수와 옴티마이저
loss_func = nn.BCEWithLogitsLoss()
optimizer = optim.Adam(classifier.parameters(), lr=args.learning_rate)

 

 

2. 훈련 반복

 - 앞서 초기화한 객체를 사용해 모델의 성능이 높아지도록 모델 파라미터를 업데이트합니다. 훈련 반복은 두 개의 반복문으로 구성됩니다. 내부 반복문은 데이터셋의 미니 배치에 대해서 반복을 수행합니다. 외부 반복문은 내부 반복문을 여러 번 반복합니다. 내부 반복문에서 미니 배치마다 손실을 계산하고 옵티마이저가 모델 파라미터를 업데이트합니다.

## 정확도 계산 함수

def compute_accuracy(y_pred, y_target):
    y_target = y_target.cpu()
    y_pred_indices = (torch.sigmoid(y_pred)>0.5).cpu().long()#.max(dim=1)[1]
    n_correct = torch.eq(y_pred_indices, y_target).sum().item()
    return n_correct / len(y_pred_indices) * 100
for epoch_index in range(args.num_epochs):
    train_state['epoch_index'] = epoch_index
    
    # 훈련 세트 순회
    # 훈련 세트와 배치 제너레이터 준비, 손실과 정확도를 0으로 설정
    dataset.set_split('train')
    batch_generator = generate_batches(dataset, batch_size=args.batch_size,device=args.device)
    running_loss = 0.0
    running_acc = 0.0
    classifier.train()
    
    print("epoch_index : ", epoch_index)
    for batch_index, batch_dict in enumerate(batch_generator):
        # 훈련 과정은 5단계로 이루어집니다.
        
        # 1단계. 그레이디언트를 0으로 초기화합니다.
        optimizer.zero_grad()
        
        # 2단계. 출력을 계산합니다.
        y_pred = classifier(x_in=batch_dict['x_data'].float())
        
        # 3단계. 손실을 계산합니다.
        loss = loss_func(y_pred, batch_dict['y_target'].float())
        loss_batch = loss.item()
        running_loss += (loss_batch - running_loss) / (batch_index + 1)        
        
        # 4단계. t손실을 사용해 그레이디언트를 계산합니다.
        loss.backward()
        
        # 5단계. 옵티마이저로 가중치를 업데이트 합니다.
        optimizer.step()
        
        # 정확도를 계산합니다.
        acc_batch = compute_accuracy(y_pred, batch_dict['y_target'])
        running_acc += (acc_batch - running_acc) / (batch_index + 1)
    
    print("epoch_index = ",epoch_index,"  train_loss = ",running_loss)
    print("epoch_index = ",epoch_index,"  train_acc = ",running_acc)
    train_state['train_loss'].append(running_loss)
    train_state['train_acc'].append(running_acc)
    
    #검증 세트 순회
    #검증 세트와 배치 제너레이터 준비, 손실과 정확도를 0으로 설정
    dataset.set_split('val')
    batch_generator = generate_batches(dataset, batch_size=args.batch_size, device=args.device)
    
    running_loss = 0.
    running_acc = 0.
    classifier.eval()
    
    for batch_index, batch_dict in enumerate(batch_generator):
        
        #1단계. 출력을 계산합니다.
        y_pred = classifier(x_in=batch_dict['x_data'].float())
        
        #2단계. 손실을 계산합니다.
        loss = loss_func(y_pred, batch_dict['y_target'].float())
        loss_batch = loss.item()
        running_loss += (loss_batch - running_loss) / (batch_index + 1)
        
        #3단계. 정확도를 계산합니다.
        acc_batch = compute_accuracy(y_pred, batch_dict['y_target'])
        running_acc += (acc_batch - running_acc) / (batch_index + 1)
        
    train_state['val_loss'].append(running_loss)
    train_state['val_acc'].append(running_acc)
    print("epoch_index = ",epoch_index,"  val_loss = ",running_loss)
    print("epoch_index = ",epoch_index,"  val_acc = ",running_acc)