📘 本文带你一步步解析一个基于 PyTorch 的中文情感分类项目,使用 双向 LSTM(TextRNN) 模型,对微博情感数据进行训练和预测。
文章重点在于:代码讲解 + 实践流程 + 模型结构说明,非常适合初学者上手循环神经网络项目。


🧠 一、RNN 原理简述

在自然语言处理中,文本是一种序列数据,词与词之间存在上下文依赖。
普通的神经网络(如全连接层)无法捕捉到“时间顺序关系”,而 循环神经网络(RNN) 则可以通过“隐藏状态(Hidden State)”在不同时间步之间传递信息,从而具备记忆能力。

RNN 的核心公式为:

其中:

  • xt:当前输入(词向量)

  • ht−1​:上一个隐藏状态(模型的记忆)

  • ht​:当前隐藏状态

  • f:激活函数(如 tanh 或 ReLU)

但是,普通 RNN 在长文本中容易出现梯度消失问题,无法学习到远距离依赖。
为此,本项目采用 LSTM(长短期记忆网络),通过“输入门、遗忘门、输出门”控制信息流动,使模型既能记住重要信息,又能忘掉无关内容。


🧩 二、项目总体结构

项目目录如下:

├── load_dataset.py       # 数据加载与预处理
├── TextRNN.py            # LSTM 模型定义
├── train_eval_test.py    # 模型训练与验证逻辑
├── main.py               # 主程序入口

任务目标:

通过 LSTM 模型,对微博数据集的文本进行情感分类(喜悦、愤怒、厌恶、低落)。


📂 三、代码详解


✅ 1. 数据加载与预处理(load_dataset.py

这一部分负责把原始的 CSV 数据转为可供模型训练的数值形式。

🔹 主要功能:
  • 读取微博文本及情感标签;

  • 将文字切分成字;

  • 转换为索引(使用词典);

  • 长度统一(填充或截断);

  • 划分训练、验证、测试集。

代码片段:
UNK, PAD = '<UNK>', '<PAD>'

def load_dataset(path, pad_size=70):
    contents = []
    vocab = pkl.load(open('simplifyweibo_4_moods.pkl', 'rb'))
    tokenizer = lambda x: [y for y in x]
    with open(path, 'r', encoding='UTF-8') as f:
        for line in tqdm(f):
            label = int(line[0])
            content = line[2:].strip()
            token = tokenizer(content)
            if len(token) < pad_size:
                token.extend([PAD] * (pad_size - len(token)))
            else:
                token = token[:pad_size]
            words_line = [vocab.get(word, vocab.get(UNK)) for word in token]
            contents.append((words_line, label, len(token)))
    random.shuffle(contents)

🔹 数据划分:
train_data = contents[: int(len(contents) * 0.8)]
dev_data   = contents[int(len(contents) * 0.8): int(len(contents) * 0.9)]
test_data  = contents[int(len(contents) * 0.9):]

🔹 数据迭代器类:

DatasetIterater 用于将数据批量(batch)送入模型:

x = torch.LongTensor([_[0] for _ in datas]).to(self.device)
y = torch.LongTensor([_[1] for _ in datas]).to(self.device)
return (x, seq_len), y


✅ 2. 模型定义(TextRNN.py

这是整个项目的核心部分,定义了 LSTM 网络结构

🔹 网络结构:
self.embedding = nn.Embedding.from_pretrained(embedding_pretrained,
                                              padding_idx = n_vocab - 1, freeze=False)
self.lstm = nn.LSTM(embed, 128, 3, bidirectional=True, batch_first=True, dropout=0.3)
self.fc = nn.Linear(128 * 2, num_classes)

解释:

  • Embedding 层:把文字索引转成词向量;

  • LSTM 层:三层双向 LSTM,隐藏单元 128;

  • 全连接层:将 LSTM 输出映射到情感类别(4 类)。

🔹 前向传播:
def forward(self, x):
    x, _ = x
    out = self.embedding(x)
    out, _ = self.lstm(out)
    out = self.fc(out[:, -1, :])  # 取最后一个时间步
    return out

✅ 注意:这里使用双向 LSTM,输出维度为 128 * 2
取最后时刻的隐藏状态作为句子表示,用于情感分类。


✅ 3. 模型训练与验证(train_eval_test.py

这一部分包括训练循环和验证逻辑。

🔹 验证函数:
def evaluate(class_list, model, data_iter, test=False):
    model.eval()
    with torch.no_grad():
        for texts, labels in data_iter:
            outputs = model(texts)
            loss = F.cross_entropy(outputs, labels)
            predic = torch.max(outputs.data, 1)[1].cpu().numpy()

计算准确率:

acc = metrics.accuracy_score(labels_all, predict_all)
🔹 训练函数:
def train(model, train_iter, dev_iter, test_iter, class_list):
    optimizer = torch.optim.Adam(model.parameters(), lr=1e-3)
    for epoch in range(20):
        for i, (trains, labels) in enumerate(train_iter):
            outputs = model(trains)
            loss = F.cross_entropy(outputs, labels)
            loss.backward()
            optimizer.step()

每 100 个 batch 打印一次训练与验证结果:

if dev_loss < dev_best_loss:
    torch.save(model.state_dict(), 'TextRNN.ckpt')

并启用早停机制防止过拟合:

if total_batch - last_improve > 10000:
    print("No optimization for a long time, auto-stopping...")

✅ 4. 主程序入口(main.py

负责整合所有模块并启动训练。

🔹 设置设备和随机种子:
device = "cuda" if torch.cuda.is_available() else "mps" if torch.backends.mps.is_available() else "cpu"
np.random.seed(1)
torch.manual_seed(1)
torch.backends.cudnn.deterministic = True

🔹 加载数据与模型:
vocab, train_data, dev_data, test_data = load_dataset.load_dataset('simplifyweibo_4_moods.csv')
train_iter = load_dataset.DatasetIterater(train_data, 128, device)
embedding_pretrained = torch.tensor(np.load('embedding_Tencent.npz')["embeddings"].astype('float32'))
🔹 启动训练:
model = TextRNN.Model(embedding_pretrained, len(vocab), embed, num_classes).to(device)
train(model, train_iter, dev_iter, test_iter, class_list)

📊 四、运行与效果

训练时控制台会输出:

Epoch [5/20]
Iter:   100, Train Loss: 0.59, Train Acc: 78.50%, Val Loss: 0.45, Val Acc: 84.20%
Iter:   200, Train Loss: 0.38, Train Acc: 86.70%, Val Loss: 0.35, Val Acc: 88.00%

训练完成后,模型文件会保存为:

TextRNN.ckpt

在测试集上运行 evaluate(..., test=True) 可以得到完整的分类报告。


🏁 五、总结与亮点

模块 功能
load_dataset.py 数据预处理与划分
TextRNN.py LSTM 模型定义
train_eval_test.py 训练与验证逻辑
main.py 程序入口,整合运行

项目亮点:

  • 使用预训练词向量(如腾讯词向量);

  • 双向 LSTM 捕捉上下文语义;

  • 模型提前停止机制;

  • 自动保存验证集最优模型;

  • 模块化清晰,易于复用。


🚀 六、结语

通过本项目,你能完整理解一个 RNN(LSTM)文本情感分类系统 的构建流程,从数据预处理到模型保存,全程使用 PyTorch 实现。

🧩 建议扩展方向:

  • 尝试 GRU、Transformer 替换 LSTM;

  • 添加 Attention 机制;

  • 微调预训练词向量;

  • 增加情感可视化或混淆矩阵分析。

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