多模态ViLT模型Huggingface源码

前言

        huggingface模型库在cv和nlp中用的太多了,而其中的模型调用方法大同小异,索性直接扒出来源码来看看这些模型的通用性。文章中的模型解析来自huggingface官方源码,该模型为源文件transformers.models.vilt.modeling_vilt.py,真的纯官方模型奥!

HuggingFace源码分析

 思维导图简介

 1. 同类架构的注意力模型适用(embedding + encoder)

        该架构在huggingface中通用,都是有模型对应的数据预处理器processor及模型model,应用from_pretrain方法载入。其中,embedding部分不同的模型在接收数据时并不统一,encoder部分几乎所有的自注意力模型都相差不大,例如vit、bert、clip等均使用该架构。

processor = ViltProcessor.from_pretrained("./vilt-b32-finetuned-vqa")  # VILT模型预处理器
model = ViltForQuestionAnswering.from_pretrained("./vilt-b32-finetuned-vqa").cuda()  # VILT预训练模型

2. 思维导图分类说明

        导图中的名称来源于源文件的类名,展示了各类的调用关系。

  • 其中加红色边框的模块是源码不存在的但是更便于理解和整合,其功能一般隐藏在上级类中。
  • 白色文字代表本类中调用了下级类而黑色文字代表其没有额外调用其余类或函数。

单模块功能(从上到下)

1. ViltModel

  • 输入:padding后的文本向量、图片向量 [batch_size, 1+text_max_length + 1+ image_length, embedding_size ] --> [batch, length, 768]
  • forward:文本向量、图片向量经过embedding层后经过encoder层,经过LN归一化后再经过pooler层。
  • 输出:encoder层后的输出和pooler层的输出 --> [batch, length, 768] 和 [batch, 768]

2. ViltEmbeddings

  • 输入:padding后的文本向量、图片向量 --> [batch, 1+text_max_length, 768] ,[batch, image_length, 768]
  • forward:文本向量经过TextEmbeddings层,图片向量经过VisualEmbeddings层,文本向量全部加0,图片向量全部加1,进行拼接
  • 输出:embedding拼接后 --> [batch, length, 768]

3. TextEmbeddings

  • 输入:文本向量 [batch, 1+text_max_length]
  • forward:输入文本向量(输入的文本)、位置编号(常量)、类型编号(常量)embedding后直接相加。
  • 输出:文本向量embedding后 --> [batch, 1+text_max_length, 768]

4. VisualEmbeddings

  • 输入:图片向量 [batch, 3, 384, 384]
  • forward:输入图片经过PatchEmbeddings层后将12*12拉直为144维,加入了图片切块坐标融入到向量与随机初始化位置编码中。最后随机初始化cls向量加到向量中变成145维向量,位置编码也做了对应的拼接,二者直接相加。
  • 输出:输出:[batch_size, 145, 768]维度的图片cls+patch后的向量

5. PatchEmbeddings

  • 输入:图片向量 [batch, 3, 384, 384]
  • forward:使用二维卷积操作直接改变图片通道数
  • 输出:[batch, 768, 12, 12]维度的图片patch后的向量

6. ViltEncoder

  • 输入:ViltEmbeddings层的输出--> [batch, length, 768]
  • forward:可更改ViltLayer的层数,有几层就几次循环
  • 输出:经过n个ViltLayer层后的输出--> [batch, length, 768]

7. VlitLayer

  • 输入:ViltEmbeddings层的输出或ViltLayer层的输出 --> [batch, length, 768]
  • forward:输入数据经过LN + ViltAttention层后与原输入数据求和得到中间向量,中间向量再经过LN + ViltMLP层后得到输出向量(第二次求和在ViltMLP层中实现)
  • 输出:经过1个ViltLayer层后的输出--> [batch, length, 768]

8. ViltAttention

  • 输入:输入数据经过LN 层后的数据 --> [batch, length, 768]
  • forward:向量经过ViltSelfAttention层后再经过ViltSelfOutput层
  • 输出:计算多头注意力后的数据 --> [batch, length, 768]

9. ViltSelfAttention

  • 进行多头注意力机制计算,文本padding的部分做掩码不算注意力,维度不变

10. ViltSelfOutput

  • 简单经过一个线性层,维度不变

11. ViltMLP

  • 输入:VlitLayer层的中间向量
  • forward:将中间向量经过ViltIntermediate层与ViltOutput层的升降维后与中间向量求和
  • 输出:经过MLP层后的输出,即ViltLayer层后的输出

12. ViltIntermediate

  • 在ViltIntermediate层中完成4倍升维的操作和glue激活函数

13. ViltOutput

  • 在ViltOutput层中完成4倍降维操作,之后将输出数据与VlitLayer层的中间向量进行求和操作

14. ViltPooler

  • 输入:encoder层的输出 --> [batch, length, 768]
  • forward:encoder的输出取出第一个结果,经过线性层和tanh激活函数
  • 输出:整个输入序列的起始cls对应位置的输出 --> [batch, 768]

整合模块前向传播

总体流程为:

1. 图像、文本数据经过resize、padding后经过processor得到了模型的输入数据encoding,其中包括图片向量、文本向量、图片与文本向量掩码。其中掩码只有文本padding的部分做了掩码,其余均不进行掩码操作。将encoding送入模型得到输出。

encoding = processor(image_list, text_list, return_tensors="pt", padding=True)
outputs = model(**encoding)

2. encoding送入模型中,文本向量与位置编码(0~max_length)同时嵌入到768维之后直接相加变成包含位置编码的文本向量,位置编码为常量不可学习。图片向量通过卷积后展开变成144维向量,随机初始化可学习的位置编码,二者分别融入了图片分块位置信息后分别拼接了cls特殊向量直接相加变成145维包含位置编码的文本向量。

3. 将包含位置编码的文本向量和包含位置编码的文本向量直接拼接,所有文本向量加0,图片向量加1作为区别文本与图片的凭证。(这个区分感觉有点玄学)

4. 拼接后的向量是[batch_size, text_max_length + 145, 768]维的,送入encoder层,VlitLayer的存在意义就是让层数可以修改。encoder层的布局和vit一模一样,绿色部分由ViltSelfAttention层和ViltSelfOutput层实现,第一次黄+绿部分由ViltAttention层实现,第二次黄+蓝由ViltMLP层实现。

 5. 经过好几层encoder后,维度不变[batch_size, text_max_length + 145, 768],把这个向量直接作为输出1。另外取向量第一个[batch_size,第一个, 768]向量经过一个线性层作为输出2。这个输出二是文本向量的头一个位置cls,不是图片添加的那个cls。

6. 从输入数据经过整个模型得到了output,这个输出包括输出1和输出2。

不同任务微调

应用输出1和输出2可以在后面加上各种各样的分类头做不同的任务,但是从官网下载下来的预训练权重并没有适配各项不同任务,相当于零样本训练模型,还是要做几轮微调才可以达到论文中的指标(我试了最高到69.3%,不知道哪里出了问题,有没有调到70的大佬呢)。在VQA2.0上不做训练验证集准确率为66.98%,微调过后可达到74.5%,代码不放了(这是不花钱能看的?),另外比较费卡,4张12G显卡跑满一个epoch大概需要1.8小时。

  • 8
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 22
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 22
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值