Использование предварительно обученных встраиваний предложений в PyTorch

[Исходное сообщение, см. отредактированное ниже]

Я новичок в PyTorch и пытаюсь выполнить в нем задачу классификации предложений.

Я усреднил вложения слов в каждом предложении (вложения перчаток), чтобы сформировать вложение предложения. Следовательно, размерность вложения каждого предложения одинакова. Насколько я понимаю, поскольку у меня уже есть вложения, мне не нужен слой встраивания перед использованием LSTM. Моя модель выглядит следующим образом:

import torch
import torch.autograd as autograd
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim

class LSTM1(nn.Module):

def __init__(self,args):
    super(LSTM1,self).__init__()
    self.args = args
    self.hidden_dim = args.hidden_dim
    self.lstm = nn.LSTM(args.embed_dim, args.hidden_dim)
    self.hidden2tag = nn.Linear(args.hidden_dim, 2)
    self.hidden = self.init_hidden()

def init_hidden(self):
    return (autograd.Variable(torch.zeros(1,1, self.hidden_dim).cuda()),
        autograd.Variable(torch.zeros(1,1, self.hidden_dim).cuda()))

def forward(self,embeds):
    embeds = autograd.Variable(torch.from_numpy(embeds[0]).float().cuda())
    lstm_output, self.hidden = self.lstm(embeds.view(1, 1, -1), self.hidden)
    tag_space = self.hidden2tag(lstm_output.view(1, -1))
    scores = F.log_softmax(tag_space)
    return scores

И я передаю предложения в виде вложений следующим образом:

model = model.LSTM1(args).cuda()
criterion = nn.NLLLoss()
optimizer = optim.SGD(model.parameters(), lr=1e-5, momentum=0.9, weight_decay=1e-5)

optimizer.zero_grad()

for epoch in range(20):
    for i in range(len(sentences)):
        optimizer.zero_grad()
        model.hidden = model.init_hidden()
        target = prepare_targets(tag_phrase[i],tag_to_ix,1) #Gets a Variable(long tensor) for the target, single value (either 0 or 1)
        score = model(sentences[i]) #sentences[i] is the embedding of sentence i

        loss = criterion(score,target)
        loss.backward()
        optimizer.step()

Мои сомнения:

  1. Таким образом, встраивание переходит в модель, где в прямой функции оно преобразуется в Variablle (тензор с плавающей запятой) и, следовательно, является подходящим входом для LSTM. Это мое понимание вещей. Это верно?
  2. Я возвращаюсь назад после каждого предложения, значит, это делает каждое предложение отдельной партией? Как мне разбить предложения на партии и какие изменения мне тогда нужно внести в модель?
  3. Каков наиболее подходящий способ использования предварительно обученных встраиваний предложений в PyTorch?
  4. Если этот код кажется правильным, то проблема, с которой я столкнулся, заключается в том, что все классифицируется в один класс из двух. Есть предложения по устранению этой ошибки?

Спасибо.

[EDIT] Улучшенный код

embeddings = torch.from_numpy(embeddings).float().cuda()
args.embed_num=embeddings.size(0)
args.embed_dim=embeddings.size(1)

seq = [i for i in range(13000)]
seq_tensor = torch.LongTensor(seq).cuda() #Index tensor corresponding to the embedding.

target = prepare_targets(tag_phrase[:13000],tag_to_ix,1)

train_data = torch.utils.data.TensorDataset(seq_tensor.cuda(),target.data.cuda())
trainloader = torch.utils.data.DataLoader(train_data, batch_size=100, shuffle=True)

model = model2.LSTM1(args,embeddings, 3).cuda()
criterion = nn.NLLLoss()
optimizer = optim.SGD(model.parameters(), lr=1e-4, momentum=0.9, weight_decay=1e-5)

for epoch in range(1000):
    avg_loss=0.
    for i, data in enumerate(trainloader,0):
        seq, target = data
        seq_var, target = autograd.Variable(seq.cuda()), autograd.Variable(target.cuda())
        correct=0
        optimizer.zero_grad()
        model.hidden=model.init_hidden()
        score=model(seq_var)
        loss = criterion(score,target)
        loss.backward()
        optimizer.step()
        epoch_lis.append(epoch)
        losses.append(loss.data[0])
        _,predicted = torch.max(score.data,1)
        correct += (predicted == target.data).sum()
        print i, correct

модель:

