240622_昇思学习打卡-Day4-ResNet50迁移学习
我们对事物的认知都是一点一点积累出来的,往往借助已经认识过的东西,可以更好地理解和认识新的有关联的东西。比如一个人会骑自行车,我们让他去骑摩托车他也很快就能学会,比如已经学会C++,现在让他去学python他也很容易就能理解。这种情况我们一般称为举一反三。反言之,我们从原始部落找出来一个人(仅作举例),指着摩托车让他骑,可能是一件特别难的事,因为他对这个领域没有丝毫的认知和理解,在实现这件事上就会特别困难。
映射到神经网络上也是一样的道理,如果我们在训练时不导入预训练权重,他就像一个没有见过现代社会的原始人,学任何东西都特别慢,学习成本特别高,但如果我们导入了相似模型结构下针对别的任务的训练权重(比如训练识别自行车),用来训练识别摩托车,我们只需要改变网络最后的分类层,即可得到比较好的训练效果,可以大大缩小模型训练的时间。
原理是我在这么多层神经网络的训练下,已经明白了轱辘(车轮)长什么样,把手长什么样,最后的分类层只是区分出来什么是自行车,你现在给我一堆摩托的照片,我就可以去寻找两者的相似处,我对轱辘和把手的认知就不用从0开始重新学习,只需要进行微调,比如摩托车的轱辘比自行车大一点,摩托车的车把手比自行车大一点。基于以前已经学习到的东西,可以大大缩小训练成本。
迁移学习就是这个道理。我们在神经网络技术的发展中,针对不同的任务,不可能每个网络都从0开始训练,那样需要的数据集及成本都是不可承受的。
本文以ResNet50迁移学习为例展开讲解,在MindSpore架构下运行。
数据准备
下载数据集
本文用到狗与狼分类数据集,使用download接口下载,也可自行下载放在项目当前目录下
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)
数据目录结构如下:
text
datasets-Canidae/data/
└── Canidae
├── train
│ ├── dogs
│ └── wolves
└── val
├── dogs
└── wolves
首先定义一些超参数:
batch_size = 18 # 批量大小
image_size = 224 # 训练图像空间大小
num_epochs = 5 # 训练周期数
lr = 0.001 # 学习率
momentum = 0.9 # 动量
workers = 4 # 并行线程个数
加载数据集以及做一些数据增强(本文所用的狼狗数据集属于ImageNet数据集,其典型mean和std值分别为[0.485, 0.456, 0.406]和[0.229, 0.224, 0.225],所以代码中直接使用):
# 导入MindSpore库,用于深度学习框架
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/"
# 定义函数,用于创建Canidae分类任务的训练集或验证集
# 参数dataset_path: 数据集路径,usage: 数据集的用途,"train"或"val"
# 返回处理后的数据集
# 创建训练数据集
def create_dataset_canidae(dataset_path, usage):
"""数据加载"""
# 初始化ImageFolderDataset,使用多线程并打乱数据顺序
# 使用mindspore.dataset.ImageFolderDataset接口来加载数据集
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
迭代访问数据集。前面 batch_size
设为18,所以使用 next
一次可获取18个图像及标签数据。
# 获取训练数据集的第一个批次数据,是18张图像及标签数据。
data = next(dataset_train.create_dict_iterator())
images = data["image"]
labels = data["label"]
print("Tensor of image", images.shape)
print("Labels:", labels)
'''
执行结果为
Tensor of image (18, 3, 224, 224) # 意思是这一批有18张3通道(RGB通道)的长224宽224的图像
Labels: [1 1 0 1 1 0 1 0 0 0 0 0 0 0 0 1 0 1] # 因为该任务是一个二分类任务,所以类别只有简单的0和1
'''
目前拿到的数据我们可以先看看长什么样,展示图像及标题,标题为对应的label名称
# 导入matplotlib.pyplot库用于绘图
import matplotlib.pyplot as plt
# 导入numpy库用于处理数组
import numpy as np
# 定义一个字典,映射类别编号到类别名称
# class_name对应label,按文件夹字符串从小到大的顺序标记label
class_name = {0: "dogs", 1: "wolves"}
# 创建一个5x5大小的画布
plt.figure(figsize=(5, 5))
# 循环遍历4个图像
for i in range(4):
# 获取当前图像的数据和标签
# 获取图像及其对应的label
data_image = images[i].asnumpy()
data_label = labels[i]
# 将图像数据从HWC格式转换为RGB格式
# 处理图像供展示使用
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()
训练模型
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)
今日就先写这些,明天学完之后汇总。
不知道为什么我在这篇里面点编辑然后发表之后变成了一篇新的博客,那这里就附上后续的博客地址吧
240622_昇思学习打卡-Day4-5-ResNet50迁移学习
打卡图片: