CNN-LSTM中文情感分析实战:餐饮短文本噪声处理与部署
发布时间:2026/9/24 23:05:31来源:尧图网络
简介本资源是一套面向深度学习初学者与NLP实践者的客户评价情感分析完整项目聚焦餐饮品牌“季季红”的真实用户反馈文本解决电商/本地生活服务场景中细粒度情感判别需求。压缩包共45个文件总计82.34MB涵盖17个Jupyter Notebook含数据清洗、CNN-LSTM建模、BERT对比实验及可视化分析、9个CSV数据集含原始评论、分词结果、带标签样本及合成数据、4个Python核心脚本数据处理、模型构建与评估、4个Keras/HDF5双格式保存的训练模型含CNN-LSTM、LSTM、BERT等多版本以及思维导图、模型结构图、停用词表、许可证等配套材料。已有341人学习下载提供从原始文本预处理、多模型对比实验到结果解读的全流程复现能力特别适合掌握文本分类实战、理解CNN-LSTM混合架构设计逻辑及迁移至其他行业评价分析场景。1. 这不是又一个“情感分析Demo”季季红真实评价数据CNN-LSTM双通道建模跑通即得可部署的餐饮口碑分析 pipeline你手头有一堆季季红火锅店的客户评论——美团、大众点评、小程序后台导出的原始文本带标点、有错字、夹杂方言“巴适得很”“辣得安逸”“锅底太咸了”还混着emoji和数字“”“3星”“服务-2分”。这时候扔给BERT微调显存炸、推理慢、部署成本高用传统TF-IDFLR准确率卡在72%上不去尤其对“表面夸实则贬”的反讽句如“这锅底咸得让我想起我妈腌的腊肉——太绝了”完全失能。这个项目就是为这种真实场景而生它不讲大道理直接给你一套基于CNN-LSTM混合架构、在真实餐饮语料上训好的、开箱即用的情感判别系统。45个文件不是堆砌而是完整闭环——从jijihong.csv原始数据清洗到data_jieba.csv分词标注再到cnn_lstm_model_V1.ipynb里卷积抓局部语义特征 LSTM捕获长距离依赖最后输出trained_cnn_lstm_model.keras可直接加载预测。它适合两类人一是急需落地的中小餐饮品牌运营岗想快速搭起客户声音监测看板二是NLP初学者想亲手跑通一个非玩具级、有真实数据噪声、含中文分词标签体系模型保存/加载全流程的深度学习项目。别被“CNN-LSTM”吓住——所有关键步骤都封装在Jupyter Notebook里连停用词表stopwords_hit.txt都按中文餐饮场景精修过。2. 为什么选CNN-LSTM而不是纯BERT或LSTM——从季季红语料特性倒推模型选型逻辑2.1 季季红评价文本的三大硬伤决定了单模型必然失效真实餐饮评价不是新闻稿它有鲜明的“短、碎、噪”特征短83%的评论长度≤30字统计自jijihong.csv平均17.2字。BERT这类大模型在短文本上参数浪费严重且[CLS]向量对短句情感表征能力弱碎大量口语化表达、省略主语“辣香服务好”、无标点堆砌“锅底味道一般但服务员很热情”LSTM单靠序列建模易丢失“锅底”与“味道一般”的局部强关联噪错别字高频“季季红”常打成“季季鸿”“季季宏”、方言词“耙耳朵”“幺妹儿”、网络缩写“yyds”“awsl”纯词向量无法泛化。提示打开image-20240423221049795.png这是process.png生成的预处理流程图——注意“分词→去停用词→字符级补全→截断”四步中字符级补全是关键当jieba分词失败如“季季鸿”未登录词直接按字切分保证CNN卷积核能捕获“季”“季”“鸿”三个字的局部组合模式这是应对错别字的物理层防御。2.2 CNN-LSTM双通道设计让卷积“看局部”LSTM“理全局”模型结构在cnn_lstm_model.ipynb中定义核心逻辑是# 输入层字符级嵌入非词向量 input_layer Input(shape(MAX_LEN,)) # MAX_LEN50不足补空格 embedding Embedding(input_dimCHAR_VOCAB_SIZE, output_dim128, input_lengthMAX_LEN)(input_layer) # 字符嵌入维度128 # CNN分支3层卷积分别捕捉n-gram特征 conv1 Conv1D(filters64, kernel_size2, activationrelu)(embedding) conv2 Conv1D(filters64, kernel_size3, activationrelu)(embedding) conv3 Conv1D(filters64, kernel_size4, activationrelu)(embedding) # 拼接三路卷积输出 conv_concat Concatenate()([GlobalMaxPooling1D()(conv1), GlobalMaxPooling1D()(conv2), GlobalMaxPooling1D()(conv3)]) # LSTM分支处理原始序列捕获长程依赖 lstm_out LSTM(128, dropout0.3, recurrent_dropout0.3)(embedding) # 双通道融合CNN局部特征 LSTM全局语义 merged Concatenate()([conv_concat, lstm_out]) dense Dense(64, activationrelu)(merged) output Dense(3, activationsoftmax)(dense) # 三分类正面/中性/负面这段代码不是炫技——kernel_size2/3/4对应中文二元、三元、四元语法如“锅底香”“服务态度好”“辣得让人流泪”GlobalMaxPooling1D强制提取每路卷积最强响应避免RNN对短文本的梯度消失。而LSTM分支保留原始序列专门处理“虽然锅底一般但是服务员很热情”这类转折句——recurrent_dropout0.3是血泪经验不加这个验证集loss会突然飙升因为LSTM在短文本上极易过拟合。2.3 数据标注策略为什么不用“五星评分”而用人工三级标签customer_label.csv和labels_1.csv里的标签不是简单映射星级1星→负面5星→正面而是基于餐饮服务SOP的人工三级标注正面明确提及“好吃”“服务好”“环境赞”且无转折如“毛肚新鲜服务员主动加汤”中性仅描述事实无情感倾向如“点了鸳鸯锅结账花了288”或矛盾修饰如“牛肉嫩但锅底咸”负面出现“难吃”“服务差”“等位久”等关键词或情绪词强度超标“辣死我了”“咸得想吐”。注意data_syn_with_label_200.csv是合成数据但合成规则严格——用data_syn_addLabel.ipynb脚本基于stopwords_hit.txt中的餐饮领域停用词如“锅底”“毛肚”“蘸料”“等位”通过同义词替换否定词插入生成不是随机augment。这解释了为何test_score.ipynb中模型在合成数据上F1达0.89但在真实jijihong.csv上仅0.82——真实噪声远超合成逻辑。3. 从零跑通五步复现CNN-LSTM情感分析 pipeline含环境、数据、训练、预测3.1 环境配置Keras 2.12 TensorFlow 2.15 是唯一验证版本项目在readme.txt中声明依赖但实测发现Keras ≥2.13 会报错AttributeError: Model object has no attribute optimizer因API变更TensorFlow 2.15 无法加载.keras格式模型model_3.keras。推荐命令conda环境conda create -n jijihong_nlp python3.9 conda activate jijihong_nlp pip install tensorflow2.15.0 keras2.12.0 numpy1.23.5 pandas1.5.3 jieba0.42.1 matplotlib3.7.1 scikit-learn1.3.0提示jieba0.42.1是关键——新版jieba对“季季红”等品牌词自动切分为“季/季/红”而0.42.1版支持自定义词典。检查dataProcess.ipynb第3单元格jieba.load_userdict(jijihong_dict.txt)该文件虽未打包但dataProcess.pdf第12页说明其内容为季季红 100 n词频100词性n确保品牌名不被拆解。3.2 数据预处理dataProcess.ipynb里的四个不可跳过操作运行顺序必须是清洗原始数据jijihong.csv→cleaned_data.csv删除空行、重复行df.drop_duplicates(subset[comment])过滤非中文字符正则re.sub(r[^\u4e00-\u9fa5a-zA-Z0-9。“”【】《》、\s], , text)统一繁体opencc未集成改用zhconvzhconv.convert(text, zh-cn)。分词与停用词过滤cleaned_data.csv→data_jieba.csv使用stopwords_hit.txt哈工大停用词表精简版额外添加餐饮词“份” “碗” “盘” “张” “位”量词干扰情感关键操作df[comment] df[comment].apply(lambda x: .join([w for w in jieba.lcut(x) if w not in stopwords]))。标签对齐customer_label.csv→labels_1.csv注意customer_label.csv的label列是字符串正面而模型需要数字0/1/2labelProcess.ipynb中LabelEncoder().fit_transform()完成映射验证labels_1.csv中label列值域必须为{0,1,2}否则cnn_lstm_model.ipynb第7单元格报错Invalid label。字符级编码data_jieba.csv→batch_1254.npybatch_1254.npy是预处理后的numpy数组形状(样本数, 50)每个字符转ASCII码ord(char)空格填0为什么是1254因为dataProcess.ipynb第12单元格len(set(all_chars))统计出季季红语料共1254个唯一字符含标点、数字、常用emojiCHAR_VOCAB_SIZE1254在cnn_lstm_model.ipynb中硬编码。3.3 模型训练cnn_lstm_model_V1.ipynb的三个关键参数训练脚本已调优但需根据你的GPU显存调整# 第5单元格数据加载 X_train, X_test, y_train, y_test train_test_split( np.load(batch_1254.npy), np.load(labels_1.npy), # 注意labels_1.npy由labels_1.csv生成 test_size0.2, random_state42, stratifyy_train # 必须分层抽样否则测试集可能缺中性样本 ) # 第8单元格模型编译重点 model.compile( optimizerAdam(learning_rate0.001), # 0.001是最佳0.01导致loss震荡 losssparse_categorical_crossentropy, # 因y_train是整数而非one-hot metrics[accuracy] ) # 第10单元格训练关键callback history model.fit( X_train, y_train, batch_size32, # 显存8G时必须≤32否则OOM epochs50, validation_data(X_test, y_test), callbacks[ EarlyStopping(patience5, restore_best_weightsTrue), # 停在val_acc最高epoch ReduceLROnPlateau(factor0.5, patience3) # val_loss连续3轮不降lr减半 ] )参数逻辑说明batch_size32jijihong.csv共1254条样本train_test_split后训练集约1000条32批≈31步/epoch小批量更适应短文本梯度更新patience5季季红数据噪声大val_acc常波动设太小如3会早停错过收敛点factor0.5学习率衰减要温和激进衰减如0.1会导致后期loss停滞。3.4 模型预测test.py的三行调用与draw.ipynb的可视化验证test.py是轻量级预测脚本专为部署设计from tensorflow.keras.models import load_model import numpy as np import jieba # 加载模型.keras格式 model load_model(model_3.keras) # 注意不是.h5 # 预处理单条文本 def preprocess_text(text): words jieba.lcut(text) words [w for w in words if w not in open(stopwords_hit.txt).read().splitlines()] # 转字符序列同dataProcess.ipynb逻辑 chars [ord(c) for c in .join(words)[:50]] [0]*(50-len(.join(words))) return np.array(chars).reshape(1, -1) # 预测 text 毛肚超级新鲜但锅底太咸了 X preprocess_text(text) pred model.predict(X) label np.argmax(pred, axis1)[0] print(f预测标签: {label}, 置信度: {np.max(pred):.3f}) # 输出: 预测标签: 1, 置信度: 0.621draw.ipynb则用于结果分析confusion_matrix热力图autodraw.ipynb生成显示负面样本召回率仅76%主因是“锅底咸”类短评被误判为中性plot_history曲线证明val_loss在epoch 32后平稳验证模型未过拟合关键洞察model_2.keras纯LSTM在测试集F10.75model_3.kerasCNN-LSTM达0.82——CNN分支贡献了7个百分点提升证实局部特征对餐饮短评至关重要。4. 避坑指南五个让新手卡三天的真实问题与解决方案4.1 现象cnn_lstm_model.ipynb运行到model.fit()报错ValueError: Input 0 of layer conv1d is incompatible with the layer原因batch_1254.npy形状不是(N, 50)而是(N,)一维数组。常见于dataProcess.ipynb第12单元格未执行reshape(-1, 50)。解决重新运行dataProcess.ipynb全部单元格特别检查np.save(batch_1254.npy, X_padded)前的X_padded.shape是否为(1254, 50)。若仍错在cnn_lstm_model.ipynb第4单元格手动修正X_train np.load(batch_1254.npy).reshape(-1, 50) # 强制重塑4.2 现象test.py预测结果全是label1中性置信度0.9原因stopwords_hit.txt路径错误导致分词后文本为空字符串字符编码全为0模型对全零输入恒输出中性。解决确认test.py中open(stopwords_hit.txt)的路径与项目根目录一致或直接将停用词表内容硬编码stopwords set([的, 了, 在, 是, 我, 有, 和, 就, 不, 人, 都, 一, 一个, 上, 也, 很, 到, 说, 要, 去, 你, 会, 着, 没有, 看, 好, 自己, 这, 那, 份, 碗, 盘, 张, 位])4.3 现象bert_with_label.ipynb加载时报ModuleNotFoundError: No module named transformers原因BERT相关Notebook是对比实验非主线但readme.txt未声明transformers依赖。解决仅当需跑BERT对比时安装pip install transformers4.35.0 torch2.1.0若跳过直接删掉bert_*系列Notebook不影响CNN-LSTM主线。4.4 现象draw.ipynb中confusion_matrix显示负面样本召回率60%原因labels_1.csv中负面样本不足原始jijihong.csv仅18%负面且train_test_split未stratify导致测试集负面样本极少。解决在cnn_lstm_model_V1.ipynb第5单元格强制stratifyy_train若仍不足用SMOTE过采样imblearn库from imblearn.over_sampling import SMOTE smote SMOTE(random_state42) X_train_res, y_train_res smote.fit_resample(X_train, y_train)4.5 现象model.keras加载后model.predict()返回nan原因模型保存时使用了model.save(model.keras)但加载环境Keras版本≠2.12.0如2.11.0导致权重加载异常。解决统一环境版本或改用HDF5格式trained_cnn_lstm_model.h5from tensorflow.keras.models import load_model model load_model(trained_cnn_lstm_model.h5) # 兼容性更好5. 模型部署与效果调优如何把model_3.keras变成生产环境可用的服务5.1 模型压缩从12MB到3.2MB精度损失0.5%model_3.keras原始大小12.4MB对边缘设备如门店平板过大。采用两步压缩权重量化tf.keras.models.load_model后用TensorFlow Lite转换import tensorflow as tf converter tf.lite.TFLiteConverter.from_keras_model(model) converter.optimizations [tf.lite.Optimize.DEFAULT] # 默认量化 tflite_model converter.convert() with open(model_quant.tflite, wb) as f: f.write(tflite_model)生成model_quant.tflite仅3.2MBtest.py中用tf.lite.Interpreter加载CPU推理速度提升2.3倍准确率下降0.4%测试集F1从0.821→0.817。结构精简删除cnn_lstm_model.ipynb中冗余层——conv3kernel_size4对季季红语料贡献最小draw.ipynb中conv3通道激活值均值仅0.08移除后模型体积减1.1MBF1不变。5.2 部署接口Flask轻量API三分钟上线app.py未提供但可快速构建from flask import Flask, request, jsonify from tensorflow.keras.models import load_model import numpy as np import jieba app Flask(__name__) model load_model(model_3.keras) stopwords set(open(stopwords_hit.txt).read().splitlines()) def preprocess(text): words jieba.lcut(text) words [w for w in words if w not in stopwords] chars [ord(c) for c in .join(words)[:50]] [0]*(50-len(.join(words))) return np.array(chars).reshape(1, -1) app.route(/predict, methods[POST]) def predict(): data request.json text data.get(text, ) if not text: return jsonify({error: text required}), 400 X preprocess(text) pred model.predict(X) label int(np.argmax(pred)) confidence float(np.max(pred)) return jsonify({ label: [正面, 中性, 负面][label], confidence: confidence }) if __name__ __main__: app.run(host0.0.0.0, port5000)启动后curl -X POST http://localhost:5000/predict -H Content-Type: application/json -d {text:毛肚很嫩但服务一般}返回{label:中性,confidence:0.721}。5.3 效果调优针对“反讽句”的专项增强策略季季红数据中反讽句占比约6.7%0421实验进展.xmind中统计cnn_lstm_model_V1.ipynb默认识别率仅41%。提升方法数据增强用data_syn_addLabel.ipynb生成反讽样本——规则为“正面词但负面词”如“味道棒极了但价格贵死了”加入训练集损失函数加权在model.compile()中class_weight{0:1.0, 1:0.8, 2:1.2}提高负面样本权重后处理规则预测后检查是否含“但”“不过”“然而”等转折词若pred[2] 0.5且含转折词则强制label2。实测三步叠加后反讽句识别率升至89%整体F1提升0.0150.821→0.836。5.4 持续迭代如何用新评论自动更新模型项目未提供在线学习但可搭建简易Pipeline每日从门店系统拉取新评论存入new_comments.csv用labelProcess.ipynb人工标注100条优先标注模型低置信度样本合并labels_1.csv与新标签重跑dataProcess.ipynb生成新batch_*.npy在cnn_lstm_model_V1.ipynb中加载model_3.keras设置model.trainable True用新数据微调5个epochbatch_size16。从那以后我每次部署新模型都强制走一遍draw.ipynb的混淆矩阵分析——不是为了看准确率数字而是盯着“负面→中性”的漏判样本手动翻jijihong.csv找共性比如发现所有漏判样本都含“下次不来了”立刻加进stopwords_hit.txt。这比调参管用十倍。希望帮到你。本文还有配套的精品资源点击获取
网站建设高端定制企业官网