先简单讲一下itc 和itm itg loss
itc loss
是将图像和query经过Q-former得到图像的表征,文本经过Q-former得到文本表征,文本和图像矩阵乘计算对比损失
itm loss
是上一步图像和文本表征,分别组成三组,一组相匹配的图像和文本,另外两组不匹配的图像和文本,将三组图像和文本、query 一起送入Q-former,得到三组的分类损失,相匹配的一组标签为1,不匹配的标签为0
itg loss
是将文本和第一步计算itc loss 过程中图像和query经过Q-former得到的每一层隐藏层状态,一起送入Q-former,计算文本生成损失
1、首先定义一个 blip2Qformer类 ,这个类里面包含一个vit视觉模型和Qformer
note:Qformer是一个12层的bert(only encoder)再加上一个全连接层
2、首先 图像经过视觉模型得到image_embeds size(16,257,1408),新建全为1的image_atts size(16,257)
3、query_tokens 是blip2Qformer类的属性,在类中被初始化全为0,size (1,32,768)
将query_tokens 复制为bachsize 为16, size为(16,32,768)
4、接下来详解 图像特征 和 query 是如何在Qformer中进行运算的
4.1 query_tokens 作为Qformer的输入 首先经过embdding层,将query_tokens进行layerNorm和dropout,得到embedding_output size(16,32,768)
根据embedding_output 的shape得到全为1的attention_mask size(16,32),把attention_mask extend为 extended_attention_mask size(16,1,1,32),现在extended_attention_mask中的值全为1,接着需要使用公式:(1-element)*-10000,作用于每一个元素。这样做的目的是将真正输入的token mask 设置为0,非token mask设置为-10000
4.2 将图像特征赋值给encoder_hidden_states size(16,257,1408),设置全为1的encoder_attention_mask size(16,257),把encoder_attention_mask extend为 encoder_extended_attention_mask size(16,1,1,257),现在encoder_extended_attention_mask中的值全为1,接着需要使用公式:(1-element)*-10000,作用于每一个元素。这样做的目的是将真正输入的token mask 设置为0,非token mask设置为-10000
4.3 将embedding_output extended_attention_mask encoder_hidden_states encoder_attention_mask 一并送入encoder中
note:encoder共计12层, 每一层有一个self-attention ,每个偶数层多加一个cross attention,如果没有cross attention,self-attention层计算完成后,输出的结果也要经过升维全连接层 gelu激活函数层 降维全连接层 和 droput层、LayerNorm层
4.3.1 首先embedding_output extended_attention_mask做self-attention,embedding_output 复制为q, k, v , qkv各自经过一层全连接层完成一次特征重提取,紧接着再用heads_num将其shape重新view,得到新的qkv size(16,12,32,64),然后q和k 先进行 matmul得到attetion_scores,attention_scores再除以根号(hidden_size / heads_num), 得到的结果再加上extended_attention_mask,再经过dropout得到最终的attention_scores size(16,12,32,32)
4.3.2 attention_scores和v在相乘得到context_layer size(16,12,32,64),将context_layer中的head_nums 的维度取消,得到outputs size(16,32,768)
4.3.3 将outputs 经过一层全连接层,并dropout之后,加上embedding_output 在经过LayerNorm 得到outputs size(16,32,768)
4.3.4 将上述得到的outputs 再和encoder_hidden_states 做交叉注意力,得到cross_attention_outputs size(16,32,768),将其经过一个升维全连接层和一个gelu激活函数层,再经过一个降维全连接层和droput层、LayerNorm层,得到layer_output size(16,32,768)
4.4 embedding_output 经过Qformer之后得到query_output size(16,32,768),query_output经过一个linear(768,256),并将输出使用F.normalize做L2范数进行归一化,得到image_feats size(16,32,256)
4.5 上述讲的是图像和query_tokens之间的计算,接下来讲训练的文本也要经过Qformer做self-attention,得到text_output size(16,32,768),将text_output第二个维度的第一维提取出来,赋值给text_feat size(16,768),在经过一个降维的全连接层得到text_feat size(16,256)
4.6
sim_q2t = torch.matmul(
image_feats.unsqueeze(1), text_feat.unsqueeze(-1)
).squeeze()
得到sim_q2t size (16,16,32), 得到每一张图像与所有文本之间的距离向量。每个距离向量找一个最大值,得到每张图像与所有文本之间的距离表示 {sim_i2t, _ = sim_q2t.max(-1)} sim_i2t size (16,16)
sim_t2q = torch.matmul(
text_feat.unsqueeze(1).unsqueeze(1), image_feats_all.permute(0, 2, 1)
).squeeze()
得到sim_t2q size(16,16,32),得到每个文本与所有图像的距离向量。每个距离向量中找一个最大值,得到每个文本与所有图像的距离表示{sim_t2i, _ = sim_t2q.max(-1)} sim_t2i size (16,16)
4.7 计算itc loss
targets = torch.linspace(rank * bs, rank * bs + bs - 1, bs, dtype=int).to(
image.device
)
loss_itc = (
F.cross_entropy(sim_i2t, targets, label_smoothing=0.1)
+ F.cross_entropy(sim_t2i, targets, label_smoothing=0.1)
) / 2
4.8 计算itm loss
sim_t2i 首先将对角线的值赋值为-10000,即盖住与自己最相似的距离,经过softmax得到weights_t2i size(16,16)代表每个文本对所有图像的距离概率
sim_i2t 首先将对角线的值赋值为-10000,即盖住与自己最相似的距离,经过softmax得到weights_i2t size(16,16)代表每张图片对所有的文本的距离概率
从sim_t2i选出每个文本最相似但不是匹配的图像(使用torch.multinomial(weights_t2i[b], 1).item()),选出16个最相似的图片,合并为
image_embeds_neg size(16,257,1408)
从sim_i2t选出每张图片最相似但不匹配的文本(使用 torch.multinomial(weights_i2t[b], 1).item()),选出16个最相似的文本,合并为
text_ids_neg size(16,32)
text_ids_all 是将两个text_tokens 和 text_ids_neg 拼接起来 size(48,32)
query_tokens_itm 是将query_tokens复制三次 size(48,32,768)
image_embeds_all 是将image_embeds 和 image_embeds_neg 和 image_embeds 拼接起来 size (48,257,1408)
text_ids_all 和 image_embeds_all 这样安排是为了只有text_tokens和image_embeds相对应的位置,文本和图片才一一对应
将text_ids_all query_tokens_itm image_embeds_all 一并送入Q-former中
第一步 先text_ids_all和query_tokens_itm 拼接起来,然后做self-attention得到outputs size(48,64,768)接着经过linear dropout LayerNorm size 仍为(48,64,768)
第二步 将上一步的outputs 选取query_tokens 的序列长度(32),得到query_attention_output size(48,32,768),与视觉特征
encoder_hidden_states size(48,257,1408) 做交叉注意力,在经过linear dropout LayerNorm 得到attention_output size(48,32,768)
attention_output经过ffn得到layer_output size (48,32,768)
第三步 将第一步得到的outputs 选取query_tokens 的序列长度之后的序列,送入ffn 得到layer_output_text size(48,32,768)
第四步 将outputs 和layer_output_text 利用concat拼接起来得到layer_output size(48,64,768)
这样做的目录是突出query,让query参与更多的学习,让query作为中间的桥梁,与图像特征交互,也与文本特征交互,最后经过12层这样的交互学习,得到Q-former的输出layer_outputs size(48,64,768),接着再取前32个序列的特征vl_embeddings size (48,32,768),这样设计还是突出query的学习特征。最终利用vl_embeddings 去得到图像和文本之间匹配的概率,vl_embeddings经过全连接层和取均值得到logits size(48,2),标签就是三组图像和文本特征,只有第一组图像和文本匹配,所以targets size(48),前16个为1,其余为零。再利用交叉熵损失得到itm 损失
4.9 计算itg loss
第一步 确定输入,将text_tokens size(16,32)复制给decoder_input_ids,将其中每个句子的开头设置为bert的起始编码值。然后将decoder_input_ids中padding的位置的数值设置为-100,作为label。
第二步 将decoder_input_ids和视觉和query经过Q-former得到的query_output 再送入Q-former,这里面特别强调的是,需要将query_output中每一层的隐藏层状态和decoder_input_ids拼接起来作为k和v。再与decoder_input_ids做self-attention,得到最终的
encoder_outputs size(16,32,768),在经过ffn得到prediction_scores size(16,32,30523)
第三步 计算prediction_scores 与label的交叉熵损失