昇思25天学习打卡营第 12 天 | mindspore 实现 ResNet50 图像分类

1. 背景:

使用 mindspore 学习神经网络,打卡第 12 天;主要内容也依据 mindspore 的学习记录。

2. ResNet 介绍:

mindspore 实现 ResNet50 图像分类;

  • ResNet 基本介绍:
    Residual Networks 是微软研究院 Kaiming He 等人于2015年在 Deep Residual Learning for Image Recognition 文章链接 一文中提出的一种网络框架。

  • 解决的问题:
    传统的卷积神经网络都是将一系列的卷积层和池化层堆叠得到的,但当网络堆叠到一定深度时,就会出现退化问题;ResNet网络提出了残差网络结构(Residual Network)来减轻退化问题,使用ResNet网络可以实现搭建较深的网络结构(突破1000层)

  • 创新点:
    a. 残差网络结构(Residual Network):
    减轻退化问题,使用ResNet网络可以实现搭建较深的网络结构;

3. 具体实现:

3.1 数据下载:

使用 CIFAR-10 数据集,共有60000张32*32的彩色图像,分为10个类别,每类有6000张图,数据集一共有50000张训练图片和10000张评估图片;

from download import downloadurl = "https://mindspore-website.obs.cn-north-4.myhuaweicloud.com/notebook/datasets/cifar-10-binary.tar.gz"download(url, "./datasets-cifar10-bin", kind="tar.gz", replace=True)

3.2 数据前处理:

对 cifar10 数据集做处理

import mindspore as ms
import mindspore.dataset as ds
import mindspore.dataset.vision as vision
import mindspore.dataset.transforms as transforms
from mindspore import dtype as mstypedata_dir = "./datasets-cifar10-bin/cifar-10-batches-bin"  # 数据集根目录
batch_size = 256  # 批量大小
image_size = 32  # 训练图像空间大小
workers = 4  # 并行线程个数
num_classes = 10  # 分类数量def create_dataset_cifar10(dataset_dir, usage, resize, batch_size, workers):data_set = ds.Cifar10Dataset(dataset_dir=dataset_dir,usage=usage,num_parallel_workers=workers,shuffle=True)trans = []if usage == "train":trans += [vision.RandomCrop((32, 32), (4, 4, 4, 4)),vision.RandomHorizontalFlip(prob=0.5)]trans += [vision.Resize(resize),vision.Rescale(1.0 / 255.0, 0.0),vision.Normalize([0.4914, 0.4822, 0.4465], [0.2023, 0.1994, 0.2010]),vision.HWC2CHW()]target_trans = transforms.TypeCast(mstype.int32)# 数据映射操作data_set = data_set.map(operations=trans,input_columns='image',num_parallel_workers=workers)data_set = data_set.map(operations=target_trans,input_columns='label',num_parallel_workers=workers)# 批量操作data_set = data_set.batch(batch_size)return data_set# 获取处理后的训练与测试数据集
dataset_train = create_dataset_cifar10(dataset_dir=data_dir,usage="train",resize=image_size,batch_size=batch_size,workers=workers)
step_size_train = dataset_train.get_dataset_size()dataset_val = create_dataset_cifar10(dataset_dir=data_dir,usage="test",resize=image_size,batch_size=batch_size,workers=workers)
step_size_val = dataset_val.get_dataset_size()

3.3 构建残差网络结构(Residual Network):

对于 ResNet 来说,主要是残差网络结构;
如论文中图所示:
残差网络结构
图像左边为浅层的残差网络结构 BuildingBlock;右边为:深层的残差网络结构 BlockNeck
卷积后,一般会增加 batch norm 和 relu; 1*1 卷积主要是为了升维与降维;

  • 浅层的残差网络结构 BuildingBlock 代码如下:
