尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

电影评论情感分析实战:从TextCNN训练到Flask服务部署

电影评论情感分析实战:从TextCNN训练到Flask服务部署 简介这是一份基于Python深度学习的电影评论情感分析系统设计与实现毕业设计文档适合计算机类专业学生、毕业设计开发者以及情感分析方向入门者使用。内容围绕flask框架与word2vec向量模型展开系统介绍了从影评文本采集、情感特征提取到正负评论比例统计的完整过程并阐述了深度学习应用于电影评论分析的现实意义。文档以docx格式呈现共1个文件压缩包大小约1.34MB内含中英文摘要、目录及正文内容结构完整便于直接查阅和参考。目前这份文档已有466人学习浏览属于较受关注的毕业设计参考资料。通过阅读可以了解深度学习情感分析系统的整体设计思路掌握flask与word2vec在文本情感分类任务中的结合方式节省自行梳理文献与代码架构的时间适合用于开题参考、论文框架搭建或项目开发前期的快速入门。1. 电影评论情感分析从“能跑通”到“能交付”很多人一开始冲着“深度学习”三个字来以为要搭一个高大上的模型结果做出来只是个文本二分类。实际做电影评论情感分析目标很清楚给一条短文本判断它是正面还是负面再带一个置信度。难点不在模型结构而在数据清洗、标签处理、训练参数和系统封装这一整套链路。这套方案适合做毕业设计、比赛 demo、以及想快速上线的内部工具。下面按我的实践顺序把从数据准备到系统部署的路走一遍。2. 选型与数据准备为什么是 Python 深度学习而不是词典和机器学习2.1 情感分析主流方案对比先放下深度学习说说选型。常见的文本情感分析有三条路词典法基于情感词典比如 SentiWordNet、中文的知网 HowNet查词打分。优点是无标注数据速度快缺点是严重依赖词典覆盖遇到“这也太好看了吧”这种反讽直接翻车准确率通常在 70% 以下而且跨领域泛化差。传统机器学习TF-IDF / Bag-of-Words SVM / 朴素贝叶斯。效果比词典好但特征稀疏、丢失语序信息。“不像之前那部那么烂”这种否定结构它基本分不出。深度学习通过嵌入层把词映射成稠密向量再用卷积或循环网络捕捉局部和序列特征。比前两种更擅长处理“画面美到哭”这类歧义表达。在电影评论这种短文本上TextCNN 这种轻量级模型十轮内就能达到 86-91% 的准确率训练时间和资源都友好。对系统设计而言深度学习的收益还在于“端到端”不需要手工设计特征从原始文本到标签只要喂分词后的句子即可。而且 Python 生态里PyTorch/Keras 加上 Flask一套代码直接把模型变成 HTTP 服务省掉很多胶水代码。这也是我倾向用 Python 做整条链路的原因。2.2 数据集获取与预处理常见做法是直接下载已有的公开评论数据集避免爬虫封禁和标签噪声。做中文系统优先找标注好的豆瓣或 IMDb 中文翻译集做英文用 IMDb 50K 影评原始集。如果非要爬热门新上映影片要考虑到短评里大量网络用语清洗成本很高。我的建议是第一版先用标准数据集把流程跑通再决定要不要再加自定义数据。拿到数据后第一步不是训练而是清洗。电影评论里常见干扰有HTML 标签、URL、空白、重复标点、表情符号、中英文混杂。下面这段预处理脚本处理这些import re import pandas as pd def clean_text(text: str) - str: # 去除HTML标签 text re.sub(r[^], , text) # 去除URL text re.sub(rhttps?://\S|www\.\S, , text) # 去除连续标点和特殊符号保留中文/英文/数字/基本标点 text re.sub(r[^\u4e00-\u9fa5a-zA-Z0-9。、\s], , text) # 合并空白 text re.sub(r\s, , text.strip()) return text def preprocess_csv(csv_path: str, output_path: str) - pd.DataFrame: df pd.read_csv(csv_path) df[text] df[text].astype(str).apply(clean_text) # 过滤空文本 df df[df[text].notna() (df[text].str.len() 2)] # 标签映射假设原始列label为1/0 df[label] df[label].map({pos: 1, neg: 0}) df.to_csv(output_path, indexFalse, encodingutf-8) return df逻辑说明clean_text 里三个 re.sub 分别是去 HTML、去 URL、去非中英文数字和常见标点。最后一步把所有空白去掉对中文评论是合理的因为中文本身不需要词间空格如果是英文就不要执行这一步否则会把词组粘在一起。label 映射成 0/1后面模型输出才干净。参数说明保留的标点集合可以根据场景调整。比如“哈哈哈哈哈”本身是情感信号去掉后损失信息但如果你先做分词再训练语气词会被单独切出来影响不大。过滤条件 len 2 是为了去掉“好”“烂”这类单字噪声它们太短模型学不到上下文。2.3 中文分词与词表构建中文不像英文有天然空格深度学习模型需要先分词。常用工具有 jieba、HanLP、LTP。系统设计里我选 jieba因为它是纯 Python 依赖安装简单在服务器上没有额外的 C 编译烦恼。分词之后把每个词映射成 ID并统一序列长度。import jieba from collections import Counter import numpy as np def tokenize_and_build_vocab(df, vocab_size20000, min_count2): # 逐条分词 df[tokens] df[text].apply(lambda x: list(jieba.cut(x))) # 统计词频 freq Counter() for tokens in df[tokens]: freq.update(tokens) # 过滤低频词预留0padding, 1unk vocab {pad: 0, unk: 1} for word, count in freq.most_common(): if count min_count and len(vocab) vocab_size: vocab[word] len(vocab) return df, vocab def encode_sequences(df, vocab, max_len256): def encode(tokens): ids [vocab.get(w, 1) for w in tokens[:max_len]] ids ids [0] * (max_len - len(ids)) # padding到固定长度 return ids df[input_ids] df[tokens].apply(encode) return df逻辑说明第一步对每一条评论切词得到 tokens 列表。第二步统计词频按频率从高到低填词表min_count2 表示出现次数少于 2 次的词直接丢进 避免词表过大和过拟合。第三步把词转成 ID超过 max_len 直接截断不够则补 0。参数说明vocab_size 不要太小。20000 对电影评论足够了很多数据集的去重词也就五六万2 万保留的是常用词。如果后续要接预训练词向量词表大小最好和预训练词表对齐。max_len 设 256 是基于统计多数影评短评平均 30-50 字长评最多也就一两百字。设太大会浪费计算资源设太小会截断重要信息。我的经验是先统计 tokens 长度的 95 分位数再把它作为 max_len。这里多说一句分词后的句子顺序对 TextCNN 和 BiLSTM 非常关键。不要对序列做随机排序也不要打乱 tokens 的先后关系。很多新手把整个文本 set 后再喂模型等于把语序信息抹掉了准确率直接掉了五个点。3. 模型搭建与训练TextCNN 和 BiLSTM 怎么选3.1 两种模型结构的取舍电影评论情感分析是一个短文本分类任务候选模型很多。我重点说两个TextCNN 和 BiLSTM Attention。TextCNN 的核心是用多个不同大小的卷积核在嵌入序列上滑动提取 n-gram 特征。它很轻训练快在句子长度 100-200 的场景下效果出色。BiLSTM 则通过两个方向的循环网络捕捉长距离依赖再配合注意力机制加权关键位置。理论上限更高但参数量大收敛慢对小数据容易过拟合。实际选型我一般用这条经验数据量在 10 万条以内优先 TextCNN超过 50 万条或者句子平均长度超过 300上 BiLSTM。做过对比实验的都知道TextCNN 在短影评上的效果并不输给复杂模型而训练时间只有后者的三分之一。系统设计要控制交付周期我选择 TextCNN 作为基线然后可以留一个切换开关给 BiLSTM。3.2 TextCNN 模型定义PyTorch下面是一个可以直接用的 TextCNN 实现我习惯把超参集中到一个配置类里。import torch import torch.nn as nn import torch.nn.functional as F class TextCNN(nn.Module): def __init__(self, vocab_size, embedding_dim128, num_filters256, kernel_sizes(3,4,5), dropout0.5, num_classes2, max_len256): super().__init__() self.embedding nn.Embedding(vocab_size, embedding_dim, padding_idx0) # 多尺寸卷积分别提取trigram、4-gram、5-gram特征 self.convs nn.ModuleList([ nn.Conv1d(in_channelsembedding_dim, out_channelsnum_filters, kernel_sizek, paddingk//2) for k in kernel_sizes ]) self.dropout nn.Dropout(dropout) self.fc nn.Linear(len(kernel_sizes) * num_filters, num_classes) def forward(self, x): # x: [batch, max_len] emb self.embedding(x) # [batch, max_len, embed_dim] emb emb.transpose(1, 2) # [batch, embed_dim, max_len] conv_out [] for conv in self.convs: c conv(emb) # [batch, num_filters, max_len] c F.relu(c) # 全局最大池化提取每个特征图的最强响应 c F.max_pool1d(c, c.size(2)).squeeze(2) # [batch, num_filters] conv_out.append(c) out torch.cat(conv_out, dim1) # [batch, num_filters * 3] out self.dropout(out) logits self.fc(out) # [batch, num_classes] return logits逻辑说明nn.Embedding 的 padding_idx0 让填充位置不参与梯度更新避免补零干扰特征提取。nn.Conv1d 的 paddingk//2 是保持序列长度不变这样最大池化可以直接在时间维度操作不需要额外的长度计算。三个卷积核大小设为 3/4/5分别对应连续 3 个词、4 个词、5 个词的局部窗口特征。对于“电影节奏缓缓推进但结局用力过猛”这种评价3-gram 能抓住“节奏缓缓”5-gram 能抓住“结局用力过猛”。全局最大池化在每个特征图上取最大值相当于只保留“最像情感信号”的窗口响应。参数说明embedding_dim 我取 128而不是传统的 300。原因是用随机初始化的 Embedding 时维度超过 128 对短文本分类的提升非常有限反而增加显存占用。如果后续要加载预训练词向量再改成 300。num_filters 设为 256是一个性价比比较高的值降到 128 准确率会掉 1-2 个点升到 512 训练时间翻倍但效果基本不变。dropout0.5 是 TextCNN 的标准配置训练时随机丢弃一半的特征可以有效抑制过拟合。如果发现训练集准确率高但验证集低优先调大这个值。3.3 训练循环与关键超参模型定好后训练循环里最值得写的是早停和学习率衰减。直接全量训练跑固定 epoch 很容易过拟合我一般用 EarlyStopping 并配合 ReduceLROnPlateau。def train_one_epoch(model, dataloader, optimizer, criterion, device): model.train() total_loss, total_acc 0, 0 for batch_x, batch_y in dataloader: batch_x, batch_y batch_x.to(device), batch_y.to(device) logits model(batch_x) loss criterion(logits, batch_y) optimizer.zero_grad() loss.backward() # 梯度裁剪防止RNN/深层CNN梯度爆炸 nn.utils.clip_grad_norm_(model.parameters(), max_norm3) optimizer.step() total_loss loss.item() total_acc ((logits.argmax(1) batch_y).float().mean()).item() return total_loss / len(dataloader), total_acc / len(dataloader) def evaluate(model, dataloader, criterion, device): model.eval() total_loss, total_acc 0, 0 with torch.no_grad(): for batch_x, batch_y in dataloader: batch_x, batch_y batch_x.to(device), batch_y.to(device) logits model(batch_x) loss criterion(logits, batch_y) total_loss loss.item() total_acc ((logits.argmax(1) batch_y).float().mean()).item() return total_loss / len(dataloader), total_acc / len(dataloader)逻辑说明train_one_epoch 里每个 batch 前先做一次 optimizer.zero_grad()防止梯度累积。损失用 nn.CrossEntropyLoss()它是 LogSoftmax NLLLoss 的合并内部做了数值稳定处理不需要在模型输出上再套 softmax。clip_grad_norm_ 是给梯度设置范数上限设成 3.0在 TextCNN 里可以防个别样本把 embedding 层的梯度拉爆。注意evaluate 函数只算损失和准确率不反传梯度所以用 torch.no_grad() 包住并且记得 model.eval()。这里的 model.eval() 会关闭 dropout 和 BatchNorm 的统计更新如果漏掉验证集结果会偏大或偏小。主循环里的早停逻辑可以是你自己写也可以用 PyTorch 原生的我直接贴一段常见写法best_val_acc 0 patience 3 bad_epoch 0 for epoch in range(epochs): train_loss, train_acc train_one_epoch(model, train_loader, optimizer, criterion, device) val_loss, val_acc evaluate(model, val_loader, criterion, device) print(fepoch {epoch1}: train_loss{train_loss:.4f}, val_loss{val_loss:.4f}, val_acc{val_acc:.4f}) if val_acc best_val_acc: best_val_acc val_acc torch.save(model.state_dict(), best_model.pt) bad_epoch 0 else: bad_epoch 1 if bad_epoch patience: print(early stop at epoch, epoch1) break关键参数说明epochs 不要直接设 50。TextCNN 在影评数据上通常 7-10 轮就收敛再多只会过拟合。我一般设 20 轮配合早停一般停在 8-10 轮。batch_size 我用 64。显存只有 4G 建议减到 3216G 以上可以用 128训练更快但效果差异不大。learning_rate 推荐 1e-3用 Adam。不要一上来就是 1e-4收敛太慢也不要 3e-3容易震荡。还有一个技巧训练前对类别做加权。电影评论数据集有时正样本多比如 7000 正 3000 负模型会倾向于预测正类。criterion nn.CrossEntropyLoss(weighttorch.tensor([1.2, 1.0])) 可以缓解这种偏差。衡量模型好坏的指标别只看准确率情感分析中 F1 更重要。尤其是数据集本身正负不平衡时准确率可能虚高。每次训练完都会打印分类报告sklearn.metrics.classification_report(pre, y_true)看正负类的 precision、recall 和 f1。3.4 可视化训练曲线训练过程中如果发现验证损失先降后升、准确率上不去这不是写轮次代码能看到的。我在每个 epoch 后把训练和验证的 loss、acc 存到 history.csv最后用 matplotlib 画曲线import matplotlib.pyplot as plt history pd.read_csv(history.csv) plt.plot(history[epoch], history[train_loss], labeltrain_loss) plt.plot(history[epoch], history[val_loss], labelval_loss) plt.legend() plt.show()这一小段代码能帮你在五分钟内判断是否欠拟合如果训练和验证 loss 都居高不下说明模型容量不足或者词表太小如果训练 loss 很低而验证 loss 一路往上说明已经过拟合应该提前停止或加大 dropout。曲线比一堆数字更直观。4. 系统实现把模型封装成可供前端调的 Web 服务4.1 Flask API 接口设计训练好的模型只是 .pt 文件必须配合词表和预处理逻辑才能服务。我一般用 Flask 写一个极简接口只暴露两个端点/predict 做单条预测/batch_predict 做批量预测。from flask import Flask, request, jsonify import torch import jieba from model import TextCNN # 前面定义的模型类 app Flask(__name__) # 加载词表 import json with open(vocab.json, r, encodingutf-8) as f: vocab json.load(f) # 加载模型 device torch.device(cuda if torch.cuda.is_available() else cpu) model TextCNN(vocab_sizelen(vocab), embedding_dim128, num_filters256) model.load_state_dict(torch.load(best_model.pt, map_locationdevice)) model.to(device) model.eval() MAX_LEN 256 def text_to_ids(text): text clean_text(text) # 复用前面的清洗函数 tokens list(jieba.cut(text)) ids [vocab.get(w, 1) for w in tokens[:MAX_LEN]] ids ids [0] * (MAX_LEN - len(ids)) return ids app.route(/predict, methods[POST]) def predict(): data request.get_json() text data.get(text, ) if not text: return jsonify({error: empty text}), 400 ids text_to_ids(text) with torch.no_grad(): logits model(torch.tensor([ids], devicedevice)) pred int(logits.argmax(1)[0]) prob torch.softmax(logits, dim1)[0].tolist() return jsonify({label: positive if pred 1 else negative, probability: prob, confidence: round(max(prob), 4)})逻辑说明接口里最重要的一点是在服务启动时就要把词表、模型、jieba 全部加载到内存不要在请求处理函数里反复 load_state_dict否则并发一上来就卡死。model.eval() 也是必须的不然 dropout 在预测时仍然随机生效同一个输入会得到不同的结果。text_to_ids 和训练时的处理保持一致先 clean_text再 jieba.cut再截断补零。很多系统上线后效果崩就是因为预测时的预处理和训练时不统一比如训练时去了 URL、上线时没去或者训练时没去标点、上线时去了导致同一句话被分进不同的语义空间。参数说明MAX_LEN256 要和训练时完全一致。如果训练时用 max_len200这里写 256输入序列会多出 56 个 padding模型能接受但白白增加计算量如果训练时 256这里写 128长影评被截断破坏语义。confidence 返回的是 softmax 概率最大值做前端展示时可以直接用。想要阈值可以针对负类概率做二次校准比如置信度低于 0.6 时返回“不确定”。4.2 批量预测与缓存单条接口可以跑通 Demo但系统如果要处理离线语料或历史评论就需要批量接口。批量接口的关键是控制显存一次不要塞太多条否则 OOM。app.route(/batch_predict, methods[POST]) def batch_predict(): data request.get_json() texts data.get(texts, []) if not texts: return jsonify({error: empty list}), 400 batch_size data.get(batch_size, 32) results [] for i in range(0, len(texts), batch_size): batch_texts texts[i:ibatch_size] ids_list [text_to_ids(t) for t in batch_texts] with torch.no_grad(): logits model(torch.tensor(ids_list, devicedevice)) preds logits.argmax(1).tolist() probs torch.softmax(logits, dim1).cpu().tolist() for p, prob in zip(preds, probs): results.append({label: positive if p 1 else negative, confidence: round(max(prob), 4)}) return jsonify({result: results})逻辑说明分批处理的好处是可以在 batch_size 参数里做一个显存预算。输入 1000 条每批 32 条内存峰值是 32 条文本的 Tensor不会因为单条超长文本把显存撑爆。这个接口也方便做文件上传服务比如前端传一个 CSV后端逐批处理完再写回 CSV。实际部署时不要在 Flask 的默认开发服务器上跑。我用gunicorn -w 4 -b 0.0.0.0:5000 app:app起服务-w 4 表示 4 个 worker能利用多核 CPU。但要注意每个 worker 都会复制一份模型4 个 worker 就是 4 份模型内存对 2G 小内存机器压力大可以减到 2。4.3 完整的系统流程把数据、模型、服务串起来整体架构是这样的原始评论文件CSV/JSON - 清洗脚本 - 干净文本干净文本 - 分词 词表构造 - input_idsinput_ids - TextCNN 训练 - best_model.pt vocab.jsonFlask 加载模型 - HTTP 接口 - 前端或调用方得到情感标签这里有一个很容易忽略的点词表文件vocab.json和模型文件best_model.pt必须绑定。如果你重新训练了一版模型词表没更新或者词表更新了但模型没重训接口就会产生大量 因为词表和 embedding 矩阵是配套的。我习惯在保存模型时同时保存 vocab.json 和一份 config.json里面记 max_len、embedding_dim、num_filters 这些超参加载模型时先读 config 再重建网络避免人脑记忆出错。5. 避坑记录训练和部署中的四个高频事故5.1 标签不均衡导致模型全预测为负现象训练时 loss 在下降但验证集准确率只有 60% 左右看看混淆矩阵发现模型把所有样本都预测成多数类。原因影评评论集如果采集自打分 1-10 分你把 7 分以下归为负、7 分以上归为正粗略采样通常得到 70% 正样本。模型发现只要全部输出正类就能拿到 70% 准确率于是梯度方向一直偏向多数类少数类几乎没有被学习到。解决一是用 WeightedRandomSampler 或 CrossEntropyLoss(weight...) 给少数类加权重二是做五折分层交叉验证确保每折里正负比例一致。我常用前者只加一行代码class_weights torch.tensor([1.0, 1.8], devicedevice) criterion nn.CrossEntropyLoss(weightclass_weights)权重怎么定先统计负样本数 neg 和正样本数 pos把权重设为 (pos / neg) 的两倍以内。权重过大会导致训练震荡验证集反而下降。设置后要重新看混淆矩阵确保正负两类的 recall 都大于 80%。5.2 训练和预测的分词不一致现象线下评估 F10.90启动 Web 服务后随便抽几条评论预测效果明显变差而且同样一句话多次预测结果有时不同。原因这是典型的“逻辑泄漏”。训练时你先分词再输入而 Web 接口里要么忘了调用 clean_text要么 jieba.cut 的位置在 clean 之前导致 URL、标点被分进词表和训练时空特征不一致。多次预测结果不同还有一个隐藏问题Flask 多线程下没有锁定 jieba 的词库初始化首次调用时可能触发重复 build 词库。解决把预处理、分词、编码封装成一个类在init中预先运行一次 jieba.initialize()并写一个测试函数在服务启动时自动跑一遍import jieba jieba.initialize() def sanity_check(): sample 这部电影太棒了每一帧都是享受 ids text_to_ids(sample) assert len(ids) MAX_LEN assert model(torch.tensor([ids])).shape (1, 2)我在上线前都会跑这个检查如果 assert 不过一定是词表或 max_len 不一致立刻修正。5.3 显存不足CUDA OOM现象训练刚开始或训练到中途程序报 RuntimeError: CUDA out of memory。原因最常见的是 batch_size 设很大、序列长度长、卷积核数量多三者叠加把显存占满。TextCNN 本身不算吃显存但如果 num_filters512 且 batch_size256中间特征图会非常大。解决按优先级依次做三件事减少 batch_size 到 32 或 16减小 num_filters 到 128 或 256截断 max_len 到 128。不要一上来就去换小模型先动 batch_size 最简单。如果还要大 batch可以用梯度累积accumulation_steps 4 optimizer.zero_grad() for i, (batch_x, batch_y) in enumerate(dataloader): loss criterion(model(batch_x), batch_y) / accumulation_steps loss.backward() if (i 1) % accumulation_steps 0: optimizer.step() optimizer.zero_grad()这个技巧用 4 个小 batch 模拟大 batch梯度被平均后再更新效果与大 batch 基本一样但显存峰值只有原来的四分之一。5.4 模型加载慢且占内存现象Flask 服务启动要 3-5 秒多进程下内存占用翻了 N 倍小服务器直接重启。原因默认 PyTorch 加载 .pt 会把整个 tensor 拷贝进内存。而且你用 model.load_state_dict(torch.load(best_model.pt))torch.load 本身还会缓存一些中间量。如果用 CPU 部署map_locationcpu 是对的但 model.to(device) 后调用预测时每次仍会有微小开销。解决第一把模型转换成 TorchScript 后再部署。做法是traced_model torch.jit.trace(model, torch.randint(0, len(vocab), (1, MAX_LEN))) traced_model.save(model.pt)推理时加载 torch.jit.load(model.pt)比原始 state_dict 加载更快也省去保留模型类定义的必要部署环境可以不带训练代码。第二生产环境如果不要求高并发可以只开一个 worker配合队列处理避免内存翻倍。TorchScript 对 TextCNN 这种简单模型非常友好不会遇到控制流转换问题。如果是 BiLSTM 和注意力机制TorchScript 有时会报算子不支持那就退回 map_location 加载。6. 进阶用预训练语言模型提准确率的低成本路径前面我们用随机初始化的 Embedding 训练 TextCNN准确率大概能到 86-88%。如果想让系统再上一个台阶又不想投入太多工程改造最快的方式是把 Embedding 换成预训练 word2vec 或 GloVe而不是直接上 BERT。做法是在建好模型后把 embedding.weight 初始化为预训练向量。以 word2vec 的 .kv 文件为例from gensim.models import KeyedVectors def load_pretrained_embeddings(vocab, vector_path, embed_dim300): wv KeyedVectors.load_word2vec_format(vector_path, binaryFalse) emb torch.randn(len(vocab), embed_dim) * 0.1 matched 0 for word, idx in vocab.items(): if word in wv: emb[idx] torch.tensor(wv[word]) matched 1 print(fmatched {matched}/{len(vocab)}) return emb然后 model.embedding.weight.data.copy_(emb)并决定是否冻结。我一般先冻结 3 个 epoch 热启动再解冻微调准确率能再提升 1-2 个点。注意这里 embed_dim 必须和预训练向量维度一致之前的 TextCNN 定义里 embedding_dim 要改成 300。如果你的数据里网络用语太多词表里有大量词在预训练词表里找不到匹配率低于 60%那预训练帮助不大还不如随机初始化。如果连 word2vec 都嫌麻烦就用 transformers 加载一个轻量 BERT 模型比如 bert-base-chinese但显存要求高只微调最后的分类层。这通常需要 8G 以上显存但准确率可以轻松上 92%。不过从系统设计角度BERT 推理延迟和内存占用是 TextCNN 的好几倍不是所有业务都值得。我的习惯是先跑通随机 Embedding 的 TextCNN把数据和预处理链路验证扎实再用预训练向量做第二个版本根据验证集对比决定要不要接受更高的硬件成本。毕竟情感分析系统的价值在于稳定的交付和可维护而不是排行榜上多一个百分点。这条进阶路径也是我最近在一个内部评论分析工具上踩完坑后的总结希望帮到你。本文还有配套的精品资源点击获取
返回列表