python之使用ViT进行图像分类

CIFAR10为数据集,该数据集共有10个分类。整个项目的处理步骤如下。

1)导入需要的库。包括与PyTorch相关的库(torch),与数据处理相关的库(如torchvision)、与张量操作方面的库(如einops)等。

2)对数据进行预处理。使用torchvision导入数据集CIFAR10,然后对数据集进行正则化、剪辑等操作,提升数据质量。

3)生成模型的输入数据。把预处理后的数据向量化,并加上位置嵌入、分类标志等信息,生成模型的输入数据。

4)构建模型。这里主要使用Transformer架构中编码器(Encoder),构建模型。

5)训练模型。定义损失函数,选择优化器,实例化模型,通过多次迭代训练模型。

import torch
import torch.nn.functional as F
import matplotlib.pyplot as plt
import torchvision
import torchvision.transforms as transforms
​
from torch import nn
from torch import Tensor
from PIL import Image
from torchvision.transforms import Compose, Resize, ToTensor
from einops import rearrange, reduce, repeat
from einops.layers.torch import Rearrange, Reduce
# 对训练数据实现数据增强方法,以便提升模型的泛化能力.
train_transform = transforms.Compose([transforms.RandomHorizontalFlip(),
                                      transforms.RandomResizedCrop((32,32),scale=(0.8,1.0),ratio=(0.9,1.1)),
                                      transforms.ToTensor(),
                                      transforms.Normalize([0.49139968, 0.48215841, 0.44653091], [0.24703223, 0.24348513, 0.26158784])
                                     ])
test_transform = transforms.Compose([transforms.ToTensor(),
                                     transforms.Normalize([0.49139968, 0.48215841, 0.44653091], [0.24703223, 0.24348513, 0.26158784])
                                     ])
trainset = torchvision.datasets.CIFAR10(root='../data/', train=True, download=False, transform=train_transform)
trainloader = torch.utils.data.DataLoader(trainset, batch_size=128, shuffle=True, drop_last=True, pin_memory=True, num_workers=4)
testset = torchvision.datasets.CIFAR10(root='../data', train=False,download=False, transform=test_transform)
testloader = torch.utils.data.DataLoader(testset, batch_size=128, shuffle=False, drop_last=False, num_workers=4)
​
classes = ('plane', 'car', 'bird', 'cat','deer', 'dog', 'frog', 'horse', 'ship', 'truck')
# 随机可视化4张图片
NUM_IMAGES = 4
CIFAR_images = torch.stack([trainset[idx][0] for idx in range(NUM_IMAGES)], dim=0)
img_grid = torchvision.utils.make_grid(CIFAR_images, nrow=4, normalize=True, pad_value=0.9)
img_grid = img_grid.permute(1, 2, 0)
​
plt.figure(figsize=(8,8))
plt.title("Image examples of the CIFAR10 dataset")
plt.imshow(img_grid)
plt.axis('off')
plt.show()
plt.close()
class PatchEmbedding(nn.Module):
    def __init__(self, in_channels = 3, patch_size = 4, emb_size = 256):
        self.patch_size = patch_size
        super().__init__()
        self.projection = nn.Sequential(
            # 在s1 x s2切片中分解图像并将其平面化
            Rearrange('b c (h s1) (w s2) -> b (h w) (s1 s2 c)', s1=patch_size, s2=patch_size),
            nn.Linear(patch_size * patch_size * in_channels, emb_size)
        )
                
    def forward(self, x):
        x = self.projection(x)
        return x