from typing import Type, Union, List, Optional
import mindspore.nn as nn
from mindspore.common.initializer import Normal# 初始化卷积层与BatchNorm的参数
weight_init = Normal(mean=0, sigma=0.02)
gamma_init = Normal(mean=1, sigma=0.02)class ResidualBlockBase(nn.Cell):expansion: int = 1  # 最后一个卷积核数量与第一个卷积核数量相等def __init__(self, in_channel: int, out_channel: int,stride: int = 1, norm: Optional[nn.Cell] = None,down_sample: Optional[nn.Cell] = None) -> None:super(ResidualBlockBase, self).__init__()if not norm:self.norm = nn.BatchNorm2d(out_channel)else:self.norm = normself.conv1 = nn.Conv2d(in_channel, out_channel,kernel_size=3, stride=stride,weight_init=weight_init)self.conv2 = nn.Conv2d(in_channel, out_channel,kernel_size=3, weight_init=weight_init)self.relu = nn.ReLU()self.down_sample = down_sampledef construct(self, x):"""ResidualBlockBase construct."""identity = x  # shortcuts分支out = self.conv1(x)  # 主分支第一层:3*3卷积层out = self.norm(out)out = self.relu(out)out = self.conv2(out)  # 主分支第二层:3*3卷积层out = self.norm(out)if self.down_sample is not None:identity = self.down_sample(x)out += identity  # 输出为主分支与shortcuts之和out = self.relu(out)return out
  • 深层的残差网络结构 BlockNeck
    代码如下:
class ResidualBlock(nn.Cell):expansion = 4  # 最后一个卷积核的数量是第一个卷积核数量的4倍def __init__(self, in_channel: int, out_channel: int,stride: int = 1, down_sample: Optional[nn.Cell] = None) -> None:super(ResidualBlock, self).__init__()self.conv1 = nn.Conv2d(in_channel, out_channel,kernel_size=1, weight_init=weight_init)self.norm1 = nn.BatchNorm2d(out_channel)self.conv2 = nn.Conv2d(out_channel, out_channel,kernel_size=3, stride=stride,weight_init=weight_init)self.norm2 = nn.BatchNorm2d(out_channel)self.conv3 = nn.Conv2d(out_channel, out_channel * self.expansion,kernel_size=1, weight_init=weight_init)self.norm3 = nn.BatchNorm2d(out_channel * self.expansion)self.relu = nn.ReLU()self.down_sample = down_sampledef construct(self, x):identity = x  # shortscuts分支out = self.conv1(x)  # 主分支第一层:1*1卷积层out = self.norm1(out)out = self.relu(out)out = self.conv2(out)  # 主分支第二层:3*3卷积层out = self.norm2(out)out = self.relu(out)out = self.conv3(out)  # 主分支第三层:1*1卷积层out = self.norm3(out)if self.down_sample is not None:identity = self.down_sample(x)out += identity  # 输出为主分支与shortcuts之和out = self.relu(out)return out

3.4 构建 ResNet50 :

ResNet 由不同的残差网络结构堆叠而成的;如下图所示:
不同的ResNet网络结构
我们以 ResNet 50 为例,
conv2_x 有 3 个 ResBlock;
conv3_x 有 4 个 ResBlock;
conv4_x 有 6 个 ResBlock;
conv5_x 有 3 个 ResBlock;

代码如下:


# last_out_channel: 最终输出的 channel 数量
def make_layer(last_out_channel, block: Type[Union[ResidualBlockBase, ResidualBlock]],channel: int, block_nums: int, stride: int = 1):down_sample = None  # shortcuts分支if stride != 1 or last_out_channel != channel * block.expansion:down_sample = nn.SequentialCell([nn.Conv2d(last_out_channel, channel * block.expansion,kernel_size=1, stride=stride, weight_init=weight_init),nn.BatchNorm2d(channel * block.expansion, gamma_init=gamma_init)])layers = []layers.append(block(last_out_channel, channel, stride=stride, down_sample=down_sample))in_channel = channel * block.expansion# 堆叠残差网络for _ in range(1, block_nums):layers.append(block(in_channel, channel))return nn.SequentialCell(layers)from mindspore import load_checkpoint, load_param_into_net
class ResNet(nn.Cell):def __init__(self, block: Type[Union[ResidualBlockBase, ResidualBlock]],layer_nums: List[int], num_classes: int, input_channel: int) -> None:super(ResNet, self).__init__()self.relu = nn.ReLU()# 第一个卷积层,输入channel为3(彩色图像),输出channel为64self.conv1 = nn.Conv2d(3, 64, kernel_size=7, stride=2, weight_init=weight_init)self.norm = nn.BatchNorm2d(64)# 最大池化层,缩小图片的尺寸self.max_pool = nn.MaxPool2d(kernel_size=3, stride=2, pad_mode='same')# 各个残差网络结构块定义self.layer1 = make_layer(64, block, 64, layer_nums[0])self.layer2 = make_layer(64 * block.expansion, block, 128, layer_nums[1], stride=2)self.layer3 = make_layer(128 * block.expansion, block, 256, layer_nums[2], stride=2)self.layer4 = make_layer(256 * block.expansion, block, 512, layer_nums[3], stride=2)# 平均池化层self.avg_pool = nn.AvgPool2d()# flattern层self.flatten = nn.Flatten()# 全连接层self.fc = nn.Dense(in_channels=input_channel, out_channels=num_classes)def construct(self, x):x = self.conv1(x)x = self.norm(x)x = self.relu(x)x = self.max_pool(x)x = self.layer1(x)x = self.layer2(x)x = self.layer3(x)x = self.layer4(x)x = self.avg_pool(x)x = self.flatten(x)x = self.fc(x)return xdef _resnet(model_url: str, block: Type[Union[ResidualBlockBase, ResidualBlock]],layers: List[int], num_classes: int, pretrained: bool, pretrained_ckpt: str,input_channel: int):model = ResNet(block, layers, num_classes, input_channel)if pretrained:# 加载预训练模型download(url=model_url, path=pretrained_ckpt, replace=True)param_dict = load_checkpoint(pretrained_ckpt)load_param_into_net(model, param_dict)return modeldef resnet50(num_classes: int = 1000, pretrained: bool = False):"""ResNet50模型"""resnet50_url = "https://mindspore-website.obs.cn-north-4.myhuaweicloud.com/notebook/models/application/resnet50_224_new.ckpt"resnet50_ckpt = "./LoadPretrainedModel/resnet50_224_new.ckpt"return _resnet(resnet50_url, ResidualBlock, [3, 4, 6, 3], num_classes,pretrained, resnet50_ckpt, 2048)

