
简介这份资源面向希望入门或实践文本分类的开发者与安全方向学习者提供了一套基于深度学习的网络欺凌网络暴力检测完整方案可用于识别带有攻击性、侮辱性的言论适合作为课程设计、毕业项目或NLP实战练手的参考。压缩包共8个文件约2.66MB包含2个ipynb笔记本、2个json数据与词表文件、1个py脚本、1个h5模型、1个md说明及1个license覆盖从数据、训练到推理的完整链路。其中训练数据集以逐行json对象组织训练笔记本展示模型构建与训练流程推理脚本与笔记本给出可直接运行的调用示例已训练好的模型与词表文件省去重复训练成本只需安装keras、tensorflow、numpy即可加载使用。目前已有200人学习下载读者可借此理解文本预处理、词表构建、模型训练与预测的完整实现并在此基础上替换数据或调整网络结构快速搭建自己的网络暴力检测原型。1. 从一条评论说起网络欺凌检测到底在做什么社交平台上一条“你怎么这么废物”的评论人眼一秒就能判断是攻击但要让机器自动识别背后是一整套文本分类工程。这个项目标题讲的就是用 Python 和深度学习做网络欺凌Cyberbullying检测交付物包括源代码、数据集和使用说明。它解决的核心问题是给定一条评论文本模型输出它是否属于欺凌、辱骂或攻击性内容。适合谁有 Python 基础、想找一个完整 NLP 二分类项目练手的学生和初级工程师也适合需要给社区产品加一层内容审核能力的开发者。数据集通常来自 Twitter、Kaggle 或 Formspring 等公开语料标签多为二分类bully / non-bully。别小看这个任务它比情感分析难——讽刺、反语、谐音脏话都会让模型翻车这也是它值得动手的原因。2. 数据管道从原始 CSV 到模型能吃的张量2.1 先搞清楚数据集长什么样这类项目的数据集一般是 CSV 或 TSV两列最关键text和label。常见来源是 Kaggle 的 Cyberbullying Classification 数据集标签可能是多类age、ethnicity、gender、religion、other也可能是二分类。拿到手第一步不是急着建模而是先做数据体检。用 pandas 读进来看类别分布、文本长度分布、有没有空值。import pandas as pd df pd.read_csv(cyberbullying.csv) print(df.shape) print(df[label].value_counts()) # 类别是否均衡 print(df[text].str.len().describe()) # 文本长度分布 print(df.isnull().sum()) # 空值检查逻辑说明value_counts判断是否需要处理类别不平衡如果某一类占比超过 80%准确率就会骗人得看 F1。str.len().describe()看文本长度决定后面max_len设多少。参数说明max_len一般取长度分布的 95 分位常见在 100200 之间设太大浪费算力设太小截断关键信息。2.2 清洗与标签处理别让噪声骗了模型原始文本里有 URL、提及、表情符号、连续空格。清洗策略直接影响效果。我的做法是保留标点因为“”和“”对攻击性判断有用去掉 URL 和 用户名统一小写。import re def clean_text(text): text str(text).lower() text re.sub(rhttp\S|www\S, , text) # 去 URL text re.sub(r\w, , text) # 去 提及 text re.sub(r\s, , text).strip() # 压缩空白 return text df[clean] df[text].apply(clean_text)逻辑说明URL 和 提及对欺凌判断几乎无信息量反而引入噪声。保留标点是血泪经验——去掉感叹号和问号后模型对攻击语气的敏感度明显下降。参数说明正则\w匹配用户名如果数据里有中文用户名要改成[\w\u4e00-\u9fa5]。标签处理上如果是多类标签可以合并成二分类有攻击性 vs 无也可以保留多类做多标签。二分类更适合入门F1 更容易调。类别不平衡时用class_weightbalanced或对少数类过采样别直接复制样本容易过拟合。2.3 分词与向量化Keras 还是 HuggingFace两条路线。路线一KerasTokenizerpad_sequences快、轻、适合教学和快速验证。路线二HuggingFacetransformers加载预训练模型如 BERT效果好但吃显存。先讲路线一因为项目标题强调“源代码数据集”大概率是轻量方案。from tensorflow.keras.preprocessing.text import Tokenizer from tensorflow.keras.preprocessing.sequence import pad_sequences MAX_WORDS 20000 MAX_LEN 120 tok Tokenizer(num_wordsMAX_WORDS, oov_tokenOOV) tok.fit_on_texts(df[clean]) seqs tok.texts_to_sequences(df[clean]) X pad_sequences(seqs, maxlenMAX_LEN, paddingpost, truncatingpost)逻辑说明num_words限制词表大小防止低频词撑爆内存。oov_token处理未登录词。paddingpost在末尾补零truncatingpost截断末尾保持长度一致。参数说明MAX_WORDS20000对多数社交文本够用词表再大收益递减MAX_LEN120覆盖大多数短评论长文本截断会丢信息可以按 95 分位调整。标签用to_categorical转 one-hot或者二分类直接用 0/1。划分训练集验证集用train_test_splitstratifyy保证类别比例一致。3. 模型搭建CNN、LSTM 还是 BERT怎么选不后悔3.1 三个基线模型的结构与取舍文本分类常见三件套TextCNN、BiLSTM、BERT。TextCNN 用不同尺寸卷积核抓 n-gram 特征训练快适合短文本BiLSTM 抓序列依赖对长文本和语序敏感BERT 靠预训练微调效果最好但资源要求高。项目标题没指定模型我一般先跑 TextCNN 做基线再上 BiLSTM 对比最后如果显存够再试 BERT。TextCNN 结构Embedding → 多尺寸 Conv1D → GlobalMaxPooling → Dropout → Dense。核心代码from tensorflow.keras import layers, Model inp layers.Input(shape(MAX_LEN,)) x layers.Embedding(MAX_WORDS, 128)(inp) x layers.Conv1D(128, 3, activationrelu)(x) x layers.GlobalMaxPooling1D()(x) x layers.Dropout(0.5)(x) out layers.Dense(1, activationsigmoid)(x) model Model(inp, out) model.compile(optimizeradam, lossbinary_crossentropy, metrics[accuracy])逻辑说明Embedding 把词索引映射成 128 维向量Conv1D 核大小 3 抓三元组特征GlobalMaxPooling 取最强特征Dropout 防过拟合sigmoid 输出二分类概率。参数说明Embedding 维度 128 是常用起点词表大可以到 256卷积核数量 128 够用多了过拟合Dropout 0.5 是文本任务常见值0.30.5 之间调。BiLSTM 把 Conv1D 换成Bidirectional(LSTM(64))其余类似。BERT 路线用transformers的AutoModelForSequenceClassification输入用 tokenizer 编码微调 23 个 epoch 即可。3.2 训练参数怎么设batch、epoch、学习率history model.fit( X_train, y_train, validation_data(X_val, y_val), epochs10, batch_size64, class_weightclass_weight )逻辑说明batch_size64平衡显存和梯度稳定性epochs10配合 EarlyStopping 防止过拟合class_weight处理不平衡。参数说明学习率默认 adam 的 1e-3如果 loss 震荡就降到 1e-4EarlyStopping 监控val_losspatience2连续两轮不降就停。别迷信大 epoch文本分类 510 轮足够再多就是过拟合。评估不能只看 accuracy。用classification_report看 precision、recall、F1。欺凌检测里 recall 更重要——漏掉一条欺凌比误判一条正常评论代价大。如果 recall 低调低分类阈值从 0.5 降到 0.30.4或者对少数类加权。3.3 用预训练词向量提升小数据集效果如果数据集只有几千条从零训练 Embedding 效果一般。加载 GloVe 或 fastText 预训练词向量初始化 Embedding 层能明显提升。做法是读词向量文件构建词到向量的映射生成 embedding matrix赋给 Embedding 层weights[embedding_matrix]并设trainableFalse或 True 微调。import numpy as np emb_index {} with open(glove.6B.100d.txt, encodingutf-8) as f: for line in f: parts line.split() emb_index[parts[0]] np.asarray(parts[1:], dtypefloat32) emb_matrix np.zeros((MAX_WORDS, 100)) for word, i in tok.word_index.items(): if i MAX_WORDS and word in emb_index: emb_matrix[i] emb_index[word] model.layers[0].set_weights([emb_matrix]) model.layers[0].trainable False逻辑说明用预训练向量填 Embedding 矩阵未登录词保持零向量。trainableFalse冻结词向量小数据集推荐数据量大可以设 True 微调。参数说明GloVe 100d 和 200d 都常用100d 够轻量词表覆盖不到的词用零向量不影响训练。4. 避坑与排查那些让 F1 掉 20 个点的细节4.1 类别不平衡导致 accuracy 虚高现象训练完 accuracy 0.92但 F1 只有 0.4少数类几乎全漏。原因数据里正常评论占 90%模型学会全预测多数类就能拿高 accuracy。解决用class_weightbalanced或者改用 F1 作为早停监控指标评估时看classification_report而不是 accuracy。4.2 数据泄漏清洗和划分的顺序错了现象验证集 F1 高得离谱上线后效果崩。原因先对全量数据 fit Tokenizer 再划分验证集词汇信息泄漏到训练过程。解决先train_test_split只用训练集 fit Tokenizer再 transform 验证集。同理过采样只能在训练集做别在划分前做。4.3 讽刺和反语让模型集体翻车现象“你可真聪明”被预测为正常实际是讽刺攻击。原因词面没有脏话模型靠关键词判断抓不到语境。解决换 BERT 类预训练模型或者加入表情、标点、上下文特征。纯 CNN/LSTM 对反语天然弱这是任务边界不是调参能解决的。4.4 中文文本分词没做对现象中文数据集上模型效果差词表里全是单字。原因Keras Tokenizer 默认按空格分词中文没空格整句变成一个 token。解决先用 jieba 分词把词用空格连起来再喂给 Tokenizer。或者直接用 BERT 的中文 tokenizer。import jieba df[clean] df[clean].apply(lambda x: .join(jieba.cut(x)))逻辑说明jieba 切词后用空格连接让 Tokenizer 按词建表。参数说明jieba 默认精确模式够用专业领域可以加载自定义词典。4.5 模型保存与加载不一致现象训练时 F1 0.85加载模型预测结果全乱。原因保存模型时没保存 Tokenizer或者加载后没重新 pad 到相同MAX_LEN。解决Tokenizer 用 pickle 存预测时先texts_to_sequences再pad_sequencesmaxlen必须和训练一致。别只存权重不存结构用model.save(model.h5)存完整模型。5. 从能跑到好用阈值调优与错误分析的具体手法模型跑通只是起点真正决定能不能用的是阈值和错误分析。默认 0.5 阈值在类别不平衡时往往不是最优。做法在验证集上画 precision-recall 曲线找 F1 最大的阈值。from sklearn.metrics import precision_recall_curve, f1_score import numpy as np probs model.predict(X_val).ravel() prec, rec, thresholds precision_recall_curve(y_val, probs) f1s [f1_score(y_val, (probs t).astype(int)) for t in thresholds] best_t thresholds[np.argmax(f1s)] print(最佳阈值:, best_t, F1:, max(f1s))逻辑说明遍历阈值算 F1取最大。参数说明如果业务更看重 recall可以手动选 recall 高、precision 可接受的阈值不一定取 F1 最大。这个阈值要写进使用说明预测时用同一个。错误分析别偷懒。把验证集预测错的样本导出来人工看 50100 条归类错误类型讽刺、谐音脏话、否定句、短文本无上下文。我一般会建一个错误表错误类型例子改进方向讽刺“你可真行”换 BERT加语境谐音脏话“沙雕”自定义词典加谐音表否定句“你不蠢”加否定词特征短文本“滚”保留单字也有攻击性这张表比任何调参都值钱它告诉你模型的天花板在哪。如果讽刺类错误占 40%别死磕 CNN 参数直接上预训练模型。最后一个习惯每次实验记录配置。用个简单表格记模型、词表大小、max_len、学习率、F1。我吃过亏调了三天参数回头发现最好那组没记只能重跑。希望帮到你。本文还有配套的精品资源点击获取