Training the model (모델 훈련)
모델을 훈련하는것은 앞에서(?) 봐왔던 이미지 분류기와 매우 비슷합니다. 그래서 같은 함수를 사용한다고 책에서는 되어 있는데, 여기에서는 이미지 분류기에 대한 설명이 없었기 때문에 그냥 차이가 별로 안난다고 생각하면 됩니다. 모델의 데이터를 일괄작업들(batchs)로 실행시키고 출력과 손실들을 계산합니다. 그리고 embedding 가중치를 포함하는 모델의 가중치들(weights)을 최적화 합니다. 다음 코드가 이것입니다.def fit(epoch,model,data_loader,phase='training',volatile=False): if phase == 'training': model.train() if phase == 'validation': model.eval() volatile=True running_loss = 0.0 running_correct = 0 for batch_idx , batch in enumerate(data_loader): text , target = batch.text , batch.label if is_cuda: text,target = text.cuda(),target.cuda() if phase == 'training': optimizer.zero_grad() output = model(text) loss = F.nll_loss(output,target) running_loss += F.nll_loss(output,target,size_average=False).data[0] preds = output.data.max(dim=1,keepdim=True)[1] running_correct += preds.eq(target.data.view_as(preds)).cpu().sum() if phase == 'training': loss.backward() optimizer.step() loss = running_loss/len(data_loader.dataset) accuracy = 100. * running_correct/len(data_loader.dataset) print(f'{phase} loss is {loss:{5}.{2}} and {phase} accuracy is {running_correct}/{len(data_loader.dataset)}{accuracy:{10}.{4}}') return loss,accuracy train_losses , train_accuracy = [],[] val_losses , val_accuracy = [],[] train_iter.repeat = False test_iter.repeat = False for epoch in range(1,10): epoch_loss, epoch_accuracy = fit(epoch,model,train_iter,phase='training') val_epoch_loss , val_epoch_accuracy = fit(epoch,model,test_iter,phase='validation') train_losses.append(epoch_loss) train_accuracy.append(epoch_accuracy) val_losses.append(val_epoch_loss) val_accuracy.append(val_epoch_accuracy)
앞선 코드에서, 데이터를 일괄 작업을 위해 생성했던 BucketIterator 오브젝트를 통과시켜 fit() 메소드를 호출합니다. 기본적을 iterator는 배치 생성을 멈추지 않습니다. 무한히 반복됩니다. 그래서 BucketIterator의 repeat 변수의 값이 무한히 반복되지 않기 위해서는 False로 설정 해야 합니다. 이 부분은 앞에서도 설명을 하였습니다. 약 10 epoches (전체 훈련 데이터를 1번 수행하는것을 1 epoch(세대)를 사용했다고 표현합니다. ) 정도 훈련을 하면 대략 70%정도의 검증 정확도를 얻습니다.
실행 가능한 소스
위의 내용은 책의 내용 소스로 위 코드만 있으면 테스트를 할 수가 없습니다. 그래서 임의의 train data를 만들고 실행 가능한 소스로 만들어 보았습니다.from torchtext.data import Field, Iterator, TabularDataset, BucketIterator import torch.nn as nn import torch.optim as optim import torch import torch.nn.functional as F is_cuda = False if torch.cuda.is_available(): is_cuda=True TEXT = Field(sequential=True, use_vocab=True, lower=True, batch_first=True,fix_length=20) LABEL = Field(sequential=False, use_vocab=False, batch_first=True) train_data = TabularDataset(path='./data7.tsv', skip_header=True, format='tsv', fields=[('text', TEXT), ('label', LABEL)]) TEXT.build_vocab(train_data, min_freq = 1) print('Total vocabulary: {}'.format(len(TEXT.vocab))) print('Token for "<unk>": {}'.format(TEXT.vocab.stoi['<unk>'])) print('Token for "<pad>": {}'.format(TEXT.vocab.stoi['<pad>'])) print('stoi {}'.format(len(TEXT.vocab.stoi))) print(train_data.text) print(train_data.label) class EmbNet(nn.Module): def __init__(self,emb_size,hidden_size1,hidden_size2=200): super().__init__() self.embedding = nn.Embedding(emb_size,hidden_size1) self.fc = nn.Linear(hidden_size2,3) def vectors(self, inputs): print( self.embedding(inputs) ) return; def forward(self,x): embeds = self.embedding(x).view(x.size(0),-1) out = self.fc(embeds) return F.log_softmax(out,dim=-1) print(len(TEXT.vocab.stoi)) model = EmbNet(len(TEXT.vocab.stoi),10) #emb_size, hidden_size1 optimizer = optim.Adam(model.parameters(),lr=0.001) train_iter = BucketIterator(train_data, batch_size=4, device=-1,shuffle=True) train_iter.repeat = False losses = [] loss_function = torch.nn.NLLLoss() def fit(epoch,model,data_loader,phase='training',volatile=False): if phase == 'training': model.train() if phase == 'validation': model.eval() volatile=True running_loss = 0.0 running_correct = 0.0 for batch_idx , batch in enumerate(data_loader): text , target = batch.text , batch.label if is_cuda: text,target = text.cuda(),target.cuda() if phase == 'training': optimizer.zero_grad() print("text",text) output = model(text) loss = F.nll_loss(output,target) running_loss += F.nll_loss(output,target,size_average=False).data[0] preds = output.data.max(dim=1,keepdim=True)[1] running_correct += preds.eq(target.data.view_as(preds)).cpu().sum() if phase == 'training': loss.backward() optimizer.step() loss = running_loss/len(data_loader.dataset) accuracy = 100.0 * running_correct/len(data_loader.dataset) print(f"{phase} loss is {loss:{5}.{2}} and {phase} accuracy is {running_correct}/{len(data_loader.dataset)} {accuracy}") return loss,accuracy train_losses , train_accuracy = [],[] val_losses , val_accuracy = [],[] for epoch in range(1,10): epoch_loss, epoch_accuracy = fit(epoch,model,train_iter,phase='training') #val_epoch_loss , val_epoch_accuracy = fit(epoch,model,test_iter,phase='validation') train_losses.append(epoch_loss) train_accuracy.append(epoch_accuracy) #val_losses.append(val_epoch_loss) #val_accuracy.append(val_epoch_accuracy) print (model.embedding.weight.data)
소스 및 데이터 링크
https://drive.google.com/open?id=1bGLwJSTibk84wTFB5Dt77z1h8SAunvt4결과
... 생략 ...
text tensor([[ 177, 11, 480, 151, 16, 4, 370, 13, 241, 2, 438, 672, 251, 683, 3, 236, 12, 264, 329, 10], [ 287, 3800, 1330, 3447, 4734, 1813, 267, 3769, 33, 2205, 5727, 37, 39, 52, 31, 522, 165, 5018, 1812, 4966], [ 11, 4476, 8, 2, 132, 3097, 295, 2752, 221, 75, 388, 6, 26, 3844, 16, 41, 7, 45, 8, 2], [ 16, 5, 11, 663, 267, 2624, 1888, 7, 4401, 43, 2104, 2271, 10, 39, 148, 5355, 2126, 5182, 4, 4951]]) text tensor([[ 61, 356, 4534, 6, 26, 1229, 18, 415, 2399, 65, 12, 4, 1173, 35, 908, 8, 4107, 3273, 1928, 3424], [ 9, 1656, 10, 13, 15, 5585, 4223, 37, 250, 520, 4, 612, 56, 212, 89, 20, 119, 1133, 91, 40], [ 11, 7, 28, 5, 2, 77, 120, 9, 24, 134, 8, 6017, 9, 196, 19, 4, 3616, 4579, 3331, 14], [ 11, 21, 7, 35, 118, 3, 166, 662, 8, 130, 3819, 3344, 63, 19, 40, 2, 310, 139, 3, 312]]) training loss is 0.37 and training accuracy is 98/100 98 tensor([[-1.9840e-01, 1.1572e+00, -6.0860e-01, ..., -5.6112e-01, -1.1015e+00, 9.2651e-01], [ 5.4855e-01, -1.0774e-02, 6.6805e-01, ..., 6.0653e-01, -1.0333e+00, 3.3314e-01], [-6.5919e-01, 4.9715e-01, 3.2769e-01, ..., -1.0122e+00, -9.2732e-01, -5.6234e-02], ..., [-1.4211e+00, -7.9993e-01, -1.1295e+00, ..., -7.8081e-01, 1.0493e+00, 3.6682e-01], [ 2.8036e-01, -4.6905e-01, 1.6400e+00, ..., -2.0514e+00, -1.8356e-01, -2.7878e-01], [ 4.8133e-02, 1.0894e-01, -6.0099e-01, ..., -7.1037e-02, -1.0001e-01, -1.8576e-02]])
댓글 없음:
댓글 쓰기