2018년 10월 21일 일요일

Deep Learning with Sequence Data and text (순차적 데이터와 텍스트의 딥러닝 PyTorch) (10)


Freeze the embedding layer weights


PyTorch에 embedding layer의 가중치를 변하지 않도록 하는것은 두단계 과정이 있습니다.
1. requires_grad 속성을 False로 설정합니다. 이것은 PyTorch는 이 가중치를 위한 기울기가 필요하지 않다는것을 지시합니다.
2. embedding layer 인자들의 optimizer로의 통과를 제거합니다. 모든 인자들은 기울기를 가지는 것이 예상되기 때문에, 이것을 하지 않으면 optimizer는 에러를 발생 시킵니다. 
다음 코드는 얼마나 쉽게 embedding layer 가중치값을 얼리는지 보여줍니다. 그리고 optimizer가 인자들을 사용하지 않도록 알려줍니다.

model.embedding.weight.requires_grad = False

optimizer = optim.Adam([ param for param in model.parameters() if param.requires_grad == True],lr=0.001)

우리는 일반적으로 모든 모델 인자를 optimizer로 통과 시켰습니다. 그러나 이전 코드에서 requires_grad 가 True인 인자들을 통과 시켰습니다.
우리는이 정확한 코드를 사용하여 모델을 훈련시킬 수 있으며 비슷한 정확도를 달성해야합니다. 이러한 모든 모델 구조는 텍스트의 순차적인 특성을 이용하지 못합니다.
다음에는 두가지 대중화된 기법인 순차적인 데이터의 이점이 있는 RNN 과 Conv1D 를 알아보겠습니다.

자체 테스트

아래 예제는 앞에서 사용했었던 예제입니다. Freeze 만을 위한 테스트 코드입니다. 다른 부분은 참고 할만한 코드는 아닙니다. 앞장에서도 설명했지만 freeze외에 vector도 로딩해야하지만 그부분은 이번장의 내용이 아니라서 생략하였습니다.
여기에서는 위 1번 항목인 model.embedding.weight.requires_grad = False 이 코드만 추가시켜 보았습니다.
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

# add
model.embedding.weight.requires_grad = False

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)

실행 결과
gradients가 없다고 에러 발생합니다.
Traceback (most recent call last):
  File "test6-2.py", line 51, in <module>
    optimizer = optim.Adam(model.parameters(),lr=0.001)
  File "E:\ProgramData\Anaconda3\lib\site-packages\torch\optim\adam.py", line 41, in __init__
    super(Adam, self).__init__(params, defaults)
  File "E:\ProgramData\Anaconda3\lib\site-packages\torch\optim\optimizer.py", line 43, in __init__
    self.add_param_group(param_group)
  File "E:\ProgramData\Anaconda3\lib\site-packages\torch\optim\optimizer.py", line 193, in add_param_group
    raise ValueError("optimizing a parameter that doesn't require gradients")
ValueError: optimizing a parameter that doesn't require gradients

2번 항목을 추가 해보겠습니다.
optimizer = optim.Adam([ param for param in model.parameters() if param.requires_grad == True],lr=0.001) 이 코드는 model.parameters() 인자들 중에 requires_grad == True 조건이 있는 값만 인자로 넘기게 됩니다.
에러는 발생하지 않습니다.
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

# add
model.embedding.weight.requires_grad = False

#optimizer = optim.Adam(model.parameters(),lr=0.001)
optimizer = optim.Adam([ param for param in model.parameters() if param.requires_grad == True],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)




댓글 없음:

댓글 쓰기