3.5 模型训练与评估:

使用预训练模型;预训练模型的全连接层的 FC 输出 1000; 因此,导入时,需要将模型的 FC 修改成 1000;导入完成后,在将网络模型的 FC 恢复到 10;

  • 定义前向传播 / 梯度计算
# 定义ResNet50网络
network = resnet50(pretrained=True)# 全连接层输入层的大小
in_channel = network.fc.in_channels
fc = nn.Dense(in_channels=in_channel, out_channels=10)
# 重置全连接层
network.fc = fc# 设置学习率
num_epochs = 5
lr = nn.cosine_decay_lr(min_lr=0.00001, max_lr=0.001, total_step=step_size_train * num_epochs,step_per_epoch=step_size_train, decay_epoch=num_epochs)
# 定义优化器和损失函数
opt = nn.Momentum(params=network.trainable_params(), learning_rate=lr, momentum=0.9)
loss_fn = nn.SoftmaxCrossEntropyWithLogits(sparse=True, reduction='mean')def forward_fn(inputs, targets):logits = network(inputs)loss = loss_fn(logits, targets)return lossgrad_fn = ms.value_and_grad(forward_fn, None, opt.parameters)def train_step(inputs, targets):loss, grads = grad_fn(inputs, targets)opt(grads)return loss
  • 创建迭代器:
import os# 创建迭代器
data_loader_train = dataset_train.create_tuple_iterator(num_epochs=num_epochs)
data_loader_val = dataset_val.create_tuple_iterator(num_epochs=num_epochs)# 最佳模型存储路径
best_acc = 0
best_ckpt_dir = "./BestCheckpoint"
best_ckpt_path = "./BestCheckpoint/resnet50-best.ckpt"if not os.path.exists(best_ckpt_dir):os.mkdir(best_ckpt_dir)
  • 训练与验证:
import mindspore.ops as opsdef train(data_loader, epoch):"""模型训练"""losses = []network.set_train(True)for i, (images, labels) in enumerate(data_loader):loss = train_step(images, labels)if i % 100 == 0 or i == step_size_train - 1:print('Epoch: [%3d/%3d], Steps: [%3d/%3d], Train Loss: [%5.3f]' %(epoch + 1, num_epochs, i + 1, step_size_train, loss))losses.append(loss)return sum(losses) / len(losses)def evaluate(data_loader):"""模型验证"""network.set_train(False)correct_num = 0.0  # 预测正确个数total_num = 0.0  # 预测总数for images, labels in data_loader:logits = network(images)pred = logits.argmax(axis=1)  # 预测结果correct = ops.equal(pred, labels).reshape((-1, ))correct_num += correct.sum().asnumpy()total_num += correct.shape[0]acc = correct_num / total_num  # 准确率return acc
  • 开始循环运行:
