Постоянная потеря обучения и утрата проверки - PullRequest
0 голосов
/ 17 апреля 2020

Я использую модель RNN с библиотекой Pytorch для анализа настроений при просмотре mov ie, но каким-то образом потеря обучения и проверка достоверности оставались неизменными на протяжении всего обучения. Я искал разные онлайн-источники, но все еще застрял.

Может ли кто-нибудь помочь и взглянуть на мой код?

Некоторые параметры указаны в присваивании:

embedding_dim = 64

n_layers = 1

n_hidden = 128

dropout = 0.5

batch_size = 32

Мой основной код

txt_field = data.Field(tokenize=word_tokenize, lower=True, include_lengths=True, batch_first=True)
label_field = data.Field(sequential=False, use_vocab=False, batch_first=True)

train = data.TabularDataset(path=part2_filepath+"train_Copy.csv", format='csv',
                            fields=[('label', label_field), ('text', txt_field)], skip_header=True)
validation = data.TabularDataset(path=part2_filepath+"validation_Copy.csv", format='csv',
                            fields=[('label', label_field), ('text', txt_field)], skip_header=True)

txt_field.build_vocab(train, min_freq=5)
label_field.build_vocab(train, min_freq=2)

device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')
train_iter, valid_iter, test_iter = data.BucketIterator.splits(
    (train, validation, test),
    batch_size=32,
    sort_key=lambda x: len(x.text),
    sort_within_batch=True,
    device=device)

n_vocab = len(txt_field.vocab)
embedding_dim = 64
n_hidden = 128
n_layers = 1
dropout = 0.5

model = Text_RNN(n_vocab, embedding_dim, n_hidden, n_layers, dropout)

optimizer = torch.optim.Adam(model.parameters(), lr=0.0001)
criterion = torch.nn.BCELoss().to(device)

N_EPOCHS = 15
best_valid_loss = float('inf')

for epoch in range(N_EPOCHS):
    train_loss, train_acc = RNN_train(model, train_iter, optimizer, criterion)
    valid_loss, valid_acc = evaluate(model, valid_iter, criterion)

Моя модель

class Text_RNN(nn.Module):
    def __init__(self, n_vocab, embedding_dim, n_hidden, n_layers, dropout):
        super(Text_RNN, self).__init__()
        self.n_layers = n_layers
        self.n_hidden = n_hidden
        self.emb = nn.Embedding(n_vocab, embedding_dim)
        self.rnn = nn.RNN(
            input_size=embedding_dim,
            hidden_size=n_hidden,
            num_layers=n_layers,
            dropout=dropout,
            batch_first=True
        )
        self.sigmoid = nn.Sigmoid()
        self.linear = nn.Linear(n_hidden, 2)

    def forward(self, sent, sent_len):
        sent_emb = self.emb(sent)
        outputs, hidden = self.rnn(sent_emb)
        prob = self.sigmoid(self.linear(hidden.squeeze(0)))

        return prob

Функция обучения

def RNN_train(model, iterator, optimizer, criterion):
    epoch_loss = 0
    epoch_acc = 0
    model.train()
    for batch in iterator:
        text, text_lengths = batch.text
        predictions = model(text, text_lengths)
        batch.label = batch.label.type(torch.FloatTensor).squeeze()
        predictions = torch.max(predictions.data, 1).indices.type(torch.FloatTensor)
        loss = criterion(predictions, batch.label)
        loss.requires_grad = True
        acc = binary_accuracy(predictions, batch.label)
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        epoch_loss += loss.item()
        epoch_acc += acc.item()

    return epoch_loss / len(iterator), epoch_acc / len(iterator)

Результаты, которые я запускаю на 10 обзорах тестирования + 5 проверочных обзорах

Epoch [1/15]:   Train Loss: 15.351 | Train Acc: 44.44%  Val. Loss: 11.052 |  Val. Acc: 60.00%
Epoch [2/15]:   Train Loss: 15.351 | Train Acc: 44.44%  Val. Loss: 11.052 |  Val. Acc: 60.00%
Epoch [3/15]:   Train Loss: 15.351 | Train Acc: 44.44%  Val. Loss: 11.052 |  Val. Acc: 60.00%
Epoch [4/15]:   Train Loss: 15.351 | Train Acc: 44.44%  Val. Loss: 11.052 |  Val. Acc: 60.00%
...

Оцените, если кто-то может указать мне правильное направление, я думаю, что-то с учебным кодом, так как в большинстве случаев я следую этой статье: https://www.analyticsvidhya.com/blog/2020/01/first-text-classification-in-pytorch/

1 Ответ

1 голос
/ 17 апреля 2020

На тренировке l oop вы используете индексы из операции max, которая не дифференцируется, поэтому вы не можете отслеживать градиенты через нее. Поскольку это не дифференцируемо, все впоследствии также не отслеживает градиенты. Вызвать loss.backward() не удастся.

# The indices of the max operation are not differentiable
predictions = torch.max(predictions.data, 1).indices.type(torch.FloatTensor)
loss = criterion(predictions, batch.label)
# Setting requires_grad to True to make .backward() work, although incorrectly.
loss.requires_grad = True

Предположительно, вы хотели это исправить, установив requires_grad, но это не соответствует вашим ожиданиям, поскольку в вашу модель не распространяются градиенты, поскольку единственное в вашем вычислительном графе была бы сама потеря, и оттуда go некуда.

Вы использовали индексы, чтобы получить либо 0, либо 1, поскольку выходные данные вашей модели по существу представляют собой два класса, и Вы хотели тот с более высокой вероятностью. Для потери двоичной перекрестной энтропии вам нужен только один класс со значением от 0 до 1 (непрерывный), который вы получите, применив сигмовидную функцию.

Таким образом, вам нужно изменить выходные каналы конечной линейной функции. слой до 1:

self.linear = nn.Linear(n_hidden, 1)

и в процессе обучения l oop вы можете удалить вызов torch.max, а также requires_grad.

# Squeeze the model's output to get rid of the single class dimension
predictions = model(text, text_lengths).squeeze()
batch.label = batch.label.type(torch.FloatTensor).squeeze()
loss = criterion(predictions, batch.label)
acc = binary_accuracy(predictions, batch.label)
optimizer.zero_grad()
loss.backward()

Так как у вас есть только 1 класс в конце, фактический прогноз будет либо 0, либо 1 (ничего между ними), для достижения этого вы можете просто использовать 0.5 в качестве порога, поэтому все ниже считается 0, а все выше считается 1. Если вы используя функцию binary_accuracy статьи, которую вы читали, это делается автоматически для вас. Они делают это, округляя это с torch.round.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...