ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

MLP实现虚假新闻检测:从TF-IDF到超参数搜索的Python完整实践

MLP实现虚假新闻检测:从TF-IDF到超参数搜索的Python完整实践 简介这是一套基于Python与MLP多层感知机的互联网虚假新闻检测项目面向机器学习初学者和自然语言处理爱好者可用于课程设计、毕业设计或竞赛练手。压缩包共21个文件涵盖.py源码fit、predict、preprocess等模块、.csv与.pkl格式的训练测试数据集、已训练好的.model模型文件以及.docx项目报告和停用词表等配套材料整体大小约91.14MB目录结构清晰便于按模块理解与复用。资源已有133人浏览学习说明其实用性得到一定认可。通过源码、数据集和报告读者可完整掌握文本预处理、特征提取、模型训练与评估流程并能在本地快速复现实验或基于现有代码进行参数调优与功能扩展是入门文本分类任务的优质参考。1. 为什么用 MLP 做虚假新闻检测Python 3.8 下的完整落地链路这个项目把互联网虚假新闻检测落到了 Python 3.8 和 MLP多层感知机上用一套包含源码、数据集、项目报告的完整资源覆盖了从中文文本预处理到模型训练、超参搜索再到预测输出的全部环节。多数人第一反应是这种文本分类任务该上 BERT 或 LSTM但 MLP 配合 TF-IDF 在数据量不大时并不明显落下风而且训练快、依赖少、可解释性强。这套源码特别适合正在做课程设计、本硕毕设或者刚入门 NLP 文本分类的从业者用来跑通完整流程对有一定经验的人fit.py 和 optimize.py 的代码结构也能直接抽出来复用到自己的分类任务里。整条链路没有黑匣子每一步产出的中间文件都看得见摸得着。2. 预处理与特征工程从 train.csv 到 train.pkl 的转换细节无论后面接的是 MLP 还是别的分类器中文文本的预处理都是决定模型上限的第一道关卡。这套源码里preprocess.py 承担了原始 CSV 到可训练 pkl 的全部转换工作而 train.pkl 和 test.pkl 正是 fit.py 直接读入的输入。我在复现时把 preprocess.py 拆成三步来理解读原始文本、jieba 分词并过滤停用词、统一序列化成 pkl。任何一步做得不干净后面模型的验证分数都会失真而且这种失真很难从训练日志里直接看出来。2.1 preprocess.py 的职责拆分分词、停用词过滤与序列化落地import pandas as pd import jieba import joblib # 读取原始训练集 train_df pd.read_csv(dataset/train.csv) # 加载停用词表 with open(dataset/cn_stopwords.txt, r, encodingutf-8) as f: stopwords set([line.strip() for line in f.readlines()]) # 分词 停用词过滤 def cut_and_filter(text): text str(text).replace(\n, ).replace(\r, ) words jieba.lcut(text) return .join([w for w in words if w.strip() and w not in stopwords]) train_df[content_cut] train_df[content].apply(cut_and_filter) # 序列化保存 joblib.dump(train_df, dataset/train.pkl) print(train.pkl saved, shape:, train_df.shape)这段代码先把 train.csv 读进 DataFrame用 jieba.lcut 做精确模式分词过滤掉停用词和空字符串后用空格拼接最后用 joblib.dump 序列化保存fit.py 加载时只需 joblib.load 一次不用每次训练重新分词。代码里我在分词前先做了换行符清洗因为新闻文本里常见的 \n 和 \r 如果不处理会被 jieba 当成独立的词元。参数上注意两个点cn_stopwords.txt 的编码必须是 utf-8Windows 下用记事本另存为带 BOM 的 utf-8 时line.strip() 会把 \ufeff 留在第一个停用词上导致过滤失效joblib.dump 默认用 pickle 协议它不保证跨 Python 小版本兼容所以 pkl 生成后最好固定在同一套环境里使用。这样做的核心收益是把计算开销前置——原始数据集如果有一万条以上文本每次训练都重新分词的话单是 jieba 的耗时就能让调试周期翻倍。预处理后的 pkl 相当于把分词结果固化成中间产物后续 fit.py 和 optimize.py 都只加载 pkl不碰原始文本。2.2 停用词表 cn_stopwords.txt中文文本分类里最容易忽略的调参项停用词表在源码里是 cn_stopwords.txt看起来是个辅助文件实际上是影响 MLP 效果最直接的隐性参数。这份停用词表覆盖了常见中文虚词、标点和无意义动词比如的了在是这类高频但不携带类别信息的词。过滤它们能让 TF-IDF 的词汇表更聚焦在辟谣官方举报这类有判别力的实义词上。单纯从数量上堆词表没有意义关键是看它是否匹配你的数据分布。# 统计当前文本中的高频词辅助判断是否该追加停用词 from collections import Counter with open(dataset/cn_stopwords.txt, r, encodingutf-8) as f: stopwords set([line.strip() for line in f.readlines()]) # 假设 train_df 已经过 2.1 的预处理 word_counter Counter() for line in train_df[content_cut]: for w in line.split(): if w not in stopwords: word_counter[w] 1 print(word_counter.most_common(30))追加停用词是个反复迭代的活。我一般会先用原始停用词表训一版然后从 MLP 预测错误的样本里抽几篇把重复出现的记者来源编辑这类内容型词加进停用词表再训一版对比验证集准确率。如果加了之后 f1 没有变化说明这个词本来就不影响判别如果 f1 掉了说明这个词实际携带了类别信息需要回滚。修改停用词表后必须重新生成 pkl因为 fit.py 读入的是预处理缓存不重跑 preprocess.py 的话改表不会生效。这里有一个容易忽略的点停用词表不是越大越好。过度过滤会把不是没有这类带否定语义的词也干掉而虚假新闻里没有证据不是事实恰恰是关键信号。我见过有人把网上找的 2000 词停用词表直接套上去模型 f1 反而掉了 3 个点。所以追加停用词时每次只加一批跑完验证看分数变化再决定是否保留。2.3 TF-IDF 向量化参数的选择max_features、ngram_range 和 sublinear_tf分词之后是对齐特征维度的问题。这份源码里 TF-IDF 向量化放在训练流程中完成但无论放在 preprocess.py 还是 fit.py三个参数决定了最终送入 MLP 的特征矩阵长什么样max_features 控制词汇表大小ngram_range 决定是否保留词组顺序信息sublinear_tf 用 log 缩放词频来压制高频词的绝对优势。from sklearn.feature_extraction.text import TfidfVectorizer vectorizer TfidfVectorizer( max_features5000, ngram_range(1, 2), sublinear_tfTrue, min_df2, max_df0.8 ) # 训练集只 fit_transform测试集只 transform X_train vectorizer.fit_transform(train_df[content_cut]) X_test vectorizer.transform(test_df[content_cut])max_features 取 5000 是对内存和效果的折中。中文新闻词汇量大设 10000 以上特征矩阵会显著变大MLP 输入层节点数跟着上涨训练变慢且容易过拟合设 2000 以下又可能漏掉低频但有判别力的词。ngram_range 从 (1,1) 扩到 (1,2) 能捕捉官方发布紧急通知这类两词搭配真假新闻在措辞上的差异往往藏在词组层面。min_df 过滤只出现一两次的生僻词max_df 过滤超过 80% 文档都出现的高频词这两个参数配合停用词表一起压制噪声比单纯堆停用词更系统。一个容易踩的细节是TfidfVectorizer 默认会对每个文档做 L2 归一化这对 MLP 是友好的能让输入向量的尺度一致避免某些特征因为文档长度差异过大而主导梯度更新。另外如果原始数据是爬虫抓来的新闻文本里面会混入大量 HTML 实体、URL 和 emoji预处理时最好先做一轮规则清洗否则 jieba 会把httpwwwcom切成特征词白白占用 max_features 的额度。3. MLP 分类器与训练模块fit.py 的参数设计与收敛处理预处理解决的是输入长什么样fit.py 解决的是模型怎么训。这个项目选择 MLP 而不是朴素贝叶斯或 SVM核心原因在于 MLP 能学到特征之间的非线性组合。互联网新闻文本经过 TF-IDF 后是稀疏高维向量真假新闻的区别往往藏在多个词的组合关系里线性模型很难抓住这种模式。MLP 在这类任务上虽然不如深度学习模型上限高但胜在训练速度快、超参数直观、对硬件没有要求在课程设计和中小规模数据场景下是性价比最高的选择。3.1 MLPClassifier 的核心参数表hidden_layer_sizes、activation、alpha 怎么配MLPClassifier 是 scikit-learn 对多层感知机的封装fit.py 里最需要认真设的参数集中在下面这张表我按复现时的实际优先级排了序参数项目推荐值作用调整建议hidden_layer_sizes(100,)隐藏层神经元数数据量小用 (100,)数据量大试 (128, 64)activationrelu激活函数relu 默认即可tanh 可以试logistic 偏慢solveradam权重优化器特征稀疏时 adam 收敛更稳alpha0.0001L2 正则化系数过拟合时调到 0.001欠拟合降到 1e-5max_iter500最大迭代次数默认 200 经常不够报收敛警告就加大random_state42随机种子固定否则每次运行结果不一样hidden_layer_sizes 是这里的核心。单一隐藏层 (100,) 对 5000 维的 TF-IDF 输入已经够用因为特征本身是带语义的可解释单元不需要太深的网络来重新提取特征。两层 (50,50) 在数据量充足时能学更复杂的组合模式但训练时间和过拟合风险同步上升。我自己的习惯是先用 (100,) 跑基线看验证集和训练集的准确率差距差距在 2% 以内说明模型容量合适训练集远高于验证集说明过拟合需要加大 alpha 或减小网络两者都低说明欠拟合再考虑加深网络。activation 用 relu 是因为它在深层网络中能缓解梯度消失而且计算代价低。alpha 是 L2 正则化系数默认 0.0001 在多数场景下够用但它对 MLP 的影响比想象中大——alpha 太大模型会偏向欠拟合太小又容易让权重过度拟合训练集里的噪声。基础调参路线是先把 hidden_layer_sizes 固定扫 alpha 的 1e-5 到 1e-2 对数区间确定合适正则强度后再调网络深度。3.2 fit.py 训练流程拆解加载 pkl、训练模型、joblib 持久化fit.py 的结构非常清晰加载预处理好的 train.pkl划分训练验证集构造 MLPClassifier 训练然后把模型存进 model 文件夹。拆开看就是下面这一段核心逻辑import pandas as pd import joblib from sklearn.neural_network import MLPClassifier from sklearn.model_selection import train_test_split from sklearn.metrics import accuracy_score, f1_score from sklearn.feature_extraction.text import TfidfVectorizer # 加载预处理后的数据 train_df joblib.load(dataset/train.pkl) X train_df[content_cut] y train_df[label] # 向量化 划分训练验证集 vectorizer TfidfVectorizer(max_features5000, ngram_range(1, 2), sublinear_tfTrue) X_vec vectorizer.fit_transform(X) X_train, X_val, y_train, y_val train_test_split( X_vec, y, test_size0.2, random_state42, stratifyy ) # 训练 MLP mlp MLPClassifier( hidden_layer_sizes(100,), activationrelu, solveradam, alpha0.0001, max_iter500, random_state42 ) mlp.fit(X_train, y_train) # 验证并保存 y_pred mlp.predict(X_val) print(val acc:, accuracy_score(y_val, y_pred)) print(val f1:, f1_score(y_val, y_pred, averagebinary)) joblib.dump(mlp, model/mlp_model.pkl) joblib.dump(vectorizer, model/tfidf_vectorizer.pkl)train_test_split 里的 stratifyy 很关键它保证划分后的训练集和验证集里真假新闻比例与原数据集一致。虚假新闻数据集常见类别不平衡如果真实新闻占 80%随机划分可能让验证集全是真实新闻准确率虚高却没意义。模型训练完成后mlp 和 vectorizer 都必须持久化因为 predict.py 做推理时既需要模型权重也需要同一份词表来计算 TF-IDF 特征——只用模型不用向量化器测试数据根本没法转换成特征矩阵。max_iter500 是为了给 adam 足够的迭代步数。sklearn 的 MLPClassifier 默认 max_iter200中文文本特征维度高200 步经常达不到收敛条件训练日志里会出现 ConvergenceWarning。如果看到这个警告先别急着调参把 max_iter 加到 500 或 1000 重跑看损失曲线是否走平再决定下一步。验证集划分比例固定 0.2 即可test_size 再大模型会训练不足再小验证结果波动会变大。3.3 solver 选 adam 还是 lbfgs两个优化器在中文新闻场景下的实际差异fit.py 用 solveradam 是合理的。MLPClassifier 提供 lbfgs、sgd、adam 三个优化器lbfgs 是拟牛顿法在数据量小、特征维度低时收敛快且稳定但需要近似计算 Hessian 矩阵特征维度一旦过万内存开销明显上升sgd 需要手动调 learning_rate 和 momentum超参数多一个新手很容易调出震荡不收敛的曲线adam 是自适应矩估计对学习率不那么敏感在稀疏特征上表现稳定。TF-IDF 向量化后的特征矩阵是典型的高维稀疏结构大部分样本在很多维度上取值为 0adam 能对不同维度自适应调整步长所以收敛速度在这类数据上普遍优于 sgd。如果要严谨对比可以把 solver 换成 lbfgs 跑一版用相同的数据和隐藏层结构看验证集 f1体验比口头描述直观得多。我自己在类似数据集上测过adam 和 lbfgs 的最终 f1 差距通常在 0.5% 以内但 adam 的收敛曲线更平滑不容易出现中途发散的情况。有一个参数容易被忽略learning_rate_init 默认 0.001这是 adam 的初始学习率。在文本分类任务里如果发现损失曲线下降极慢可能是学习率偏小如果损失曲线震荡剧烈可能是偏大。调这个参数的优先级低于调 alpha 和 hidden_layer_sizes但比调 activation 高值得在 optimize.py 里纳入搜索空间。4. optimize.py用 GridSearchCV 自动搜索超参数不靠手感调fit.py 里的参数是一次性定的但真实项目里这些参数到底取多少最合适需要用 optimize.py 来回答。这个模块用 GridSearchCV 在参数网格上做交叉验证搜索把 hidden_layer_sizes、alpha 这些参数的组合自动跑一遍返回最优参数组合。我跑完 optimize.py 后最大的感受是手动调参和网格搜索之间的差距在 MLP 上比在树模型上更大因为 MLP 对参数的耦合反应更敏感单变量调参很难找到好的组合。4.1 搜索空间怎么设计哪些参数值得搜、哪些参数别浪费算力GridSearchCV 的搜索空间不是越大越好MLP 的参数组合爆炸速度非常快。hidden_layer_sizes 有三个候选值alpha 有四个候选值组合就是 12 个每个组合再乘交叉验证的折数就是几十次 MLP 训练。MLP 本身就比逻辑回归慢得多搜索空间设计不好一次 optimize.py 跑几个小时很正常。所以搜索前要想清楚哪些参数值得搜哪些固定就好。from sklearn.model_selection import GridSearchCV from sklearn.neural_network import MLPClassifier param_grid { hidden_layer_sizes: [(50,), (100,), (50, 50)], alpha: [0.0001, 0.001, 0.01], solver: [adam], activation: [relu], learning_rate_init: [0.001, 0.0001] } grid GridSearchCV( MLPClassifier(max_iter500, random_state42), param_gridparam_grid, cv3, scoringf1_macro, n_jobs-1, verbose1 ) grid.fit(X_train_vec, y_train) print(best params:, grid.best_params_) print(best f1:, grid.best_score_)我一般把 activation 和 solver 固定成 relu 和 adam不去搜原因是这两个参数在中文文本场景下几乎没有悬念搜它们只是白白把搜索空间扩大一倍。值得搜的是 hidden_layer_sizes、alpha 和 learning_rate_inithidden_layer_sizes 决定模型容量alpha 控制正则强度learning_rate_init 对稀疏特征的收敛速度有实际影响。scoring 用 f1_macro 而不是 accuracy因为在虚假新闻这种类别不平衡的数据上全部预测为多数类也能拿到相当高的准确率只有 f1 能反映少数类被分对了多少。cv3 而不是 5是为了控制总训练次数。3 折交叉验证在 18 个参数组合下是 54 次 MLP 训练5 折就是 90 次耗时接近翻倍而 f1 估计的稳定性提升有限。n_jobs-1 会让 GridSearchCV 使用全部 CPU 核并行训练但需要注意MLP 训练本身是多线程的n_jobs-1 配合底层 OpenBLAS 的线程池反而可能造成资源争抢如果发现 CPU 跑满但速度没有提升可以试试 n_jobs1 配合单线程对比。4.2 搜索结果如何回流到 fit.py从 grid.best_params_ 到最终训练脚本GridSearchCV 跑完最优参数不会自动更新到 fit.py 里。这里有两种做法一种是把 grid.best_params_ 打印出来手动抄回 fit.py另一种是在 fit.py 里直接读一份 JSON 参数配置。原项目的做法偏向前者fit.py 里参数是写死的这更适合课程设计和报告展示因为步骤清晰、每个参数都能在报告里单独解释。手动抄写要特别小心数值精度0.0001 和 0.001 差一个数量级抄错一次模型效果就会有肉眼可见的差异。# 从网格搜索结果生成最终训练配置 import json best grid.best_params_ # 补上不需要搜索但必须指定的参数 fit_config { hidden_layer_sizes: best[hidden_layer_sizes], alpha: best[alpha], learning_rate_init: best[learning_rate_init], activation: relu, solver: adam, max_iter: 500, random_state: 42 } with open(model/best_params.json, w, encodingutf-8) as f: json.dump(fit_config, f, indent2, ensure_asciiFalse) print(json.dumps(fit_config, indent2, ensure_asciiFalse))把最优参数落成 JSON 的好处是 fit.py 里可以直接读取训练和搜索共用同一份参数源避免手动抄写出错。网格搜索的另一个价值是给出了参数的稳定区间比如搜索结果里 alpha 取 0.001 和 0.0001 的 f1 差距只有 0.003说明这个参数不敏感选更小的 alpha 让模型保留更多细节即可如果差距接近 1%说明这个参数是决定性的值得在最终报告里作为核心结论展开。我一般会记录搜索过程中每个参数组合的得分而不是只看最优解这能帮你理解模型对哪些参数敏感后续做特征工程时思路更清晰。5. 避坑与常见问题五个我在复现过程中实际翻车的位置这份源码整体能跑通但我在复现过程中换了环境、改了数据翻了好几次车。下面五个坑按现象、原因、解决三个维度拆解每一个都是实际踩过的不是从文档里抄来的理论问题。这些坑分布在从预处理到预测的各个阶段任何一个都可能导致最终结果和项目报告里的分数对不上。5.1 train.pkl 换机器后 load 报 UnicodeDecodeError现象是运行 predict.py 加载 train.pkl 时报 UnicodeDecodeError: utf-8 codec cant decode byte 0x80。第一次遇到时我以为是文件损坏重新下载了一遍还是一样。原因是 joblib 序列化的 pkl 文件依赖 Python 版本和 joblib 版本的一致性。原项目用 Python 3.8.0 和 joblib 1.1.0 生成 pkl我的环境是 Python 3.9 加更新的 joblibpickle 协议不兼容反序列化时字节流解析失败。pkl 本质上是 pickle 协议的字节流跨小版本升级时协议版本号不匹配就会报这种错。解决方法是不要试图直接加载旧 pkl回到 preprocess.py 重新执行一遍生成新环境下的 pkl。这也养成一个习惯pkl 是缓存产物不是数据源train.csv 和 test.csv 才是原始数据重跑预处理最多一两分钟永远优先重新生成而不是跨环境迁移 pkl。如果项目交付时要换环境演示最好连源码带 CSV 一起给让对方自己生成 pkl避免协议不兼容的问题。5.2 MLP 训练时反复触发 ConvergenceWarning现象是 fit.py 跑训练时 sklearn 弹出 ConvergenceWarning提示 max_iter 达到上限但未收敛。第一次遇到我以为代码写错了排查了半天发现是 max_iter 太短不是代码问题。原因是 MLPClassifier 默认 max_iter200在 5000 维特征、一万条样本上adam 优化器 200 步不足以让损失降到平台期。特征维度高、样本量大时每轮迭代的计算量大需要更多轮数才能充分优化。这不是 bug是默认参数在文本分类场景下不适用。解决方法是把 max_iter 调大同时观察 loss_curve。如果损失曲线在训练结束前还在明显下降继续加大 max_iter 到 800 或 1000如果损失已经走平但优化器还没退出说明 tol 设得太严可以把 tol 从默认 1e-4 放宽到 1e-3。注意 max_iter 超过 1000 步还没收敛多半是学习率偏小或特征设计有问题不是迭代次数不够这时候加大迭代次数只会白白浪费时间。5.3 TF-IDF 在训练集和测试集上重复 fit 导致验证分数失真现象是验证集 f1 高得离谱接近 1.0但测试集表现一塌糊涂。我最初以为模型训练得特别好后来发现是特征空间错位导致的假象。原因是自己在写预处理代码时对训练集做了 fit_transform对测试集也做了 fit_transform。TfidfVectorizer 在测试集上独立 fit 会生成一套全新的词汇表特征维度和训练集完全不同。MLP 训练时学到的是训练集特征维度的权重测试时输入的是另一套特征维度的向量模型相当于在随机猜测而交叉验证恰好把这个错误掩盖了——验证集是在训练集特征空间内划分的测试集的错误在验证阶段暴露不出来。解决方法是严格遵循训练集只 fit_transform测试集只 transform。transform 会沿用训练集拟合出的词汇表和 IDF 权重保证特征空间一致。这也是这份源码把向量化放在 fit.py 单一位置而不是分散在多个脚本里的原因从架构上避免了这个问题。5.4 predict.py 输出的 mlp_pred.txt 行数比 test.csv 少现象是跑完 predict.py 后对比 mlp_pred.txt 和 test.csv 的行数发现预测结果少了十几行。我第一次对比时还用 wc -l 数了两遍确认不是自己数错。原因是预测脚本在处理文本时丢弃了空值样本。中文新闻数据里经常混入空行或纯标点符号的脏数据分词后变成空字符串模型无法处理这些样本预测脚本可能直接跳过导致最终输出行数比测试集少。解决方法是保持 test.csv 的行号索引预测结果按行号对齐写入。对空文本样本在预处理阶段填充一个特殊标记词比如空保证每条测试样本都有对应的预测输出。行数对齐是文本分类项目里最容易被忽略的检查项预测结果行数不对后面所有评价指标都会错位。我后来写预测脚本都会先断言 len(predictions) len(test_df)不等就直接抛异常而不是默默跳过。5.5 jieba 加载自定义词典后分类效果反而变差现象是尝试给 jieba 加专业领域词典来提升分词质量结果验证集 f1 反而下降了 2 到 3 个点。我一开始不理解分词更准了分类效果怎么反而更差原因是自定义词典里的词大多是领域专有名词但项目的新闻数据是通用社会新闻专有名词的粒度更细反而稀释了原有特征。TF-IDF 的词表容纳了更多低频专有词MLP 无法从这些低频词学到有效模式反而挤掉了原本有判别力的通用词特征。分词质量提升不等于分类效果提升两者之间的传导并不是直接的。解决方法是先用原始分词跑一版作为基线再加载自定义词典跑一版做对比f1 提升才保留否则回滚。不要指望自定义词典一定能提升效果在通用领域数据上往往适得其反。如果确实要用词典里只放那些出现频率高且带有明显真假信号的专业词比如卫健委辟谣疫苗这类而不是把一本专业词典整本灌进去。6. 从这份源码迁移到新数据集predict.py 的复用与扩展技巧6.1 predict.py 的运行链路从 .pkl 模型到 mlp_pred.txtpredict.py 的核心价值在于展示训练好的模型如何被用于推理。它加载 model 文件夹里保存的 mlp_model.pkl 和 tfidf_vectorizer.pkl用同一套向量化器转换测试数据再输出预测结果到 mlp_pred.txt。这套链路在课程设计里是完整的交付形态在真实项目里对应模型上线前的离线批量预测流程。复现时我有一个习惯先跑出一版预测结果抽样 20 条人工对比原文和预测标签确认预测不是全猜一个类后才继续往下做。有些数据集里真实新闻和虚假新闻本身就能通过某些强特征区分哪怕模型只学到一个词也能拿到不错的分数抽样检查能帮你判断模型到底学到了什么。迁移改动点原始配置迁移建议停用词表cn_stopwords.txt按新数据的高频噪声词重新过滤max_features5000数据量翻倍时调大反之调小hidden_layer_sizes(100,)用网格搜索在新数据上重新确认类别比例训练集自带新数据若不平衡stratify 参数必须保留6.2 迁移到自有数据集的三个改动点如果要把这套源码迁移到自己的新闻数据集最值得改的是停用词表、TF-IDF 的 max_features、MLP 的 hidden_layer_sizes。停用词表要按自己数据的噪声词重新过滤——比如财经新闻里的股市涨停、体育新闻里的比赛进球这些词在特定领域里可能没有判别力但在通用数据里有直接套用通用停用词表会让特征空间被领域高频词污染。max_features 根据数据量调整英文或已分词文本需要重新评估 ngram_range。hidden_layer_sizes 必须结合网格搜索重新确定而不是沿用原参数——上一份数据的最优网络结构换一份数据很可能不是最优。我之前复现这个项目时犯的最大错误是跳过了 optimize.py 直接跑 fit.py把参数随手填了就训练结果验证集 f1 和项目报告里的分数差了一大截。后来我养成了一个习惯每次拿这类源码强制走完整流程预处理—基线训练—网格搜索—用最优参数重训—推理验证确认每一步的输出文件都能对上拿到的分数才可信。先把链路跑通再谈优化和魔改顺序反过来一定会翻车。希望这套复现路径能帮到你少走我走过的弯路。本文还有配套的精品资源点击获取
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进