在自然语言处理(NLP)领域,循环神经网络(RNN) 是处理序列数据的经典利器,尤其擅长捕捉文本中的上下文依赖关系。对于情感分析这类任务——判断一段文字是正面还是负面——RNN 能够逐词“阅读”句子,并基于语义顺序做出判断,因此被广泛应用。
本文从零构建一个 IMDb 电影评论情感分类模型,不仅使用 LSTM(RNN 的改进版本)作为核心结构,还引入 Keras Tuner 实现超参数自动搜索,结合早停机制与 TensorBoard 可视化,打造一个完整、高效、可复现的深度学习实战项目。
✅ 项目特点:
- 使用 Google Colab 免费 GPU 加速训练
- 基于 Keras 内置 IMDB 数据集,开箱即用
- 自动化超参数调优,告别手动“调参炼丹”
- 输出结构化实验结果,支持后续分析
一、项目背景与数据准备
📚 数据集简介:IMDb 电影评论
我们使用的 IMDb 数据集 包含 50,000 条经过标注的电影评论,每条被标记为“正面”(1)或“负面”(0),是情感分析领域的标准 benchmark 数据集。
目标:训练一个 RNN 模型,自动判断新评论的情感倾向。
🛠️ 环境与依赖
本项目在 Google Colab 中运行,支持免费 GPU 加速(MacBook Air上要跑一个多小时,Colab上不到半个小时,如果自己电脑性能好的话可以在本地跑)。
首先安装 keras-tuner并导入所需库:
# 安装 Keras Tuner
!pip install -q keras-tuner
# 导入基础库
import numpy as np
import pandas as pd
import tensorflow as tf
# 导入 IMDB 数据集
from tensorflow.keras.datasets import imdb
# 定义基础参数
NUM_WORDS = 10000 # 保留最常见的 10000 个词
MAX_LEN = 150 # 每条评论最大长度
TRAIN_SAMPLES = 20000 # 训练样本数
TEST_SAMPLES = 5000 # 测试样本数
# 加载数据
print("📥 正在加载 IMDB 数据集...")
(x_train, y_train), (x_test, y_test) = imdb.load_data(num_words=NUM_WORDS)
# 截取指定数量样本
x_train, y_train = x_train[:TRAIN_SAMPLES], y_train[:TRAIN_SAMPLES]
x_test, y_test = x_test[:TEST_SAMPLES], y_test[:TEST_SAMPLES]
print(f"✅ 数据加载完成!")
print(f"训练集大小: {len(x_train)} 条评论")
print(f"测试集大小: {len(x_test)} 条评论")
💡
imdb.load_data(num_words=10000)会自动将文本转换为整数序列(每个词对应一个 ID),极大简化预处理流程。
🧹 数据预处理:统一长度,划分验证集
由于评论长度不一,必须填充或截断至固定长度才能批量训练。我们使用 pad_sequences 将所有序列统一为 MAX_LEN=150。
同时,从训练集中划分出 20% 作为验证集,用于超参数搜索时评估模型性能:
# 划分训练集和验证集
from sklearn.model_selection import train_test_split
from tensorflow.keras.preprocessing.sequence import pad_sequences
print("🧹 正在进行数据预处理...")
# 划分:80% 训练,20% 验证
x_train, x_val, y_train, y_val = train_test_split(
x_train, y_train,
test_size=0.2,
random_state=42
)
# 序列填充到统一长度
x_train = pad_sequences(x_train, maxlen=MAX_LEN, padding='post', truncating='post')
x_val = pad_sequences(x_val, maxlen=MAX_LEN, padding='post', truncating='post')
x_test = pad_sequences(x_test, maxlen=MAX_LEN, padding='post', truncating='post')
print(f"✅ 数据预处理完成!")
print(f"训练集形状: {x_train.shape}")
print(f"验证集形状: {x_val.shape}")
print(f"测试集形状: {x_test.shape}")
✅ 输出:
🧹 正在进行数据预处理... ✅ 数据预处理完成! 训练集形状: (16000, 150) 验证集形状: (4000, 150) 测试集形状: (5000, 150)
二、构建可搜索的 RNN 模型
传统建模往往依赖经验“试错”调参,效率低下。我们使用 Keras Tuner,让机器自动探索最优超参数组合。
定义 build_model(hp) 函数,将关键参数设为可调选项:
# 导入建模所需模块
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Embedding, LSTM, Dense, Dropout, Bidirectional
from tensorflow.keras.optimizers import Adam, RMSprop
import keras_tuner as kt
def build_model(hp):
"""构建带超参数的 RNN 模型"""
model = Sequential()
# 嵌入层:将词 ID 映射为向量
embedding_dim = hp.Choice('embedding_dim', [64, 100, 128], default=128)
model.add(Embedding(NUM_WORDS, embedding_dim))
# LSTM 层:支持多层、双向、Dropout
lstm_layers = hp.Choice('lstm_layers', [1, 2])
lstm_units = hp.Choice('lstm_units', [64, 128])
dropout = hp.Float('dropout', 0.2, 0.5, step=0.1)
use_bidirectional = hp.Boolean('use_bidirectional', default=False)
for i in range(lstm_layers):
return_sequences = (i < lstm_layers - 1)
if use_bidirectional:
model.add(Bidirectional(
LSTM(lstm_units, dropout=dropout, return_sequences=return_sequences)
))
else:
model.add(LSTM(lstm_units, dropout=dropout, return_sequences=return_sequences))
# 可选全连接层
if hp.Boolean('use_dense', default=True):
dense_units = hp.Choice('dense_units', [32, 64])
model.add(Dense(dense_units, activation='relu'))
model.add(Dropout(dropout))
# 输出层:二分类,使用 sigmoid
model.add(Dense(1, activation='sigmoid'))
# 优化器与学习率
lr = hp.Float('learning_rate', 1e-4, 1e-3, sampling='log')
optimizer_name = hp.Choice('optimizer', ['adam', 'rmsprop'])
optimizer = Adam(learning_rate=lr) if optimizer_name == 'adam' else RMSprop(learning_rate=lr)
model.compile(
optimizer=optimizer,
loss='binary_crossentropy',
metrics=['accuracy']
)
return model
print("✅ 模型构建函数已定义!")
🔍 超参数搜索空间说明:
| 参数 | 可选值 | 说明 |
|---|---|---|
embedding_dim |
64, 100, 128 | 词向量维度 |
lstm_layers |

最低0.47元/天 解锁文章
1278






