简介:这份资源是面向计算机相关专业学生与深度学习入门者的中文情感分析系统源码,采用CNN与Bi-LSTM混合网络结构,可直接用于毕业设计、课程设计或项目初期立项演示,也支持在现有代码基础上二次开发扩展功能。压缩包共46个文件,约75.78MB,包含19个Python脚本、10个文本说明、3份CSV情感语料、2个模型pb文件及配套索引文件,另有设计报告docx、README与运行截图,覆盖数据预处理、模型训练、评估报告等完整流程。项目围绕酒店评论等中文语料展开,提供正负中性三分类数据与多版本Keras实现脚本,便于对比不同网络结构的实验效果。目前已有61人学习关注,适合希望快速理解文本分类建模思路、需要可运行参考代码的学习者借鉴使用。
1. 中文情感分析毕设怎么选:CNN-Bi-LSTM 这套源码能省下多少返工
做中文情感分析方向的毕设,最耗时间的往往不是模型本身,而是数据清洗、标签对齐、训练脚本调通、报告凑齐这一整条链路。这套 Python 中文情感分析系统源码(CNN-Bi-LSTM)打包了从 v1 到 v5 的 Keras 迭代脚本、三份情感语料(neg/neutral/pos)、酒店评论数据、模型目录以及一份设计报告文档,属于典型的「拿来能跑、改完能交」的毕设级资源。它解决的核心问题是:让你跳过从零搭环境的重复劳动,把精力放在模型调参和论文写作上。适合计算机、人工智能、通信工程等专业需要交毕设或课设的学生,也适合想快速摸一遍文本分类完整流程的入门者。下面按「资源是什么 → 怎么跑起来 → 坑在哪 → 怎么改出花」的顺序拆开讲。
2. 拆开压缩包先看什么:文件结构与 CNN-Bi-LSTM 的技术选型
拿到一个源码包,我习惯先不急着跑,而是把目录结构和脚本命名逻辑过一遍,判断作者的技术路线和代码成熟度。这套资源的结构比较清晰,能看出是一个从简单到复杂的迭代过程。
2.1 目录清单与各文件职责
解压后大致能看到这几类内容:
| 文件/目录 | 类型 | 作用 |
|---|---|---|
| keras_sentiment_analysis_v1.py ~ v5.py | 脚本 | 五个版本的训练脚本,迭代关系 |
| sentiment_analysis_ml.py | 脚本 | 传统机器学习基线(TF-IDF + 分类器) |
| score_report.py | 脚本 | 模型评估,输出分类报告 |
| data/neg.csv、neutral.csv、pos.csv | 数据 | 三分类中文情感语料 |
| data/hotel_comment | 数据 | 酒店评论语料,偏真实场景 |
| model/cnn、model/lstm | 模型 | 训练产出的权重文件 |
| 设计报告.docx | 文档 | 毕设报告参考 |
| README.md | 文档 | 运行说明 |
| pic/、clip.png 等 | 图片 | 截图与流程图素材 |
从命名能推断出作者的思路:v1 到 v5 是逐步加料的版本,早期可能是简单 Embedding + LSTM,后期引入 CNN 做局部特征提取,再拼 Bi-LSTM 捕捉上下文。sentiment_analysis_ml.py是传统机器学习对照组,用来在报告里做「深度学习 vs 传统方法」的对比,这个设计对毕设答辩很加分。
2.2 为什么是 CNN + Bi-LSTM 而不是单用其一
中文情感分析的本质是文本分类,但中文没有天然空格分词,且情感倾向往往藏在局部短语(「不是很满意」)和长距离依赖(「虽然……但是……」)里。CNN 的卷积核擅长抓 n-gram 级别的局部特征,比如「太差了」「非常满意」这种情感词组;Bi-LSTM 则从前向和后向两个方向读序列,能捕捉「虽然开头夸了,但结尾转折」这类上下文关系。两者拼接后,CNN 输出的局部特征和 Bi-LSTM 输出的序列特征在维度上 concat,再进全连接层分类,是文本分类里非常成熟的混合结构。
常见做法是:Embedding 层把词映射成向量,CNN 分支用多个尺寸的卷积核(比如 2、3、4)并行提取不同粒度的局部特征,Bi-LSTM 分支输出最后时刻的隐藏态,两路特征拼接后接 Dropout 和 Dense。这套源码的 v4、v5 大概率就是这个结构,v1 到 v3 是过渡版本,方便你在报告里写「模型演进过程」。
提示:先打开 README.md 确认作者标注的运行入口是哪个版本,别一上来就五个脚本全跑,浪费时间。
3. 把环境跑通:从依赖安装到第一个训练脚本出结果
环境配置是新手翻车最集中的地方。这套代码基于 Keras,而 Keras 的版本兼容性在深度学习圈里是出了名的玄学,TensorFlow 2.x 内置的 tf.keras 和独立 Keras 包混用经常报错。下面按顺序走一遍。
3.1 依赖安装与版本锁定
先建虚拟环境,别在系统 Python 里直接装,否则后面版本冲突很难回退:
# 创建并激活虚拟环境 python -m venv sentiment_env # Windows sentiment_env\Scripts\activate # Linux / macOS source sentiment_env/bin/activate # 安装核心依赖,版本按这套代码的常见搭配 pip install tensorflow==2.10.0 pip install numpy pandas scikit-learn jieba matplotlib这里锁 TensorFlow 2.10 是因为它同时支持 GPU 和 CPU,且 tf.keras 接口稳定。如果你机器上没有 NVIDIA 显卡,装 CPU 版即可,训练小规模语料完全够用。jieba是中文分词必备,scikit-learn用来出分类报告和混淆矩阵。
参数说明:tensorflow==2.10.0是这套代码最常见的兼容版本,如果你装 2.15 以上,部分tf.keras.preprocessing.text的 API 会有弃用警告甚至报错。jieba不需要指定版本,最新版即可。
3.2 数据加载与分词流程
中文文本进模型前必须转成数字序列,这一步在脚本里通常封装成load_data之类的函数。核心逻辑是:读 CSV → jieba 分词 → 建词表 → 转索引序列 → padding 对齐长度。
import jieba import pandas as pd from tensorflow.keras.preprocessing.text import Tokenizer from tensorflow.keras.preprocessing.sequence import pad_sequences # 读取三分类语料,假设 CSV 有两列:text, label def load_corpus(path): df = pd.read_csv(path, encoding='utf-8') # jieba 分词,用空格连接成字符串 df['cut'] = df['text'].apply(lambda x: ' '.join(jieba.lcut(str(x)))) return df['cut'].tolist(), df['label'].tolist() texts, labels = load_corpus('data/pos.csv') # 三个文件分别读入后合并 # 建词表,只保留出现频率最高的 20000 个词 tokenizer = Tokenizer(num_words=20000, oov_token='<UNK>') tokenizer.fit_on_texts(texts) sequences = tokenizer.texts_to_sequences(texts) # 统一 padding 到 200 长度,不足补 0,超出截断 X = pad_sequences(sequences, maxlen=200, padding='post', truncating='post')逻辑说明:jieba.lcut是精确模式分词,适合情感分析这种需要保留完整词义的场景。num_words=20000控制词表大小,太大容易过拟合且占内存,太小会丢词。maxlen=200是中文短文本的常见长度,酒店评论一般不超过这个数。padding='post'表示在序列后面补零,truncating='post'表示超长时从后面截断,这两个参数要和后面模型输入维度保持一致。
注意:如果你的 CSV 编码是 GBK,
pd.read_csv会报 UnicodeDecodeError,改成encoding='gbk'或先用记事本另存为 UTF-8。
3.3 模型搭建与训练启动
CNN-Bi-LSTM 的 Keras 实现大致如下,这段代码你可以直接对照源码里的 v4 或 v5 看差异:
from tensorflow.keras import layers, models, Input def build_cnn_bilstm(vocab_size=20000, embed_dim=128, maxlen=200): inputs = Input(shape=(maxlen,)) # 嵌入层,把词索引映射成向量 x = layers.Embedding(vocab_size, embed_dim, input_length=maxlen)(inputs) # CNN 分支:三种卷积核尺寸并行 convs = [] for kernel_size in [2, 3, 4]: c = layers.Conv1D(filters=64, kernel_size=kernel_size, activation='relu', padding='same')(x) c = layers.GlobalMaxPooling1D()(c) convs.append(c) cnn_out = layers.Concatenate()(convs) # Bi-LSTM 分支 lstm_out = layers.Bidirectional(layers.LSTM(64, return_sequences=False))(x) # 两路特征拼接 merged = layers.Concatenate()([cnn_out, lstm_out]) merged = layers.Dropout(0.5)(merged) merged = layers.Dense(64, activation='relu')(merged) outputs = layers.Dense(3, activation='softmax')(merged) # 三分类 model = models.Model(inputs=inputs, outputs=outputs) model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy']) return model model = build_cnn_bilstm() model.summary() history = model.fit(X, y, batch_size=64, epochs=10, validation_split=0.2)逻辑说明:Embedding的embed_dim=128是词向量维度,中文任务常用 100 到 300,128 是折中值。CNN 分支用GlobalMaxPooling1D把每个卷积核的输出压成一个向量,保留最强特征。Bi-LSTM 的return_sequences=False表示只取最后时刻输出,和 CNN 特征维度对齐后拼接。Dropout(0.5)是防过拟合的关键,情感分析语料通常只有几千到几万条,不加 Dropout 验证集准确率会明显低于训练集。Dense(3, activation='softmax')对应 neg/neutral/pos 三分类。
参数怎么改:如果显存不够,把batch_size降到 32 或 16;如果欠拟合,把epochs加到 20 并观察验证集 loss;如果过拟合,把embed_dim降到 64 或加大 Dropout。
3.4 训练结果评估
跑完训练后,用score_report.py或自己写一段评估:
from sklearn.metrics import classification_report, confusion_matrix import numpy as np y_pred = model.predict(X_test) y_pred_label = np.argmax(y_pred, axis=1) print(classification_report(y_test, y_pred_label, target_names=['neg', 'neutral', 'pos'])) print(confusion_matrix(y_test, y_pred_label))classification_report会输出每个类别的 precision、recall、f1-score,毕设报告里直接放这张表。confusion_matrix能看出模型在哪两类之间容易混淆,比如 neutral 和 pos 边界模糊是常见现象,可以在报告里分析原因。
4. 避坑与排查:这套源码最容易翻车的五个地方
以下是我在类似项目里踩过的坑,按「现象 → 原因 → 解决」整理,你对照排查能省不少时间。
现象一:运行脚本报ModuleNotFoundError: No module named 'keras'。原因:TensorFlow 2.10 之后独立 Keras 包和 tf.keras 分离,代码里import keras和from tensorflow.keras import混用会找不到模块。 解决:统一改成from tensorflow.keras import ...,或者单独pip install keras==2.10.0与 TensorFlow 版本对齐。
现象二:训练准确率一直卡在 33% 左右,等于随机猜。原因:标签没做 one-hot 编码,或者categorical_crossentropy配了整数标签。三分类随机准确率就是 1/3。 解决:确认标签用to_categorical(y, num_classes=3)转成 one-hot,或者把 loss 改成sparse_categorical_crossentropy直接用整数标签。
现象三:分词后词表里全是单字,模型学不到词级语义。原因:CSV 读取时编码错误导致中文变成乱码,jieba 对乱码只能按字符切。 解决:检查pd.read_csv的 encoding 参数,打印前几行确认中文正常显示。
现象四:验证集 loss 先降后升,准确率波动大。原因:学习率默认 0.001 对这个数据量偏大,或者 batch_size 太小导致梯度噪声大。 解决:加EarlyStopping(patience=3)回调,或把优化器换成Adam(learning_rate=1e-4),batch_size 提到 64。
现象五:模型保存后重新加载预测结果全错。原因:保存时只存了权重没存结构,或者加载时词表 tokenizer 没一起保存,索引对不上。 解决:用model.save('model.h5')存完整模型,同时用pickle把 tokenizer 存下来,预测时先加载 tokenizer 再转序列。
提示:这套代码有 v1 到 v5 多个版本,如果某个版本报错,先换另一个版本试,作者迭代过程中可能修过 bug。
5. 二次开发与毕设加分:从三分类到多模态、从脚本到可演示系统
把基础版本跑通只是及格线,毕设要拿高分得在原有代码上做出增量。这套源码标注了「支持二次开发」,下面给几个可落地的改造方向,按投入产出比排序。
5.1 改造方向与难度对照
| 改造方向 | 具体做法 | 难度 | 报告加分点 |
|---|---|---|---|
| 换数据集 | 用 hotel_comment 替换通用语料 | 低 | 领域适应性分析 |
| 加注意力机制 | Bi-LSTM 后接 Attention 层 | 中 | 模型创新点 |
| 多分类扩展 | 从 3 类扩到 5 类细粒度情感 | 中 | 数据标注与类别不平衡处理 |
| 传统方法对比 | 跑 sentiment_analysis_ml.py 做基线 | 低 | 实验对比章节 |
| 封装成 Web 演示 | Flask + 前端页面调用模型 | 中高 | 系统完整性 |
5.2 加注意力层的具体改法
注意力机制能让模型对情感关键词分配更高权重,是毕设里性价比很高的创新点。在 Bi-LSTM 输出后加一层 Attention:
from tensorflow.keras import backend as K def attention_layer(inputs): # inputs shape: (batch, timesteps, features) score = layers.Dense(1, activation='tanh')(inputs) # 计算每个时刻的分数 weights = layers.Softmax(axis=1)(score) # 归一化成权重 weighted = layers.Multiply()([inputs, weights]) # 加权 return layers.Lambda(lambda x: K.sum(x, axis=1))(weighted) # 求和 # 在 Bi-LSTM 分支替换原来的输出 lstm_seq = layers.Bidirectional(layers.LSTM(64, return_sequences=True))(x) lstm_out = attention_layer(lstm_seq)逻辑说明:return_sequences=True让 Bi-LSTM 输出每个时刻的隐藏态,Dense(1, activation='tanh')给每个时刻打一个分数,Softmax 归一化后得到注意力权重,加权求和得到最终表示。这样模型能自动学到「差」「满意」这些词更重要。参数上,Dense(1)的输出维度固定为 1,因为每个时刻只需要一个标量分数。
5.3 用 score_report.py 做完整评估
毕设报告需要量化结果,建议在原有评估基础上补上混淆矩阵热力图和 ROC 曲线。score_report.py里通常已经有分类报告,你可以扩展:
import matplotlib.pyplot as plt import seaborn as sns from sklearn.metrics import confusion_matrix cm = confusion_matrix(y_test, y_pred_label) plt.figure(figsize=(6, 5)) sns.heatmap(cm, annot=True, fmt='d', cmap='Blues', xticklabels=['neg', 'neutral', 'pos'], yticklabels=['neg', 'neutral', 'pos']) plt.xlabel('Predicted') plt.ylabel('True') plt.title('Confusion Matrix') plt.savefig('confusion_matrix.png', dpi=300)这张图放进报告比纯数字表格直观得多。注意dpi=300保证打印清晰,annot=True显示具体数值。
5.4 封装成可演示系统的思路
如果毕设要求「系统」而不只是「模型」,可以用 Flask 包一层:
from flask import Flask, request, jsonify import pickle from tensorflow.keras.models import load_model from tensorflow.keras.preprocessing.sequence import pad_sequences import jieba app = Flask(__name__) model = load_model('model/cnn_bilstm.h5') with open('tokenizer.pkl', 'rb') as f: tokenizer = pickle.load(f) @app.route('/predict', methods=['POST']) def predict(): text = request.json.get('text', '') seq = tokenizer.texts_to_sequences([' '.join(jieba.lcut(text))]) X = pad_sequences(seq, maxlen=200, padding='post', truncating='post') pred = model.predict(X)[0] label = ['neg', 'neutral', 'pos'][pred.argmax()] return jsonify({'label': label, 'confidence': float(pred.max())}) if __name__ == '__main__': app.run(debug=True, port=5000)逻辑说明:加载模型和 tokenizer 后,接口接收 JSON 文本,走和训练时完全一致的分词、转序列、padding 流程,返回预测标签和置信度。port=5000是 Flask 默认端口,前端用 fetch 或 axios 调用即可。这一步做完,答辩时能现场演示,比只放几张训练曲线图有说服力。
从那以后我每次拿到这类毕设源码,都强制先跑通最小闭环——读一份数据、训一个 epoch、出一张预测结果——再动任何改造念头,因为环境没通之前改代码全是白费。希望这套 CNN-Bi-LSTM 中文情感分析源码能帮你把毕设的重复劳动砍掉一半,把时间留给真正要动脑的部分。
本文还有配套的精品资源,点击获取