从零搭建Pytorch模型教程(三)搭建Transformer网络

Python微信订餐小程序课程视频

https://blog.csdn.net/m0_56069948/article/details/122285951

Python实战量化交易理财系统

https://blog.csdn.net/m0_56069948/article/details/122285941

前言本文介绍了Transformer的基本流程,分块的两种实现方式,Position Emebdding的几种实现方式,Encoder的实现方式,最后分类的两种方式,以及最重要的数据格式的介绍。

本文来自公众号CV技术指南的技术总结系列

欢迎关注公众号CV技术指南,专注于计算机视觉的技术总结、最新技术跟踪、经典论文解读、CV招聘信息。

在讲如何搭建之前,先回顾一下Transformer在计算机视觉中的结构是怎样的。这里以最典型的ViT为例。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TGvuBSdt-1650084198228)(https://img2022.cnblogs.com/blog/1432790/202204/1432790-20220415204408620-2044020585.gif “点击并拖拽以移动”)]
如图所示,对于一张图像,先将其分割成NxN个patches,把patches进行Flatten,再通过一个全连接层映射成tokens,对每一个tokens加入位置编码(position embedding),会随机初始化一个tokens,concate到通过图像生成的tokens后,再经过transformer的Encoder模块,经过多层Encoder后,取出最后的tokens(即随机初始化的tokens),再通过全连接层作为分类网络进行分类。

下面我们就根据这个流程来一步一步介绍如何搭建一个Transformer模型。、

分块


目前有两种方式实现分块,一种是直接分割,一种是通过卷积核和步长都为patch大小的卷积来分割。

直接分割

直接分割即把图像直接分成多块。在代码实现上需要使用einops这个库,完成的操作是将(B,C,H,W)的shape调整为(B,(H/P W/P),PP*C)。

from einops import rearrange, repeat
from einops.layers.torch import Rearrange

self.to_patch_embedding = nn.Sequential(
           Rearrange('b c (h p1) (w p2) -> b (h w) (p1 p2 c)', p1 = patch_height, p2 = patch_width),
           nn.Linear(patch_dim, dim),
      )

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qxlnZvgf-1650084198233)(https://img2022.cnblogs.com/blog/1432790/202204/1432790-20220415204408620-2044020585.gif “点击并拖拽以移动”)]
这里简单介绍一下Rearrange。

Rearrange用于对张量的维度进行重新变换排序,可用于替换pytorch中的reshape,view,transpose和permute等操作。举几个例子

#假设images的shape为[32,200,400,3]
#实现view和reshape的功能
Rearrange(images,'b h w c -> (b h) w c')#shape变为(32*200, 400, 3)
#实现permute的功能
Rearrange(images, 'b h w c -> b c h w')#shape变为(32, 3, 200, 400)
#实现这几个都很难实现的功能
Rearrange(images, 'b h w c -> (b c w) h')#shape变为(32*3*400, 200)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iD3FaLXx-1650084198234)(https://img2022.cnblogs.com/blog/1432790/202204/1432790-20220415204408620-2044020585.gif “点击并拖拽以移动”)]
从这几个例子看可以看出,Rearrange非常简单好用,这里的b, c, h, w都可以理解为表示符号,用来表示操作变化。通过这几个例子似乎也能理解下面这行代码是如何将图像分割的。

Rearrange('b c (h p1) (w p2) -> b (h w) (p1 p2 c)', p1 = patch_height, p2 = patch_width)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hboCHhft-1650084198235)(https://img2022.cnblogs.com/blog/1432790/202204/1432790-20220415204408620-2044020585.gif “点击并拖拽以移动”)]
这里需要解释的是,一个括号内的两个变量相乘表示的是该维度的长度,因此不要把"h"和"w"理解成图像的宽和高。这里实际上h = H/p1, w = W/p2,代表的是高度上有几块,宽度上有几块。h和w都不需要赋值,代码会自动根据这个表达式计算,b和c也会自动对应到输入数据的B和C。

后面的"b (h w) (p1 p2 c)"表示了图像分块后的shape: (B,(H/P W/P),PP*C)

这种方式在分块后还需要通过一层全连接层将分块的向量映射为tokens。

在ViT中使用的就是这种直接分块方式。

卷积分割

卷积分割比较容易理解,使用卷积核和步长都为patch大小的卷积对图像卷积一次就可以了。

self.proj = nn.Conv2d(in_chans, embed_dim, kernel_size=patch_size, stride=patch_size)

x = self.proj(x).flatten(2).transpose(1, 2)  # B Ph*Pw C

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0kA8XEya-1650084198236)(ht

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
抱歉,Transformer模型通常用于自然语言处理任务,而不是图像分类任务。对于图像分类任务,通常使用卷积神经网络(CNN)等模型。以下是使用PyTorch搭建CNN进行图像分类的示例代码: ```python import torch import torch.nn as nn import torch.optim as optim import torchvision import torchvision.transforms as transforms # 定义数据预处理 transform = transforms.Compose( [transforms.ToTensor(), transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))]) # 加载数据集 trainset = torchvision.datasets.CIFAR10(root='./data', train=True, download=True, transform=transform) trainloader = torch.utils.data.DataLoader(trainset, batch_size=4, shuffle=True, num_workers=2) # 定义模型 class Net(nn.Module): def __init__(self): super(Net, self).__init__() self.conv1 = nn.Conv2d(3, 6, 5) self.pool = nn.MaxPool2d(2, 2) self.conv2 = nn.Conv2d(6, 16, 5) self.fc1 = nn.Linear(16 * 5 * 5, 120) self.fc2 = nn.Linear(120, 84) self.fc3 = nn.Linear(84, 3) def forward(self, x): x = self.pool(torch.relu(self.conv1(x))) x = self.pool(torch.relu(self.conv2(x))) x = x.view(-1, 16 * 5 * 5) x = torch.relu(self.fc1(x)) x = torch.relu(self.fc2(x)) x = self.fc3(x) return x net = Net() # 定义损失函数和优化器 criterion = nn.CrossEntropyLoss() optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9) # 训练模型 for epoch in range(2): # 多次迭代数据集 running_loss = 0.0 for i, data in enumerate(trainloader, 0): # 获取输入数据 inputs, labels = data # 梯度清 optimizer.zero_grad() # 前向传播,计算损失 outputs = net(inputs) loss = criterion(outputs, labels) # 反向传播,更新参数 loss.backward() optimizer.step() # 打印训练状态 running_loss += loss.item() if i % 2000 == 1999: # 每2000批次打印一次训练状态 print('[%d, %5d] loss: %.3f' % (epoch + 1, i + 1, running_loss / 2000)) running_loss = 0.0 print('Finished Training') ``` 在上面的代码中,我们使用了CIFAR-10数据集进行训练,模型使用了两个卷积层和个全连接层。训练完成后,可以使用该模型对新的图像进行分类。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值