简体中文 | English
这是一个面向课程设计与项目展示的英文 YouTube 评论情感分析项目。项目以
bert-base-uncased 为基线,使用 PyTorch、Hugging Face Transformers 与 Accelerate 完成
Positive / Negative / Neutral 三分类,覆盖数据检查、可复现训练、批量预测、训练曲线和
可选 Streamlit 界面。
仓库只保存源码、文档、匿名化小样例和一张历史训练曲线。原始评论、模型权重、训练日志和 完整预测结果均默认留在本地,避免大文件污染 Git 历史,也减少公开数据中的隐私风险。
当前实验说明:仓库保留的历史曲线显示模型较早出现过拟合,但原始运行日志和独立测试集的 精确报告没有完整保留。因此本文不声明无法复核的准确率或 F1 数值。重新训练后,应以生成的 日志、分类报告和机器可读指标为准。
- 统一 CLI:
train、predict、inspect-data三个子命令; - 支持 CSV、XLSX 和 XLS 输入,并验证模型需要的字段;
- 将可选
VideoTitle与CommentText编码为 sentence pair,支持标题消融实验; - 默认按视频分组隔离训练/验证/测试集,并从多个候选切分中选择类别比例近似方案;
- 以验证集 macro-F1 选模,并记录 accuracy、逐类 classification report 与训练曲线;
- 保存验证集 macro-F1 最优的模型,并在独立测试集上生成结构化报告;
- 提供数据匿名化抽样、token 长度检查和 Streamlit 展示入口;
- 原始数据、作者标识、模型权重、日志和预测结果默认不进入版本控制。
flowchart LR
A["CSV / XLSX / XLS"] --> B["字段校验与隐私清理"]
B --> C["标题 + 评论文本预处理"]
C --> D["BERT Tokenizer"]
D --> E["BERT 三分类微调"]
E --> F["Positive / Negative / Neutral"]
E --> G["模型、日志、指标与训练曲线"]
F --> H["CLI 批量预测 / Streamlit 展示"]
| 模块 | 技术 |
|---|---|
| 深度学习 | PyTorch、Hugging Face Transformers |
| 训练调度 | Accelerate、AdamW、warmup scheduler |
| 数据处理 | pandas、NumPy、scikit-learn |
| 评估 | 项目内固定标签指标模块(accuracy、macro/weighted F1、balanced accuracy) |
| 可视化 | Matplotlib、Streamlit |
| 文件格式 | CSV、openpyxl(XLSX)、xlrd(XLS) |
| 自动化 | unittest、GitHub Actions |
.
├── README.md # 中文项目说明(默认首页)
├── README_EN.md # English documentation
├── main.py # 统一 train/predict/inspect-data CLI
├── src/
│ ├── config.py # 路径、标签和训练超参数
│ ├── data_processor.py # 文本清洗与标签映射
│ ├── train_model.py # BERT 训练实现
│ ├── predict_model.py # 批量预测实现
│ ├── text_length.py # 可独立运行的 token 长度检查工具
│ └── app.py # 可选 Streamlit 界面
├── data/
│ ├── preprocessing_data.py # 匿名化、去重、确定性抽样工具
│ └── sample_comments.csv # 可公开的小型匿名化样例
├── result_images/
│ └── training_metrics_plot_20250610-123453.png
├── docs/
│ ├── MODEL_CARD.md # 模型用途、限制和数据治理
│ └── OPTIMIZATION.md # 优化实验路线
├── tests/ # 单元测试
├── requirements.txt # 运行依赖
├── requirements-dev.txt # 轻量 CI/测试依赖
└── LICENSE # 项目代码 MIT License
models/、logs/、predictions/ 等目录会在运行时使用,但被 .gitignore 排除。
- Python 3.10–3.12;CI 使用 Python 3.11;
- CPU 可以运行数据检查和小规模推理,BERT 微调建议使用 CUDA GPU;
- 完整训练所需显存取决于 batch size、最大长度与是否使用混合精度;
- 首次从 Hugging Face 加载模型需要网络,或事先准备本地模型缓存。
git clone https://github.com/computersciencefreshmen/YouTube_Sentiment_Analysis_BERT.git
cd YouTube_Sentiment_Analysis_BERT
python -m venv .venvWindows PowerShell:
.\.venv\Scripts\Activate.ps1Linux / macOS:
source .venv/bin/activateCPU 或不需要指定 CUDA wheel 的环境:
python -m pip install --upgrade pip
python -m pip install -r requirements.txtCUDA 环境建议先在 PyTorch 官方安装选择器 中选择与
驱动匹配的命令安装 PyTorch,再安装其余依赖。requirements.txt 只声明兼容版本范围,
不固定某个 CUDA wheel:
# 先执行 PyTorch 官网为当前 CUDA 环境生成的安装命令
python -m pip install -r requirements.txt检查运行环境:
python -c "import torch; print('torch:', torch.__version__); print('cuda:', torch.cuda.is_available())"训练命令的默认模型标识为 bert-base-uncased。首次运行时 Transformers 会将模型下载到
Hugging Face 用户缓存,而不是写入 Git 仓库。也可以通过 --model-name 指定其他兼容模型
标识或本地目录。
如需在有网络的机器上提前准备离线目录:
下面的 /path/to/bert-base-uncased 应替换为仓库外或本机缓存中的实际目录:
python -c "from huggingface_hub import snapshot_download; snapshot_download('google-bert/bert-base-uncased', local_dir='/path/to/bert-base-uncased')"
python main.py train --data data/train.csv --model-name /path/to/bert-base-uncased请勿把 pytorch_model.bin、model.safetensors 或其他训练权重直接提交到普通 Git 历史。
| 字段 | 类型 | 训练 | 预测 | 说明 |
|---|---|---|---|---|
VideoTitle |
string | 可选 | 可选 | 存在时作为 sentence A;缺失时使用空标题 |
CommentText |
string | 必需 | 必需 | 评论正文,空文本不应参与训练 |
Sentiment |
string | 必需 | 可选 | Positive、Negative 或 Neutral |
Likes、Replies 等 |
numeric | 可选 | 可选 | 当前 BERT 文本基线不使用 |
字段名必须与表中写法一致;标签会去除首尾空格并按不区分大小写的方式规范化,但值只能是
Positive、Negative 或 Neutral。CSV 建议使用 UTF-8;XLSX 由 openpyxl 读取,旧 XLS
由 xlrd 读取。一个最小示例:
VideoTitle,CommentText,Sentiment
Building a Small Robot,This explanation was clear and useful,Positive
Building a Small Robot,I am not sure how I feel about the result,Neutral
Building a Small Robot,The instructions did not work for me,Negative原始 YouTube 数据可能包含作者名称、频道 ID、评论 ID、视频 ID 和发布时间。先在本地执行:
python data/preprocessing_data.py \
--input /path/to/raw_comments.csv \
--output data/sample_comments.csv \
--sample-size 2000 \
--seed 42脚本默认删除作者名称、作者频道 ID、评论 ID 和发布时间,清理空评论、按标题和评论去重,并
用指定 seed 抽样。VideoID 默认保留,供训练时进行视频级分组切分;真正发布样例前还应按
数据授权决定删除或不可逆映射该字段。--keep-author-metadata 只应在具备合法依据且无需公开
数据时使用。
查看总帮助和子命令帮助:
python main.py --help
python main.py train --help
python main.py predict --help
python main.py inspect-data --help所有命令都应从项目根目录执行。输入文件可以位于任意目录;工具内部不会依赖编辑器设置或 硬编码的个人绝对路径。
python main.py inspect-data --data data/train.csv该命令要求带 Sentiment 的训练数据,只执行字段、标签、空文本、重复文本、视频分组和类别分布
检查,并输出 JSON 报告;它不会加载 tokenizer,也不统计 token 长度。
token 长度工具默认按可选 VideoTitle(sentence A)和 CommentText(sentence B)的真实 BERT
pair 编码统计,用于验证 MAX_SEQUENCE_LENGTH 的覆盖率:
python src/text_length.py \
--input data/train.csv \
--column CommentText \
--model-name bert-base-uncased \
--max-length 128 \
--sample-size 5000 \
--seed 42 \
--output-json results/token_lengths.jsonpython main.py train \
--data data/train.csv \
--model-name bert-base-uncased \
--output-dir models/runs \
--run-name showcase-baseline--output-dir 是多个独立实验 run 的父目录,不是可直接推理的模型目录。上例会生成
models/runs/showcase-baseline/;不传 --run-name 时名称形如
bert-YYYYMMDD-HHMMSS。训练结束后终端会打印实际 run 路径。
不指定 --model-name 时使用 bert-base-uncased;不指定 --output-dir 时使用
models/runs/。新训练流程以验证集 macro-F1 选择最佳模型。当前默认参数为:
实际运行值以 src/config.py 和保存的 run config 为准:
| 参数 | 基线值 | 说明 |
|---|---|---|
| 随机种子 | 42 | 数据划分和训练复现 |
| 划分比例 | 80% / 10% / 10% | train / validation / test |
| Batch size | 16 | 显存不足时继续降低 |
| Learning rate | 2e-5 |
BERT 微调基线 |
| 最大 Epoch | 5 | 达到 early stopping 条件时提前结束 |
| Weight decay | 0.01 |
正则化 |
| Warmup ratio | 0.1 |
学习率预热 |
| Max sequence length | 128 | 按标题/评论 sentence pair 重新检查 |
| Early-stopping patience | 2 | 连续两轮 macro-F1 无充分改善后停止 |
| Label smoothing | 0.05 |
缓解过度自信 |
每次训练在 <output-dir>/<run>/ 中保存一组互不覆盖的实际产物:
best_model/:验证集 macro-F1 最优模型、tokenizer 和selection.json;training_config.json:命令参数、数据指纹、依赖和运行环境;data_report.json、split_report.json:清洗、分组和数据划分审计;history.json、history.csv:逐轮训练/验证指标;test_metrics.json、classification_report.json:独立测试集指标;run_summary.json:最佳 epoch、最佳验证 macro-F1 和最终测试摘要;training_metrics.png、confusion_matrix.png:环境支持 Matplotlib 初始化与写入时生成;对应 JSON 指标始终保存;training.log:本次运行日志。
python main.py predict \
--input data/test.csv \
--model models/runs/showcase-baseline/best_model \
--output-csv predictions/detailed_predictions.csv \
--output-txt predictions/result.txt--model 必须指向具体 run 内的 best_model/,不能指向 --output-dir 父目录或基础 BERT。
预测文件只强制要求 CommentText;VideoTitle 可选,缺失时使用空标题。预测命令不会因为输入
存在 Sentiment 就自动评估;CSV 用于详细结果分析,TXT 提供按样本序号排列的简洁标签。
streamlit run src/app.pyStreamlit 是单条和批量本地推理界面,不在页面内训练模型。它复用 CLI 的数据处理和预测器;
侧栏模型路径同样必须指向某个 run 的 best_model/。训练始终使用 CLI,以保存完整实验产物。
这张曲线显示:
- 训练 loss 持续下降;
- 验证 loss 在较早轮次后持续上升;
- 验证 F1 与 accuracy 在早期达到相对高点,后续没有改善。
图中的 F1 来自历史旧实现,当时使用 weighted-F1;曲线时期代码配置为 batch size 32、学习率
5e-5、5 个 epoch、最大长度 64,未采用当前的 patience 2 与 label smoothing 0.05。新训练流程
改用 macro-F1 选模和当前默认参数,两者不能直接比较。因此,当前最明确的结论是“旧模型出现
过拟合”,而不是某个无法复核的最终分数。原实验缺少完整逐轮日志、数据指纹和独立测试报告,
不能根据图片目测填写精确指标。重新运行后应引用 history.json、test_metrics.json、
classification_report.json、混淆矩阵、数据划分和硬件信息,再把结果表更新到主页。
为定位历史实验的评估风险,曾对旧的本地训练文件做只读审计。该数据不随仓库发布,以下数字 是数据审计记录,不是模型成绩,也不代表未来用户提供的数据:
| 项目 | 审计结果 |
|---|---|
| 总行数 | 9,335 |
唯一 VideoTitle |
3,674 |
| Negative | 34.44% |
| Neutral | 33.56% |
| Positive | 32.00% |
三个标签在这份旧数据中相对均衡,但旧的“按行分层随机 80/10/10”切分存在明显的视频标题
交叉:train–validation 重叠 656 个标题,train–test 重叠 667 个,validation–test 重叠 174 个。
同一视频的标题和语境跨集合出现,会让测试结果偏乐观。因此后续基线应按 VideoID 分组;若
无法使用视频 ID,至少按规范化后的 VideoTitle 分组,并在报告中保存重叠检查结果。
优先级从高到低:
- 按视频分组隔离数据,并在候选切分中近似保持类别分布,排除视频级泄漏;
- 保存固定测试集、数据指纹、运行配置和逐类指标;
- 加入 early stopping,比较 3–5 个 epoch、学习率和正则化强度;
- 对比轻量文本规范化与停用词/词形还原,保留 emoji、标点和否定信息;
- 处理类别不平衡,同时关注 macro F1 与少数类 recall;
- 对比“仅评论”和“标题 + 评论”,确认提升不是视频记忆造成;
- 使用动态 padding、混合精度,并比较 DistilBERT 的速度/精度折中。
完整实验矩阵与停止条件见 docs/OPTIMIZATION.md。用途、限制和数据治理 见 docs/MODEL_CARD.md。
本地执行与 GitHub Actions 相同的核心检查:
python -m pip install -r requirements-dev.txt
python -m compileall -q main.py src data tests
python -m unittest discover -s tests -p "test_*.py" -v
python main.py --help
python main.py train --help
python main.py predict --help
python main.py inspect-data --helpCI 使用轻量依赖,不下载 BERT 权重,也不执行 GPU 训练。模型训练属于需要单独数据和计算资源 的实验任务,不应伪装成普通单元测试。
发布实验结果前记录:
- Git commit 与完整命令;
- Python、PyTorch、Transformers、CUDA 版本;
- CPU/GPU 型号与显存;
- 数据来源、哈希、清洗规则、总量和逐类分布;
- train/validation/test 样本清单与 seed;
- 所有超参数、最佳 epoch 和模型选择指标;
- macro/weighted F1、accuracy、逐类报告和混淆矩阵。
requirements.txt 使用兼容版本范围,便于 CPU/CUDA 环境选择。正式复现实验可在成功运行后额外
保存 python -m pip freeze 输出,但不要把本机路径或凭据写入仓库。
- 基线面向英文评论,不适合直接分析中文或多语混写;
- 讽刺、反语、emoji、缩写和上下文依赖可能导致误判;
- YouTube 评论样本存在主题、地区和用户群体偏差;
- 三分类标签有主观边界,模型性能受标注一致性限制;
- 项目处理离线文件,不包含 YouTube 评论抓取或实时 API 服务;
- 输出是统计模型预测,不能替代人工判断或用于高风险决策。
- 不要提交原始评论、作者名称、频道 ID、访问令牌或私有数据;
- 公开样例必须匿名化,并确认再分发符合数据来源许可与 YouTube 条款;
.gitignore只能防止新的误提交,已进入历史的大文件仍需重写历史才能移除;- 项目原创代码采用 MIT License;
- BERT 基础模型及其 tokenizer 适用自身许可证;
- MIT License 不授予第三方 YouTube 数据的再分发权。
如果将本项目用于课程报告或作品集,建议同时展示一次可复现运行的配置、分类报告、错误分析 和优化前后对照,而不仅是一张训练曲线。
