3. 文本情感分析

任务说明

构建一个基于LSTM的文本情感分类模型,对IMDb电影评论进行正面/负面二分类。核心路径为:文本预处理 → 词嵌入 → LSTM编码 → 全连接分类,最终输出测试集准确率作为性能指标。

环境依赖

需要 tensorflow 2.x、numpy、tensorflow_datasets。若使用GPU训练需安装对应CUDA环境,CPU训练亦可完成本案例。

完整实现代码

import tensorflow as tf
import tensorflow_datasets as tfds
import numpy as np

# 1. 加载IMDb数据集(仅保留训练/测试划分)
(train_data, test_data), info = tfds.load(
    'imdb_reviews',
    split=['train', 'test'],
    as_supervised=True,
    with_info=True
)

# 2. 超参数
VOCAB_SIZE = 10000
MAX_LENGTH = 200
EMBEDDING_DIM = 64
LSTM_UNITS = 64
BATCH_SIZE = 128
EPOCHS = 3

# 3. 文本向量化:仅保留最频繁的VOCAB_SIZE个词
def encode(text_tensor, label):
    tokens = tf.strings.split(text_tensor)
    table = tf.lookup.StaticVocabularyTable(
        tf.lookup.TextFileInitializer(
            'vocab.txt', tf.string, tf.lookup.TextFileIndex.WHOLE_LINE,
            tf.int64, tf.lookup.TextFileIndex.LINE_NUMBER
        ), num_oov_buckets=1
    )
    # 简化:使用tfds内置tokenizer
    return tokens, label

# 使用tfds的tokenizer构建词表
tokenizer = tfds.deprecated.text.Tokenizer()
vocab = set()
for text, _ in train_data.take(2000):
    vocab.update(tokenizer.tokenize(text.numpy().decode('utf-8')))
vocab = list(vocab)[:VOCAB_SIZE-1]
vocab.append('<UNK>')

# 保存词表文件(供StaticVocabularyTable使用)
with open('vocab.txt', 'w') as f:
    for word in vocab:
        f.write(word + '\n')

# 4. 编码函数
def encode_map(text, label):
    tokens = tokenizer.tokenize(text.numpy().decode('utf-8'))
    ids = [vocab.index(t) if t in vocab else VOCAB_SIZE-1 for t in tokens]
    ids = ids[:MAX_LENGTH] + [0] * (MAX_LENGTH - len(ids))  # 截断+填充
    return np.array(ids, dtype=np.int32), label

def tf_encode(text, label):
    return tf.py_function(encode_map, [text, label], [tf.int32, tf.int64])

# 5. 构建数据集管道
train_ds = train_data.map(tf_encode).batch(BATCH_SIZE).prefetch(tf.data.AUTOTUNE)
test_ds = test_data.map(tf_encode).batch(BATCH_SIZE).prefetch(tf.data.AUTOTUNE)

# 6. 模型定义
model = tf.keras.Sequential([
    tf.keras.layers.Embedding(VOCAB_SIZE, EMBEDDING_DIM, input_length=MAX_LENGTH),
    tf.keras.layers.LSTM(LSTM_UNITS, return_sequences=False),
    tf.keras.layers.Dense(1, activation='sigmoid')
])

model.compile(optimizer='adam',
              loss='binary_crossentropy',
              metrics=['accuracy'])

# 7. 训练
history = model.fit(train_ds, epochs=EPOCHS, validation_data=test_ds)

# 8. 评估
test_loss, test_acc = model.evaluate(test_ds)
print(f'测试集准确率: {test_acc:.4f}')

运行方式

  1. 将上述代码保存为 lstm_imdb.py,在命令行执行 python lstm_imdb.py。
  2. 首次运行会自动下载IMDb数据集(约80MB),需保持网络畅通。
  3. 训练过程约需5-15分钟(CPU),GPU环境可显著加速。

验证方法

训练完成后观察终端输出的测试集准确率。当测试集准确率 ≥ 85% 时,判定模型训练成功。同时可查看训练过程中验证集准确率是否随epoch递增,若出现持续下降则说明过拟合,可增加Dropout层或减小LSTM单元数。

预期输出

Epoch 1/3
...
Epoch 3/3
...
测试集准确率: 0.8724

以上准确率数值为示例,实际结果因随机初始化略有波动,但通常落在0.85-0.89区间。

常见问题

  • 内存不足:降低 BATCH_SIZE 至64或32。
  • 词表文件缺失:确保 vocab.txt 与脚本在同一目录,且已通过前2000条训练样本生成。
  • tfds版本兼容:若使用tensorflow 2.16+,tfds.deprecated.text.Tokenizer 可能不可用,可改用 tf.keras.layers.TextVectorization 替代(需调整编码部分)。