当前位置:   article > 正文

多模态视觉大模型(2): 常用模型介绍(CLIP和LLAVA)_llava的 loss函数

llava的 loss函数

1.CLIP 讲解

1.1 clip 预训练过程

CLIP (Contrastive Language-Image Pre-training)是一种利用对比学习进行语言、图像预训练的模型,它是OpenAI的一项工作,当时他们的工作还是开源的。对比学习思想是:将正样本拉近,将负样本拉远的这一类算法

在这里插入图片描述

  • 输入一张Image以及对这张图像的描述,比如一张dog的图像和 “澳洲小狗Pepper”的描述,我们认为这张image 和这段文本就是一对正样本。相对于可以输入多张图像以及这些图像的文本描述,匹配的文本和图像之间是正样本,不匹配的文本和图像是负样本。对比学习的目标就是拉近正样本之间的距离拉远负样本之间的距离。通过Text Encoder来编码文本的信息,通过Image Encoder来编码图像信息,来最大化正样本之间的相似度,来最小化负样本的相似度。
  • 通过Encoder 会得到多个Text对应的多个Embedding(t_1,t_2,…,t_N)和多张image对应的多个Embedding(I_1,I_2,I_3,…I_N), 对角线上属于同一对pair, 这样通过Loss 来最大化对角线上的相似度,来最小化其他元素之间的相似度,这样网络学习到了同一个目标的图像和文本得到的Embedding就尽可能相同。对应于多模态的三要素:1. 各个模态都有各自的Encoder 2. 对齐策略:通过Loss来约束让同一个样本的文本和Image的Embedding的相似度尽可能大,不同样本间相似度尽可能小的对比学习策略来对齐文本和图像模态。3. LLM模型, 该要素是可选的,对于CLIP模型中肯定是没有包括LLM模型的。
  • CLIP 相对于单模态的对比学习来说,任务肯定是更复杂一些的,通过引入了不同的模态信息比如Text,这样通过对比学习效果肯定是非常不错的。

1.2 利用clip进行图像分类

如何利用预训练得到的clip模型来做图像分类任务呢?这里就和传图的CV模型是不一样的。

  • 对于CV来说通常是拿到预训练的权重,针对下游任务通过接一个任务Head来训练任务头或者Fine-tune整个网络来得到预测输出。

  • CLIP则设计了一种新的方式,它首先从标签label层面入手, 对数据集可能存在的类名,使用prompt模板,比如对于飞机plane这个类,我们将飞机这个类转换为一个文本如A photo of a plane,同理将car类,将它转换为文本A photo of a car

  • 然后将所有类别得到的文本信息,输入预训练好的Text Encoder, 这样对于数据集中的每一个类别都会生成一个向量。这个向量就能代表这一个类别的通用的Embedding。

  • 最后将输入的一张image,它经过Image Encoder会得到对应的图像Embedding,和每个类别所代表的文本Embedding来计算相似度,找到相似度最大的文本标签类别,就认为该图像就是该类别。

  • Clip这种图像分类的Idea是一种非常创新的想法,可以从输入和label之间同时经过网络来约束他们之间的距离,而不是只有输入到预测目标这一单向的路径。这一idea也是Lecun大佬提出world model的概念。

    在这里插入图片描述

总结

clip 这样设计的模型它的最大的能力可以让图像和Text各自的Embedding, 能够在共享的空间下,通过输入一张图像和该图像的描述信息会得到两个相同的Embedding。这样,比如在一个语言大模型中,如果我们想加入图像信息,可以将图像通过编码映射到文本的Embedding中,因为他们之间的Embedding已经对齐了。

这样在训练好clip模型之后,可以直接将Text EncoderImage Encoder拿过来使用,在构建自己的大模型的时候,就不在需要重新训练这两个Encoder了。在后续介绍的多模态大模型比如Flamingo和LLaVA,他们对于图像的编码就直接使用CLIP中训练好的Image Encoder

1.3 CLIP代码详解

在这里插入图片描述

图1 clip 模型结构

CLIP 模型结构其实非常简单,针对两个模态Text和Image,分别通过各自Encoder编码(Text EncoderImage Encoder), 得到经过编码后的高纬向量Embedding, 然后计算相似度,最终使得匹配的image 和Text对的相似度尽可能大,其他没有匹配到的Embedding相似度尽可能小。

1.3.1 Image Encoder 和 Text Encoder的实现
class ViT(nn.Module):
    def __init__(self,output_dim):
        # 使用来自timm的VIT模型
        self.vit = timm.create_model('vit_small_patch16_224',pretrained=True,num_classes =output_dim)
        
    def forward(self,x):
        return self.vit(x)

class TextEncoder(nn.Module):
    def __init__(self):
        super(TextEncoder,self).__init__()
        
        BERT_LOCAL_PATH ='./bert-base-uncased'
        self.model = BertModel.from_pretrained(BERT_LOCAL_PATH)
        self.tokenizer = BertTokenizer.from_pretrained(BERT_LOCAL_PATH)
    
    def forward(self,texts):
        encoded_input = self.tokenizer(texts, return_tensors ='pt',padding= True,truncation =True)
        outputs = self.model(**encoded_input)
        return outputs.last_hidden_state[:,0,:]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • Image Encoder : 使用的是ViT模型,为了方便起见使用timm工具来搭建,使用的是vit_small_patch16_224版本的模型,也可以使用vit-base版本的。得到编码后的embedding维度为output_dim
  • TextEncoder: 文本编码器使用的是Bert模型,利用transformers工具进行构建。由于是文本,除了模型本身之外,还需要实例化一个tokenizer
  • 文本输入模型前,首先需要经过tokenizer操作,然后将tokenizer后的encoded_input, 输入到TextEncoder
1.3.2 搭建CLIP模型
class CLIP(nn.Module):
    def __init__(self, image_output_dim, text_output_dim):
        super(CLIP, self).__init__()
        self.image_encoder = ViT(image_output_dim)
        self.text_encoder = TextEncoder()

        # 因为图像和文本emb可能维度不同(图像512,文本768),所以需要对图像和文本的emb再经过一层以将维度持平
        self.W_i = nn.Parameter(torch.randn(image_output_dim, text_output_dim))
        self.W_t = nn.Parameter(torch.randn(768, text_output_dim)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家自动化/article/detail/708021
推荐阅读
相关标签
  

闽ICP备14008679号