Transformer 优秀开源工作:timm 库 vision transformer 代码解读

Transformer 优秀开源工作:timm 库 vision transformer 代码解读,第1张

timm库(PyTorchImageModels,简称timm)是一个巨大的PyTorch代码集合,已经被官方使用了。

一、修改num_classes提取分类前和后的特征

我们使用模型:vit_tiny_patch16_224

1.1 修改为num_classes=0提取classify之前的特征192:
self.transformer_model = creat('vit_tiny_patch16_224', pretrained=True, num_classes=0)

打印模型结构可以发现:先经过PatchEmbed然后经历vit_tiny_patch16_224的 6 \color{red}{6} 6个Block,然后得到的是classifier 之前的特征


这里输入特征维度【b, 3, 224, 224】,输出特征维度【b,192】:

1.2 得到网络分类器之前的输出t_q_feature = self.transformer_model.forward_features(t_q_x)

示例:

print("如果设置num_classes,表示重设全连接层,该 *** 作通常用于迁移学习")
m = timm.create_model('resnet50', pretrained=True,num_classes=10)
m.eval()
o = m(torch.randn(2, 3, 224, 224))
print(f'Classification layer shape: {o.shape}')
#输出flatten层或者global_pool层的前一层的数据(flatten层和global_pool层通常接分类层)
o = m.forward_features(torch.randn(2, 3, 224, 224))
print(f'Feature shape: {o.shape}')

代码执行输出如下所示:

如果设置num_classes,表示重设全连接层,该 *** 作通常用于迁移学习
Classification layer shape: torch.Size([2, 10])
Feature shape: torch.Size([2, 2048, 7, 7])
1.3 正常修改head的类别

打印模型结构,前面的到normal都一样,最后的head Linear层发生变化(head): Linear(in_features=192, out_features=3600, bias=True)

这里输入特征维度【b, 3, 224, 224】,输出特征维度【b,3600】3600是我们修改的最后一层输出

PS:直接修改num_classes=3600,就可以不用添加一层self.transformer_model.head了,是一样的模型结构和结果:

1.3 VIT模型结构

参考:【超详细】初学者包会的Vision Transformer(ViT)的PyTorch实现代码学习
可以看到一张图片

  • 经过Encoder Block,再经过MLP Block全连接层变为197*768的特征图。
  • 接着下一个块层标准化…最后堆叠完块之后。
  • 堆叠完Block,出来经过一个层标准化变为197* 768、提取类别Token变为1* 768、经过MLP Head最后输出了1*class的特征向量。

timm库中的features_only=True不适用于vision transformer模型,会报错:RuntimeError: features_only not implemented for Vision Transformer models.

使用summary(self.transformer_model, (3, 224, 224))打印网络结构 PS:torchsummary能够查看模型的输入和输出的形状,可以更加清楚地输出模型的结构。

参考:pytorch 中的torchsummary

  • 第一个参数是model:pytorch 模型,必须继承自 nn.Module
  • 第二个参数是输入的尺寸,input_size:模型输入 size,形状为 C,H ,W,不包括batchsize
  • device:“cuda"或者"cpu”
    使用时需要注意,默认device=‘cuda’,如果是在‘cpu’,那么就需要更改。不匹配就会出现下面的错误:
RuntimeError: Input type (torch.cuda.FloatTensor) and weight type (torch.FloatTensor) should be the same

二、timm库中VisionTransformer代码解读 PS:torch.nn.Identity()

今天看源码时,遇到的这个恒等函数,就如同名字那样
占位符,并没有实际 *** 作
主要使用场景:
不区分参数的占位符标识运算符
if 某个 *** 作 else Identity()
在增减网络过程中,可以使得整个网络层数据不变,便于迁移权重数据。

2.1 输入进vit的x维度为,首先经过x = self.patch_embed(x)


经过x = self.patch_embed(x)内的forward函数:

  • 输入x维度(b,3,224,224),经过x = self.proj(x)后变为(b,192,14,14)
  • 经过x = x.flatten(2).transpose(1, 2) # BCHW -> BNC【用到了flatten(2)将BCHW -> BNC,之后变为196(1414)768(16 16 3通道)】,14*14合并为192,这个出来后变为(16,196,192)
  • 最后经过x = self.norm(x)后return

经过 p a t c h e m b e d \color{red}{patch_embed} patchembed后维度变为:

PS:python:flatten()参数详解

参考:python:flatten()参数详解

  • flatten()是对多维数据的降维函数。
  • flatten(),默认缺省参数为0,也就是说flatten()和flatte(0)效果一样。
  • python里的flatten(dim)表示,从第dim个维度开始展开,将后面的维度转化为一维.也就是说,只保留dim之前的维度,其他维度的数据全都挤在dim这一维。
2.2 vit中的特征提取`forward_features(self, x):
  • 经过提取cls_token
  • 拼接token后变为(b,197,192)
  • 进入堆叠的block后输出为(b,197,92)不变

注意blocks中堆叠块是使用nn.Sequential(*配合下面list的用法,重复depth个Block:

[1 for i in range(5)]
Out[2]: [1, 1, 1, 1, 1]


  • 之后标准化x = self.norm(x)
  • 最后修改了输出如下,提取后的特征维度变为(b,197,102)
2.3 回归forward,上面的forward_features(self, x)是forward中的第一步

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/798985.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-06
下一篇 2022-05-06

发表评论

登录后才能评论

评论列表(0条)

保存