BLIP论文笔记

blip这篇论文中提到两个创新点:1、提出了一个新的多模态架构(我暂时没看出来架构哪里新),可以通过三个预训练任务进行训练,文本图像的对比学习、图像文本匹配和图像-语言建模;2、提出了一个新的数据生成和清洗方法,清洗后的数据比直接用网络上获得的图文数据训练模型效果更好。
一、背景
本文的大意是之前已经有了一些视觉-语言的预训练的工作,但是这些工作存在2个主要缺陷:1、模型层面,大部分都是采用编码器的结构,在生成文本的时候不好用,还有一些编码器-解码器的结构,但是尚未成功应用于图像-文本检索任务;2、数据都是从网络上爬取,质量不高。
针对这2点,作者提出了本文的2个创新点:1、模型架构采用多模态混合编码器-解码器结构,可以适用多种任务;2、提出CapFilt,也就是一种数据过滤和清洗的策略。
二、模型结构
在这里插入图片描述

模型结构如上图,包含一个视觉编码器-vit(使用之前别人在ImageNet上预训练的vit进行初始化),文本编码器-bert(BERTbase进行初始化),文本解码器-bert改(将bert的双向注意力替换成因果注意力)。并设计了3个loss:1、图像-文本对比损失(ITC),类似clip,将匹配的文本对编码到相似的特征空间;2、图像-文本匹配损失(ITM),给文本编码器加上一个线性层做二分类任务,判断这个图像-文本对是否匹配,采用了困难负样本挖掘策略,选择批次中具有较高对比相似性的负样本来计算损失。;3、语言建模损失(LM),给定图片生成文本描述并计算损失。
模型预训练的时候,对图像进行随机裁剪,分辨率为224×224,微调时将图像分辨率提高到384×384。clip是中心裁剪为224×224。先在低分辨率上训练,最后再高分辨率上微调感觉现在很多工作也是这么做的(华为的文生图模型PixArt-α也是这么做的)。有点类似于数据退火的感觉,训练模型的时候,最后拿一些高质量数据进行最后的训练效果更好一些。并且在预训练期间,文本编码器和解码器共享除自注意力层以外的所有参数。
个人感觉这个模型设计的有点复杂了,这么复杂的任务和模型结构感觉不太适合scaling,为了适应多任务,组合了多个模型和损失函数,直觉上也感觉不太直观。

三、数据策略
在这里插入图片描述

CapFilt就是一个数据处理的流程,从之前预训练的模型中初始化多模态模型,并在COCO数据集上微调。然后文本解码器的部分负责生成图像的描述,文本编码器用来判断图像和文本是否匹配,如果不匹配则将这个数据过滤,将过滤后的数据和人工标注的数据组合重新训练,这个过程可以不断迭代,不断提高数据质量和模型效果。
这个过程感觉更偏工程一些,不少数据清洗的项目也是这么做的,提高数据质量-训练模型-训练模型提高数据质量,不断的正向循环。
四、模型评估
这部分就不细讲了,感兴趣的可以看一下。感觉模型评估的方法太多,大家一般也都是拿自己效果好的出来说,实际效果怎么想只能实际用的时候测试了。
整体感觉这篇文章模型结构、训练方法设计的都比较复杂,但是涨点并不明显,感觉没有太大的必要。
五、代码分析
模型结构和训练任务很复杂,感觉不太好应用,不过这种复杂的模型和任务还挺考验代码能力。下面对部分代码进行解析。
1、损失函数的定义
class BLIP_Pretrain(nn.Module):
……
def init(…… queue_size = 57600):
……
def forward(self, image, caption, alpha):
……
sim_i2t = image_feat @ text_feat_all / self.temp
sim_t2i = text_feat @ image_feat_all / self.temp

    loss_i2t = -torch.sum(F.log_softmax(sim_i2t, dim=1)*sim_i2t_targets,dim=1).mean()
    loss_t2i = -torch.sum(F.log_softmax(sim_t2i, dim=1)*sim_t2i_targets,dim=1).mean() 

    loss_ita = (loss_i2t+loss_t2i)/2
    ……
    return loss_ita, loss_itm, loss_lm

这里直接在模型的定义中返回了三个损失函数,其中loss_ita是对比学习的损失函数,text_feat_all是维持了一个大小为57600的队列,先计算当前batch的文本特征(或者图像特征)与队列中所有图像特征(或者文本特征)的相似的矩阵。将相似的矩阵归一化后与理想目标分布相乘(理论上是一个对角线的矩阵,代码中加入了动量模型的预测分布)来计算损失。
2、权重更新
loss_ita, loss_itm, loss_lm = model(image, caption, alpha = alpha)
loss = loss_ita + loss_itm + loss_lm
训练的时候将三个loss直接相加,当成总的loss,用来更新模型。
3、图片处理
图片预处理
normalize = transforms.Normalize((0.48145466, 0.4578275, 0.40821073), (0.26862954, 0.26130258, 0.27577711))
transform_train = transforms.Compose([
transforms.RandomResizedCrop(config[‘image_size’],scale=(min_scale, 1.0),interpolation=InterpolationMode.BICUBIC),
transforms.RandomHorizontalFlip(),
RandomAugment(2,5,isPIL=True,augs=[‘Identity’,‘AutoContrast’,‘Brightness’,‘Sharpness’,‘Equalize’,
‘ShearX’, ‘ShearY’, ‘TranslateX’, ‘TranslateY’, ‘Rotate’]),
transforms.ToTensor(),
normalize,
])
transform_test = transforms.Compose([
transforms.Resize((config[‘image_size’],config[‘image_size’]),interpolation=InterpolationMode.BICUBIC),
transforms.ToTensor(),
normalize,
])
首先对图像进行随机裁剪,并使用双三次插值方法调整图片大小,然后以 50% 的概率水平翻转图像,然后随机选择2-5种亮度调整、平移、旋转等数据增强操作进行图片增强,最后对图片进行归一化。这里归一化的参数与clip相同。
进入模型后的图像处理。

class VisionTransformer(nn.Module):
……
def forward(self, x, register_blk=-1):
B = x.shape[0]
x = self.patch_embed(x)
……

class PatchEmbed(nn.Module):
……
def forward(self, x):
B, C, H, W = x.shape

    x = self.proj(x)
    if self.flatten:
        x = x.flatten(2).transpose(1, 2)  # NCHW -> NLC
    elif self.output_fmt != Format.NCHW:
        x = nchw_to(x, self.output_fmt)
    x = self.norm(x)
    return x

这里是通过卷积,将图片映射到一个高维向量,并展开,然后进行归一化就得到的图像的embedding。
六、总结
总的来说,blip就是设计了一个更复杂的模型,更复杂的损失函数,提出了一个提高数据质量的流程,效果上有一些提升。
这里介绍一个我的多模态大模型开源项目:Zero-Qwen-VL。这个项目项目的初衷是想训练一个对中文支持更友好的图文多模态模型,所以挑了qwen-vl的图片编码器,语言模型选择了qwen2,这个项目提供了模型权重组合的方法,用中文数据集对模型进行训练,可以完成基本的中文图文问答。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值