news 2026/9/24 18:59:24

Flask+深度学习中文情感分析系统实战:从模型推理到Web部署

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Flask+深度学习中文情感分析系统实战:从模型推理到Web部署

简介:本资源为基于Python与深度学习的中文情感分析系统毕业设计完整资料包,面向计算机相关专业需要完成毕业设计的学生及希望学习Flask Web开发与文本分类的开发者。系统采用Flask框架搭配MySQL数据库,实现用户注册登录、后台数据统计首页以及文本情感分析等核心模块,可将输入文本自动判别为正面或负面评价,并借助柱状图、饼图进行多维度数据汇总展示。压缩包共378个文件,涵盖20个py源码、12个html模板、18个css样式、52个js脚本,以及深度学习模型相关的npy、pkl、pb权重文件,另附sql建库脚本、docx说明文档、pptx演示文稿与mp4演示视频,整体约97.54MB。目前已有217人学习下载,适合作为毕业设计参考模板,帮助读者快速理解情感分析系统的整体架构、前后端交互流程与模型调用方式,并在此基础上进行二次开发与功能扩展。

1. 从一份 Flask 情感分析系统源码说起:它到底能跑出什么结果

很多同学做毕业设计时,最头疼的不是写不出代码,而是拼不出一套能演示、能答辩、能交差的完整系统。这份基于 Python 深度学习的中文情感分析系统,用 Flask 做 Web 层、MySQL 存数据、深度学习模型做文本分类,把登录注册、后台首页、文本分析、数据可视化串成了一条完整链路。它适合正在做计算机毕业设计、软件工程毕业设计,或者想找一个 Flask 开发实战项目练手的人。你拿到手后,能直接看到一条中文评论从输入框进去、经过模型推理、最后吐出正面或负面标签的全过程,而不是只对着一个孤零零的模型脚本发呆。这套东西的价值在于:它把深度学习模型和 Web 系统之间的那层胶水代码写清楚了,而这恰恰是很多教程里缺失的部分。

2. 拆开这套 Flask 情感分析系统:模型、后端、前端怎么串起来

2.1 深度学习模型在系统里扮演什么角色

中文情感分析的核心任务,是判断一段文本的情绪倾向。常见做法有两种:一种是传统机器学习模型,比如用 TF-IDF 加朴素贝叶斯或 SVM;另一种是深度学习模型,比如 TextCNN、BiLSTM 或者 BERT 微调。这份资源走的是深度学习路线,模型部分大概率是一个 TextCNN 或 LSTM 结构,因为这类模型在中文短文本分类上表现稳定,训练成本也比 BERT 低得多,适合毕业设计这种算力有限、时间有限的场景。

模型在系统里的位置很明确:它不直接面对用户,而是被 Flask 后端封装成一个推理接口。用户在前端文本框里输入一段中文,比如“这家店的服务态度太差了”,Flask 收到请求后,先做分词和序列填充,再把处理好的张量喂给模型,模型输出一个概率值,最后后端根据阈值判定是正面还是负面,把结果返回给前端渲染。

这里有个关键点:模型文件通常是离线训练好之后保存成.h5.pth格式,Flask 启动时加载到内存里,而不是每次请求都重新训练。我一般会在 Flask 应用初始化时用model.load_weights()把权重读进来,避免请求时反复 IO 导致响应慢。

2.2 Flask 后端如何组织推理接口

Flask 在这套系统里承担的是调度中心的角色。它要处理用户登录态、接收文本、调用模型、写数据库、返回 JSON。下面是一个典型的推理接口写法,你可以直接抄到自己项目里改:

from flask import Flask, request, jsonify import jieba import numpy as np from tensorflow.keras.models import load_model from tensorflow.keras.preprocessing.sequence import pad_sequences app = Flask(__name__) # 启动时加载模型和分词器,避免每次请求重复加载 model = load_model('sentiment_model.h5') tokenizer = ... # 从 pickle 加载训练时保存的 tokenizer MAX_LEN = 100 # 与训练时保持一致 @app.route('/api/predict', methods=['POST']) def predict(): data = request.get_json() text = data.get('text', '').strip() if not text: return jsonify({'error': '文本不能为空'}), 400 # 中文分词,用空格拼接成模型能吃的格式 words = jieba.lcut(text) seq = tokenizer.texts_to_sequences([' '.join(words)]) padded = pad_sequences(seq, maxlen=MAX_LEN, padding='post', truncating='post') # 模型输出概率,0 到 1 之间 prob = model.predict(padded)[0][0] label = '正面' if prob > 0.5 else '负面' return jsonify({ 'text': text, 'label': label, 'confidence': float(prob) }) if __name__ == '__main__': app.run(debug=True, host='0.0.0.0', port=5000)

