第50步 深度学习图像识别:Data-efficient Image Transformers建模(Pytorch)

基于WIN10的64位系统演示

一、写在前面

(1)Data-efficient Image Transformers

Data-efficient Image Transformers (DeiT)是一种用于图像分类的新型模型,由Facebook AI在2020年底提出。这种方法基于视觉Transformer,通过训练策略的改进,使得模型能在少量数据下达到更高的性能。

在许多情况下,Transformer模型需要大量的数据才能得到好的结果。然而,这在某些场景下是不可能的,例如在只有少量标注数据的情况下。DeiT方法通过在训练过程中使用知识蒸馏,解决了这个问题。知识蒸馏是一种让小型模型学习大型模型行为的技术。

DeiT中的关键技术之一是使用学生模型预测教师模型的类别分布,而不仅仅是硬标签(原始数据集中的类别标签)。这样做的好处是,学生模型可以从教师模型的软标签(类别概率分布)中学习更多的信息。另外,DeiT还引入了一种新的训练方法,称为“硬标签蒸馏”,这种方法更进一步提高了模型的性能。通过这种方法,即使在ImageNet这样的大规模数据集上,DeiT也可以与更复杂的卷积神经网络(如ResNet和EfficientNet)相媲美或者超越,同时还使用了更少的计算资源。

(2)Data-efficient Image Transformers的预训练版本

本文继续使用Facebook的高级深度学习框架PyTorchImageModels (timm)。该库提供了多种预训练的模型,太多了,我还是给网址吧:

https://github.com/huggingface/pytorch-image-models/blob/main/timm/models/deit.py

从第155行到第249行都是:

 

比如“deit_tiny_patch16_224”

"deit": 这是模型类型的缩写,代表 "Data-efficient Image Transformers"。

"tiny": 这个词说明了模型的大小。在此情况下,"tiny"意味着这是一个更小、计算成本更低的模型版本。相对的,还有"small","base"等不同规模的模型。

"patch16": 这是指在模型的输入阶段,原始图像被分割成大小为16x16像素的小方块(也被称为patch)进行处理。

"224": 这是指模型接受的输入图像的尺寸是224x224像素。这是在计算机视觉领域常用的图像尺寸。

二、Data-efficient Image Transformers迁移学习代码实战

我们继续胸片的数据集:肺结核病人和健康人的胸片的识别。其中,肺结核病人700张,健康人900张,分别存入单独的文件夹中。

(a)导入包

import copy
import torch
import torchvision
import torchvision.transforms as transforms
from torchvision import models
from torch.utils.data import DataLoader
from torch import optim, nn
from torch.optim import lr_scheduler
import os
import matplotlib.pyplot as plt
import warnings
import numpy as npwarnings.filterwarnings("ignore")
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False# 设置GPU
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")

(b)导入数据集

import torch
from torchvision import datasets, transforms
import os# 数据集路径
data_dir = "./MTB"# 图像的大小
img_height = 100
img_width = 100# 数据预处理
data_transforms = {'train': transforms.Compose([transforms.RandomResizedCrop(img_height),transforms.RandomHorizontalFlip(),transforms.RandomVerticalFlip(),transforms.RandomRotation(0.2),transforms.ToTensor(),transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])]),'val': transforms.Compose([transforms.Resize((img_height, img_width)),transforms.ToTensor(),transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])]),
}# 加载数据集
full_dataset = datasets.ImageFolder(data_dir)# 获取数据集的大小
full_size = len(full_dataset)
train_size = int(0.7 * full_size)  # 假设训练集占80%
val_size = full_size - train_size  # 验证集的大小# 随机分割数据集
torch.manual_seed(0)  # 设置随机种子以确保结果可重复
train_dataset, val_dataset = torch.utils.data.random_split(full_dataset, [train_size, val_size])# 将数据增强应用到训练集
train_dataset.dataset.transform = data_transforms['train']# 创建数据加载器
batch_size = 32
train_dataloader = torch.utils.data.DataLoader(train_dataset, batch_size=batch_size, shuffle=True, num_workers=4)
val_dataloader = torch.utils.data.DataLoader(val_dataset, batch_size=batch_size, shuffle=True, num_workers=4)dataloaders = {'train': train_dataloader, 'val': val_dataloader}
dataset_sizes = {'train': len(train_dataset), 'val': len(val_dataset)}
class_names = full_dataset.classes

(c)导入Data-efficient Image Transformers

