В чем разница между применением функции потерь после каждой ячейки RNN и применением всей последовательности? - PullRequest
0 голосов
/ 08 апреля 2019

Приветствую всех!

У меня был проект, в котором я должен генерировать язык с помощью Recurrent Neural Network.В начале я просто взял последовательность символов, подал их в RNN и взял вывод, чтобы вычислить потери.Проблема в том, что этот подход не сработал, как я ожидал.Фактически, это работало очень плохо, принимая во внимание тот факт, что сгенерированные последовательности были почти всегда в диапазоне 200-300, и я не мог генерировать длинные последовательности текста.

Единственное решение, которое работало для меня вэтот контекст заключался в том, чтобы вводить по одному символу за раз в нейронную сеть и вычислять потери после подачи следующего набора символов.

На мой взгляд, два подхода в основном одно и то же, но разница очевидна.

Если кто-то может объяснить эти результаты, это мне очень поможет.Я приведу фрагменты кода ниже:

Ввод представляет собой последовательность из 300 символов

Версия, которая работает

for index, (input, target, lengths) in enumerate(trainLoader):

        loss = 0
        input = Variable(input.to(device))
        target = Variable(target.to(device))

        hidden = model.init_hidden(input)

        lengths = Variable(torch.tensor(lengths).to(device))


        optimizer.zero_grad()

        #Iterate over each character from the sequence, excluding the padding zeroes from the mini-batch 
        for c in range(input.size(1)):
            [input[:,c].nonzero()].size(0)).shape)

            output, hidden = model(input[:,c][input[:,c].nonzero()].contiguous(), 
                                   hidden.narrow(1, 0, input[:,c][input[:,c].nonzero()].size(0)).contiguous())
            hidden = repackage_hidden(hidden)
            loss += criterion(output, target[:,c][target[:,c].nonzero()])


        loss.backward()
        optimizer.step()

        cummulative_loss += loss.item()

Версия, которая не дает удовлетворительногорезультат

for index, (input, target, lengths) in enumerate(trainLoader):

        loss = 0
        input = Variable(input.to(device))
        target = Variable(target.to(device))

        hidden = model.init_hidden(input)

        lengths = Variable(torch.tensor(lengths).to(device))

        optimizer.zero_grad()   


        output, _ = model(input)

        #hidden = repackage_hidden(hidden)

        loss = criterion(output, target)

        loss.backward()

        optimizer.step()

        cummulative_loss += loss.item()

Также ниже приведен код генерации последовательности:

Настройка начального состояния ввода и слова ввода (мы используем «[START]»).

def sample_sentence():
    words = list()
    count = 0
    model.eval()
    with torch.no_grad():
        previousWord = torch.LongTensor(1, 1).fill_(trainData.vocabulary['letter2id']['[START]'])
        hidden =  Variable(torch.zeros(6, 1, 300).to(device))


        while True:
            # Predict the next word based on the previous hidden state and previous word.
            inputWord = torch.autograd.Variable(previousWord.to(device))

            #print("Prediction: ")

            predictions, newHidden = model(inputWord, hidden)            

            hidden = newHidden

            #print("After prediction")

            pred = torch.nn.functional.softmax(predictions.squeeze()).data.cpu().numpy().astype('float64')

            pred = pred/np.sum(pred)

            nextWordId = np.random.multinomial(1, pred, 1).argmax()

            if nextWordId == 0:
                continue

            words.append(trainData.vocabulary['id2letter'][nextWordId])
            # Setup the inputs for the next round.
            previousWord.fill_(nextWordId)


            # Keep adding words until the [END] token is generated.
            if nextWordId == trainData.vocabulary['letter2id']['[END]']:
                break

            if count>10000:
                break
            count += 1
        words.insert(0, '[START]')



        return words

Заранее спасибо!

...