class PatchEmbedding(nn.Module):
    def __init__(self, in_channels= 3, patch_size= 4, emb_size= 256):
        self.patch_size = patch_size
        super().__init__()
        self.proj = nn.Sequential(
            # 用卷积层代替线性层->性能提升
            nn.Conv2d(in_channels, emb_size, kernel_size=patch_size, stride=patch_size),
            Rearrange('b e (h) (w) -> b (h w) e'),
        )
        
        self.cls_token = nn.Parameter(torch.randn(1,1, emb_size))
        
    def forward(self, x):
        b, _, _, _ = x.shape
        x = self.proj(x)
        cls_tokens = repeat(self.cls_token, '() n e -> b n e', b=b)
        # 在输入前添加cls标记
        x = torch.cat([cls_tokens, x], dim=1)
        return x
class PatchEmbedding(nn.Module):
    def __init__(self, in_channels= 3, patch_size= 4, emb_size= 256, img_size= 32):
        self.patch_size = patch_size
        super().__init__()
        self.projection = nn.Sequential(
            # 用卷积层代替线性层->性能提升
            nn.Conv2d(in_channels, emb_size, kernel_size=patch_size, stride=patch_size),
            Rearrange('b e (h) (w) -> b (h w) e'),
        )
        self.cls_token = nn.Parameter(torch.randn(1,1, emb_size))
        self.positions = nn.Parameter(torch.randn((img_size // patch_size) **2 + 1, emb_size))
​
        
    def forward(self, x):
        b, _, _, _ = x.shape
        x = self.projection(x)
        cls_tokens = repeat(self.cls_token, '() n e -> b n e', b=b)
        # 在输入前添加cls标记
        x = torch.cat([cls_tokens, x], dim=1)
        # 加位置嵌入
        x += self.positions
        return x
class MultiHeadAttention(nn.Module):
    def __init__(self, emb_size = 256, num_heads = 8, dropout = 0):
        super().__init__()
        self.emb_size = emb_size
        self.num_heads = num_heads
        # 将查询、键和值融合到一个矩阵中
        self.qkv = nn.Linear(emb_size, emb_size * 3)
        self.att_drop = nn.Dropout(dropout)
        self.projection = nn.Linear(emb_size, emb_size)
        
    def forward(self, x , mask = None):
        # 分割num_heads中的键、查询和值
        qkv = rearrange(self.qkv(x), "b n (h d qkv) -> (qkv) b h n d", h=self.num_heads, qkv=3)
        queries, keys, values = qkv[0], qkv[1], qkv[2]
        # 最后一个轴上求和
        energy = torch.einsum('bhqd, bhkd -> bhqk', queries, keys) # batch, num_heads, query_len, key_len
        if mask is not None:
            fill_value = torch.finfo(torch.float32).min
            energy.mask_fill(~mask, fill_value)
            
        scaling = self.emb_size ** (1/2)
        att = F.softmax(energy, dim=-1) / scaling
        att = self.att_drop(att)
        # 在第三个轴上求和
        out = torch.einsum('bhal, bhlv -> bhav ', att, values)
        out = rearrange(out, "b h n d -> b n (h d)")
        out = self.projection(out)
        return out
class ResidualAdd(nn.Module):
    def __init__(self, fn):
        super().__init__()
        self.fn = fn
        
    def forward(self, x, **kwargs):
        res = x
        x = self.fn(x, **kwargs)
        x += res
        return x
class FeedForwardBlock(nn.Sequential):
    def __init__(self, emb_size=256, expansion= 4, drop_p= 0.):
        super().__init__(
            nn.Linear(emb_size, expansion * emb_size),
            nn.GELU(),
            nn.Dropout(drop_p),
            nn.Linear(expansion * emb_size, emb_size),
        )
class TransformerEncoderBlock(nn.Sequential):
    def __init__(self,
                 emb_size= 256,
                 drop_p = 0.,
                 forward_expansion = 4,
                 forward_drop_p = 0.,
                 ** kwargs):
        super().__init__(
            ResidualAdd(nn.Sequential(
                nn.LayerNorm(emb_size),
                MultiHeadAttention(emb_size, **kwargs),
                nn.Dropout(drop_p)
            )),
            ResidualAdd(nn.Sequential(
                nn.LayerNorm(emb_size),
                FeedForwardBlock(
                    emb_size, expansion=forward_expansion, drop_p=forward_drop_p),
                nn.Dropout(drop_p)
            )
            ))
class TransformerEncoder(nn.Sequential):
    def __init__(self, depth: int = 12, **kwargs):
        super().__init__(*[TransformerEncoderBlock(**kwargs) for _ in range(depth)])
class ClassificationHead(nn.Sequential):
    def __init__(self, emb_size= 256, n_classes = 10):
        super().__init__(
            Reduce('b n e -> b e', reduction='mean'),
            nn.LayerNorm(emb_size), 
            nn.Linear(emb_size, n_classes))
class ViT(nn.Sequential):
    def __init__(self,     
                in_channels = 3,
                patch_size = 4,
                emb_size = 256,
                img_size = 32,
                depth = 12,
                n_classes = 10,
                **kwargs):
        super().__init__(
            PatchEmbedding(in_channels, patch_size, emb_size, img_size),
            TransformerEncoder(depth, emb_size=emb_size, **kwargs),
            ClassificationHead(emb_size, n_classes)
        )
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
​
vit = ViT()
vit=vit.to(device)
import torch.optim as optim
LR=0.001
​
criterion = nn.CrossEntropyLoss()
optimizer = optim.AdamW(vit.parameters(), lr=0.001)
for epoch in range(10):  
​
    running_loss = 0.0
    for i, data in enumerate(trainloader, 0):
        # 获取训练数据
        #print(i)
        inputs, labels = data
        inputs, labels = inputs.to(device), labels.to(device)
       
        # 权重参数梯度清零
        optimizer.zero_grad()
​
        # 正向及反向传播
        outputs = vit(inputs)
        loss = criterion(outputs, labels)
        loss.backward()
        optimizer.step()
​
        # 显示损失值
        running_loss += loss.item()
        if i % 100 == 99:    # print every 100 mini-batches
            print('[%d, %5d] loss: %.3f' %(epoch + 1, i + 1, running_loss / 100))
            running_loss = 0.0
​
print('Finished Training')
​

 

                
  • 13
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
【资源说明】 基于强化学习的自动化裁剪CIFAR-10分类任务python源码+项目部署说明(提升模型精度+减少计算量).zip 1、该资源内项目代码都是经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载使用,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能。 目前的强化学习工作很多集中在利用外部环境的反馈训练agent,忽略了模型本身就是一种能够获得反馈的环境。本项目的核心思想是:将模型视为环境,构建附生于模型的 agent ,以辅助模型进一步拟合真实样本。 大多数领域的模型都可以采用这种方式来优化,如cv\多模态等。它至少能够以三种方式工作:1.过滤噪音信息,如删减语音或图像特征;2.进一步丰富表征信息,如高效引用外部信息;3.实现记忆、联想、推理等复杂工作,如构建重要信息的记忆池。 这里推出一款早期完成的裁剪机制transformer版本(后面称为APT),实现了一种更高效的训练模式,能够优化模型指标;此外,可以使用动态图丢弃大量的不必要单元,在指标基本不变的情况下,大幅降低计算量。 该项目希望为大家抛砖引玉。 为什么要做自动剪枝 在具体任务中,往往存在大量毫无价值的信息和过渡性信息,有时不但对任务无益,还会成为噪声。比如:表述会存在冗余/无关片段以及过渡性信息;动物图像识别中,有时候背景无益于辨别动物主体,即使是动物部分图像,也仅有小部分是关键的特征。 以transformer为例,在进行self-attention计算时其复杂度与序列长度平方成正比。长度为10,复杂度为100;长度为9,复杂度为81。 利用强化学习构建agent,能够精准且自动化地动态裁剪已丧失意义部分,甚至能将长序列信息压缩到50-100之内(实验中有从500+的序列长度压缩到个位数的示例),以大幅减少计算量。 ***实验中,发现与裁剪agent联合训练的模型比普通方法训练的模型效果要更好。*** 使用说明 环境 ``` torch numpy tqdm tensorboard ml-collections ``` 下载经过预先​​训练的模型(来自Google官方) 本项目使用的型号:ViT-B_16(您也可以选择其它型号进行测试) ``` imagenet21k pre-train wget https://storage.googleapis.com/vit_models/imagenet21k/ViT-B_16.npz ``` 训练与推理 下载好预训练模型就可以跑了。 ``` 训练 python3 train.py --name cifar10-100_500 --dataset cifar100 --model_type ViT-B_16 --pretrained_dir checkpoint/ViT-B_16.npz 推理 python3 infer.py --name cifar10-100_500 --dataset cifar100 --model_type ViT-B_16 --pretrained_dir checkpoint/ViT-B_16.npz ``` CIFAR-10和CIFAR-100会自动下载和培训。如果使用其他数据集,您需要自定义data_utils.py。 在裁剪模式的推理过程中,预期您将看到如下格式的输出 关于裁剪器的模型结构设计,本模型中认为如何衡量一个信息单元是否对模型有意义,建立于其自身的信息及它与任务的相关性上。 因此以信息单元本身及它与CLS单元的交互作为agent的输入信息。
【资源介绍】 基于ViT模型的医疗图像辅助诊断系统python源码+项目说明.zip 基于ViT模型的医疗图像辅助诊断系统python源码+项目说明.zip 基于ViT模型的医疗图像辅助诊断系统python源码+项目说明.zip astor==0.8.1 gast==0.3.3 h5py==2.10.0 idna==3.4 matplotlib==3.1.2 memory-profiler==0.61.0 mkl-fft==1.3.0 mkl-random==1.1.0 mkl-service==2.3.0 numpy==1.17.0 opencv-python==4.1.2.30 opt-einsum==3.3.0 paddle-bfloat==0.1.7 paddlepaddle==2.4.2 Pillow==8.2.0 ply==3.11 protobuf==3.20.0 PyQt5==5.15.7 pywin32==305.1 PyYAML==6.0 requests==2.28.1 scipy==1.2.1 torch==1.13.1+cu117 torchaudio==0.13.1+cu117 torchvision==0.14.1+cu117 tqdm==4.66.1 typing==3.7.4.3 urllib3==1.26.13 wincertstore==0.2 【备注】 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用!有问题请及时沟通交流。 2、适用人群:计算机相关专业(如计科、信息安全、数据科学与大数据技术、人工智能、通信、物联网、自动化、电子信息等)在校学生、专业老师或者企业员工下载使用。 3、用途:项目具有较高的学习借鉴价值,也适用于小白学习入门进阶。当然也可作为毕设项目、课程设计、大作业、初期项目立项演示等。 4、如果基础还行,或者热爱钻研,亦可在此项目代码基础上进行修改添加,实现其他不同功能。 欢迎下载,沟通交流,互相学习,共同进步!
【资源介绍】 基于HAM10000数据集实现皮肤癌分类python源码+使用说明.zip 这是一个用于训练图像分类模型的代码。在运行代码之前,用户需要安装以下依赖库:argparse, os, pandas, numpy, PIL, datasets, torchvision, tqdm和transformers。用户还需要从Hugging Face上下载所需的预训练模型。 参数说明 - `--metadata_path`:metadata文件的路径。默认为"./archive/HAM10000_metadata.csv"。 - `--images_dir`:图像文件夹的路径。默认为"./archive/HAM10000_images/"。 - `--model_dir`:预训练模型的路径。默认为"../model/vit-large-patch16-224-in21k"。 - `--checkpoints_dir`:保存检查点文件的文件夹路径。默认为"./checkpoints"。 - `--learning_rate`:学习率。默认为1e-5。 - `--batch_size`:批大小。默认为64。 - `--epochs`:训练轮数。默认为5。 - `--warmup_ratio`:预热步骤的比例。默认为0.1。 - `--split`:训练-验证数据集的分割比例。默认为0.8。 - `--gpu`:指定使用哪张GPU。默认为"0"。 - `--logging_steps`:每隔多少步记录一次训练日志。默认为50。 用户可以在命令行中传递这些参数,例如: ```shell python train-hf.py --metadata_path ./archive/HAM4000_metadata.csv \ --images_dir ./archive/HAM10000_images/ \ --checkpoints_dir ./checkpoints \ --learning_rate 1e-4 \ --batch_size 64 \ --epochs 20 \ --warmup_ratio 0.1 \ --model_dir ../model/vit-large-patch16-224-in21k \ --gpu 5,6,7 \ --logging_steps 1 ``` 在代码运行过程中,会执行以下步骤: 1. 读取metadata文件,获取图像文件名和标签。 2. 将图像读入内存,并随机打乱。 3. 将数据集划分为训练集和验证集。 4. 对图像进行预处理,包括随机裁剪、归一化和转换为tensor。 5. 加载预训练模型,构建分类器。 6. 训练模型,并在验证集上评估模型性能。 7. 在训练过程中,每隔logging_steps步记录一次训练日志,包括损失值、准确率等指标。 8. 在训练结束后,保存模型的权重文件到checkpoints_dir文件夹中。 【备注】 该项目是个人毕设/课设/大作业项目,代码都经过本地调试测试,功能ok才上传,高分作品,可快速上手运行!欢迎下载使用,可用于小白学习、进阶。 该资源主要针对计算机、通信、人工智能、自动化等相关专业的学生、老师或从业者下载使用,亦可作为期末课程设计、课程大作业、毕业设计等。 项目整体具有较高的学习借鉴价值!基础能力强的可以在此基础上修改调整,以实现不同的功能。 欢迎下载使用,也欢迎交流学习!
以下是基于TensorFlow的ViT模型的图像分类代码示例: ```python import tensorflow as tf import tensorflow_datasets as tfds from tensorflow.keras.layers.experimental.preprocessing import Resizing from vit_keras import vit, utils # Load the CIFAR-10 dataset (ds_train, ds_test), ds_info = tfds.load('cifar10', split=['train', 'test'], with_info=True) # Define some constants NUM_CLASSES = ds_info.features['label'].num_classes IMAGE_SIZE = 72 # ViT requires images to be divisible by 8 # Preprocess the data def preprocess_data(data): x = data['image'] y = tf.one_hot(data['label'], NUM_CLASSES) x = Resizing(IMAGE_SIZE, IMAGE_SIZE)(x) / 255.0 # Resize and normalize return x, y ds_train = ds_train.map(preprocess_data).batch(32).prefetch(tf.data.experimental.AUTOTUNE) ds_test = ds_test.map(preprocess_data).batch(32).prefetch(tf.data.experimental.AUTOTUNE) # Define the ViT model model = vit.vit_b16( image_size=IMAGE_SIZE, activation='softmax', classes=NUM_CLASSES, include_top=True, pretrained=True ) # Compile the model model.compile( optimizer=tf.keras.optimizers.Adam(), loss=tf.keras.losses.CategoricalCrossentropy(), metrics=[tf.keras.metrics.CategoricalAccuracy()] ) # Train the model model.fit( ds_train, validation_data=ds_test, epochs=10 ) # Evaluate the model model.evaluate(ds_test) ``` 这个代码示例使用了 TensorFlow Datasets 中的 CIFAR-10 数据集,并使用ViT-B16 模型进行图像分类。首先,我们定义了一些常量,包括类别数量和图像大小。然后,我们定义了一个函数来对数据进行预处理,包括缩放和归一化。接下来,我们使用 `vit.vit_b16` 函数定义了 ViT 模型,并将其编译。最后,我们使用 `model.fit` 函数训练模型,并使用 `model.evaluate` 函数评估模型。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值