# 开始循环训练
print("Start Training Loop ...")for epoch in range(num_epochs):curr_loss = train(data_loader_train, epoch)curr_acc = evaluate(data_loader_val)print("-" * 50)print("Epoch: [%3d/%3d], Average Train Loss: [%5.3f], Accuracy: [%5.3f]" % (epoch+1, num_epochs, curr_loss, curr_acc))print("-" * 50)# 保存当前预测准确率最高的模型if curr_acc > best_acc:best_acc = curr_accms.save_checkpoint(network, best_ckpt_path)print("=" * 80)
print(f"End of validation the best Accuracy is: {best_acc: 5.3f}, "f"save the best ckpt file in {best_ckpt_path}", flush=True)

3.6 可视化模型预测:

import matplotlib.pyplot as pltdef visualize_model(best_ckpt_path, dataset_val):num_class = 10  # 对狼和狗图像进行二分类net = resnet50(num_class)# 加载模型参数param_dict = ms.load_checkpoint(best_ckpt_path)ms.load_param_into_net(net, param_dict)# 加载验证集的数据进行验证data = next(dataset_val.create_dict_iterator())images = data["image"]labels = data["label"]# 预测图像类别output = net(data['image'])pred = np.argmax(output.asnumpy(), axis=1)# 图像分类classes = []with open(data_dir + "/batches.meta.txt", "r") as f:for line in f:line = line.rstrip()if line:classes.append(line)# 显示图像及图像的预测值plt.figure()for i in range(6):plt.subplot(2, 3, i + 1)# 若预测正确,显示为蓝色;若预测错误,显示为红色color = 'blue' if pred[i] == labels.asnumpy()[i] else 'red'plt.title('predict:{}'.format(classes[pred[i]]), color=color)picture_show = np.transpose(images.asnumpy()[i], (1, 2, 0))mean = np.array([0.4914, 0.4822, 0.4465])std = np.array([0.2023, 0.1994, 0.2010])picture_show = std * picture_show + meanpicture_show = np.clip(picture_show, 0, 1)plt.imshow(picture_show)plt.axis('off')plt.show()# 使用测试数据集进行验证
visualize_model(best_ckpt_path=best_ckpt_path, dataset_val=dataset_val)

4. 相关链接:

  • ResNet 论文
  • https://xihe.mindspore.cn/events/mindspore-training-camp
  • mindspore - resnet 50 图形分类

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

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

港股指数实时行情API接口

港股 指数 实时 行情 API接口 # Restful API https://tsanghi.com/api/fin/index/HKG/realtime?token{token}&ticker{ticker}指定指数代码,获取该指数的实时行情(开、高、低、收、量)。 更新周期:实时。 请求方式&#xff1a…

GuLi商城-商品服务-API-属性分组-分组修改级联选择器回显

前端代码:略 后端回显接口: 递归方法: @Override publi

linux进程——父子进程层面的PID,fork的原理与理解

前言:本篇内容主要讲解进程中系统调用fork和父子进程的概念与原理, 想要系统学习linux进程的友友们只管看本篇文章是不行的。 还要学习一些linux进程的周边知识以及linux进程其他方面的知识,博主的linux专栏中已经加入了这些文章方便友友们进…

连锁零售门店分析思路-人货场 数据分析

连锁零售门店分析思路 以下是一个连锁零售门店的分析思路: 一、市场与竞争分析 二、门店运营分析(销售分析) 三、销售与财务分析 四、客户分析 五、数字化与营销分析 最近帮一个大学生培训,就门店销售分析 ,说到门店…

记录些MySQL题集(8)

ACID原则、事务隔离级别及事务机制原理 一、事务的ACID原则 什么是事务呢?事务通常是由一个或一组SQL组成的,组成一个事务的SQL一般都是一个业务操作,例如聊到的下单:「扣库存数量、增加订单详情记录、插入物流信息」&#xff0…

Css布局-伸缩盒笔记

前言 伸缩盒作为css3中的布局标准,不得不学呀,跟着b站yu神走一遍,yushen牛逼! 伸缩盒子布局的优势 当然是伸缩了 伸缩容器与伸缩项目 display: flex display: inline-flex (用的少) 一个html元素既可以是…

我们距离通用人工智能还有多远?当它诞生后,会给社会发展带来哪些变革?

当我们谈论通用人工智能(AGI),我们指的是一种能够像人类一样执行各种认知任务的人工智能系统。目前,我们所拥有的人工智能技术主要是狭义人工智能(ANI),专注于特定任务,如语音识别、…

老司机减分宝典助手-学法减分扣分题目及答案 #经验分享#经验分享#职场发展

学法减分其实就是把我们驾驶证上面的分数一分一分地找回来,为什么说是一分一分地找回来呢?因为必须先把违章处理完才可以,无论这辆车是不是你的,无论这辆车挂靠在谁的公司名下或者是单位名下,你都可以把这个分找回来&a…

