昇思25天学习打卡营第13天 | ResNet50迁徙学习
在现实应用场景中,由于训练数据集不敷,很少重新开始训练整个网络。普遍做法是在一个非常大的基础数据集上训练得到一个 预训练模型,然后利用该模型来初始化网络的权重参数或作为固定特征提取器应用于特定的任务。
数据集
利用ResNet50在狗与狼分类数据集上举行训练,数据会合图片来自ImageNet,每个分类大约120张训练图像和30张验证图像。
- from download import download
- dataset_url = "https://mindspore-website.obs.cn-north-4.myhuaweicloud.com/notebook/datasets/intermediate/Canidae_data.zip"
- download(dataset_url, "./datasets-Canidae", kind="zip", replace=True)
复制代码 加载数据集
利用mindspore.dataset.ImageFolderDataset接口来加载数据集,并举行数据增强::
- batch_size = 18 # 批量大小
- image_size = 224 # 训练图像空间大小
- num_epochs = 5 # 训练周期数
- lr = 0.001 # 学习率
- momentum = 0.9 # 动量
- workers = 4 # 并行线程个数
- 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_workers=workers,
- shuffle=True,)
- # 数据增强操作
- mean = [0.485 * 255, 0.456 * 255, 0.406 * 255]
- std = [0.229 * 255, 0.224 * 255, 0.225 * 255]
- scale = 32
- if usage == "train":
- # Define map operations for training dataset
- trans = [
- vision.RandomCropDecodeResize(size=image_size, scale=(0.08, 1.0), ratio=(0.75, 1.333)),
- vision.RandomHorizontalFlip(prob=0.5),
- vision.Normalize(mean=mean, std=std),
- vision.HWC2CHW()
- ]
- else:
- # Define map operations for inference dataset
- trans = [
- vision.Decode(),
- vision.Resize(image_size + scale),
- vision.CenterCrop(image_size),
- vision.Normalize(mean=mean, std=std),
- vision.HWC2CHW()
- ]
- # 数据映射操作
- data_set = data_set.map(
- operations=trans,
- input_columns='image',
- num_parallel_workers=workers)
- # 批量操作
- data_set = data_set.batch(batch_size)
- return data_set
- 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()
复制代码 数据集可视化
通过next迭代访问数据集,一次获取batch_size个图像及标签:
- data = next(dataset_train.create_dict_iterator())
- images = data["image"]
- labels = data["label"]
- print("Tensor of image", images.shape)
- print("Labels:", labels)
- 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):
- # 获取图像及其对应的label
- data_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 + mean
- data_image = np.clip(data_image, 0, 1)
- # 显示图像
- plt.subplot(2, 2, i+1)
- plt.imshow(data_image)
- plt.title(class_name[int(labels[i].asnumpy())])
- plt.axis("off")
- plt.show()
复制代码 模型训练
利用ResNet50网络,通过将pretrained设置为True来加载预训练模型:
- class ResNet(nn.Cell):
- def __init__(self, block: Type[Union[ResidualBlockBase, ResidualBlock]],layer_nums: List[int], num_classes: int, input_channel: int) -> None:
- # ...
- def construct(self, x):
- # ...
- def _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(url=model_url, path=pretrianed_ckpt, replace=True)
- param_dict = load_checkpoint(pretrianed_ckpt)
- load_param_into_net(model, param_dict)
- return model
- def 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)
复制代码 通过resnet50接口创建网络模型,假如设置pretrained=True,则下载并加载预训练模型到ResNet50中。
固定特征
利用固定特征举行训练时,必要冻结除末了一层之外的所有网络层。通过设置requires_grad=False冻结参数,使其不在反向流传中盘算梯度。
- import mindspore as ms
- import matplotlib.pyplot as plt
- import os
- import time
- net_work = resnet50(pretrained=True)
- # 全连接层输入层的大小
- 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_size=7)
- # 重置平均池化层
- 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(params=net_work.trainable_params(), learning_rate=lr, momentum=0.5)
- loss_fn = nn.SoftmaxCrossEntropyWithLogits(sparse=True, reduction='mean')
- def forward_fn(inputs, targets):
- logits = net_work(inputs)
- loss = loss_fn(logits, targets)
- return loss
- grad_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()})
复制代码 总结
这一小节对预训练模型引入的缘故原由举行了说明,通过加载预训练模型的参数到ResNet50模型中举行参数初始化,从而加速网络的训练过程。可以通过设置参数requires_grad=False来冻结参数,使其作为固定特征,不参与梯度盘算与参数优化。
打卡
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |