训练损失和验证损失保持不变

我在使用Pytorch库运行一个RNN模型来对电影评论进行情感分析,但不知为何,训练损失和验证损失在整个训练过程中保持不变。我查阅了不同的在线资源,但仍然卡住了。

请有人能帮助我并查看我的代码吗?

一些参数是由作业指定的:

embedding_dim = 64n_layers = 1n_hidden = 128dropout = 0.5batch_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 = 64n_hidden = 128n_layers = 1dropout = 0.5model = 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 = 15best_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/


回答:

在你的训练循环中,你使用了最大操作的索引,这是不可以微分的,因此你无法通过它来追踪梯度。因为它不可微分,所以之后的所有操作也无法追踪梯度。调用loss.backward()将会失败。

# 最大操作的索引是不可以微分的predictions = torch.max(predictions.data, 1).indices.type(torch.FloatTensor)loss = criterion(predictions, batch.label)# 设置requires_grad为True以使.backward()工作,尽管不正确。loss.requires_grad = True

你可能希望通过设置requires_grad来解决这个问题,但那并不会达到你期望的效果,因为没有梯度传播到你的模型中,因为你的计算图中唯一的东西就是损失本身,并且从那里开始无处可去。

你使用索引来得到0或1,因为你的模型的输出基本上是两个类,你想要那个概率较高的类。对于二元交叉熵损失,你只需要一个类,其值在0和1之间(连续的),你可以通过应用sigmoid函数来获得这个值。

因此,你需要将最终线性层的输出通道更改为1:

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

并且在你的训练循环中,你可以移除torch.max调用以及requires_grad

# 压缩模型的输出以去除单个类维度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()

由于你最后只有一个类,一个实际的预测将是0或1(没有中间值),要实现这一点,你可以简单地使用0.5作为阈值,因此一切低于这个值的都被认为是0,一切高于这个值的都被认为是1。如果你使用的是你所遵循的文章中的binary_accuracy函数,这会自动为你完成。他们通过torch.round来实现这一点。

Related Posts

使用LSTM在Python中预测未来值

这段代码可以预测指定股票的当前日期之前的值,但不能预测…

如何在gensim的word2vec模型中查找双词组的相似性

我有一个word2vec模型,假设我使用的是googl…

dask_xgboost.predict 可以工作但无法显示 – 数据必须是一维的

我试图使用 XGBoost 创建模型。 看起来我成功地…

ML Tuning – Cross Validation in Spark

我在https://spark.apache.org/…

如何在React JS中使用fetch从REST API获取预测

我正在开发一个应用程序,其中Flask REST AP…

如何分析ML.NET中多类分类预测得分数组?

我在ML.NET中创建了一个多类分类项目。该项目可以对…

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注