# 导入所需的库
import torch.nn as nn
import timm# 定义Data-efficient Image Transformers模型
model = timm.create_model('deit_base_patch16_224', pretrained=True)  # 你可以选择适合你需求的DeiT版本,这里以deit_base_patch16_224为例
num_ftrs = model.head.in_features# 根据分类任务修改最后一层
model.head = nn.Linear(num_ftrs, len(class_names))# 将模型移至指定设备
model = model.to(device)# 打印模型摘要
print(model)

(d)编译模型

# 定义损失函数
criterion = nn.CrossEntropyLoss()# 定义优化器
optimizer = optim.Adam(model.parameters())# 定义学习率调度器
exp_lr_scheduler = lr_scheduler.StepLR(optimizer, step_size=7, gamma=0.1)# 开始训练模型
num_epochs = 10
best_model_wts = copy.deepcopy(model.state_dict())
best_acc = 0.0# 初始化记录器
train_loss_history = []
train_acc_history = []
val_loss_history = []
val_acc_history = []for epoch in range(num_epochs):print('Epoch {}/{}'.format(epoch, num_epochs - 1))print('-' * 10)# 每个epoch都有一个训练和验证阶段for phase in ['train', 'val']:if phase == 'train':model.train()  # Set model to training modeelse:model.eval()   # Set model to evaluate moderunning_loss = 0.0running_corrects = 0# 遍历数据for inputs, labels in dataloaders[phase]:inputs = inputs.to(device)labels = labels.to(device)# 零参数梯度optimizer.zero_grad()# 前向with torch.set_grad_enabled(phase == 'train'):outputs = model(inputs)_, preds = torch.max(outputs, 1)loss = criterion(outputs, labels)# 只在训练模式下进行反向和优化if phase == 'train':loss.backward()optimizer.step()# 统计running_loss += loss.item() * inputs.size(0)running_corrects += torch.sum(preds == labels.data)epoch_loss = running_loss / dataset_sizes[phase]epoch_acc = (running_corrects.double() / dataset_sizes[phase]).item()# 记录每个epoch的loss和accuracyif phase == 'train':train_loss_history.append(epoch_loss)train_acc_history.append(epoch_acc)else:val_loss_history.append(epoch_loss)val_acc_history.append(epoch_acc)print('{} Loss: {:.4f} Acc: {:.4f}'.format(phase, epoch_loss, epoch_acc))# 深拷贝模型if phase == 'val' and epoch_acc > best_acc:best_acc = epoch_accbest_model_wts = copy.deepcopy(model.state_dict())print()print('Best val Acc: {:4f}'.format(best_acc))

(e)Accuracy和Loss可视化

epoch = range(1, len(train_loss_history)+1)fig, ax = plt.subplots(1, 2, figsize=(10,4))
ax[0].plot(epoch, train_loss_history, label='Train loss')
ax[0].plot(epoch, val_loss_history, label='Validation loss')
ax[0].set_xlabel('Epochs')
ax[0].set_ylabel('Loss')
ax[0].legend()ax[1].plot(epoch, train_acc_history, label='Train acc')
ax[1].plot(epoch, val_acc_history, label='Validation acc')
ax[1].set_xlabel('Epochs')
ax[1].set_ylabel('Accuracy')
ax[1].legend()#plt.savefig("loss-acc.pdf", dpi=300,format="pdf")

观察模型训练情况:

蓝色为训练集,橙色为验证集。

(f)混淆矩阵可视化以及模型参数

from sklearn.metrics import classification_report, confusion_matrix
import math
import pandas as pd
import numpy as np
import seaborn as sns
from matplotlib.pyplot import imshow# 定义一个绘制混淆矩阵图的函数
def plot_cm(labels, predictions):# 生成混淆矩阵conf_numpy = confusion_matrix(labels, predictions)# 将矩阵转化为 DataFrameconf_df = pd.DataFrame(conf_numpy, index=class_names ,columns=class_names)  plt.figure(figsize=(8,7))sns.heatmap(conf_df, annot=True, fmt="d", cmap="BuPu")plt.title('Confusion matrix',fontsize=15)plt.ylabel('Actual value',fontsize=14)plt.xlabel('Predictive value',fontsize=14)def evaluate_model(model, dataloader, device):model.eval()   # 设置模型为评估模式true_labels = []pred_labels = []# 遍历数据for inputs, labels in dataloader:inputs = inputs.to(device)labels = labels.to(device)# 前向with torch.no_grad():outputs = model(inputs)_, preds = torch.max(outputs, 1)true_labels.extend(labels.cpu().numpy())pred_labels.extend(preds.cpu().numpy())return true_labels, pred_labels# 获取预测和真实标签
true_labels, pred_labels = evaluate_model(model, dataloaders['val'], device)# 计算混淆矩阵
cm_val = confusion_matrix(true_labels, pred_labels)
a_val = cm_val[0,0]
b_val = cm_val[0,1]
c_val = cm_val[1,0]
d_val = cm_val[1,1]# 计算各种性能指标
acc_val = (a_val+d_val)/(a_val+b_val+c_val+d_val)  # 准确率
error_rate_val = 1 - acc_val  # 错误率
sen_val = d_val/(d_val+c_val)  # 灵敏度
sep_val = a_val/(a_val+b_val)  # 特异度
precision_val = d_val/(b_val+d_val)  # 精确度
F1_val = (2*precision_val*sen_val)/(precision_val+sen_val)  # F1值
MCC_val = (d_val*a_val-b_val*c_val) / (np.sqrt((d_val+b_val)*(d_val+c_val)*(a_val+b_val)*(a_val+c_val)))  # 马修斯相关系数# 打印出性能指标
print("验证集的灵敏度为:", sen_val, "验证集的特异度为:", sep_val,"验证集的准确率为:", acc_val, "验证集的错误率为:", error_rate_val,"验证集的精确度为:", precision_val, "验证集的F1为:", F1_val,"验证集的MCC为:", MCC_val)# 绘制混淆矩阵
plot_cm(true_labels, pred_labels)# 获取预测和真实标签
train_true_labels, train_pred_labels = evaluate_model(model, dataloaders['train'], device)
# 计算混淆矩阵
cm_train = confusion_matrix(train_true_labels, train_pred_labels)  
a_train = cm_train[0,0]
b_train = cm_train[0,1]
c_train = cm_train[1,0]
d_train = cm_train[1,1]
acc_train = (a_train+d_train)/(a_train+b_train+c_train+d_train)
error_rate_train = 1 - acc_train
sen_train = d_train/(d_train+c_train)
sep_train = a_train/(a_train+b_train)
precision_train = d_train/(b_train+d_train)
F1_train = (2*precision_train*sen_train)/(precision_train+sen_train)
MCC_train = (d_train*a_train-b_train*c_train) / (math.sqrt((d_train+b_train)*(d_train+c_train)*(a_train+b_train)*(a_train+c_train))) 
print("训练集的灵敏度为:",sen_train, "训练集的特异度为:",sep_train,"训练集的准确率为:",acc_train, "训练集的错误率为:",error_rate_train,"训练集的精确度为:",precision_train, "训练集的F1为:",F1_train,"训练集的MCC为:",MCC_train)# 绘制混淆矩阵
plot_cm(train_true_labels, train_pred_labels)

效果不错:

(g)AUC曲线绘制

from sklearn import metrics
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.pyplot import imshow
from sklearn.metrics import classification_report, confusion_matrix
import seaborn as sns
import pandas as pd
import mathdef plot_roc(name, labels, predictions, **kwargs):fp, tp, _ = metrics.roc_curve(labels, predictions)plt.plot(fp, tp, label=name, linewidth=2, **kwargs)plt.plot([0, 1], [0, 1], color='orange', linestyle='--')plt.xlabel('False positives rate')plt.ylabel('True positives rate')ax = plt.gca()ax.set_aspect('equal')# 确保模型处于评估模式
model.eval()train_ds = dataloaders['train']
val_ds = dataloaders['val']val_pre_auc   = []
val_label_auc = []for images, labels in val_ds:for image, label in zip(images, labels):      img_array = image.unsqueeze(0).to(device)  # 在第0维增加一个维度并将图像转移到适当的设备上prediction_auc = model(img_array)  # 使用模型进行预测val_pre_auc.append(prediction_auc.detach().cpu().numpy()[:,1])val_label_auc.append(label.item())  # 使用Tensor.item()获取Tensor的值
auc_score_val = metrics.roc_auc_score(val_label_auc, val_pre_auc)train_pre_auc   = []
train_label_auc = []for images, labels in train_ds:for image, label in zip(images, labels):img_array_train = image.unsqueeze(0).to(device) prediction_auc = model(img_array_train)train_pre_auc.append(prediction_auc.detach().cpu().numpy()[:,1])  # 输出概率而不是标签!train_label_auc.append(label.item())
auc_score_train = metrics.roc_auc_score(train_label_auc, train_pre_auc)plot_roc('validation AUC: {0:.4f}'.format(auc_score_val), val_label_auc , val_pre_auc , color="red", linestyle='--')
plot_roc('training AUC: {0:.4f}'.format(auc_score_train), train_label_auc, train_pre_auc, color="blue", linestyle='--')
plt.legend(loc='lower right')
#plt.savefig("roc.pdf", dpi=300,format="pdf")print("训练集的AUC值为:",auc_score_train, "验证集的AUC值为:",auc_score_val)

 ROC曲线如下:

 很优秀的ROC曲线!

三、写在最后

运算量和消耗的计算资源还是大,在这个数据集上跑出来的性能比ViT模型要好一些,说明优化策略还是起到效果的。

四、数据

链接:https://pan.baidu.com/s/15vSVhz1rQBtqNkNp2GQyVw?pwd=x3jf

提取码:x3jf

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/20133.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

LoRA指令微调——源码解析

目录 1. lit-llama工程2. LoRA部分3. 代码部分4. LoRA模型文件 (本次博文的LoRA代码主要基于lit-llama工程) 1. lit-llama工程 lit-llama是一个大语言模型的工程,可用于语言模型的训练、测试等优点:很简洁,代码也很容…

健身房综合云管理项目

博主简介: 河南沐斯特网络科技有限公司技术顾问; 天津集创科技有限公司创始人之一兼前端开发工程师/python开发; 第十四届中国服务外包大赛华北地区(九个省加自治区直辖市)三等奖; CSDN官方内容合伙人, CSDN.2023年…

C++_简单模拟实现string的增删查改

目录 一、模拟reserve 二、模拟push_back 三、模拟append 四、模拟operator 五、模拟insert 六、模拟erase 七、模拟find 八、模拟substr 一、模拟reserve 要添加数据,首先要考虑的是扩容。有必要用reserve辅助扩容。reserve的作用就是给一个预期的值作为扩…

2023金九银十大厂 Java 面试八股文大全(整理版)附答案详解

Java 面试八股文有必要背吗? 我的回答是:很有必要。你可以讨厌这种模式,但你一定要去背,因为不背你就进不了大厂。现如今,Java 面试的本质就是八股文,把八股文面试题背好,面试才有可能表现好。…

STM32 Proteus仿真空气质量检测环境监测苯PM2.5 MQ135温度湿度 -0068

STM32 Proteus仿真空气质量检测环境监测苯PM2.5 MQ135温度湿度 -0068 Proteus仿真小实验: STM32 Proteus仿真空气质量检测环境监测苯PM2.5 MQ135温度湿度 -0068 功能: 硬件组成:STM32F103R6单片机 LCD1602显示器DHT11温度湿度多个按键蜂鸣…

Visual Studio 2017下的C++开发环境搭建

Visual Studio 是Microsoft旗下的开发工具包系列产品,是一个基本完整的开发工具集,它包括整个软件生命周期中所需要的大部分工具,如UML工具、代码管控工具、集成开发环境(IDE)等等,是最流行的Windows平台应用程序的集成开发环境。…

ESPHOME max7219点阵时钟

Note ESPHome中max7219digit驱动仅支持驱动点阵显示,对于7段数码管,请参考官方原文MAX7219 7-Segment Display。 本文参考自官方文档MAX7219 Digit Display 硬件连接 由于与MAX7219Digit的通信是使用SPI进行此集成的,因此您需要在配置中使用…

git国内下载

https://npm.taobao.org/mirrors/git-for-windows/点进去最新的最后一条 选择.exe文件点击

微信小程序之网络数据请求 wx:request的简单使用

网络数据请求 1. 网络数据请求 wx:request2. 请求格式3. 关闭request的合法检验 1. 网络数据请求 wx:request 出于安全性方面的考虑,小程序官方对数据接口的请求做出了两个限制:只能请求 HTTPS 类型的接口必须将接口的域名添加到信任列表中. 在自己的微…

数据备份与还原,(mysqldump,source)索引(index),创建视图(view)

一、备份与还原 /***************************样例表***************************/ CREATE DATABASE booksDB; use booksDB;CREATE TABLE books (bk_id INT NOT NULL PRIMARY KEY,bk_title VARCHAR(50) NOT NULL,copyright YEAR NOT NULL ); INSERT INTO books VALUES (11078…

【NLP】BERT和原理揭示

一、说明 BERT(来自transformer的双向编码器表示)是Google AI Language研究人员最近发表的一篇论文。它通过在各种NLP任务中展示最先进的结果,在机器学习社区引起了轰动,包括问答(SQuAD v1.1),自…

免费的云数据库:探索PlanetScale,划分分支的MySQL Serverless平台

最近我发现了一个非常有趣的国外MySQL Serverless平台,它叫做PlanetScale。这个平台不仅仅是一个数据库,它能像代码一样轻松地创建开发和测试环境。你可以从主库中拉出一个与之完全相同结构的development或staging数据库,并在这个环境中进行开…