ResNet50是一种深度残差网络(Residual Network)模型,它是由微软研究院的研究员Kaiming He等人在2015年提出的一种深度学习模型。ResNet50是其中的一种变体,它有50层深度。

ResNet50的核心思想是引入“残差学习”的概念,通过在神经网络中添加“跳跃连接”(skip connections)来解决深度神经网络训练时的梯度消失和梯度爆炸问题。跳跃连接能够将前面层的输出直接传递到后面层,使得信息可以直接流动,从而使得网络可以更好地训练。

ResNet50在多个基准测试中表现出色,例如ImageNet图像识别挑战赛。它在图像分类、目标检测和图像分割等领域得到了广泛应用。由于其优越的性能和广泛的应用,ResNet50成为了深度学习领域中最重要的模型之一。

迁移学习(Transfer Learning)是机器学习的一个分支,它涉及到将一个领域中学习到的知识应用到另一个不同的但相关的领域。在深度学习的背景下,迁移学习通常指的是使用在一个大型数据集上预训练的模型(例如ResNet50)作为起点,然后在新的任务上微调该模型。

迁移学习的过程通常包括以下几个步骤:

  1. 预训练:在一个大规模的数据集上训练一个模型,通常是 ImageNet 数据集,它包含了数百万个带有标签的图像。这个阶段的目标是让模型学习到通用的特征表示,这些特征在许多不同的视觉任务中都是有用的。

  2. 特征提取:将预训练模型的最后一层(通常是全连接层)替换成新的层,这样新的层可以针对特定任务进行训练。预训练模型的其余部分被冻结,其参数在微调阶段保持不变。

  3. 微调:使用新任务的数据来微调模型。在这个阶段,可以选择只训练新添加的层,或者解冻预训练模型的一部分层,让它们也参与到微调过程中。微调的目的是让模型适应新的数据分布。

  4. 部署:微调后的模型可以用于新的任务,比如不同的图像分类任务、目标检测、分割等。

迁移学习的好处包括:

  • 节省资源:不需要从零开始训练一个大型模型,这样可以节省计算资源和时间。
  • 提高性能:使用预训练模型作为起点通常能够提供比从头开始训练更好的性能,尤其是在目标任务数据量有限的情况下。
  • 减少过拟合:预训练模型已经学习到了大量的通用特征,这有助于在新任务上减少过拟合的风险。
  • 加载数据集

  • 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()

数据集可视化

mindspore.dataset.ImageFolderDataset接口中加载的训练数据集返回值为字典,用户可通过 create_dict_iterator 接口创建数据迭代器,使用 next 迭代访问数据集。

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来下载ResNet50的预训练模型并将权重参数加载到网络中。

构建Resnet50网络
from typing import Type, Union, List, Optional
from mindspore import nn, train
from mindspore.common.initializer import Normal


weight_init = Normal(mean=0, sigma=0.02)
gamma_init = Normal(mean=1, sigma=0.02)

固定特征进行训练

使用固定特征进行训练的时候,需要冻结除最后一层之外的所有网络层。通过设置 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()})

Logo

鲲鹏昇腾开发者社区是面向全社会开放的“联接全球计算开发者,聚合华为+生态”的社区,内容涵盖鲲鹏、昇腾资源,帮助开发者快速获取所需的知识、经验、软件、工具、算力,支撑开发者易学、好用、成功,成为核心开发者。

更多推荐