卷积神经网络图像识别车辆类型

卷积神经网络图像识别车辆类型 1、图像 自行车: 汽车: 摩托车: 2、数据集目录 3、流程 1、获取数据,把图像转成矩阵,并随机划分训练集、测试集 2、把标签转为数值,将标签向量转换为二值矩阵 3、图像数据归一化,0-1之间的值 4、构造卷积神经网络 5、设置图像输入…

3.RabbitMQ安装-Centos7

官方网址:gInstalling RabbitMQ | RabbitMQ 安装前提,需要一个erlang语言环境。 下载 erlang: Releases rabbitmq/erlang-rpm GitHub rabbitmq-server: 3.8.8 Releases rabbitmq/rabbitmq-server GitHub 安装命令 (说明i表示安装&#xff…

FPGA FIR fdatool filter designer MATLAB

位数问题 fdatool 先确定输入信号的位宽,比如17位在fdatool中,选set quantization parameters 选input/output 设置input word length 为17bit(not confirmed) fir compiler implementation 注意: 当设置输入位宽为16位时,ip核…

深入解析HNSW:Faiss中的层次化可导航小世界图

层次化可导航小世界(HNSW)图是向量相似性搜索中表现最佳的索引之一。HNSW 技术以其超级快速的搜索速度和出色的召回率,在近似最近邻(ANN)搜索中表现卓越。尽管 HNSW 是近似最近邻搜索中强大且受欢迎的算法,…

具有I2S输出的多模数字麦克风ICS-43434咪头

外观和丝印 ICS-43434麦克风3.50 mm x 2.65 mm,丝印为434(图片不好拍,隐约可见434) 一般描述 ICS-43434 是一款数字 IS 输出底部收音孔麦克风。完整的 ICS-43434 解决方案包括 MEMS 传感器、信号调理、模数转换器、抽取和抗混叠滤…

智能手术新时代:Apple Vision Pro在医疗领域的突破性应用

无人驾驶的未来:AI如何重塑我们的出行世界-CSDN博客文章浏览阅读2.2k次,点赞109次,收藏64次。无人驾驶汽车的发展是AI技术应用的一次伟大尝试。特斯拉与百度“萝卜快跑”在这个领域的竞争与合作,不仅展示了AI技术的强大潜力&#…

Heterophilous Distribution Propagation for Graph Neural Networks

推荐指数:2颗星 HDP不是聚集所有邻居信息,而是根据训练期间的伪标签自适应的将邻居分为同配和异配.并通过原型对比,垂直约束异配邻居分布 前人的问题 1.邻居划分的不足.已存在的方法要不不能区分同配和异配,要不简单的采用阈值去划分同配异配 2.以往的异配GNN仅仅是简单的邻居…

【C++】拷贝构造函数及析构函数

📢博客主页:https://blog.csdn.net/2301_779549673 📢欢迎点赞 👍 收藏 ⭐留言 📝 如有错误敬请指正! 📢本文由 JohnKi 原创,首发于 CSDN🙉 📢未来很长&#…

嵌入式Linux:文件属主和属组

目录 1、修改文件所有者和组 2、chown函数 3、fchown函数 4、lchown函数 在Linux系统中,每个文件都有一个属主(owner)和一个属组(group)。文件权限系统根据这些信息来决定哪些用户和组可以访问和操作文件。 文件属…

简单爬虫案例

准备工作: 1. 安装好python3 最低为3.6以上, 并成功运行pyhthon3 程序 2. 了解python 多进程原理 3. 了解 python HTTP 请求库 requests 的基本使用 4. 了解正则表达式的用法和python 中 re 库的基本使用 爬取目标 目标网站: https://…

【C++】类和对象的基本概念与使用

本文通过面向对象的概念以及通俗易懂的例子介绍面向对象引出类和对象。最后通过与之有相似之处的C语言中的struct一步步引出C中的类的定义方式,并提出了一些注意事项,最后描述了类的大小的计算方法。 一、什么是面向对象? 1.面向对象的概念 …

CH390H+STM32F1+LWIP

文章目录 1、CH390芯片介绍2、电路部分3、LWIP调试3.1修改点13.2 修改点2 4、结果展示参考 1、CH390芯片介绍 官网地址: 南京沁恒微电子股份有限公司 特点: 2、电路部分 CH390及接口: STM32F1引脚: 不含LWIP的demo及LWIP…