VIT大模型浅要了解

本文章主要了解vit-patch16-224模型,更多详情请直接在huggingface中了解。

链接:google/vit-base-patch16-224 · Hugging Face

要实现ViT大模型,请看博客:ViT大模型浅要实现-CSDN博客

vit模型架构:

一、VIT-patch16-224模型整体配置:

        Vision Transformer (ViT) 模型在分辨率为 224x224 的 ImageNet-21k(1400 万张图像,21843 个类别)上进行了预训练,并在分辨率为 224x224 的 ImageNet 2012(100 万张图像,1000 个类别)上进行了微调。

{

  "_name_or_path": "google/vit-base-patch16-224",

  "architectures": [

    "ViTForImageClassification"

  ],

  "attention_probs_dropout_prob": 0.0,

  "hidden_act": "gelu",

  "hidden_dropout_prob": 0.0,

  "hidden_size": 768,

  "id2label": { },#1000个类别

  "image_size": 224,

  "initializer_range": 0.02,

  "intermediate_size": 3072,

  "label2id": { },

  "layer_norm_eps": 1e-12,

  "model_type": "vit",

  "num_attention_heads": 12,

  "num_channels": 3,

  "num_hidden_layers": 12,

  "patch_size": 16,

  "qkv_bias": true,

  "transformers_version": "4.13.0.dev0"

}

        #一个224*224的图片,被分成一个个16*16的patch,则一共有(224//16)*(224//16)个patch,每个patch可以当作一个元素。

二、模型各部分组成:

2.1 图片嵌入处理ViTImageProcessor:

        该部分需要找到配置文件preprocessor_config.json:

{

  "do_normalize": true,

  "do_resize": true,

  "image_mean": [

    0.5,

    0.5,

    0.5

  ],

  "image_std": [

    0.5,

    0.5,

    0.5

  ],

  "size": 224

}

        该部分主要调用ViTImageProcessor类的preprocess函数,在该函数内,需要进行重塑形状(do_resize)、重新缩放(do_rescale),归一化(do_normalize)。

        在重塑形状时,需要将所有像素点放大到0-255区间内,之后采用双线性插值对图片尺寸进行修改,应该返回一个[batch_size,3,224,224]的images张量。

        之后对图像重新缩放,缩放因子为1/255,将元素点缩小到0-1之间。

        最后进行归一化,mean和std均由配置文件给出,利用image = ((image.T - mean) / std).T进行归一化。(image通道数如果在最后面,则直接使用image = (image - mean) / std即可)。

2.2 ViTPatchEmbeddings:

        在该层中,主要需要利用一个卷积层将输入通道由3变为hidden_size,同时设置卷积核为16,步长为16,填充为0:

self.projection = nn.Conv2d(num_channels, hidden_size, kernel_size=patch_size, stride=patch_size)

由卷积计算公式可得:

H_out=(H_in+2*p-K)//S+1=(224-16)//16+1=14

W_out=(W_in+2*p-K)//S+1=(224-16)//16+1=14

        故经过卷积图像变为[batch_size,hidden_sie,14,14],之后压缩后两维,将第一维和第二维交换位置得到该部分的输出:[batch_size,196,hidden_size]

2.3 ViTEmbeddings:

   该模块主要是为了将图像编码与标志cls编码拼接,之后与位置编码相加得到后续transformers模块的输出。

        图像编码由ViTPatchEmbeddings层得到,标志cls编码是一个可学习参数,二者在第一维拼接得到[batch_size,196+1,hidden_size],位置编码也是一个一维可学习参数,这时候需要注意:

        如果输入图像尺寸为224,patch大小为16,则直接将位置编码与之前的拼接结果相加即可,但如果尺寸或者patch大小有改变,则不能直接相加,需要对位置编码进行双三次插值:

patch_pos_embed = nn.functional.interpolate(
    patch_pos_embed,
    scale_factor=(h0 / math.sqrt(num_positions), w0 / math.sqrt(num_positions)),
    mode="bicubic",
    align_corners=False,
)

        这里的patch_pos_embed是经过处理的图像的位置编码,形状为[1,768,14,14], num_positions=196,h0和w0是新的应该得到的尺寸大小,最后应该将原本的位置编码[1,197,768]变为[1,768,14,14],再变为[1,768,h0,w0],再变为[1, h0*w0+1,768],之后才能相加。

2.4 ViTForImageClassification:

   该部分是模型主体,主要由一个ViT模块和一个全连接输出层组成,全连接输出层为nn.Linear(config.hidden_size, config.num_labels),ViT模块和transformers的Encoder模块基本相似。

   ViT模块由ViTEmbeddings、ViTEncoder、ViTPooler组成,ViTEmbeddings在2.3介绍过,这里介绍后两个。

ViTEncoder:

   ViTEncoder由12层ViTLayer组成,每个ViTLayer包括一个多头自注意力层、一个中间层、一个输出层。下图是一个ViTLayer:

   多头自注意力层如下:

class ViTSdpaSelfAttention(ViTSelfAttention):
    def __init__(self, config: ViTConfig) -> None:
        super().__init__(config)
        self.attention_probs_dropout_prob = config.attention_probs_dropout_prob

    def forward(
        self, hidden_states, head_mask: Optional[torch.Tensor] = None, output_attentions: bool = False
    ) -> Union[Tuple[torch.Tensor, torch.Tensor], Tuple[torch.Tensor]]:
        mixed_query_layer = self.query(hidden_states)
        # 变为【batch_size,heads,seq,head_dim】
        key_layer = self.transpose_for_scores(self.key(hidden_states))
        value_layer = self.transpose_for_scores(self.value(hidden_states))
        query_layer = self.transpose_for_scores(mixed_query_layer)

        context_layer = torch.nn.functional.scaled_dot_product_attention(
            query_layer,
            key_layer,
            value_layer,
            head_mask,
            self.attention_probs_dropout_prob if self.training else 0.0,
            is_causal=False,
            scale=None,
        )
        # 变为原来的形状“【batch_size,seq,hidden_dim】
        context_layer = context_layer.permute(0, 2, 1, 3).contiguous()
        new_context_layer_shape = context_layer.size()[:-2] + (self.all_head_size,)
        context_layer = context_layer.view(new_context_layer_shape)

        return context_layer, None

   其中self.query、self.key、self.value均为线性层,transpose_for_scores方法负责将hidden_states的形状由[batch_size,seq,hidden_dim]调整为[batch_size,heads,seq,head_dim]。在计算得到注意力分数之后在将context_layer形状调整为[batch_size,seq,hidden_size]输出

   中间层主要包括一个将最后一维由hissen_size变为intermediate_size的线性层,之后经过"gelu"激活后返回。输出层包括一个将最后一维由intermediate_size变为hidden_size的线性层,之后经过dropout后返回。

   得到ViTEncoder的输出后,图像形状为[batch_size,197,768],此时经过一个归一化层,之后输入池化层,池化层包括一个不做形状变化的线性层和一个tanh激活函数。最后池化层输出、归一化层输出,以及可能存在的每一个ViTLayer的输出和注意力矩阵返回。

   之后取归一化层输出作为全连接输出层的输入,得到分类结果,通过判断分类数量选择CrossEntropyLoss()作为损失函数,将损失loss、分类结果logits、以及可能存在的每一个ViTLayer的输出和注意力矩阵返回,后续当将数据输入model后,可调用output.logits获取分类结果。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值