昇思25天学习打卡营第13天 | ResNet50迁移学习

昇思25天学习打卡营第13天 | ResNet50迁移学习

文章目录

在实际应用场景中,由于训练数据集不足,很少从头开始训练整个网络。普遍做法是在一个非常大的基础数据集上训练得到一个 预训练模型 ,然后使用该模型来初始化网络的权重参数或作为固定特征提取器应用于特定的任务。

数据集

使用ResNet50在狗与狼分类数据集上进行训练,数据集中图片来自ImageNet,每个分类大约120张训练图像和30张验证图像。

python 复制代码
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接口来加载数据集,并进行数据增强::

python 复制代码
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个图像及标签:

python 复制代码
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来加载预训练模型:

python 复制代码
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冻结参数,使其不在反向传播中计算梯度。

python 复制代码
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来冻结参数,使其作为固定特征,不参与梯度计算与参数优化。

打卡

相关推荐
2201_7576799812 分钟前
QT学习第五天
开发语言·qt·学习
2401_826044791 小时前
Python学习——第二阶段:面向对象
学习
Achanss7 小时前
C#学习笔记 .NET Core使用注意事项
笔记·学习·c#
爱分享的益达7 小时前
往年互联网大厂腾讯华为百度等校招面试笔试题合集
学习·程序人生·面试·生活
B.-7 小时前
Remix 学习 - 路由模块(Route Module)
前端·javascript·学习·react·web
limengshi1383927 小时前
通信工程学习:什么是GFP通用成帧规范
服务器·网络·网络协议·学习·信息与通信
月夕花晨3747 小时前
C++学习笔记(14)
c++·笔记·学习
lagransun8 小时前
Linux内核学习之 -- 系统调用open()和write()的实现笔记
linux·笔记·学习
Invulnerabl_DL8 小时前
《基于深度半监督学习的目标检测综述》泛读
笔记·深度学习·学习·目标检测·计算机视觉
宇寒风暖9 小时前
计算机操作系统之并行性与并发性笔记
学习·操作系统·并行性·并发性