本项目基于给定的“文本 + 图像”配对数据,完成三分类情感识别:positive / neutral / negative。
模型架构严格按要求实现:
- 双模态编码:文本用 BERT,图像用 ViT
- 融合方式:支持前期融合 / 中期融合 / 后期融合(三种可对比)
- 分类头:拼接两端 CLS 表征后做 3 类分类
融合方式定义:
- 前期融合(early):先把文本 token 序列与图像 patch token 序列拼接,然后用轻量 Transformer self-attention 做跨模态交互。
- 中期融合(middle):双编码器先各自编码,再用 Cross-Attention(双向:Text→Image 与 Image→Text) 做 token 级别交互(本项目默认)。
- 后期融合(late):不做 token 级交互,仅取文本/图像的 CLS 向量拼接后分类。
补充两种对比基线(新增):
- CLIP(clip):使用 CLIP 预训练的图文对齐表征(text/image pooled embedding),拼接后接分类头。
- BLIP(blip):使用 BLIP 预训练的图文表征(text/image embedding),拼接后接分类头。
数据位于 data/:
data/train.txt:CSV(表头为guid,tag),tag为negative/neutral/positivedata/test_without_label.txt:CSV(表头为guid,tag),tag全为nulldata/data/:配对文件data/data/<guid>.txt:文本data/data/<guid>.jpg:图片
code/data.py:读取索引 CSV,并加载<guid>.txt与<guid>.jpgcode/collator.py:Tokenizer + ImageProcessor 的 batch 组装code/model.py:BERT+ViT 双编码器 + 三种融合方式(early/middle/late)+ 分类头code/train.py:训练/验证/保存 checkpointcode/predict.py:加载 checkpoint,对测试集输出预测code/utils.py:标签映射、随机种子、checkpoint 读写
建议 Python 3.10/3.11(Windows 可用)。
1)创建环境:
conda create -n ai_project5 python=3.10 -y
conda activate ai_project52)安装依赖:
pip install -r requirements.txt说明:requirements.txt 记录了本实验的主要依赖(PyTorch / Transformers / sklearn / pandas 等)。
默认使用:
- 文本编码器:
bert-base-uncased - 图像编码器:
google/vit-base-patch16-224-in21k
在仓库根目录运行:
python -m code.train --data_dir data --output_dir outputs --epochs 3 --batch_size 16如需在每个 epoch 的验证阶段打印混淆矩阵:
python -m code.train --data_dir data --output_dir outputs --epochs 3 --batch_size 16 --print_cm常用可调参数:
--text_model:替换 BERT 预训练模型--image_model:替换 ViT 预训练模型--clip_model:CLIP 预训练模型(仅--fusion_mode clip生效)--blip_model:BLIP 预训练模型(仅--fusion_mode blip生效)--max_length:文本最大长度(默认 128)--d_model/--num_heads:Cross-Attention 融合维度与头数--fusion_mode:融合方式(early/middle/late/clip/blip)--early_fusion_layers:前期融合 Transformer 层数(仅early生效)--fp16:启用 AMP(仅 CUDA 时生效)--device:指定运行设备(auto/cpu/cuda/cuda:0/cuda:1等)--print_cm:验证阶段打印混淆矩阵--eval_ablation:验证阶段额外评估 text-only / image-only 消融表现--eval_preprocess_ablation:验证阶段额外评估 数据预处理消融(切换文本清洗开关、以及验证时启用图像增强的鲁棒性评估)--no_text_clean:关闭文本清洗(默认开启)--no_image_aug:关闭训练图像增强(默认开启;验证/测试不增强)--early_stop_patience:早停耐心值(连续多少个 epoch 无提升就停止;0 表示关闭)--early_stop_metric:早停监控指标(val_f1_macro/val_loss/val_acc,默认val_f1_macro)--early_stop_min_delta:认为“有提升”的最小变化量(默认 0.0)--select_best_metric:选择/保存最佳模型的指标(val_f1_macro/val_loss/val_acc,默认val_f1_macro)--label_smoothing:label smoothing(0 关闭;常用 0.05~0.15)--grad_clip_norm:梯度裁剪(0 关闭;如 1.0/2.0 可提升稳定性)--freeze_backbone_epochs:前 N 轮冻结 backbone(0 关闭;小数据集常用 1~3)--backbone_lr:backbone 学习率(-1 表示用--lr)--head_lr:融合/分类头学习率(-1 表示用--lr;常用略大于 backbone)--class_weighting:类别加权(none/inverse_freq,类别不均衡时可尝试)
如果你觉得 epoch 太少曲线不稳定,可以把 --epochs 设大一些并开启早停(推荐监控 val_f1_macro):
python -m code.train --data_dir data --output_dir outputs_middle --fusion_mode middle --epochs 30 --batch_size 16 --seed 42 --early_stop_patience 3 --early_stop_metric val_f1_macro如果你遇到“train_loss 一直下降但 val_loss 从一开始就上升/越训越差”,这通常是过拟合。可以改成按 val_loss 早停,并且按 val_loss 保存最优 checkpoint:
python -m code.train --data_dir data --output_dir outputs_middle --fusion_mode middle --epochs 30 --batch_size 16 --seed 42 --early_stop_patience 2 --early_stop_metric val_loss --select_best_metric val_loss训练会自动从 train.txt 按 --val_ratio 做分层划分验证集,并以 macro-F1 选择最佳模型,保存到:
outputs/best_checkpoint.pt
同时会把每次实验的配置与每个 epoch 的验证结果追加保存到:
<output_dir>/experiment_results.txt
为方便后续可视化(loss/acc/F1 曲线、消融对比等),还会输出结构化文件(每次运行覆盖,只保留最新一次实验):
<output_dir>/metrics.csv:每个 epoch 一行(包含 val 指标与可选的消融指标)<output_dir>/run_config.json:本次运行的参数与标签顺序
- 文本清洗(默认开启):对文本做 Unicode 规范化、去除不可见/控制字符、压缩多余空白等。
- 图像增强(仅训练集,默认开启):随机裁剪、翻转、颜色扰动等;验证/测试不做增强以保证评估稳定。
如需关闭:
python -m code.train --data_dir data --output_dir outputs --no_text_clean --no_image_aug说明:训练图像增强依赖 torchvision。
为了公平对比,建议保持:同随机种子(--seed)、同数据划分(脚本固定按 seed 分层划分)、同 epoch/学习率等超参。
1)前期融合(early):
python -m code.train --data_dir data --output_dir outputs_early_tuned --fusion_mode early --early_fusion_layers 2 --epochs 30 --early_stop_patience 3 --early_stop_metric val_f1_macro --select_best_metric val_f1_macro --freeze_backbone_epochs 2 --backbone_lr 1e-5 --head_lr 5e-5 --label_smoothing 0.1 --grad_clip_norm 1.0 --print_cm --eval_ablation --eval_preprocess_ablation2)中期融合(middle,默认 Cross-Attention):
python -m code.train --data_dir data --output_dir outputs_middle_tuned --fusion_mode middle --epochs 30 --early_stop_patience 3 --early_stop_metric val_f1_macro --select_best_metric val_f1_macro --freeze_backbone_epochs 2 --backbone_lr 1e-5 --head_lr 5e-5 --label_smoothing 0.1 --grad_clip_norm 1.0 --print_cm --eval_ablation --eval_preprocess_ablation3)后期融合(late):
python -m code.train --data_dir data --output_dir outputs_late_tuned --fusion_mode late --epochs 30 --early_stop_patience 3 --early_stop_metric val_f1_macro --select_best_metric val_f1_macro --freeze_backbone_epochs 2 --backbone_lr 1e-5 --head_lr 5e-5 --label_smoothing 0.1 --grad_clip_norm 1.0 --print_cm --eval_ablation --eval_preprocess_ablation4)CLIP(clip):
python -m code.train --data_dir data --output_dir outputs_clip_tuned --fusion_mode clip --clip_model openai/clip-vit-base-patch32 --epochs 30 --early_stop_patience 3 --early_stop_metric val_f1_macro --select_best_metric val_f1_macro --freeze_backbone_epochs 2 --backbone_lr 1e-5 --head_lr 5e-5 --label_smoothing 0.1 --grad_clip_norm 1.0 --print_cm --eval_ablation --eval_preprocess_ablation5)BLIP(blip):
python -m code.train --data_dir data --output_dir outputs_blip_tuned --fusion_mode blip --blip_model Salesforce/blip-itm-base-coco --epochs 30 --early_stop_patience 3 --early_stop_metric val_f1_macro --select_best_metric val_f1_macro --freeze_backbone_epochs 2 --backbone_lr 1e-5 --head_lr 5e-5 --label_smoothing 0.1 --grad_clip_norm 1.0 --print_cm --eval_ablation --eval_preprocess_ablation在验证集上额外评估:
- text-only:只输入文本(图像置空)
- image-only:只输入图像(文本置空)
运行示例:
python -m code.train --data_dir data --output_dir outputs_middle --fusion_mode middle --epochs 3 --batch_size 16 --seed 42 --print_cm --eval_ablation如果你还想评估“数据预处理”的影响(文本清洗开/关、以及对验证集做图像增强的鲁棒性):
python -m code.train --data_dir data --output_dir outputs_middle --fusion_mode middle --epochs 3 --batch_size 16 --seed 42 --print_cm --eval_ablation --eval_preprocess_ablation结果会同时打印到控制台,并写入 <output_dir>/experiment_results.txt
对 data/test_without_label.txt 进行预测并输出 CSV:
python -m code.predict --data_dir data --checkpoint outputs/best_checkpoint.pt --output outputs/test_predictions.csv输出文件格式:
guid,tagtag为negative/neutral/positive
训练完成后,每个实验目录下会生成:
metrics.csv(每个 epoch 一行)run_config.json
安装依赖:
pip install -r requirements.txt生成对比图(示例:对比 early/middle/late 三次实验):
python -m code.plot_metrics --inputs outputs_early outputs_middle outputs_late --out_dir plots如果你要把 early/middle/late/clip/blip 五种方法一起对比:
python -m code.plot_metrics --inputs outputs_early outputs_middle outputs_late outputs_clip outputs_blip --out_dir plots输出图像默认保存在 plots/:
loss.png(train/val loss 同图,平滑曲线)val_acc.png/val_f1_macro.pngablation_acc.png/ablation_f1_macro.png(仅当运行时开启过--eval_ablation才有意义)
如果你想用“val_f1_macro 最好的一轮”来做消融柱状图,而不是最后一轮:
python -m code.plot_metrics --inputs outputs_middle --out_dir plots --pick best_f1