简介面向计算机、通信、人工智能、自动化等相关专业的学生、教师及从业者这是一份基于深度学习长短期记忆网络LSTM的虚假新闻检测本科毕业设计资源包含完整可运行的Python源码、训练与测试数据集以及配套文档说明。项目从数据读取、中文文本预处理、停用词过滤到长短期记忆网络模型搭建、训练与结果输出覆盖了虚假新闻分类的完整实现路径个人答辩评审分达到98分代码经过调试测试可直接复用适合期末课程设计或毕业设计参考。压缩包共6个文件其中三个CSV文件承载训练与测试样本一个Python主程序实现整体流程停用词表用于文本清洗文档文件说明运行方式与环境配置整体体积仅5.86MB结构紧凑清晰。截至目前已有273人学习下载既适合初学者按步骤理解深度学习文本分类的思路也便于进阶者在此基础上调整网络结构或扩展应用具有较高的学习借鉴价值。1. 基于深度学习的LSTM虚假新闻检测为什么这个毕设方向常年被选虚假新闻检测在本科毕设里几乎是常青树选题核心场景很简单给一条新闻文本判断它是真实报道还是造假内容。做这个方向你不需要摄像头、不需要传感器一台普通笔记本电脑就能完成数据下载、模型训练和效果验证技术栈固定为 Python TensorFlow/Keras LSTM找参考代码容易踩坑记录也多。对想拿一个深度学习确实有用的结论、同时控制时间成本的本科生来说这个选题天然合适——你只需要把数据集准备好把 LSTM 的前向传播和训练流程跑通再做一个能说明问题的评估实验毕设的深度和完整性就都有了。2. 虚假新闻检测的数据准备数据集选型、标签体系与文本预处理2.1 数据集选型公开数据集与自建数据的取舍做虚假新闻检测第一步不是搭模型而是定数据集。常见做法是优先考虑公开的英文数据集比如 LIAR 这类以短文本和声明级标签为特征的数据集每一条样本包含说话人、声明内容和真实度标签适合拿来做基于 LSTM 的短文本分类还有一些英文新闻语料会按 real/fake 二分类组织每条样本是一篇完整新闻标题加正文。选数据集的判断标准有三条样本量是否够 LSTM 学出语义模式我一般建议至少 2 万条以上、标签是否有据可依最好是人工标注而不是爬虫自动贴标签、正负样本比例是否失调失调需要你在后期做采样或加权处理。中文数据集的公开整理相对少很多本科毕设会选择爬取微博、知乎或新闻门户的评论和转载内容再根据官方辟谣平台给的名单打标签这条路工作量大但可控适合做中文数据增强或跨语言迁移相关的进阶实验。数据集类型粒度样本规模起点标签质量适合场景声明级如 LIAR 类单句/单条声明1 万条以上人工标注可靠短文本分类、LSTM 基线文章级标题正文一篇新闻2 万条以上需人工复核长文本语义建模自建爬虫数据单条博文/新闻自定依赖辟谣平台名单中文场景、个性化实验数据集的粒度决定了模型的设计方向。声明级数据每条只有一两句话LSTM 能捕捉的上下文有限这时候模型能力再强也难有质的飞跃文章级数据则能完整使用时序建模能力但文本更长、噪声更多对预处理要求更高。我建议本科毕设优先选文章级数据因为 LSTM 的强项就是长序列语义建模用短文本数据集会让你的毕设难以展示模型的真实价值。如果选 LIAR 这类声明级数据那就要在特征工程上多做文章比如把说话人历史可信度、声明主题类别作为附加特征拼进模型这部分在文档说明里的可写内容反而更丰富。2.2 中文文本预处理分词、去停用词与序列截断数据拿到手之后LSTM 并不能直接读字符串。中文预处理的第一步是分词常见做法是使用 jieba 分词把整句拆成词序列。分词结果直接影响词表大小和模型对语义的建模能力——分词太粗词表膨胀且低频词多分词太细会把核酸检测拆成核酸和检测两个词丢失整体语义。我一般会对 jieba 加载自定义词典把新闻领域常见专有名词预先维护进去同时开启 jieba 的 HMM 新词发现避免网络流行语被切碎。分词做完之后要去停用词但注意停用词表不能照搬通用版本不很没这类带有语气和否定含义的词必须保留否则 LSTM 会丢失关键的语义转折信号。预处理还有一个关键步骤是序列截断与填充。LSTM 的输入要求每条样本长度一致常见做法是设定一个 max_len比如 128 或 256 个 token超过的截断不足的补零。这里有个细节截断到底是保留开头还是保留结尾对新闻文本来说标题和导语通常在开头正文观点在中间和结尾所以我在做新闻分类时更倾向保留开头 256 token 再补尾部这样模型既能读取核心信息又能感知结尾的收束语气。如果你用的是双向 LSTM截断位置的影响会更明显需要在实验里固定下来并在文档里写清楚。还有一个很多教程不会提的点截断位置是超参数不是固定值你可以在实验里对比 pre 和 post 两种截断方式的效果差异这本身就可以写进毕设的实验章节展现出你对问题理解的深度。2.3 词向量与序列填充Keras 的数据管道实现预处理完成之后要把词序列转成数值索引再经过 Embedding 层变成向量。import pickle import numpy as np from tensorflow.keras.preprocessing.text import Tokenizer from tensorflow.keras.preprocessing.sequence import pad_sequences # 假设 texts 是分词并去停用词后的词列表labels 是 0/1 标签 tokenizer Tokenizer(num_words20000, filters, oov_tokenUNK) tokenizer.fit_on_texts(texts) sequences tokenizer.texts_to_sequences(texts) # 截断策略保留开头信息0 作为 padding token X pad_sequences(sequences, maxlen256, paddingpost, truncatingpost) y np.array(labels) # 保存 tokenizer保证预测时用同一套词表 with open(tokenizer.pkl, wb) as f: pickle.dump(tokenizer, f)这段代码里Tokenizer 的 num_words 控制了词表大小设为 20000 是因为新闻语料里高频词的覆盖已经能到 90% 以上超出部分会被 oov_token 统一映射为 避免 Embedding 层参数过多。pad_sequences 的三个参数里maxlen256 是序列长度上限过长会显著拉长训练时间过短会丢失文本信息paddingpost 表示在尾部补零truncatingpost 表示从尾部开始截断——这两个参数默认都是 pre也就是从头截断对新闻文本来说默认值往往不是最优。训练结束之后 tokenizer 必须序列化保存否则你在预测阶段重建词表时会发现索引错位这是新手最容易踩的静默错误。3. 搭建 LSTM 检测模型从 Embedding 层到二分类输出的完整实现3.1 网络结构选型LSTM、BiLSTM 与堆叠 LSTM 的适用场景LSTM 的核心能力是建模序列中的长距离依赖在虚假新闻检测里这意味着模型能捕捉开头说某地又发生地震结尾却说这是旧闻改编这类跨句语义信号。单层 LSTM 是毕设的标准配置参数量小、训练快、不容易过拟合双向 LSTMBiLSTM会从正向和反向两个方向分别建模语义对新闻这种上下文互相印证的文本通常能提升 3~5 个百分点的准确率但训练时间几乎翻倍。堆叠 LSTM两层以上在文本分类里的收益普遍递减而且会让梯度在长序列上更容易不稳定。我的建议是如果数据集在 2 万到 5 万条之间选 BiLSTM 做 final 模型、单层 LSTM 做基线对比如果数据量很小低于 1 万条单层 LSTM 反而更稳定因为双向结构在小样本上更容易过拟合。除了深度LSTM 的隐藏维度也需要说清楚。隐藏维度units决定了模型对文本语义的表示能力128 和 256 是文本分类里最常见的两个值。并不是越大越好units 从 128 提到 256模型参数将近翻倍在小数据集上准确率未必提升训练时间却明显变长。我在做实验时习惯固定 units128 跑通全流程再用 256 做一组对照实验写进毕设的参数影响分析章节——毕设老师喜欢看到这类有对比的严谨性。另外Embedding 的维度通常设置在 64 到 300 之间和 LSTM 隐藏维度不必相等两者是独立的表征空间这个不要搞混。3.2 模型实现代码Embedding LSTM Dropout Dense 的经典组合下面是一份可以直接运行的 Keras 模型代码使用函数式 API 搭建结构为 Embedding → BiLSTM → Dropout → Dense 二分类输出。from tensorflow.keras.models import Model from tensorflow.keras.layers import Input, Embedding, LSTM, Bidirectional, Dropout, Dense max_len 256 vocab_size 20000 embedding_dim 128 lstm_units 128 inputs Input(shape(max_len,), namenews_input) # Embedding 层把词索引映射为稠密向量mask_zeroTrue 让 padding 位置不参与计算 embedding Embedding(input_dimvocab_size, output_dimembedding_dim, mask_zeroTrue)(inputs) # 双向 LSTMreturn_sequencesFalse 输出最后一个时间步的隐藏状态 lstm_out Bidirectional(LSTM(unitslstm_units, dropout0.3, recurrent_dropout0.3))(embedding) dropout Dropout(0.5)(lstm_out) outputs Dense(1, activationsigmoid, nameoutput)(dropout) model Model(inputsinputs, outputsoutputs) model.compile(optimizeradam, lossbinary_crossentropy, metrics[accuracy, AUC]) model.summary()这段结构里Embedding 层的 mask_zeroTrue 是一个关键参数它告诉 LSTM 忽略 padding 产生的 0 位置避免补零被当成真实语义参与计算如果去掉这个参数模型会把填充位也当作词汇学习导致最后的输出受到大量无意义位置的影响。LSTM 层内部的 dropout 和 recurrent_dropout 分别给输入和循环连接加随机失活是防止过拟合的第一道防线数值通常设在 0.2~0.4 之间recurrent_dropout 会显著拖慢训练但如果你的机器支持 GPU这点开销可以接受。编译时的 metrics 里加 AUC 而不是只看 accuracy是因为虚假新闻检测里正负样本往往不平衡AUC 能更客观地反映排序能力——后面第五节会专门展开。3.3 损失函数与评估指标为什么准确率会骗人虚假新闻检测用的是二分类交叉熵损失binary_crossentropy这是分类模型的标准选择内部计算方式是 y_true * log(y_pred) (1 - y_true) * log(1 - y_pred)对假新闻正样本和真新闻负样本分别惩罚。但如果你的数据集中 90% 都是真实新闻模型只需要全部预测为真就能拿 90% 准确率这就是准确率的欺骗性。所以评估时至少要看三个指标准确率整体正确率、精确率预测为假的里面有多少是真假、召回率所有假新闻里有多少被正确识别出来以及由精确率和召回率计算出的 F1 分数。对虚假新闻检测的实际使用场景漏判一条假新闻召回率低比误判一条真新闻精确率低后果更严重所以毕设文档里最好明确写出你是以 F1 还是以召回率作为优化的主要目标模型训练时的早停标准也要与之对齐。4. 训练与调参让 LSTM 检测模型收敛的实操细节4.1 数据集切分与验证策略不能只随机打乱拿到数据后最常见的做法是按 8:1:1 切成训练集、验证集、测试集但这里有一个很容易被忽略的坑新闻数据往往存在同源聚合现象比如同一事件被多家媒体改写转发如果随机打乱同一个事件的不同版本会同时出现在训练集和测试集模型实际学到的是认出这个事件而不是判断新闻真假测试分数虚高。更严谨的做法是按新闻来源或事件 ID 分组切分保证同一事件的所有文本只落入一个集合。做这种分组切分时数据必须包含原始来源字段如果数据集中没有至少也要按发布时间段切分把时间靠前的样本放训练、靠后的放测试这更接近真实场景中用历史数据判断未来新闻的设定。切分之后还要确定训练轮数。LSTM 在文本分类上通常需要 5~15 个 epoch 才会收敛但具体轮数严重依赖学习率和 batch size。判断收敛状态不能只盯训练集准确率要同时打印验证集 loss——当验证集 loss 开始上升而训练集 loss 继续下降就是过拟合的明确信号。常见做法是在回调中同时记录训练和验证两条曲线观察全程趋势而不是在最后一个 epoch 看一个孤立的分数。我见过不少同学只保存最后 epoch 的模型结果验证集最优出现在第 7 轮、第 10 轮已经过拟合最后评测时用了一个明显更差的参数状态这个细节处理好了能挽回好几个百分点的成绩。4.2 超参数设置学习率、batch size、epochs、dropout 的推荐起点超参数的起点设置直接影响训练效率下面是文本分类场景下的一组常用起点值以 TensorFlow 默认配置为基准。参数推荐起点调整方向常见错误学习率 (Adam)1e-3验证 loss 震荡时降到 1e-4不调整默认 1e-3 到底batch size32 或 64显存/内存不够时降半设置过大导致训练不稳定epochs10结合早停不要硬跑满盲目跑 50 轮LSTM dropout0.3过拟合明显时提到 0.5设为 0 求全量信息Dense dropout0.5同上与 LSTM dropout 混为一谈学习率是这里最需要手动干预的参数。Adam 优化器的默认学习率是 1e-3很多人拿到就直接跑但如果数据量小、文本噪声大训练 loss 可能在 5 个 epoch 后出现震荡甚至发散此时优先做的是把学习率降一个数量级到 1e-4而不是无休止加 dropout。我的习惯是使用 ReduceLROnPlateau 回调监控验证 loss连续 2 个 epoch 不下降就把学习率乘 0.5比手动改参数迭代效率高得多。batch size 的选择比较机械32 和 64 在 2 万条数据上的收敛速度差异不大过大的 batch 反而会让梯度方向过于平均说白了就是不敏感适合 128 个隐藏单元这种小模型如果内存不够把 batch size 减半比改序列长度更安全。4.3 过拟合与早停小数据集上最常见的翻车现场LSTM 在小样本上的过拟合几乎是毕设翻车的高发区。典型现象是训练集准确率到 97%验证集准确率只有 82%模型把训练样本中的用词习惯背了下来而不是学到真假新闻的语义规律。应对手段按优先级排列第一是增加数据这最有效但成本最高第二是加大 dropout同时把 LSTM 隐藏单元从 256 降到 128减少模型容量第三是加 L2 正则化在 Embedding 或 Dense 层的 kernel_regularizer 上设置 l2(1e-5)这一项在文本分类里的收益不如 CV 任务明显但聊胜于无第四是用早停EarlyStopping监控验证 loss连续 3 个 epoch 不降低就恢复最佳权重并停止训练避免最后几个 epoch 的过拟合覆盖掉之前的理想状态。在 Keras 里使用早停和动态学习率的完整写法如下from tensorflow.keras.callbacks import EarlyStopping, ReduceLROnPlateau, ModelCheckpoint early_stop EarlyStopping( monitorval_loss, patience3, restore_best_weightsTrue, verbose1 ) reduce_lr ReduceLROnPlateau( monitorval_loss, factor0.5, patience2, min_lr1e-5, verbose1 ) checkpoint ModelCheckpoint( best_model.keras, monitorval_auc, save_best_onlyTrue, modemax, verbose1 ) history model.fit( X_train, y_train, validation_data(X_val, y_val), epochs15, batch_size64, callbacks[early_stop, reduce_lr, checkpoint], verbose1 )这段代码里 EarlyStopping 的 patience3 意思是连续 3 个 epoch 验证 loss 没有下降就停止并恢复历史最优权重restore_best_weightsTrue 非常关键如果不设模型停止后会停在最后一个 epoch 的权重上而这个权重往往已经不是最佳。ReduceLROnPlateau 的 factor0.5 表示学习率减半patience2 表示连续 2 个 epoch 不下降就触发min_lr1e-5 防止学习率衰减到零。ModelCheckpoint 的 monitor 用的是 val_auc 而不是 val_loss因为对类别不平衡的数据集AUC 更能反映模型真实的排序能力save_best_onlyTrue 配合 modemax 只保留历史上 AUC 最高的权重文件这个文件就是你后续测试阶段要加载的最终模型。5. LSTM 虚假新闻检测避坑指南现象、原因与解决方案5.1 标签泄漏预处理信息被错误带进训练集现象训练时验证集 AUC 高达 0.98但换一批新数据测试直接掉到 0.72。 原因你在预处理阶段无意中把和标签强相关的信息带进了特征。最常见的两个泄漏源一是爬虫数据里每条样本自带来源域名或作者 ID而某些来源域名本身就是假新闻重灾区模型直接学了特征二是文本里保留了辟谣平台在标注时添加的【辟谣】等前缀这类前缀和标签的对应关系比正文语义强得多模型根本不用看内容就能做出正确判断。 解决预处理时显式剔除标题前缀、来源字段、URL 和作者信息只在文本中保留新闻正文在毕设文档里专门写一段特征独立性说明证明你进入模型的特征不包含任何标签派生信息。这个坑如果不排查答辩时评委用一条带【辟谣】前缀的新闻就能把你问住。5.2 类别不平衡真实新闻远多于假新闻时模型会偷懒现象训练结束后模型准确率 88%但把所有新闻都预测为真实AUC 也仅有 0.5。 原因数据集中真新闻占比过高比如 9:1二分类交叉熵损失的最小化策略就是全部预测为多数类LSTM 在训练过程中学不到少数类的有效梯度信号因此精准率和召回率严重失衡。 解决先做训练集层面的类别加权在 model.fit 中设置 class_weight{0: 1.0, 1: 5.0}让少数类样本的损失放大如果效果还不够再对训练集少数类做上采样但注意复制增强不要造成重复样本导致的过拟合。评估指标必须看 F1 和 AUC不能看 accuracy。加 class_weight 的代码只影响训练集损失计算不会改变验证集和测试集的分布所以可以放心用。5.3 序列长度不一致推理时 padding 位置错了导致效果崩现象训练时验证集 F1 0.85部署或测试时加载同一个模型单条预测结果却明显变差。 原因训练时 pad_sequences 用的是 maxlen256 paddingpost但你在推理阶段重新处理单条新闻时要么没截断、要么默认使用了 paddingpre导致序列前 256 个位置全部是零向量真正的文本被挤到后面LSTM 建模的是从左到右的语义流前面全是零时模型的内部状态完全错位。 解决推理阶段把文本处理封装成和训练完全一致的工具函数包括分词、去停用词、调 tokenizer、pad_sequences并且从同一个 pickle 文件加载词表。我这里有一段血泪经验是不要在生产环境里手写一份简单版预处理预处理不同步是推理性能下降的最常见原因没有之一。5.4 中文词向量 OOV新词和网络流行语全被当成 UNK现象中文新闻语料里模型对信息熵奥密克戎这类词预测不准对当年新出现的网络词基本失效。 原因预先固定的词表只有 2 万词当年不在语料里的新闻新词全部映射到 这些词在 Embedding 矩阵中共享同一个随机向量模型无法区分它们的语义。 解决一是扩大 num_words 到 5 万以上提升词表覆盖率但要注意参数量会同步增加二是专门在 jieba 自定义词典里维护新闻领域术语保证分词时不会被切碎三是如果数据集规模允许用 word2vec 或 fastText 在更大的新闻语料上预训练词向量再用 Embedding 层的 weights 参数初始化并设置 trainableTrue 做微调能显著提升新词的泛化能力。fastText 对 OOV 更友好因为它用子词信息编码词向量非常适合中文这种构词灵活的语言。6. 进阶优化注意力机制与模型融合让 LSTM 检测效果再上一个台阶如果毕设题目里要求创新点只做标准 LSTM 双向结构通常说服力不够。一个低成本但有效的改进是在 LSTM 输出之上加一层注意力机制让模型对更有判别力的片段赋予更高权重。做法是让 LSTM 层设置 return_sequencesTrue输出每个时间步的隐状态再经过一个可学习权重向量计算每个时间步的注意力分数softmax 归一化后加权求和得到整段文本的汇总向量。注意力层代码量不大但能带来两个直接收益模型可以学到结尾信号比开头更关键这类权重模式你也能在毕设论文里把分数最高的几个词列出来证明模型确实关注到了辟谣转发事实核查等典型判别词。import tensorflow as tf from tensorflow.keras.layers import Layer class AttentionLayer(Layer): def __init__(self, **kwargs): super().__init__(**kwargs) def build(self, input_shape): # input_shape: (batch, time_steps, features) self.W self.add_weight( nameattention_weight, shape(input_shape[-1], 1), initializerrandom_normal, trainableTrue ) super().build(input_shape) def call(self, lstm_outputs): # 计算每个时间步的注意力分数并归一化 score tf.nn.softmax(tf.matmul(lstm_outputs, self.W), axis1) # 按分数加权求和得到整段文本的汇总向量 context tf.reduce_sum(score * lstm_outputs, axis1) return context使用这个层时LSTM 的 return_sequences 要改成 True否则拿不到完整的时间步输出。我在实验里发现注意力机制在短文本上收益有限在长新闻上收益更明显如果你的 maxlen 只有 128加注意力可能提升不到 1 个百分点把序列长度提到 256 再测会更客观。模型融合是另一个高性价比方案把同一段文本分别送进 LSTM 和 TextCNN 两个分支各自得到特征向量后拼接再接全连接层。LSTM 擅长建模全局序列依赖TextCNN 擅长提取局部 n-gram 特征两者互补融合后 F1 通常比单 LSTM 高 2~4 个百分点训练耗时几乎没有增加。训练结束后有一个我坚持做的验收动作从测试集里挑 50 条预测错误的样本逐条打印预处理后的文本检查是被截断位置过早、OOV 过多还是标注本身有争议。做完这一步你就能在答辩前把模型失败在哪、还能怎么改讲清楚。我做这类课题的习惯是从一开始就把预处理、模型定义、训练脚本拆成三个独立文件每次实验只改模型文件确保对比时的唯一变量真的是模型结构而非预处理差异。很多毕设项目最终实验不可复现就是因为数据前处理逻辑在脚本之间出现了不一致。希望上面这些参数、代码和踩坑记录能帮到你让你在这个方向少走弯路。本文还有配套的精品资源点击获取