本项目基于kaggle上的一个已有的项目(OpenAI CLIP simple implementation)实现。我在此基础上添加了一个公共数据集(flickr8k)和一个由我队友们设计的大小为300的数据集。并把损失函数由
需要注意的是,flickr30k是flickr8k的扩展(图片部分重复,但是标注是不同的)。
三元组损失【这里我选取的正样本是样本对应的标签,比如在训练集中的image样本对应的Text样本】:
或者下面那种(更方便理解:InfoNCE Loss公式及源码理解-CSDN博客):
- 这里它同时把每个正对 (xi,yi)(x_i,y_i)(xi,yi) 与所有其他负对拉开。InfoNCE 的优点是批内全负样本一次考虑,保证全局分布对齐;但缺点也明显:
- 弱化最难负样本:对所有负样本一视同仁,hard negative(最具迷惑性的负样本)得到的梯度信号比较平均,不够突出;
- 只关注相似度,不直接控制“距离 margin”:没有显式 margin,将相似度推低的“安全边界”是隐含的。
- 三元组损失则:
- 显式控制 margin:保证每个锚点到正样本的距离,至少比到负样本距离小 margin;
- 聚焦 hardest negative:如果采样 hardest 或 semi-hard 负样本,会给最具挑战性的负对更大梯度,能更快收敛到更区分度高的嵌入空间。
- 融合的思路
- 全局+局部:InfoNCE 保证批内全局语义对齐,Triplet Loss 强化 hardest negative 的 margin 分离;
- 互补提升:InfoNCE 平滑分布式对比,Triplet Loss 明确 margin 约束,二者结合能让嵌入空间既整体一致,又局部更具判别力;
-
超参可调:
$\alpha$ 控制二者权重,可在验证集上调优,找到性能最优的平衡。
这样,融合后既保留了 CLIP 原有的高效全负样本对比,又通过三元组的硬负样本挖掘和 margin 强化,实现了更鲁棒、更具区分度的视觉–语言表示学习。
- 导入环境变量(覆盖kaggle默认的存储位置)
export KAGGLEHUB_CACHE="./autodl-tmp"
echo $KAGGLEHUB_CACHE- 执行下面的python脚本(随便放到一个.py文件然后执行即可):
import kagglehub
# 下载数据集
path = kagglehub.dataset_download("hsankesara/flickr-image-dataset")
print("Path to dataset Flickr 30k:", path) #下载模型到本地然后加载,由此避免国内访问HF的超时问题。
# 安装 huggingface_hub 工具包
pip install huggingface_hub
# 设置镜像网站
export HF_ENDPOINT=https://hf-mirror.com
# 下载 distilbert-base-uncased 模型到本地目录
huggingface-cli download distilbert-base-uncased \
--resume-download \
--local-dir ./autodl-tmp/model/distilbert-base-uncased \
# 下载resnet50 模型到本地目录
huggingface-cli download timm/resnet50.a1_in1k \
--local-dir ./autodl-tmp/model/resnet50
部分实验条件:
$Epoch=30$ $训练集:测试集 = 4:1$ $Batch\ size = 32$ $\alpha = 0.1$
在GTX 3090显卡上,对数据集flickr30k 训练用时为4h 47min 38s。
下面的是在测试集上得出的平均损失值。
| Dataset | ||
|---|---|---|
但是实际上在这几个数据集的表现并不理想。
| Dataset | ||
|---|---|---|
可以看出
在我修正这个问题后,又出现了out of CUDA memory 的问题,这说明如果按照修正后的方式(比如一次性计算一张图与所有文本间的 out of CUDA memory)。
这个问题理论上可以通过3种方式解决:
(1) 不推荐: 冻结2个编码器,只训练并更新投影头。因为文本编码器是已经预训练好的模型,所以估计性能不会很差,但是模型性能不会很好(特别是对于较大规模的数据集)。
(2) 不太推荐: 直接租显存更高的服务器,但是成本较高。根据查阅到的资料:OpenAI公司对预训练阶段的CLIP用了大量的训练数据以及训练资源,大力出奇迹。CLIP用了400million的image-text pair对进行训练(实际上原论文是采用我参考的那个 Kaggle 项目的做法。只是依靠一个较大的
(3) 推荐:选取一个大小和步长都为
图例中的
下面是图片展示:












