ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Django与深度学习驱动的酒店评论情感分析系统设计与实战

Django与深度学习驱动的酒店评论情感分析系统设计与实战 这是一篇之前做完、最近又被好几个学弟学妹问过的课程设计基于Django和深度学习的酒店评论文本情感分析系统。这题在本科毕设和课程设计里都属于典型的“综合型题目”既有实际业务意义——帮酒店和平台自动判断客服评论是好评还是差评又有可以展示的技术点Web开发、数据库设计、深度学习模型训练、文本处理一条链路全都有。对想找项目练手的同学来说这套组合能覆盖的知识面很广答辩也有东西可讲。过去大半年我前后复现和改造了不少类似项目这一套的坑和细节我很清楚。很多同学拿着“附源码、数据库、万字文档”的资源包结果跑不起来或者跑起来不知道哪里改原因往往不是源码本身差而是缺少对整条链路的理解。这篇就按我实际做的顺序把这套系统从数据到模型再到Django展示的每个环节拆开讲带上具体的参数、代码片段和踩坑记录看完你至少能自己把项目完整跑通并且有能力回答答辩老师的几个“为什么”。1. 项目整体拆解这个毕设到底在做什么1.1 选题价值为什么偏偏是酒店评论情感分析酒店评论是文本情感分析里最“规矩”也最好入手的数据之一。和微博、新闻评论不一样酒店评论文本通常围绕服务、卫生、位置、价格、餐饮这些固定维度句式相对完整情感倾向也比较明确“房间很干净”“前台服务态度差”基本一眼就能判断这对模型学习很友好。在线旅游平台上的评论数量海量人工审核根本不现实情感分析可以直接把好评、差评、中性评价自动归类再进一步统计出用户最在意的问题——卫生、隔音、早餐还是位置这是有真实商业价值的场景。选这个题目还有一个实际好处数据集好找公开的酒店评论数据集不少也可以自己去OTA平台上爬中文语料质量普遍不错标注成本低。对课程设计来说它不需要像医疗影像那样复杂的前置知识也不需要生成类模型那样大的算力一台普通笔记本用CPU就能把训练跑完这是很多深度学习选题做不到的。综合来看这个题目“性价比”很高能出成果、能写代码、能画图、能讲清楚。1.2 技术栈选型Django加深度学习是怎么走到一起的框架选型是很多同学拿到项目后第一个困惑的点为什么偏偏是DjangoFlask不是更轻吗FastAPI不是性能更好吗我个人的建议是课程设计场景下Django就是最稳妥的选择没有之一。先算一笔账。Flask确实轻两小时就能写出一个简单的预测接口但一套完整的课程设计系统通常要包含用户登录注册、评论数据管理、历史记录展示、后台统计分析、Admin管理界面这些功能。在Flask里这些全部要自己集成登录要配Flask-Login、ORM要配SQLAlchemy、后台要自己写页面最终代码量和Django差不多框架自带的便利还全丢了。FastAPI性能好、自动生成接口文档但它的异步模型和Django的MTT结构差异大网上的课程设计案例数量远不如Django遇到问题搜起来困难。Django自带Admin、ORM、Auth、Session、CSRF防护一个命令把数据库表结构建好再花几分钟注册到Admin后台后台管理界面直接就有了。答辩时说自己用了Django的Admin这也算一个完整的模块。深度学习框架同样面临选型。现在主流就是PyTorch和TensorFlow课程设计我推荐PyTorch。它写起来非常接近纯Python和NumPy的思维习惯模型定义、数据加载、训练循环的逻辑都是透明的不像TensorFlow 2.x那样各种API层叠版本之间改动还大很多老教程已经跑不通了。PyTorch在CPU上的训练表现也不差TextCNN这种轻量模型用CPU跑一个epoch也就几分钟完全适配课程设计。数据库的选择比较灵活。本地开发默认用SQLite零配置Django直接支持如果要演示MySQL在settings.py里改DATABASES配置即可。建议开发过程用SQLite写文档时提一下“生产环境可平滑迁移到MySQL”并给出完整的pymysql配置代码。1.3 系统功能模块划分这套系统从用户角度看核心功能一般这么几个注册登录、提交评论进行情感分析、查看分析结果、查看历史记录、平台分词云和统计图表、后台管理。把它们映射到Django的MTV架构里功能模块对应实现涉及技术点用户认证Django Auth注册、登录、Session、csrf情感预测深度学习模型接口文本预处理、模型推理、结果映射历史记录ORM增删改查Review/Comment模型、查询、删除数据统计聚合查询图表annotate、aggregate、ECharts后台管理Django Adminlist_display、search_fields、自定义方法选型上精简掉所有不必要的复杂度是很重要的一条原则。有些同学喜欢往上加Redis缓存、Celery异步任务、JWT鉴权这些在实际项目里当然有用但对课程设计来说如果答辩老师问两句“为什么用Redis”“消息队列在这里解决了什么实际问题”你答不上来反而减分。先把一条完整链路跑通比堆中间件重要得多。2. 数据处理与文本预处理最容易低估的一环2.1 数据集从哪来合法获取与格式整理数据集是整个项目的地基。课程设计最常用的两个渠道一是公开数据集比如ChnSentiCorp酒店评论语料包含正面和负面各几千条格式干净直接CSV读入就行二是自己通过爬虫采集主流OTA平台上的酒店评论这个技术含量更高但要注意遵守robots协议和目标平台的条款且只能用于学习和论文实验不能把数据再公开分发。我复现时用的就是公开数据集总共7000多条评论字段就三个label0负面/1正面、review评论文本、source来源平台。读取方式很简单import pandas as pd df pd.read_csv(hotel_reviews.csv, encodingutf-8) df df[[label, review]].dropna() # 丢掉空评论文本 print(df[label].value_counts())拿到数据第一步是看类别分布和文本长度分布。我第一次处理这份数据时发现负面评论数量明显少于正面这说明有类别不平衡问题后面训练时如果不处理模型很容易“偷懒”——全预测成正面也能有不错的准确率。文本长度则决定后面padding时的最大长度先画个长度分布直方图看到大部分评论在50到200字之间就基本能确定截断长度。2.2 清洗与分词酒店评论文本的特殊性原始评论文本是很脏的里面经常夹杂HTML标签、URL链接、表情符号、特殊符号和多余空白这些内容对情感判断没什么帮助还会干扰词向量训练。清洗这一步我通常会确保把数据变成下面这种干净状态后再进入分词环节import re def clean_review(text): # 去除HTML标签 text re.sub(r[^], , text) # 去除URL text re.sub(rhttp\S|www\.\S, , text) # 去除特殊符号和多余空白 text re.sub(r[^\u4e00-\u9fa5a-zA-Z0-9。、], , text) text re.sub(r\s, , text) return text.strip() df[clean_review] df[review].apply(clean_review)这里有个细节值得注意酒店评论文本里经常出现“5分”“3星”这类评分词条直接去除数字会把评分信息丢掉但不丢影响也不大——因为我们的训练标签本身就是评分映射出来的通常低于3分算负面、高于3分算正面文本里的数字大多和标签高度重合模型即使不看数字也能学习到情感词。当然如果你做的是评分预测而不是正负面分类那数字就不能随便删。分词我用的是jieba中文文本分词的社区老牌工具稳定、文档全。酒店评论里有些词容易被切错“性价比”“前台服务”“无线网络”“停车位”“自助餐”这些领域词汇jieba的默认词典未必能正确处理。解决方法是建立自定义词典import jieba hotel_words [性价比, 前台服务, 无线网络, 停车位, 自助餐, 隔音效果, 免费升级] for word in hotel_words: jieba.add_word(word) def tokenize(text): return [w for w in jieba.lcut(text) if w.strip()]注意这里用的是lcut返回列表后面处理起来方便别用生成器版本的cut——虽然效果一样但迭代两遍时容易踩坑。2.3 停用词、标点与否定词处理停用词表几乎是文本分类项目的标配但处理情感分析时必须留个心眼。标准中文停用词表里通常包含“不”“没”“别”“没有”这类词这些词在主题分类里是噪声在情感分析里却是关键的极性反转词。“房间不小”和“房间小”情感完全相反如果无脑把“不”删掉模型永远分不清这两句话。我的做法是先把停用词表加载出来过滤掉其中所有否定词和程度副词再用于分词后的过滤。程度副词比如“很”“太”“极其”“非常”也建议保留它们的出现能增强情感强度。实践上我直接用公开停用词表过滤标点和虚词然后手动检查清单里有没有否定词有就加回白名单。这一步做对后面模型分数能稳定提升两个点左右。2.4 数据切分与类别平衡清洗和分词完成后把文本拼接回带空格的形式然后建立词表。词表构建要做两件事一是统计每个词的出现频次过滤掉只出现一两次的词控制词表大小二是给每个词编号同时预留UNK和PAD两个特殊编号。这两步缺失会导致后面模型输入对不齐。数据切分按6:2:2划分训练集、验证集、测试集注意用train_test_split时要设置stratify参数按标签比例做分层采样防止随机切分导致某一类在验证集里占比异常。类别不平衡这块如果正负比超过3比1建议先做下采样或采用加权损失函数。下采样简单直接随机删掉一部分多数类样本让训练集比例接近1比1加权损失函数则是在计算交叉熵时给少数类更大的权重。我用的是加权损失函数在PyTorch里几行就能实现信息保留更完整。3. 模型设计与训练全过程3.1 模型选型思考TextCNN、LSTM还是注意力机制到了模型选择这步很多同学会直接上BERT觉得大模型效果好、说出来高级。但我想先劝一句课程设计选用BERT性价比其实很低。BERT模型本身几百MBCPU推理一次少则几秒训练微调更是需要GPU和时间而且答辩时很难讲清楚Transformer内部机制。当然如果你的机器有GPU且视频成绩要冲高分可以用BERT做个对比实验但主模型建议还是TextCNN或BiLSTM这些经典结构。TextCNN和LSTM怎么选短文本分类任务我实测下来TextCNN表现相当扎实。它的核心思想是用多个不同宽度的卷积核去提取句子中的N-Gram局部特征“服务很差”和“环境优美”这类关键词组合正好能被卷积核捕获训练速度也快CPU上表现绰绰有余。LSTM的优势在于能建模长距离依赖但酒店评论普遍在200字以内这种优势体现得不明显训练却慢得多。所以推荐方案主模型用TextCNN对比模型可以用BiLSTM最终结果表里放两组对比。3.2 改进TextCNN的网络结构详解标准的TextCNN结构是这样的Embedding层把每个词映射成向量然后并行经过多个尺寸不同的卷积核每个卷积核做MaxPooling把池化结果拼接起来经过Dropout和全连接层最后Softmax输出情感类别的概率分布。完整定义代码可以直接抄import torch import torch.nn as nn import torch.nn.functional as F class TextCNN(nn.Module): def __init__(self, vocab_size, embed_dim128, num_filters128, filter_sizes(2, 3, 5), num_classes2, dropout0.5): super().__init__() self.embedding nn.Embedding(vocab_size, embed_dim, padding_idx0) self.convs nn.ModuleList([ nn.Conv2d(1, num_filters, (size, embed_dim)) for size in filter_sizes ]) self.dropout nn.Dropout(dropout) self.fc nn.Linear(num_filters * len(filter_sizes), num_classes) def forward(self, x): # x shape: (batch, seq_len) x self.embedding(x) # (batch, seq_len, embed_dim) x x.unsqueeze(1) # (batch, 1, seq_len, embed_dim) conv_outputs [] for conv in self.convs: c conv(x).squeeze(3) # (batch, num_filters, conv_seq_len) c F.relu(c) c F.max_pool1d(c, c.size(2)).squeeze(2) conv_outputs.append(c) x torch.cat(conv_outputs, dim1) # (batch, num_filters * len) x self.dropout(x) return self.fc(x)卷积核尺寸为什么要选(2, 3, 5)这是TextCNN经典论文和大量实践总结出来的经验窗口2-gram覆盖“很差”“不错”这类短语3-gram覆盖“服务态度好”5-gram覆盖更长的局部片段。卷积核宽度对应词窗口高度固定为embedding维度这样每次卷积就提取一个局部词组特征。MaxPooling取每个feature map的最大值相当于把每个卷积核最强烈的激活信号提取出来代表这一类特征是否出现这是TextCNN的核心思想。如果你只想增分可以在全连接之前加一层注意力机制给不同词窗口的特征分配权重让“差劲”“失望”这种词获得更高权重。这个改进不大但答辩时可以说“我在TextCNN基础上引入了注意力权重缓解了关键词信息在池化过程中的损失”效果描述有依据、实现也不复杂。3.3 关键超参设置与训练策略我复现时使用的超参数组合如下效果和训练时间的平衡比较理想超参数取值说明max_len100超过截断不足补齐太长增加计算量vocab_size8000-10000低频词过滤后的词表规模embed_dim128词向量维度再大CPU训练变慢num_filters128每个卷积核尺寸的输出通道数filter_sizes(2, 3, 5)卷积窗口宽度dropout0.5全连接前随机失活比例batch_size64略大一些训练稳定learning_rate0.001Adam优化器默认学习率epochs20配合早停防止过拟合patienct3验证集F1连续3轮不升则停词向量的初始化方式是一个关键决策点。随机初始化最简单训练也从零学习词与情感的关联。用预训练词向量则能利用大规模语料学到的语义信息模型收敛更快、效果略好。课程设计阶段我建议直接随机初始化但训练时把embedding层设置为可训练这已经能取得不错效果。如果做对比实验想提分可以下载现成的中文预训练词向量加载到Embedding层并微调。训练循环是标准的PyTorch流程唯一值得提醒的是验证集上关注的指标不能只看loss要计算F1分数并且实现early stoppingbest_f1 0 patience 0 for epoch in range(epochs): model.train() for xb, yb in train_loader: optimizer.zero_grad() loss criterion(model(xb), yb) loss.backward() optimizer.step() val_f1 evaluate(model, val_loader) if val_f1 best_f1: best_f1 val_f1 torch.save(model.state_dict(), best_model.pt) patience 0 else: patience 1 if patience 3: print(fearly stop at epoch {epoch}) breakEarly stopping是课程设计里非常容易加分的一个细节导师或答辩老师看到训练曲线有防止过拟合的机制比看到你盲跑20个epoch印象好得多。保存best_model.pt而不是最后一个epoch的模型也很关键验证集F1最高点的模型在测试集上通常表现更好。3.4 评估指标到底看什么准确率、F1还是混淆矩阵情感分析分类最常见的错误就是只看准确率。数据不平衡时这个指标会严重骗人——比如90%是正面评论模型全部预测正面准确率就有90%看起来非常好实际毫无用处。课程设计阶段建议至少报告三个指标准确率、精确率、召回率以及它们的调和平均F1值。F1在正负样本不平衡时更能反映模型的真实分类能力。混淆矩阵是答辩的另一个“杀手锏”。画一张4格矩阵图摆在论文里老师一眼能看到模型在哪个类别上误判多、容易把差评误判成好评还是相反。这种可视化比大段文字描述直观得多属于“做了就有印象分”的内容。3.5 与朴素贝叶斯、SVM的对比实测深度学习模型蕞好在课程设计里和传统机器学习方法做一个横向对比这是论文和答辩都绕不开的对比实验。我当时用同一份酒店评论数据分别做了朴素贝叶斯、SVM和TextCNN训练结果如下模型准确率F1值训练时间CPU朴素贝叶斯84.2%83.1%秒级SVM TF-IDF86.5%85.4%分钟级BiLSTM87.8%87.0%25分钟TextCNN89.1%88.3%8分钟这个对比表的结论很清晰传统方法有效但上限有限深度学习方法在同等条件下确实带来了提升TextCNN在训练速度和效果之间取了很好的平衡点。写论文时重点分析那句“注意力机制与卷积窗口结合让TextCNN在短文本关键特征提取上优于BiLSTM”老师看到这样的结论会觉得你有分析总结能力而不是单纯堆实验。4. Django端实现与数据库交互细节4.1 数据库设计与ORM模型编写项目的数据层是Django的ORM体系核心模型我拆成两个一个存储爬取或导入的原始酒店评论另一个存储用户通过系统预测的记录。分开存的原因是二者生命周期不同原始评论是“数据资产”预测记录是“用户成果”混在一张表里后期统计会很混乱。from django.db import models class Review(models.Model): content models.TextField(verbose_name评论文本) label models.IntegerField(nullTrue, blankTrue, verbose_name情感标签) source models.CharField(max_length50, blankTrue, verbose_name来源平台) created_at models.DateTimeField(auto_now_addTrue) class Meta: db_table review ordering [-created_at] class SentimentRecord(models.Model): user models.ForeignKey(auth.User, on_deletemodels.CASCADE, verbose_name用户) content models.TextField(verbose_name评论文本) pred_label models.IntegerField(verbose_name预测标签) pred_score models.FloatField(verbose_name置信分数) created_at models.DateTimeField(auto_now_addTrue) class Meta: db_table sentiment_record ordering [-created_at]外键on_deletemodels.CASCADE的含义是关联的用户被删除时该用户的所有预测记录同步删除。如果改成PROTECT用户删除时会报受保护错误需要先清理记录。这块答辩时经常被追问建议把Django支持的几种on_delete行为都看一遍。字段类型上评论文本一定要用TextField不要用CharField。CharField默认最大长度255但酒店评论几百上千字很常见超出会被数据库拒绝或截断。数据库层面如果你迁移到MySQL要确认建表编码是utf8mb4否则中文和emoji字符会乱码或报错。4.2 迁移、查询与管理后台模型定义好后生成数据库表的命令是python manage.py makemigrations python manage.py migrate先makemigrations生成迁移文件再migrate执行迁移。很多同学在这里翻车是因为项目里已经有了迁移文件自己改模型后又makemigrations多个迁移文件冲突导致报错“django.db.migrations.exceptions.InconsistentMigrationHistory”。解决方案看情况要么删除最新的冲突迁移文件重新生成要么干脆备份数据后删除db.sqlite3再重新migrate。课程设计阶段还没有“不能删库”的硬约束重新迁移通常不会损失什么。ORM查询是另一个高频面试和答辩考点。这里给出几个常用写法# 查询所有正面预测记录 pos_records SentimentRecord.objects.filter(pred_label1) # 排除某些置信度过低的记录 high_conf SentimentRecord.objects.exclude(pred_score__lt0.6) # 统计每位用户的预测次数 from django.db.models import Count user_counts SentimentRecord.objects.values(user__username).annotate(cntCount(id)) # 删除某条历史记录 record SentimentRecord.objects.get(id1) record.delete()这里正好对应了“django执行查询-删除对象”这一热搜场景。需要注意delete()是物理删除记录直接被移除无法恢复。如果产品上需要“回收站”逻辑就要在模型里加一个is_deleted models.BooleanField(defaultFalse)软删除字段查询时过滤掉已删除的即可。管理后台的配置也能快速提升项目“高级感”。把模型注册到admin之后自定义一下列表显示列、筛选字段和搜索字段from django.contrib import admin admin.register(SentimentRecord) class SentimentRecordAdmin(admin.ModelAdmin): list_display (user, content, pred_label, pred_score, created_at) search_fields (content,) list_filter (pred_label, created_at)这样管理后台可以直接看预测记录列表还能按标签过滤对演示和验收都很有帮助。4.3 情感分析核心接口的完整实现整个项目最关键的部分是用户提交评论后Django视图层调起深度学习模型完成预测。这里有一个最容易出性能问题的设计千万别在每个请求里重新加载模型。PyTorch模型加载耗费时间如果在视图函数里写model TextCNN(...); model.load_state_dict(...)每次请求都要重新读文件接口响应会慢到无法接受。正确的做法是利用Python模块只加载一次的特性在视图模块顶部加载模型# sentiment/views.py import joblib import torch import jieba from django.http import JsonResponse from django.shortcuts import render from .model_utils import TextCNN, MODEL_PATH, VOCAB_PATH, load_model具体实现里我再把模型加载封装成独立模块并加一个懒加载模式让只在真正用到时初始化一次# model_utils.py import torch import pickle import threading MODEL_PATH model/TextCNN_epoch9_F1_0.883.pt VOCAB_PATH model/vocab.pkl class Predictor: _instance None _lock threading.Lock() def __init__(self): with open(VOCAB_PATH, rb) as f: self.vocab pickle.load(f) self.model TextCNN(vocab_sizelen(self.vocab)) self.model.load_state_dict(torch.load(MODEL_PATH, map_locationcpu)) self.model.eval() classmethod def get_instance(cls): if cls._instance is None: with cls._lock: if cls._instance is None: cls._instance cls() return cls._instance def predict(self, text): tokens [self.vocab.get(w, self.vocab[UNK]) for w in jieba.lcut(text)] tokens tokens[:100] [0] * (100 - len(tokens)) x torch.tensor([tokens]) with torch.no_grad(): logits self.model(x) prob torch.softmax(logits, dim1) label int(torch.argmax(prob, dim1).item()) score float(prob[0][label]) return label, score给模型加载加了一个线程锁防止多线程请求时重复实例化这是Django生产环境部署时很容易忽视的问题。视图函数只需要调用这个预加载的Predictor即可from .model_utils import Predictor def analyze(request): if request.method POST: content request.POST.get(content, ).strip() if not content: return JsonResponse({code: 1, msg: 评论内容不能为空}) predictor Predictor.get_instance() label, score predictor.predict(content) SentimentRecord.objects.create( userrequest.user if request.user.is_authenticated else None, contentcontent, pred_labellabel, pred_scorescore ) return JsonResponse({code: 0, label: label, score: round(score, 4)}) return render(request, sentiment/analyze.html)这里加了一句很关键把预测结果写入SentimentRecord这样历史记录模块才有数据可以展示同时论文里也可以写“系统具备用户交互和记录管理能力”。如果预测完不落库整个模块就少了一大块功能答辩时也不好讲。4.4 前端展示与静态文件问题前端展示一般用模板图表库就能搞定不推荐为了界面好看硬上个前后端分离的Vue项目会增加不少工作量。预测结果页面除了显示标签和置信度我建议加上情感分布统计图这里用ECharts的饼图就能实现div idpieChart stylewidth: 600px; height: 400px;/div script src{% static js/echarts.min.js %}/scriptDjango的static配置是新手最容易卡住的地方。你在VSCode里写HTMLimg srcimg/logo.png直接拖进浏览器看能显示但放到Django模板里就不显示了——原因是模板里的静态文件路径必须经过Django的static标签解析{% load static %} img src{% static img/logo.png %} altlogo同时要在settings.py里设置STATIC_URL /static/ STATICFILES_DIRS [ BASE_DIR / static, ]模板里只管用static标签引用的资源放项目根目录的static文件夹下就基本不会再出现“图片显示不了”的问题。开发环境DEBUGTrue时Django会自动服务static文件这个没问题。但如果后面用runserver --insecure或者部署到服务器上还需要collectstatic配置这部分可以在论文“系统部署”章节里写一笔。4.5 请求处理与并发下的模型调用Django自带的开发服务器是单进程的课程设计演示单用户操作完全够用。但如果你的系统里加了并发压力测试或者想展示多用户同时访问的能力就要注意两点一是改用daphne或uwsgi等多进程部署方式静态文件交给nginx处理二是确保模型预测逻辑线程安全。很多同学跑测试时发现第一次请求特别慢后面就快了这是正常的——第一次请求需要初始化模型加载权重文件可能要几秒。我的方案是在项目启动后自定义一个AppConfig的ready()方法里触发一次Predictor.get_instance()预加载这样用户访问时模型已经在内存里第一次请求也不会卡顿。这种做法写进文档里细节提现出的工程能力是很加分的。5. 课程设计常见问题与排查速查表5.1 训练阶段的翻车现场训练过程中最常见的问题不外乎几个loss变成NaN、验证集F1不升反降、模型预测全部是同一类。我把它们整理成一个速查表方便你照着排查。症状原因解决办法loss一开始就是NaN学习率过大分词后部分样本为空Embedding层出现NaN权重降低学习率到1e-4清洗过滤空文本检查输入id是否越界训练准确率100%测试很差过拟合增大dropout到0.5early stopping数据增强或增加数据量预测结果全部是同一类类别不平衡模型退化解加权损失函数重新检查分层采样减少训练epoch加早停验证集波动很大batch_size过小数据集未打乱设置batch_size不小于32DataLoader加shuffleTrue中文显示为乱码数据文件编码问题CSV统一用utf-8-sig读取PyTorch内部字符串无关其中有一个坑是很多人遇到过的jieba分词后个别评论的分词结果为空列表如果直接转成词向量就是全0输入模型打印出来全是NaN。解决办法是在预处理阶段加一条过滤规则if len(tokens) 0: drop。5.2 Django运行阶段的坑Django层面的问题主要集中在数据库迁移、中文乱码、静态文件加载和模版报错四类。这里把高频问题列成表格每一项我都实际踩过症状原因解决办法python manage.py migrate报错冲突迁移文件历史混乱备份后删除db.sqlite3重新迁移或只保留最早的迁移文件页面中文变成问号乱码数据库编码不是utf8mb4HTML模板缺charset模板加 meta charsetutf-8 MySQL建库指定utf8mb4静态文件加载失败404static路径配置错误模板忘记load static检查STATICFILES_DIRS模板首行加{% load static %}ORM批量插入太慢一条一条create用bulk_create批量创建列表用pymysql连接MySQL报错未注册pymysql在__init__.py中pymysql.install_as_MySQLdb()SQLite文件复制到另一机器打不开版本兼容或文件损坏用完整副本低版本SQLite升级5.3 文档与答辩准备经验撑到这一步代码基本跑通了。但很多同学拿到项目之后下意识犯一个错误把附带的万字文档直接提交结果答辩老师问到一个细节自己完全答不上来。文档再长如果和你实际代码对不上那它就是减分项而不是加分项。真正有效的做法是把万字文档当成“故事线”先通读一遍了解结构再跟着核心代码逐段对照。重点检查三块一是摘要和结论是否和你的实际效果一致有些模板项目在文档里写的准确率是95%你复现跑出来只有88%不改直接交会翻车二是技术选型章节文档里如果写“选用TensorFlow 2.0”而你用的是PyTorch整个章节都得改三是图表特别是流程图、架构图、混淆矩阵图确认图上说的是不是你自己的项目结构。答辩演练也很有用。把文档里每个“系统采用某某技术实现某某功能”的句子都向自己追问一个“为什么选它”和“它解决了什么问题”。能回答上来的就是自己的回答不上来的赶紧补课。这样过一轮之后老师怎么问基本都能接住。6. 关于源码、数据库和万字文档我的实际体验6.1 拿到开源项目后建议先做什么你下载到的项目包里通常包括源代码、数据库文件和万字文档。我的建议是三步走先跑通、后看懂、再改造。先跑通是底线。装好Python环境和依赖库把python manage.py runserver跑起来浏览器访问首页和预测页面确认功能正常。然后打开数据库文件看一下里面有没有自带的用户、评论、预测记录数据——这些数据会直接影响演示效果和文档中的截图。接着是看懂源码这一步不能只停留在点开文件看而要把关键流程读出来请求从URLconf进来后经过哪个视图、调用了什么函数、读取了哪个表、最终怎么返回页面。能用一句话讲清楚每一条链路才算真正看懂了。最后是改造。所谓改造其实不需要大改一个小的个性化项目就能让整份作业看起来不一样。比如换个词云配色、给数据集加上来源平台的筛选、在统计区域加一张近30天的预测趋势图。这些改动代码量不大但答辩时你能说“这是我做的基础上加的”和只会复制的人高下立判。6.2 这套系统还能怎么扩展做完这个课程设计之后我被问过最多的两个问题一是“能不能换成BERT”二是“能不能支持新的OTA平台实时评论分析”。这两个其实正好代表了两个扩展方向。换BERT方向代码逻辑不用变只要把模型部分替换成预训练的BERT模型比如huggingface的bert-base-chinese然后把分词器换成BERT自己的tokenizerDjango接口层完全不用动。这个扩展非常适合有GPU的同学做完效果能提升不少但要注意模型文件体积很大、推理速度慢部署时要考虑性能。实时爬取方向则是把Review表的来源从静态CSV换成爬虫服务定时抓取OTA平台的新评论入库系统隔一段时间再批量预测。这需要加一个定时任务模块比如Django-crontab或APScheduler。扩展起来也不复杂但生产平台协议、爬虫合法性、数据存储这些都涉及工程合规问题只是作为课程设计的扩展方向反而很有亮点。如果让我重新再做一遍这个项目我会把更多的精力放在数据预处理和模型对比两个环节。毕竟“基于Django深度学习的酒店评论文本情感分析”这个题目骨架就是“数据-模型-Web展示”三个环节任何一个环节有深度整个项目都能立得住。少花力气在花哨的前端特效上多花时间搞清楚为什么model.load_state_dict之后要model.eval()、为什么类别不平衡要用F1而不是准确率这些“为什么”才是你真正能从课程设计里带走的东西。
返回列表