这段代码的逻辑说明:jieba.lcut做中文分词,因为训练时用的也是分词后的文本,推理时必须保持一致,否则模型看到的输入分布和训练时不一样,准确率会掉得厉害。pad_sequences把变长序列补齐到固定长度,padding='post'表示在末尾补零,truncating='post'表示超长时从末尾截断。model.predict返回的是 sigmoid 输出的概率值,大于 0.5 判正面,小于等于 0.5 判负面。

参数方面,MAX_LEN必须和训练时一致,常见取值是 100 或 200。如果你的文本普遍较长,可以调到 300,但要注意模型输入维度也得跟着改。port=5000是 Flask 默认端口,部署到服务器时记得改成 80 或 443,或者用 Nginx 做反向代理。

2.3 数据库表结构和登录注册逻辑

MySQL 在这套系统里存两类数据:用户信息和历史分析记录。用户表一般包含idusernamepassword_hashphonecreate_time这几个字段。密码不能明文存,常见做法是用werkzeug.security里的generate_password_hashcheck_password_hash做哈希和校验。

历史记录表用来存每次分析的文本、预测标签、置信度和时间戳,方便后台首页做统计图表。下面是一个建表 SQL:

CREATE TABLE user ( id INT AUTO_INCREMENT PRIMARY KEY, username VARCHAR(50) NOT NULL UNIQUE, password_hash VARCHAR(255) NOT NULL, phone VARCHAR(20), create_time DATETIME DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE analysis_record ( id INT AUTO_INCREMENT PRIMARY KEY, user_id INT, input_text TEXT, predict_label VARCHAR(10), confidence FLOAT, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (user_id) REFERENCES user(id) );

登录注册的逻辑用 Flask 的 session 或 JWT 都能做。session 更简单,适合毕业设计这种单机部署场景。注册时校验用户名是否已存在、手机号格式是否正确、两次密码是否一致;登录时用check_password_hash比对哈希值,成功则把user_id写进 session。

后台首页的柱状图和饼图,数据来源就是analysis_record表。常见做法是用GROUP BY predict_label统计正面和负面的数量,再用 ECharts 或 Chart.js 在前端渲染。这里有个容易翻车的地方:如果记录表数据量很大,每次刷新首页都全表扫描会很慢,我一般会加一个create_time索引,并且只查最近 30 天的数据。

3. 把系统跑起来:环境配置、模型加载和前后端联调

3.1 Python 环境与依赖安装的版本坑

这套系统依赖 TensorFlow 或 PyTorch、Flask、jieba、MySQL 驱动等库。Python 版本建议用 3.8 到 3.10,太新的版本可能和 TensorFlow 某些版本不兼容。我见过太多人卡在pip install tensorflow这一步,要么是网络问题,要么是版本冲突。

常见做法是先用 conda 建一个干净环境:

conda create -n sentiment python=3.9 conda activate sentiment pip install flask tensorflow jieba pymysql werkzeug

如果你用的是 PyTorch 版本的模型,把tensorflow换成torch就行。注意 TensorFlow 2.x 和 1.x 的 API 差异很大,load_model的行为也不一样。这份资源如果用的是 2.x,那model.predict返回的是 numpy 数组;如果是 1.x,可能需要用sessiongraph,写法完全不同。拿到源码后先看requirements.txt或者模型保存时的版本注释,别上来就装最新版。

MySQL 驱动推荐用pymysql,因为它纯 Python 实现,不需要编译,安装成功率高。连接数据库时记得指定charset='utf8mb4',否则中文会乱码。

3.2 模型文件加载与推理性能调优

模型加载是 Flask 启动阶段最耗时的操作。如果模型文件有几百 MB,每次flask run都要等十几秒。我一般会把模型加载放在if __name__ == '__main__'之前,确保只加载一次。如果用的是 gunicorn 多 worker 部署,每个 worker 都会加载一份模型,内存占用会翻倍,这时候要么减少 worker 数量,要么把模型推理拆成独立的服务。

推理性能方面,单条文本预测通常在几十毫秒到几百毫秒之间,取决于模型复杂度和 CPU 性能。如果并发量不大,Flask 自带的开发服务器够用;如果要演示给老师看,建议用gunicorn -w 2 -b 0.0.0.0:5000 app:app启动,稳定性比flask run好很多。

还有一个细节:model.predict默认会做 batch 推理,如果你一次只传一条数据,可以改成model(tf.constant(padded))直接调用,省掉一些开销。不过这个优化对毕业设计来说不是必须的,知道有这么回事就行。

3.3 前后端联调时最容易断的链路

前后端联调阶段,最常见的问题是跨域和请求格式不对。Flask 默认不开启 CORS,如果前端是单独跑的 Vue 或 React 项目,浏览器会报跨域错误。解决办法是装flask-cors

from flask_cors import CORS CORS(app)

如果前端就是 Flask 模板渲染的 HTML,那不存在跨域问题,直接用fetchaxios请求同源接口就行。

另一个坑是请求体格式。前端如果发的是application/x-www-form-urlencoded,后端用request.get_json()会拿到None。要么前端改成JSON.stringifyContent-Type: application/json,要么后端用request.form.get('text')取值。我一般统一用 JSON,因为结构清晰,调试也方便。

数据库连接方面,Flask 里不要每次请求都新建连接,用连接池或者flask-sqlalchemy管理会话。如果直接用pymysql,记得在请求结束时关闭游标和连接,否则并发一上来就会报Too many connections

4. 避坑指南:这套系统跑不起来时先查这五个地方

4.1 模型加载报错:版本不匹配或文件损坏

现象:Flask 启动时报OSError: Unable to open fileValueError: Unknown layer

原因:模型保存时的 TensorFlow 版本和当前环境不一致,或者.h5文件在传输过程中损坏。

解决:先确认requirements.txt里的版本号,用pip install tensorflow==2.x.x装对应版本。如果是自定义层导致Unknown layer,需要在加载时用custom_objects参数把自定义层传进去。文件损坏的话,重新解压资源包,比对文件大小是否一致。

4.2 中文乱码:数据库字符集没设对

现象:存入数据库的中文变成???或者乱码,前端显示也异常。

原因:MySQL 建库时用了latin1字符集,或者连接字符串没指定utf8mb4

解决:建库时执行CREATE DATABASE sentiment DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;,连接时用pymysql.connect(..., charset='utf8mb4')。已经建好的表可以用ALTER TABLE analysis_record CONVERT TO CHARACTER SET utf8mb4;修复。

4.3 分词结果与训练不一致导致准确率暴跌

现象:模型在测试集上准确率 90%,但系统里实际用的时候感觉像随机猜。

原因:训练时用的分词工具或分词模式与推理时不一致。比如训练用了jieba.lcut,推理用了jieba.cut,或者训练时没去停用词,推理时去了。

解决:把训练时的预处理代码原封不动搬到推理流程里,包括分词、去停用词、大小写转换等。最好把预处理逻辑封装成一个函数,训练和推理共用同一份代码。

4.4 Flask 端口被占用或无法外部访问

现象:flask runAddress already in use,或者本机能访问但局域网内其他设备打不开。

原因:5000 端口被其他程序占用,或者 Flask 默认只监听127.0.0.1

解决:换端口用flask run --port 5001,或者启动时指定app.run(host='0.0.0.0', port=5000)。如果服务器有防火墙,还要放行对应端口。Windows 上可以用netstat -ano | findstr :5000找到占用进程并结束。

4.5 后台首页图表数据不更新

现象:分析了几条文本,但首页柱状图还是旧数据。

原因:前端图表数据是页面加载时一次性获取的,没有做轮询或手动刷新;或者后端查询语句有缓存。

解决:在图表容器上加一个刷新按钮,点击时重新请求/api/stats接口。后端查询时加ORDER BY create_time DESC LIMIT 100确保拿到最新记录。如果用了 Flask-Caching,记得设置较短的过期时间或者手动清缓存。

5. 进阶技巧:用混淆矩阵验证模型真实水平,别只看准确率

很多人拿到这套系统后,跑通就完事了,答辩时被问到“模型到底靠不靠谱”就支支吾吾。我一般会强制自己做一件事:在测试集上跑一遍混淆矩阵,看看正面和负面到底有没有被均衡地识别出来。

假设你已经有了测试集和训练好的模型,下面这段代码可以直接用:

from sklearn.metrics import confusion_matrix, classification_report import seaborn as sns import matplotlib.pyplot as plt # X_test 是 padded 后的测试数据,y_test 是真实标签 y_pred_prob = model.predict(X_test) y_pred = (y_pred_prob > 0.5).astype(int).flatten() cm = confusion_matrix(y_test, y_pred) print(classification_report(y_test, y_pred, target_names=['负面', '正面'])) sns.heatmap(cm, annot=True, fmt='d', cmap='Blues', xticklabels=['负面', '正面'], yticklabels=['负面', '正面']) plt.xlabel('预测标签') plt.ylabel('真实标签') plt.title('混淆矩阵') plt.show()

逻辑说明:model.predict输出概率,用 0.5 做阈值切成 0 和 1。confusion_matrix返回一个 2x2 矩阵,对角线是分对的,非对角线是分错的。classification_report会给出精确率、召回率和 F1 值。如果负面样本的召回率特别低,说明模型倾向于把负面判成正面,这时候要么调整阈值,要么检查训练数据是否正负样本不均衡。

参数方面,阈值 0.5 不是固定的。如果业务上更怕漏掉负面评价,可以把阈值降到 0.4,让更多样本被判为负面。但这样会牺牲精确率,具体怎么调要看你的场景。我一般会画一条 P-R 曲线,找到 F1 最高的那个阈值点。

还有一个习惯:每次改完模型结构或预处理逻辑,都重新跑一遍混淆矩阵,和上一次的结果对比。如果 F1 掉了超过 2 个百分点,就说明改动有问题,得回滚。这个习惯帮我省了很多次“以为优化了其实退步了”的尴尬。

从那以后我每次交付类似系统前,都强制走一遍混淆矩阵加分类报告,不看一眼不放心。希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/24 18:59:22

Codewhale Web 客户端完整教程:把终端 Agent 搬进浏览器

Codewhale Web 客户端完整教程:把终端 Agent 搬进浏览器 【免费下载链接】Codewhale Open-source coding agent for your terminal, built in Rust and on a journey of continuous community improvement. Issues and PRs welcome. 项目地址: https://gitcode.co…

作者头像 李华
网站建设 2026/9/24 18:58:47

从Navicat迁移到DBX:轻量级多数据库客户端的实战体验

1. 从"启动五分钟"说起:我为什么开始找 Navicat 的替代品如果你日常和数据库打交道,大概率电脑里都躺着一个 Navicat。它确实是这个领域的老牌选手,功能全、界面熟、教程多,很多人从学生时代做课程设计就开始用它连 MyS…

作者头像 李华
网站建设 2026/9/24 18:58:42

InTouch HMI为何成为工业现场的确定性基石

1. 为什么工业现场还在用InTouch HMI?——从“能用”到“必须用”的底层逻辑AVEVA InTouch HMI不是一款普通意义上的组态软件,它是工业自动化系统中少数几个真正把“人机交互的确定性”刻进基因里的产品。我第一次在某汽车焊装车间调试产线时&#xff0c…

作者头像 李华
网站建设 2026/9/24 18:58:39

从bit到TB:网速与硬盘容量为何总对不上?一文搞懂单位换算

你有没有遇到过这种情况:刚办了 1000M 宽带,结果测速软件里死活只显示 120MB/s;新买一块 1TB 移动硬盘,插上电脑却只剩 931GB;把标称 64GB 的存储卡塞进行车记录仪,格式化完发现可用空间只有 58GB。每次都觉…

作者头像 李华
网站建设 2026/9/24 18:58:14

InTouch HMI工业可视化原理与可靠性工程实践

1. 为什么工业现场还在用 InTouch?不是它多先进,而是它把“可靠”二字刻进了骨头里AVEVA InTouch HMI 这个名字,在国内工控圈子里,老工程师听到会下意识摸摸口袋里的U盘——里面大概率存着十年前某个电厂DCS改造项目的工程备份。它…

作者头像 李华
网站建设 2026/9/24 18:57:48

Linux目录流API实战:从opendir到目录遍历的高效实现

刚接触Linux系统编程的人,通常都会经历这么一道坎:文件I/O已经用得很熟了,open、read、write、lseek各种调,但一碰到目录就有点懵。好像目录也能打开,但打开之后读出来的东西和普通文件完全不一样;想遍历一…

作者头像 李华