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

    打卡

    在这里插入图片描述

  • 相关阅读:
    原型链解释
    C++特殊定制:揭秘cpo与tag_invoke!
    天佑药品销售管理系统
    mybatis---->tx中weekend类
    Qt 为Android app添加系统签名
    神经网络中的核心概念是,神经网络的主要内容
    【数据库MySql】数据库基础——库和表的基础操作
    Web蜜罐
    网安面经之文件上传漏洞
    代码审计之路之白盒挖掘机 | 技术精选01
  • 原文地址:https://blog.csdn.net/qq_31254435/article/details/140406958