class LSTM1(nn.Module):

    def __init__(self,args,embeddings, layers):
        super(LSTM1,self).__init__()
        self.num_layers=layers
        self.args = args
        self.hidden_dim = args.hidden_dim
        self.embed = nn.Embedding(args.embed_num, args.embed_dim)
        self.embed.weight = nn.Parameter(embeddings)
        self.lstm = nn.LSTM(args.embed_dim, args.hidden_dim, num_layers=self.num_layers)
        self.hidden2tag = nn.Linear(args.hidden_dim, 2)
        self.hidden = self.init_hidden()

    def init_hidden(self):
        return (autograd.Variable(torch.zeros(self.num_layers,1, self.hidden_dim).cuda()),
            autograd.Variable(torch.zeros(self.num_layers,1, self.hidden_dim).cuda()))

    def forward(self,sentence):
        embeds = self.embed(sentence)
        lstm_output, self.hidden = self.lstm(embeds.view(len(sentence), 1, -1), self.hidden)
        tag_space = self.hidden2tag(lstm_output.view(len(sentence), -1))
        scores = F.log_softmax(tag_space)
        return scores

person codeninja    schedule 01.10.2017    source источник


Ответы (1)


  1. Да, возможно, в autograd.Variable(torch.from_numpy(embeds[0]).float().cuda()) - вам не нужно .float(), поскольку embeds уже является тензором с плавающей запятой. Кстати, комбинирование векторов слов для формирования вектора предложения - это нормально, но тогда зачем вам нужна RNN для генерации представлений предложений? Пожалуйста, внимательно просмотрите, что вы делаете.

  2. Да, вы следуете стохастическому градиентному спуску (после каждого предложения запускаете обратную связь). Чтобы узнать, как использовать мини-пакетный градиентный спуск, вы можете увидеть пример pytorch на основе любой языковой модели. Например, snli является хорошим примером классификации текста.

  3. Это зависит от того, как вы хотите его использовать. Я считаю, что не существует концепции «наиболее подходящего способа» использования предварительно обученных встраиваний предложений в pytorch.

  4. В вашем коде есть серьезные проблемы. Например, LSTM в вашей модели ничего не делает! Более того, если вы хотите отладить свой код, я бы посоветовал вам распечатать значения потерь и проверить, снижается ли значение потерь при все большем и большем количестве итераций. Если нет, то вам нужно выяснить, почему ваша модель ничему не учится.

Предложение: Судя по вашим вопросам, похоже, что вы новичок в pytorch. Итак, я хочу порекомендовать вам ознакомиться с официальными руководствами и примерами, прежде чем двигаться дальше.

person Wasi Ahmad    schedule 02.10.2017
comment
Спасибо, Васи, 1. Я не пытаюсь создавать представления предложений, я хочу использовать эти вложения для дальнейшей классификации предложений. 2. Я изменил модель на модель на основе мини-партии. 4. Подскажите, пожалуйста, почему LSTM ничего не делает по вашему мнению, что я здесь сделал не так? Большое спасибо! Я обновлю свой код новым. - person codeninja; 02.10.2017
comment
Я обновил код, пожалуйста, посмотрите! Я изучил много руководств и примеров по pytorch. В этом новом коде я передаю матрицу вложения предложений в качестве начальных весов встраиваемых слоев. Индексы предложений и соответствующие цели для классификации предложений передаются как LongTensors внутри модели. Все вычисления выполняются небольшими партиями. Я разместил свой код на примерах сайтов SNLI и pytorch. - person codeninja; 02.10.2017
comment
@codeninja, вы печатали значение потерь после каждой итерации мини-пакета? Можете ли вы распечатать список losses и проверить, снижается ли значение потерь с увеличением количества итераций? - person Wasi Ahmad; 02.10.2017
comment
Вы правы, это не тренировка. После первой эпохи я распечатал значение потерь после каждой итерации мини-пакета. Значения стагнируют около одной точки, слегка перемещаясь вверх и вниз. iter0: 0,696107327938 iter1: 0,693988800049 iter2: 0,696617126465 iter3: 0,694681763649 iter4: 0,695053875446 Хотя среднее значение потерь в каждую эпоху снижается в течение первых нескольких эпох, а затем становится постоянным. Раньше я рисовал потерю эпох, поэтому подумал, что это тренировка. Но похоже, что это не так. Есть предложения о том, что может быть не так с новым кодом? - person codeninja; 02.10.2017