怎么做捕鱼网站,制作服务网站,wordpress图片lazyload,广州通和通信建设有限公司网站今天分享ResNet50迁移学习。 在实际应用场景中#xff0c;由于训练数据集不足#xff0c;所以很少有人会从头开始训练整个网络。普遍的做法是#xff0c;在一个非常大的基础数据集上训练得到一个预训练模型#xff0c;然后使用该模型来初始化网络的权重参数或作为固定特征提… 今天分享ResNet50迁移学习。 在实际应用场景中由于训练数据集不足所以很少有人会从头开始训练整个网络。普遍的做法是在一个非常大的基础数据集上训练得到一个预训练模型然后使用该模型来初始化网络的权重参数或作为固定特征提取器应用于特定的任务中。本章将使用迁移学习的方法对ImageNet数据集中的狼和狗图像进行分类。 目录 一、 数据准备 1. 下载数据集 2. 数据集的目录结构 二、 加载数据集 1. 定义执行过程中的全局变量 2. 加载数据 3. 数据集可视化 三、训练模型 1. 构建ResNet50网络 2. 固定特征进行训练 3. 训练和评估 4. 可视化模型预测 一、 数据准备 1. 下载数据集 下载案例所用到的狗与狼分类数据集数据集中的图像来自于ImageNet每个分类有大约120张训练图像与30张验证图像。使用download接口下载数据集并将下载后的数据集自动解压到当前目录下。
from download import downloaddataset_url https://mindspore-website.obs.cn-north-4.myhuaweicloud.com/notebook/datasets/intermediate/Canidae_data.zipdownload(dataset_url, ./datasets-Canidae, kindzip, replaceTrue) 运行结果
Creating data folder...
Downloading data from https://mindspore-website.obs.cn-north-4.myhuaweicloud.com/notebook/datasets/intermediate/Canidae_data.zip (11.3 MB)file_sizes: 100%|███████████████████████████| 11.9M/11.9M [00:0000:00, 116MB/s]
Extracting zip file...
Successfully downloaded / unzipped to ./datasets-Canidae./datasets-Canidae 2. 数据集的目录结构 二、 加载数据集 狼狗数据集提取自ImageNet分类数据集使用mindspore.dataset.ImageFolderDataset接口来加载数据集并进行相关图像增强操作。 1. 定义执行过程中的全局变量
# 为执行过程定义一些输入
batch_size 18 # 批量大小
image_size 224 # 训练图像空间大小
num_epochs 5 # 训练周期数
lr 0.001 # 学习率
momentum 0.9 # 动量
workers 4 # 并行线程个数 2. 加载数据
import mindspore as ms
import mindspore.dataset as ds
import mindspore.dataset.vision as vision# 数据集目录路径
data_path_train ./datasets-Canidae/data/Canidae/train/
data_path_val ./datasets-Canidae/data/Canidae/val/# 创建训练数据集
def create_dataset_canidae(dataset_path, usage):数据加载data_set ds.ImageFolderDataset(dataset_path,num_parallel_workersworkers,shuffleTrue,)# 数据增强操作mean [0.485 * 255, 0.456 * 255, 0.406 * 255]std [0.229 * 255, 0.224 * 255, 0.225 * 255]scale 32if usage train:# Define map operations for training datasettrans [vision.RandomCropDecodeResize(sizeimage_size, scale(0.08, 1.0), ratio(0.75, 1.333)),vision.RandomHorizontalFlip(prob0.5),vision.Normalize(meanmean, stdstd),vision.HWC2CHW()]else:# Define map operations for inference datasettrans [vision.Decode(),vision.Resize(image_size scale),vision.CenterCrop(image_size),vision.Normalize(meanmean, stdstd),vision.HWC2CHW()]# 数据映射操作data_set data_set.map(operationstrans,input_columnsimage,num_parallel_workersworkers)# 批量操作data_set data_set.batch(batch_size)return data_setdataset_train create_dataset_canidae(data_path_train, train)
step_size_train dataset_train.get_dataset_size()dataset_val create_dataset_canidae(data_path_val, val)
step_size_val dataset_val.get_dataset_size() 3. 数据集可视化 从mindspore.dataset.ImageFolderDataset接口中加载的训练数据集返回值为字典用户可通过 create_dict_iterator 接口创建数据迭代器使用 next 迭代访问数据集。本章中 batch_size 设为18所以使用 next 一次可获取18个图像及标签数据。
data next(dataset_train.create_dict_iterator())
images data[image]
labels data[label]print(Tensor of image, images.shape)
print(Labels:, labels) 运行结果
Tensor of image (18, 3, 224, 224)
Labels: [0 1 0 0 1 1 0 0 0 1 0 1 1 1 1 1 0 0] 对获取到的图像及标签数据进行可视化标题为图像对应的label名称。
import matplotlib.pyplot as plt
import numpy as np# class_name对应label按文件夹字符串从小到大的顺序标记label
class_name {0: dogs, 1: wolves}plt.figure(figsize(5, 5))
for i in range(4):# 获取图像及其对应的labeldata_image images[i].asnumpy()data_label labels[i]# 处理图像供展示使用data_image np.transpose(data_image, (1, 2, 0))mean np.array([0.485, 0.456, 0.406])std np.array([0.229, 0.224, 0.225])data_image std * data_image meandata_image np.clip(data_image, 0, 1)# 显示图像plt.subplot(2, 2, i1)plt.imshow(data_image)plt.title(class_name[int(labels[i].asnumpy())])plt.axis(off)plt.show() 运行结果 三、训练模型 本章使用ResNet50模型进行训练。搭建好模型框架后通过将pretrained参数设置为True来下载ResNet50的预训练模型并将权重参数加载到网络中。 1. 构建ResNet50网络
定义ResidualBlockBase 类这个类实现了一个基本的残差块Residual Block结构它是卷积神经网络CNN中常用的一种构建块特别是在构建非常深的网络如ResNet时残差块的主要目的是通过引入“短路连接”或称为“恒等映射”、“跳跃连接”来解决深度网络训练过程中的梯度消失或梯度爆炸问题使得网络能够更容易地学习和优化。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_size3, stridestride,weight_initweight_init)self.conv2 nn.Conv2d(in_channel, out_channel,kernel_size3, weight_initweight_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
定义 ResidualBlock 类它是用于构建深度神经网络中的一个残差块Residual Block。残差块是深度残差网络ResNet的核心组成部分旨在解决深度神经网络在训练过程中出现的梯度消失或梯度爆炸问题从而允许训练更深的网络。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_size1, weight_initweight_init)self.norm1 nn.BatchNorm2d(out_channel)self.conv2 nn.Conv2d(out_channel, out_channel,kernel_size3, stridestride,weight_initweight_init)self.norm2 nn.BatchNorm2d(out_channel)self.conv3 nn.Conv2d(out_channel, out_channel * self.expansion,kernel_size1, weight_initweight_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)# 将主分支的输出与shortcuts分支相加实现残差连接 out identityout self.relu(out)return out
定义make_layer函数它负责构建一个由多个残差块block组成的网络层。这个函数首先检查是否需要创建下采样层down_sample这通常是为了匹配输入和输出的维度或进行特征图的空间降维。然后它添加第一个残差块可能需要下采样层并基于第一个残差块的输出通道数考虑扩展因子堆叠剩余的残差块。最后所有的残差块被封装在一个nn.SequentialCell中以便可以作为一个整体进行前向传播。def make_layer(last_out_channel, block: Type[Union[ResidualBlockBase, ResidualBlock]],channel: int, block_nums: int, stride: int 1):down_sample None # shortcuts分支# 如果步长不为1或者上一层的输出通道数与当前层首个残差块的期望输出通道数不匹配则创建下采样层if stride ! 1 or last_out_channel ! channel * block.expansion:down_sample nn.SequentialCell([nn.Conv2d(last_out_channel, channel * block.expansion,kernel_size1, stridestride, weight_initweight_init),nn.BatchNorm2d(channel * block.expansion, gamma_initgamma_init)])# 初始化残差块列表layers []layers.append(block(last_out_channel, channel, stridestride, down_sampledown_sample))# 更新输入通道数为当前残差块的输出通道数考虑扩展因子in_channel channel * block.expansion# 堆叠残差网络for _ in range(1, block_nums):layers.append(block(in_channel, channel))return nn.SequentialCell(layers)
# 构建ResNet50网络
from mindspore import load_checkpoint, load_param_into_netclass 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_size7, stride2, weight_initweight_init)self.norm nn.BatchNorm2d(64)# 最大池化层缩小图片的尺寸self.max_pool nn.MaxPool2d(kernel_size3, stride2, pad_modesame)# 各个残差网络结构块定义self.layer1 make_layer(64, block, 64, layer_nums[0])self.layer2 make_layer(64 * block.expansion, block, 128, layer_nums[1], stride2)self.layer3 make_layer(128 * block.expansion, block, 256, layer_nums[2], stride2)self.layer4 make_layer(256 * block.expansion, block, 512, layer_nums[3], stride2)# 平均池化层self.avg_pool nn.AvgPool2d()# flattern层self.flatten nn.Flatten()# 全连接层self.fc nn.Dense(in_channelsinput_channel, out_channelsnum_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, pretrianed_ckpt: str,input_channel: int):model ResNet(block, layers, num_classes, input_channel)if pretrained:# 加载预训练模型download(urlmodel_url, pathpretrianed_ckpt, replaceTrue)param_dict load_checkpoint(pretrianed_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.ckptresnet50_ckpt ./LoadPretrainedModel/resnet50_224_new.ckptreturn _resnet(resnet50_url, ResidualBlock, [3, 4, 6, 3], num_classes,pretrained, resnet50_ckpt, 2048) 2. 固定特征进行训练 使用固定特征进行训练的时候需要冻结除最后一层之外的所有网络层。通过设置 requires_grad False 冻结参数以便不在反向传播中计算梯度。
import mindspore as ms
import matplotlib.pyplot as plt
import os
import timenet_work resnet50(pretrainedTrue)# 全连接层输入层的大小
in_channels net_work.fc.in_channels
# 输出通道数大小为狼狗分类数2
head nn.Dense(in_channels, 2)
# 重置全连接层
net_work.fc head# 平均池化层kernel size为7
avg_pool nn.AvgPool2d(kernel_size7)
# 重置平均池化层
net_work.avg_pool avg_pool# 冻结除最后一层外的所有参数
for param in net_work.get_parameters():if param.name not in [fc.weight, fc.bias]:param.requires_grad False# 定义优化器和损失函数
opt nn.Momentum(paramsnet_work.trainable_params(), learning_ratelr, momentum0.5)
loss_fn nn.SoftmaxCrossEntropyWithLogits(sparseTrue, reductionmean)def forward_fn(inputs, targets):logits net_work(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# 实例化模型
model1 train.Model(net_work, loss_fn, opt, metrics{Accuracy: train.Accuracy()}) 3. 训练和评估 开始训练模型与没有预训练模型相比将节约一大半时间因为此时可以不用计算部分梯度。保存评估精度最高的ckpt文件于当前路径的./BestCheckpoint/resnet50-best-freezing-param.ckpt。
import mindspore as ms
import matplotlib.pyplot as plt
import os
import time
dataset_train create_dataset_canidae(data_path_train, train)
step_size_train dataset_train.get_dataset_size()dataset_val create_dataset_canidae(data_path_val, val)
step_size_val dataset_val.get_dataset_size()num_epochs 5# 创建迭代器
data_loader_train dataset_train.create_tuple_iterator(num_epochsnum_epochs)
data_loader_val dataset_val.create_tuple_iterator(num_epochsnum_epochs)
best_ckpt_dir ./BestCheckpoint
best_ckpt_path ./BestCheckpoint/resnet50-best-freezing-param.ckpt# 开始循环训练
print(Start Training Loop ...)best_acc 0for epoch in range(num_epochs):losses []net_work.set_train()epoch_start time.time()# 为每轮训练读入数据for i, (images, labels) in enumerate(data_loader_train):labels labels.astype(ms.int32)loss train_step(images, labels)losses.append(loss)# 每个epoch结束后验证准确率acc model1.eval(dataset_val)[Accuracy]epoch_end time.time()epoch_seconds (epoch_end - epoch_start) * 1000step_seconds epoch_seconds/step_size_trainprint(- * 20)print(Epoch: [%3d/%3d], Average Train Loss: [%5.3f], Accuracy: [%5.3f] % (epoch1, num_epochs, sum(losses)/len(losses), acc))print(epoch time: %5.3f ms, per step time: %5.3f ms % (epoch_seconds, step_seconds))if acc best_acc:best_acc accif not os.path.exists(best_ckpt_dir):os.mkdir(best_ckpt_dir)ms.save_checkpoint(net_work, best_ckpt_path)print( * 80)
print(fEnd of validation the best Accuracy is: {best_acc: 5.3f}, fsave the best ckpt file in {best_ckpt_path}, flushTrue) 运行结果
Start Training Loop ...
--------------------
Epoch: [ 1/ 5], Average Train Loss: [0.664], Accuracy: [0.800]
epoch time: 50934.131 ms, per step time: 3638.152 ms
--------------------
Epoch: [ 2/ 5], Average Train Loss: [0.556], Accuracy: [0.817]
epoch time: 824.633 ms, per step time: 58.902 ms
--------------------
Epoch: [ 3/ 5], Average Train Loss: [0.510], Accuracy: [0.967]
epoch time: 767.022 ms, per step time: 54.787 ms
--------------------
Epoch: [ 4/ 5], Average Train Loss: [0.438], Accuracy: [1.000]
epoch time: 714.965 ms, per step time: 51.069 ms
--------------------
Epoch: [ 5/ 5], Average Train Loss: [0.395], Accuracy: [1.000]
epoch time: 734.045 ms, per step time: 52.432 msEnd of validation the best Accuracy is: 1.000, save the best ckpt file in ./BestCheckpoint/resnet50-best-freezing-param.ckpt 4. 可视化模型预测 使用固定特征得到的best.ckpt文件对验证集的狼和狗图像数据进行预测。若预测字体为蓝色即为预测正确若预测字体为红色则预测错误。
import matplotlib.pyplot as plt
import mindspore as msdef visualize_model(best_ckpt_path, val_ds):net resnet50()# 全连接层输入层的大小in_channels net.fc.in_channels# 输出通道数大小为狼狗分类数2head nn.Dense(in_channels, 2)# 重置全连接层net.fc head# 平均池化层kernel size为7avg_pool nn.AvgPool2d(kernel_size7)# 重置平均池化层net.avg_pool avg_pool# 加载模型参数param_dict ms.load_checkpoint(best_ckpt_path)ms.load_param_into_net(net, param_dict)model train.Model(net)# 加载验证集的数据进行验证data next(val_ds.create_dict_iterator())images data[image].asnumpy()labels data[label].asnumpy()class_name {0: dogs, 1: wolves}# 预测图像类别output model.predict(ms.Tensor(data[image]))pred np.argmax(output.asnumpy(), axis1)# 显示图像及图像的预测值plt.figure(figsize(5, 5))for i in range(4):plt.subplot(2, 2, i 1)# 若预测正确显示为蓝色若预测错误显示为红色color blue if pred[i] labels[i] else redplt.title(predict:{}.format(class_name[pred[i]]), colorcolor)picture_show np.transpose(images[i], (1, 2, 0))mean np.array([0.485, 0.456, 0.406])std np.array([0.229, 0.224, 0.225])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, dataset_val) 运行结果