VISION TRANSFORMER简称ViT,是2020年提出的一种先进的视觉注意力模型,利用transformer及自注意力机制,通过一个标准图像分类数据集ImageNet,基本和SOTA的卷积神经网络相媲美。
我们这里利用简单的ViT进行猫狗数据集的分类,具体数据集可参考这个链接
猫狗数据集
依赖
from functools import partial
from collections import OrderedDict
import torch
import torch.nn as nn
import torchvision
from torchvision import datasets,transforms,models
import os
import matplotlib.pyplot as plt
import time
from torch.autograd import Variable # torch 中 Variable 模块
%matplotlib inline
准备数据集合
data_dir = "dogs-vs-cats"
data_tansform = {
x:transforms.Compose([transforms.Resize([224,224]), # 固定图像大小
transforms.ToTensor(),
transforms.Normalize(mean=[.5,.5,.5],std=[.5,.5,.5])])
for x in ["train","valid"]}
image_datasets = {
x:datasets.ImageFolder(root=os.path.join(data_dir,x),
transform = data_tansform[x])
for x in ["train","valid"]}
dataloader = {
x:torch.utils.data.DataLoader(dataset=image_datasets[x],
batch_size=16,
shuffle=True)
for x in ["train","valid"]}
检查一下数据情况
# 获取一个批次,并进行数据预览和分析
x_example,y_example = next(iter(dataloader["train"]))
example_clasees = image_datasets["train"].classes
index_classes = image_datasets["train"].class_to_idx
img = torchvision.utils.make_grid(x_example)
img = img.numpy().transpose([1,2,0])
print([example_clasees[i] for i in y_example])
plt.imshow(img)
plt.show()

残差结构
在深度学习中,一种被广泛使用的技术是随机深度(Stochastic Depth),它可以在训练过程中随机丢弃网络中的一部分层,从而增强模型的鲁棒性。在Vision Transformer(ViT)中,随机深度被应用在了残差连接中,即在残差块的主路径中随机丢弃一些通道,以增加网络深度时的稳定性。
drop_path的函数,它用于在训练过程中应用随机深度。该函数需要传入的参数包括输入张量x、丢失路径的比例drop_prob和当前是否处于训练模式training,函数的返回值为一个经过随机深度处理后的输出张量output。
首先,函数会判断drop_prob是否为0或者当前不处于训练模式,如果是的话,直接返回输入张量x,不做任何处理。
如果不满足上述条件,则根据drop_prob计算出保留每个元素的概 keep_prob,即1-drop_prob。接下来,函数会获取输入张量的形状信息,并且生成一个相同形状的随机张量。其中,随机张量的每个元素取值为keep_prob和一个随机值之间的最大值。这里的操作有些类似于dropout,在训练时,我们会把神经元的输出乘以一个二元随机变量,从而随机地丢弃一些神经元,来增加模型的泛化能力和鲁棒性。
最后,函数使用生成的随机张量对输入张量进行二元操作,并且除以keep_prob,得到最终的输出。这里的随机维度上的值更有可能为0,因此输出张量的期望值保持一致,起到适应网络深度的剪枝效果。
DropPath的神经网络模块,用于实现随机深度(Stochastic Depth)中的路径丢弃。这个模块用于被主路径的残差块调用,通过随机丢弃一些神经元,减少了网络中的一些层,从而增强了模型的实用性和泛化性能。
DropPath类继承自PyTorch的nn.Module类,DropPath可以直接使用PyTorch提供的前向传播方法forward()。
在DropPath的构造函数__init__()中,定义了一个成员变量drop_prob,它将用于影响DropPath在前向传播的过程中对输入数据的随机丢弃比例。可以看出,这个变量是可选的,如果其值为None,则代表不进行丢弃。
在DropPath的前向传播方法forward()中,我们会调用上文中定义的drop_path()函数,来完成具体的随机丢弃操作。
Drop-path函数
def drop_path(x, drop_prob: float = 0., training: bool = False):
if drop_prob == 0. or not training:
return x
keep_prob = 1 - drop_prob
shape = (x.shape[0],) + (1,) * (x.ndim - 1) # work with diff dim tensors, not just 2D ConvNets
random_tensor = keep_prob + torch.rand(shape, dtype=x.dtype, device=x.device)
random_tensor.floor_() # binarize
output = x.div(keep_prob) * random_tensor
return output
class DropPath(nn.Module):
"""
Drop paths (Stochastic Depth) per sample (when applied in main path of residual blocks).
"""
def __init__(self, drop_prob=None):
super(DropPath, self).__init__()
self.drop_prob = drop_prob
def forward(self, x):
return drop_path(x, self.drop_prob, self.training)
PatchEmbed模块
PatchEmbed是ViT模型的第一个模块,它的作用是将二维图像数据转换为一维序列数据,并进行特征提取和正则化。
Patch Embedding,即将2D图像划分为固定大小、不重叠的patch,,并把每个patch中的像素视为一个向量进行处理。这里对每个patch进行嵌入向量映射的方法是使用一个2D卷积层(nn.Conv2d)对patch进行卷积处理,然后将卷积结果展平成一维向量,进一步转置(transpose)成尺寸为(batch_size, num_patches, embedding_size)的输出序列。这个序列中的每个元素就是一个patch的嵌入向量。
这个序列的长度是设定的num_patches,即输入图像的面积除以patch面积。注意到这里的标准化操作使用了一个可选参数norm_layer,如果传入了一个标准化层,就会使用它来对嵌入向量进行标准化;否则就使用一个恒等映射层对嵌入向量保持不变。
img_size: 输入图像的大小(高度、宽度,均为整数)。默认值为224。patch_size:patch的大小(高度、宽度,均为整数)。默认值为16。
in_c: 输入图像的通道数(整数)。默认值为3。
embed_dim:patch嵌入后的维度(整数)。默认值为768。
norm_layer:可选参数,对嵌入向量进行标准化的层(标准化层或恒等映射层)。默认值为None,代表不进行标准化处理。
class PatchEmbed(nn.Module)

本文介绍了如何利用VISIONTRANSFORMER(ViT)模型对猫狗数据集进行图像分类。模型基于Transformer架构,结合残差结构和随机深度(DropPath)增强网络的鲁棒性。文章详细展示了数据预处理、残差结构的随机丢弃层、PatchEmbed模块、Attention模块以及MLPBlock的实现,并提供了模型训练的代码示例。
最低0.47元/天 解锁文章
4026

被折叠的 条评论
为什么被折叠?



