基于PyTorch的双向LSTM模型在IMDB情感分析中的应用
引言
情感分析是自然语言处理(NLP)中的一个重要任务,它旨在确定文本中表达的情感倾向。本文将通过一个基于PyTorch实现的双向LSTM模型,展示如何对IMDB电影评论进行情感分类。我们将从数据准备、模型构建到训练评估,完整地介绍这一过程。
环境与数据准备
基本设置
首先我们需要设置一些基本参数:
RANDOM_SEED = 123 # 随机种子
VOCABULARY_SIZE = 20000 # 词汇表大小
LEARNING_RATE = 1e-4 # 学习率
BATCH_SIZE = 128 # 批量大小
NUM_EPOCHS = 15 # 训练轮数
EMBEDDING_DIM = 128 # 词嵌入维度
HIDDEN_DIM = 128 # 隐藏层维度
NUM_LAYERS = 2 # LSTM层数
BIDIRECTIONAL = True # 使用双向LSTM
数据加载与预处理
我们使用torchtext库加载IMDB数据集,并进行预处理:
TEXT = data.Field(tokenize='spacy', include_lengths=True)
LABEL = data.LabelField(dtype=torch.float)
train_data, test_data = datasets.IMDB.splits(TEXT, LABEL)
train_data, valid_data = train_data.split(random_state=random.seed(RANDOM_SEED), split_ratio=0.8)
数据分割后,我们构建词汇表,只保留最常见的20000个词:
TEXT.build_vocab(train_data, max_size=VOCABULARY_SIZE)
LABEL.build_vocab(train_data)
词汇表中会包含两个特殊标记:<unk>
表示未知词,<pad>
用于填充。
数据迭代器
我们使用BucketIterator创建数据加载器,它能自动将相似长度的样本分组,减少填充量:
train_loader, valid_loader, test_loader = data.BucketIterator.splits(
(train_data, valid_data, test_data),
batch_size=BATCH_SIZE,
sort_within_batch=True,
device=DEVICE)
模型架构
双向LSTM模型
我们构建一个包含嵌入层、双向LSTM层和全连接层的模型:
class RNN(nn.Module):
def __init__(self, input_dim, embedding_dim, hidden_dim, output_dim):
super().__init__()
self.embedding = nn.Embedding(input_dim, embedding_dim)
self.rnn = nn.LSTM(embedding_dim,
hidden_dim,
num_layers=NUM_LAYERS,
bidirectional=BIDIRECTIONAL)
self.fc = nn.Linear(hidden_dim*2, output_dim)
def forward(self, text, text_length):
embedded = self.embedding(text)
packed = torch.nn.utils.rnn.pack_padded_sequence(embedded, text_length)
packed_output, (hidden, cell) = self.rnn(packed)
combined = torch.cat((hidden[-2,:,:], hidden[-1,:,:]), dim=1)
return self.fc(combined.squeeze(0)).view(-1)
模型的关键点:
- 嵌入层:将单词索引转换为密集向量表示
- 双向LSTM:同时考虑前向和后向的上下文信息
- 填充序列打包:使用pack_padded_sequence处理变长序列,提高效率
- 输出合并:将双向LSTM的最终隐藏状态连接后通过全连接层
训练过程
训练设置
我们使用Adam优化器和二元交叉熵损失函数:
model = RNN(len(TEXT.vocab), EMBEDDING_DIM, HIDDEN_DIM, OUTPUT_DIM)
optimizer = torch.optim.Adam(model.parameters(), lr=LEARNING_RATE)
训练循环
训练过程中,我们定期计算训练集和验证集的准确率:
for epoch in range(NUM_EPOCHS):
model.train()
for batch in train_loader:
text, lengths = batch.text
logits = model(text, lengths)
loss = F.binary_cross_entropy_with_logits(logits, batch.label)
optimizer.zero_grad()
loss.backward()
optimizer.step()
# 计算准确率
train_acc = compute_binary_accuracy(model, train_loader)
valid_acc = compute_binary_accuracy(model, valid_loader)
准确率计算
我们定义一个辅助函数来计算二元分类的准确率:
def compute_binary_accuracy(model, data_loader):
model.eval()
correct = 0
total = 0
with torch.no_grad():
for batch in data_loader:
text, lengths = batch.text
logits = model(text, lengths)
preds = (torch.sigmoid(logits) > 0.5).long()
correct += (preds == batch.label.long()).sum()
total += batch.label.size(0)
return correct.float() / total * 100
结果分析
经过15轮训练后,模型在测试集上达到了约83%的准确率。训练过程中的一些观察:
- 随着训练进行,训练准确率稳步提升
- 验证准确率与训练准确率保持同步增长,表明没有明显过拟合
- 最终测试准确率与验证准确率接近,说明模型泛化能力良好
模型应用
训练好的模型可以用于预测新的电影评论情感:
def predict_sentiment(model, sentence):
model.eval()
tokenized = [tok.text for tok in nlp.tokenizer(sentence)]
indexed = [TEXT.vocab.stoi[t] for t in tokenized]
tensor = torch.LongTensor(indexed).to(DEVICE)
tensor = tensor.unsqueeze(1) # 添加batch维度
prediction = torch.sigmoid(model(tensor, [len(indexed)]))
return prediction.item()
总结
本文实现了一个基于双向LSTM的情感分析模型,主要特点包括:
- 使用双向LSTM捕捉上下文信息
- 采用填充序列打包提高训练效率
- 实现了约83%的分类准确率
- 展示了完整的训练评估流程
这种架构可以轻松扩展到其他文本分类任务,通过调整超参数和模型结构,还可能获得更好的性能。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考