Multimodal Video Similarity Challenge
@CIKM 2021
第四名解决方案
Implementation source codes of team <618大庆神!>.
Final score: 82.8307 on test_b.
1. 模型总览
我们的最终结果由6个模型的ensemble组成,先在开头概述这6个模型:(test_a上的结果)
Model | single-model | 10fold | weight |
---|---|---|---|
MixNextvlad | 81.2 | 81.6 | 0.17 |
MixNextvlad_ASL | 80.9 | 81.8 | 0.2 |
MixNextvlad_roformer | 80.5 | 81.3 | 0.13 |
Uniter | 80.3 | 81.4 | 0.13 |
Uniter_ASL | 80.6 | x | 0.2 |
Uniter_roformer | 80.2 | x | 0.17 |
部分test_b的结果:
Model | single-model | 10fold | weight |
---|---|---|---|
Uniter | x | 81.4 | 0.13 |
Uniter_ASL | 80.5 | x | 0.2 |
Uniter_roformer | 80.1 | x | 0.17 |
虽然MixNextvlad单模型会高一些,但是10fold之后Uniter模型应该会好一些,因为观察到MixNextvlad模型生成的结果由许多0.
2. 模型介绍
主要使用了两种模型,第一种是基于baseline改进的MixNextvald,在[1]中提出;第二种是基于transformer的Uniter [2]模型。
2.1 MixNextvlad
2.2 Uniter
如图,视频的帧feature和句子的单词embedding经过concat之后送入bert-encoder,输出的features取平均得到最后的embedding。使用该模型时预训练任务增加了MLM(masked language modeling),只对文本进行mask,然后通过上下文的文本和图像特征共同进行MLM。
细解:
模型:视频帧feature+word embedding concat之后送入12层的预训练bert & roformer,得到的features取mean。
pretrain:最终的embedding经过cls层进行tag id的多标签分类;对输入word进行15%的随机mask,然后在输出端预测这些mask的单词(MLM)。
finetune:不再mask,直接用图像特征和文本作为输入,得到mean pooling之后的256维向量,pair计算sim后和标签算mse。
2.3 ASL
这是阿里巴巴最新提出的一种用于多标签分类的Loss [3],可以有效解决多标签分类长尾样本的噪声问题。用它来替换baseline中的多标签分类的BCE损失,可以使得收敛更快,最终F1 score也更高。
2.4 Roformer
用来替换bert。[4]
3. 一些tricks
总体来说:先进性pretrain(多标签分类 or MLM),再进行finetune (MSE).
NextVLAD里面的bn层不能注释掉(baseline中注释掉了)
针对预训练
- 替换原来的bert model,baseline中的是bert-uncased-chinese,更换成更好的chinese-roberta-wwm-ext;或者更换为roformer_chinese_base。
- 对于MixNextvlad 模型,在文本特征和图像特征进行fusion前增加一个对比损失函数(contrastive loss),我们认为这样能平衡二者的量纲,能促进fusion的效果,在pretrain时能有效提升spearman 3个百分点。
针对finetune
- 使用11-fold-cross-validation:将pairwise的数据分成11份,每次用一份进行验证,这样同一个模型可以训11个模型,最终embedding取平均。
- finetune时使用三个损失函数,包括:mse loss (直接优化similarity)、KL loss (优化模型得到的sim和label sim的分布差距)、tag loss (也就是预训练的多标签分类loss)。单独使用mse会过拟合,增加后两个之后可以有效缓解。
- 训练轮次不宜过多,我们128的batch size只需要训练 3000或4000 steps。
4. 如何复现?
所有实验在一块3090上完成。(mixnextvlad模型在1080ti也可以跑,batch调小一些) 环境:
python==3.8.0
tensorflow==2.5.0
transformers
4.1 数据准备
- 下载data并解压至 Video_sim 文件夹中 (包括test_b)
- 生成pair对的tfrecord,且有11个文件(11-fold-cross-validation)
python write_tfrecord.py
生成的结果:(每个路径下面包含 train.tfrecord & val.tfrecord)
├── data/
| ├── pairwise/
| | ├── 0-5999val/
| | ├── 6000-11999val/
| | ├── 12000-17999val/
| | ├── 18000-23999val/
| | ├── 24000-29999val/
| | ├── 30000-35999val/
| | ├── 36000-41999val/
| | ├── 42000-47999val/
| | ├── 48000-53999val/
| | ├── 54000-59999val/
| | ├── 60000-65999val/
4.2 直接测试(通过现有的ckpt得到最终的结果)
先下载final_save [这个不方便给出],mv至Video_sim文件夹中,然后直接运行run.sh文件. 该sh会运行所有模型的inference,包括6个模型的11-fold,然后对所有embedding进行一个加权的ensemble。 最后输出为 result_10_b.zip
sh run.sh
PS:如果只想测试一个模型的话,以MixNextvlad为例,那只需要下载一个 final_save/10fold_1_mix, 然后运行:
python inference_pair_b.py --ckpt-file final_save/10fold_1_mix/ckpt-4014 --output-zip 10fold_b_zip/10fold_1_mix.zip
4.3 模型预训练
- Pre-Train on MixNextvlad models:
- MixNextvlad:
python cqrtrain_mix.py --batch-size 256 --savedmodel-path save/mix
- MixNextvlad_ASL:
python cqrtrain_mix_asl.py --batch-size 256 --savedmodel-path save/mix_asl
- MixNextvlad_roformer:
python cqrtrain_mix_roformer.py --batch-size 256 --savedmodel-path save/mix_roformer --bert-dir junnyu/roformer_chinese_base
- Pre-Train on Uniter models:
- Uniter:
python cqrtrain_mlm_mm_tag.py --batch-size 256 --savedmodel-path save/uniter --uniter-pooling mean
- Uniter_ASL:
python cqrtrain_mlm_mm_tag_asl.py --batch-size 256 --savedmodel-path save/uniter_asl --uniter-pooling mean
- Uniter_roformer:
python cqrtrain_mlm_mm_tag_roformer.py --batch-size 210 --savedmodel-path save/uniter_roformer --uniter-pooling mean --bert-dir junnyu/roformer_chinese_base
4.4 模型finetune
注意!在训练ASL的时候有可能会出现NAN,这种情况需要重跑一次相应的模型. 建议每次只跑sh文件里面的一个模型,把其他的注释掉,这样方便debug。
sh finetune_all.sh
如何训练单模型?
详见finetune_all.sh,里面有6个模型的单模型训练命令。
例子:
python train_pair_mix.py --batch-size 128 --savedmodel-path save/10fold/10fold_1_mix --pretrain_model_dir save/mix --kl-weight 0.5 --total-steps 4000 --train-record-pattern data/pairwise/0-5999val/train.tfrecord --val-record-pattern data/pairwise/0-5999val/val.tfrecord
参数解释:pretrain_model_dir:load的预训练模型的路径 (mix/mix_asl/mix_roformer/uniter/uniter_asl/uniter_roformer)
4.5 模型inference
建议每次只跑sh文件里面的一个模型,把其他的注释掉,这样方便debug。
sh infer_all.sh
如何测试单模型?
例子:
python inference_pair_b.py --ckpt-file save/10fold/10fold_1_mix/ckpt-4012 --output-zip 10fold_b_zip/10fold_1_mix.zip
4.6 ensemble
6个10fold的模型得到的embedding进行加权求和。
python ensemble_final.py
5. References
[1] Lin R, Xiao J, Fan J. Nextvlad: An efficient neural network to aggregate frame-level features for large-scale video classification[C]//Proceedings of the European Conference on Computer Vision (ECCV) Workshops. 2018: 0-0.
[2] Chen Y C, Li L, Yu L, et al. Uniter: Universal image-text representation learning[C]//European conference on computer vision. Springer, Cham, 2020: 104-120.
[3] Ridnik T, Ben-Baruch E, Zamir N, et al. Asymmetric Loss for Multi-Label Classification[C]//Proceedings of the IEEE/CVF International Conference on Computer Vision. 2021: 82-91.
[4] Su J, Lu Y, Pan S, et al. Roformer: Enhanced transformer with rotary position embedding[J]. arXiv preprint arXiv:2104.09864, 2021.