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

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

打卡

在这里插入图片描述

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-14 04:50:04       50 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-14 04:50:04       54 阅读
  3. 在Django里面运行非项目文件

    2024-07-14 04:50:04       43 阅读
  4. Python语言-面向对象

    2024-07-14 04:50:04       54 阅读

热门阅读

  1. 设计模式详解(十八)——责任链模式

    2024-07-14 04:50:04       17 阅读
  2. Vue3 关于scss预编译中:deep 其中的deep如何理解

    2024-07-14 04:50:04       18 阅读
  3. stm32使用通用定时器生成pwm

    2024-07-14 04:50:04       22 阅读
  4. 如何实现一个分布式锁

    2024-07-14 04:50:04       17 阅读
  5. BGP笔记的基本概要

    2024-07-14 04:50:04       18 阅读
  6. 在RHEL9.4上安装Python3.11环境

    2024-07-14 04:50:04       18 阅读
  7. Hypertable install of rhel6.0

    2024-07-14 04:50:04       19 阅读
  8. 60、基于浅层神经网络的数据拟合(matlab)

    2024-07-14 04:50:04       22 阅读
  9. conda激活的虚拟环境的python版本不对应

    2024-07-14 04:50:04       20 阅读
  10. 实变函数精解【4】

    2024-07-14 04:50:04       19 阅读
  11. react详解

    2024-07-14 04:50:04       24 阅读
  12. 第一节 SHELL脚本中的常用命令(7)

    2024-07-14 04:50:04       23 阅读
  13. Python中的lambda表达式

    2024-07-14 04:50:04       21 阅读
  14. WSGI 服务器教程:`full_dispatch_request` 方法解析

    2024-07-14 04:50:04       21 阅读
  15. Facebook Research 的 Ocean 框架用于AR和CV的C++库

    2024-07-14 04:50:04       17 阅读