深度学习-图像分类问题-核心代码梳理(MindSpore版)
'data_path': './photos/', # 数据存储路径'image_width': 100, # 图片宽度'image_height': 100, # 图片高度'channel': 3, # 图片通道数'num_class':5, # 分类类别'lr':0.0001, # 学习率'epoch_size': 400, # 训练次数'save_checkpoint_steps': 1,
模块导入
# 基础工具库:文件路径与字典操作
import os
import glob
from easydict import EasyDict as edict
# 科学计算与可视化库
import numpy as np
import matplotlib.pyplot as plt
# MindSpore框架核心库
import mindspore
from mindspore import Tensor, context
from mindspore.common import dtype as mstype
from mindspore.common.initializer import TruncatedNormal
# MindSpore数据集与数据处理模块
import mindspore.dataset as ds
import mindspore.dataset.vision.c_transforms as CV
import mindspore.dataset.transforms.c_transforms as C
# MindSpore神经网络与训练相关模块
from mindspore import nn
from mindspore.train import Model
from mindspore.train.callback import ModelCheckpoint, CheckpointConfig, LossMonitor, TimeMonitor
from mindspore.train.serialization import load_checkpoint, load_param_into_net
# 设置MindSpore的执行模式和设备(此处Ascend也可以为CPU/GPU)
context.set_context(mode=context.GRAPH_MODE, device_target="Ascend")
1. easydict 库
- 功能:提供了
EasyDict类,可将普通字典转换为支持 “属性式访问” 的对象。easydict模块用于以属性的方式访问字典的值 - 示例:普通字典访问用
dict['key'],而EasyDict可直接用edict.key,简化代码书写。
2. glob 库
- 功能:用于查找符合特定规则的文件路径名,类似操作系统的文件搜索功能。
- 特点:支持通配符(如
*、?、[]),方便批量获取文件路径(例如glob.glob('data/*.jpg')获取所有 jpg 文件)。
3. os 库
- 功能:提供与操作系统交互的接口,主要用于处理文件和目录操作。
- 常用功能:创建目录(
os.mkdir)、获取当前路径(os.getcwd)、路径拼接(os.path.join)等。
4. numpy 库(别名 np)
- 功能:Python 科学计算的核心库,提供高性能的多维数组(
ndarray)及数学运算函数。 - 应用:在深度学习中常用于数据存储、预处理(如数组转换、维度操作)等。
5. matplotlib.pyplot 模块(别名 plt)
- 功能:
matplotlib库的绘图接口,用于生成各类可视化图表(如折线图、直方图、图像显示等)。 - 应用:在深度学习中常用于可视化训练曲线、数据分布或预测结果。
6. mindspore 框架
华为推出的全场景深度学习框架,以下是代码中涉及的核心模块:
(1)mindspore.dataset 模块(别名 ds)
- 功能:提供数据加载和预处理的统一接口,支持多种数据源(如图片、文本、自定义数据集)。
- 作用:构建高效的数据管道,为模型训练提供标准化输入。
(2)mindspore.dataset.vision.c_transforms 模块(别名 CV)
- 功能:提供基于 C++ 的高性能图像增强算子(如 Resize、Normalize、HWC2CHW 等)。
- 作用:用于图像数据的预处理和数据增强,提升模型泛化能力。
(3)mindspore.dataset.transforms.c_transforms 模块(别名 C)
- 功能:提供通用的数据转换算子,支持非图像数据的处理(如类型转换、One-Hot 编码等)。
- 常用算子:
TypeCast(数据类型转换)、OneHotOp(独热编码)等。
(4)mindspore.common.dtype 模块(别名 mstype)
- 功能:定义 MindSpore 支持的数据类型(如
mstype.float32、mstype.int64等)。 - 作用:在数据转换、网络定义中指定数据类型,确保计算一致性。
(5)mindspore.common.initializer.TruncatedNormal
- 功能:截断正态分布初始化器,用于神经网络权重参数的初始化。
- 特点:生成落在均值附近一定范围内的随机数,避免权重过大或过小影响训练。
(6)mindspore.nn 模块
- 功能:MindSpore 的神经网络模块,提供常用网络层(如 Conv2d、Linear)、损失函数(如 CrossEntropyLoss)、优化器(如 Adam)等。
- 作用:用于搭建深度学习模型的核心组件。
(7)mindspore.train 相关模块
Model:封装了模型的训练、评估流程,简化训练接口。- 回调函数(
ModelCheckpoint、CheckpointConfig、LossMonitor、TimeMonitor):ModelCheckpoint:保存模型 checkpoint(参数文件)。CheckpointConfig:配置 checkpoint 的保存策略(如保存频率、最大数量)。LossMonitor:监控训练过程中的损失值变化。TimeMonitor:记录每个 epoch 的训练时间。
load_checkpoint、load_param_into_net:加载已保存的模型参数,并注入到网络中(用于断点续训或推理)。
(8)mindspore.Tensor
- 功能:MindSpore 的核心数据结构,类似 Numpy 的数组,但支持自动微分和硬件加速(如 Ascend/GPU)。
- 作用:作为网络输入、参数和计算结果的载体。
(9)mindspore.context 模块
- 功能:配置 MindSpore 的运行环境,如执行模式(图模式 / 动态图模式)、运行设备(Ascend/CPU/GPU)等。
- 示例:
context.set_context(mode=GRAPH_MODE, device_target="Ascend")表示使用图模式在昇腾芯片上运行。
统一定义变量(可选,不写则对应位置专门写)
cfg = edict({
'data_path': './photos/', # 数据存储路径
'data_size':3670,
'image_width': 100, # 图片宽度
'image_height': 100, # 图片高度
'batch_size': 32,
'channel': 3, # 图片通道数
'num_class':5, # 分类类别
'weight_decay': 0.01,
'lr':0.0001, # 学习率
'dropout_ratio': 0.5,
'epoch_size': 400, # 训练次数
'sigma':0.01,
'save_checkpoint_steps': 1, # 多少步保存一次模型
'keep_checkpoint_max': 1, # 最多保存多少个模型
'output_directory': './', # 保存模型路径
'output_prefix': "checkpoint_classification" # 保存模型文件名字
})
获取数据集(得是非解压的)
1,直接导入数据集到指定目录
2,代码下载到指定目录
数据预处理
-
mindspore.dataset提供了ImageFolderDatasetV2函数,可以直接读取文件夹图片数据并映射文件夹名字为其标签(label)。
这里我们使用ImageFolderDatasetV2函数读取’daisy’,‘dandelion’,‘roses’,‘sunflowers’,'tulips’数据,并将这五类标签映射为: {‘daisy’:0,‘dandelion’:1,‘roses’:2,‘sunflowers’:3,‘tulips’:4};
-
使用RandomCropDecodeResize、HWC2CHW、TypeCast、shuffle进行数据预处理。
#从目录中读取图像的源数据集
de_dataset = ds.ImageFolderDataset(cfg.data_path,
class_indexing={'daisy':0,'dandelion':1,'roses':2,'sunflowers':3,'tulips':4})
#解码前将输入图像随机选择一个区域裁剪,再将裁剪区域缩放为指定大小
#随机裁剪的区域面积相对于原图面积的比例范围(8%~100%)
#随机裁剪的区域宽高比范围(0.75≈3/4到1.333≈4/3)
transform_img = CV.RandomCropDecodeResize([cfg.image_width,cfg.image_height], scale=(0.08, 1.0), ratio=(0.75, 1.333)) #改变尺寸
#转换输入图像的维度从(H, W, C)为(C, H, W)
hwc2chw_op = CV.HWC2CHW()
#转换为给定MindSpore数据类型的Tensor操作
# 神经网络通常使用float32进行计算,确保数据类型匹配
#此处创建一个数据转换算子 type_cast_op,它的作用是将输入数据转换为 MindSpore 定义的 float32 类型
type_cast_op = C.TypeCast(mstype.float32)
#对数据集的"image"列应用operations中操作
# num_parallel_workers=8:使用8个并行进程处理数据,加速预处理
de_dataset = de_dataset.map(input_columns="image", operations=transform_img, num_parallel_workers=8)
de_dataset = de_dataset.map(input_columns="image", operations=hwc2chw_op, num_parallel_workers=8)
de_dataset = de_dataset.map(input_columns="image", operations=type_cast_op, num_parallel_workers=8)
# 对数据集进行打乱操作
# buffer_size:打乱时使用的缓冲区大小(通常设为数据集总样本数),缓冲区越大,打乱越充分
de_dataset = de_dataset.shuffle(buffer_size=cfg.data_size)
数据集划分+批处理配置+可视化(可选)
#划分训练集测试集
(de_train,de_test)=de_dataset.split([0.8,0.2])
#设置每个批处理的行数
#drop_remainder确定是否删除最后一个可能不完整的批(default=False)。
#如果为True,并且如果可用于生成最后一个批的batch_size行小于batch_size行,则这些行将被删除,并且不会传播到子节点。
#当最后一批数据的样本数不足 batch_size 时,直接丢弃该批,确保每批样本数量一致,避免训练时因批次大小不统一导致报错
de_train=de_train.batch(cfg.batch_size, drop_remainder=True)
de_test=de_test.batch(cfg.batch_size, drop_remainder=True)
# 查看数据集划分和批处理配置是否正确,确保训练 / 测试数据量符合预期
#get_dataset_size()获取批处理的大小,即总批次数
print('训练数据集数量:',de_train.get_dataset_size()*cfg.batch_size)
print('测试数据集数量:',de_test.get_dataset_size()*cfg.batch_size)
# 查看单样本(即一个批次)的数据格式
# 创建数据集迭代器,获取一个批次的样本数据(以字典形式存储,包含 image 图像数据和 label 标签)
data_next=de_dataset.create_dict_iterator(output_numpy=True).__next__()
print('通道数/图像长/宽:', data_next['image'].shape)
print('一张图像的标签样式:', data_next['label']) # 一共5类,用0-4的数字表达类别。
# 可视化该批次中的第一张图像,检查预处理效果(如尺寸是否正确、是否因随机裁剪导致图像内容随机化)
plt.figure()
plt.imshow(data_next['image'][0,...])
plt.colorbar()
plt.grid(False)
#每次输出图片不全相同,原因是数据集做了 shuffle(打乱)操作,每次运行代码时样本顺序都会随机重组
plt.show()
定义模型(自定义即可)
# 定义CNN图像识别网络
class Identification_Net(nn.Cell):
def __init__(self, num_class=5,channel=3,dropout_ratio=0.5,trun_sigma=0.01): # 一共分五类,图片通道数是3
super(Identification_Net, self).__init__()
self.num_class = num_class
self.channel = channel
self.dropout_ratio = dropout_ratio
#设置卷积层
self.conv1 = nn.Conv2d(self.channel, 32,
kernel_size=5, stride=1, padding=0,
has_bias=True, pad_mode="same",
weight_init=TruncatedNormal(sigma=trun_sigma),bias_init='zeros')
#设置ReLU激活函数
self.relu = nn.ReLU()
#设置最大池化层
self.max_pool2d = nn.MaxPool2d(kernel_size=2, stride=2,pad_mode="valid")
self.conv2 = nn.Conv2d(32, 64,
kernel_size=5, stride=1, padding=0,
has_bias=True, pad_mode="same",
weight_init=TruncatedNormal(sigma=trun_sigma),bias_init='zeros')
self.conv3 = nn.Conv2d(64, 128,
kernel_size=3, stride=1, padding=0,
has_bias=True, pad_mode="same",
weight_init=TruncatedNormal(sigma=trun_sigma),bias_init='zeros')
self.conv4 = nn.Conv2d(128, 128,
kernel_size=3, stride=1, padding=0,
has_bias=True, pad_mode="same",
weight_init=TruncatedNormal(sigma=trun_sigma), bias_init='zeros')
self.flatten = nn.Flatten()
self.fc1 = nn.Dense(6*6*128, 1024,weight_init =TruncatedNormal(sigma=trun_sigma),bias_init = 0.1)
self.dropout = nn.Dropout(self.dropout_ratio)
self.fc2 = nn.Dense(1024, 512, weight_init=TruncatedNormal(sigma=trun_sigma), bias_init=0.1)
self.fc3 = nn.Dense(512, self.num_class, weight_init=TruncatedNormal(sigma=trun_sigma), bias_init=0.1)
#构建模型
def construct(self, x):
x = self.conv1(x)
#print(x.shape)
x = self.relu(x)
x = self.max_pool2d(x)
x = self.conv2(x)
x = self.relu(x)
x = self.max_pool2d(x)
x = self.conv3(x)
x = self.max_pool2d(x)
x = self.conv4(x)
x = self.max_pool2d(x)
x = self.flatten(x)
x = self.fc1(x)
x = self.relu(x)
#print(x.shape)
x = self.dropout(x)
x = self.fc2(x)
x = self.relu(x)
x = self.dropout(x)
x = self.fc3(x)
return x
训练模型
1,模型定义
net=Identification_Net(num_class=cfg.num_class, channel=cfg.channel, dropout_ratio=cfg.dropout_ratio)
2,损失函数定义
如果是无监督学习任务(如自编码器),可能不需要传统的分类 / 回归损失函数;但有监督任务必须配置。
#计算softmax交叉熵。
net_loss = nn.SoftmaxCrossEntropyWithLogits(sparse=True, reduction="mean")
3,优化器配置
# 按参数类型分组(区分全连接层权重与其他参数)
fc_weight_params = list(filter(lambda x: 'fc' in x.name and 'weight' in x.name, net.trainable_params())) # 全连接层权重参数
other_params = list(filter(lambda x: 'fc' not in x.name or 'weight' not in x.name, net.trainable_params())) # 其他可训练参数(如卷积层参数、偏置等)
# 定义参数组(可对不同组参数设置不同的优化策略)
group_params = [
{'params': fc_weight_params, 'weight_decay': cfg.weight_decay}, # 对全连接层权重应用权重衰减(正则化)
{'params': other_params}, # 其他参数不额外设置权重衰减(或使用默认)
{'order_params': net.trainable_params()} # 保持参数更新顺序与网络定义一致
]
# 初始化Adam优化器(用于更新网络参数)
net_opt = nn.Adam(
group_params, # 待优化的参数组
learning_rate=cfg.lr, # 学习率(控制参数更新步长)
weight_decay=0.0 # 全局权重衰减(这里被参数组的设置覆盖)
)
4,模型训练参数封装
# 封装模型(整合网络、损失函数、优化器和评估指标)
model = Model(
net, # 定义的网络
loss_fn=net_loss, # 损失函数
optimizer=net_opt, # 优化器
metrics={"acc"} # 评估指标(这里为准确率)
)
5,损失监控回调配置(可选)
# 定义损失监控回调(训练过程中打印损失值)
loss_cb = LossMonitor(
per_print_times=de_train.get_dataset_size() * 10 # 每训练10个epoch打印一次损失
)
6,模型保存配置(可选)
# 定义模型保存配置
config_ck = CheckpointConfig(
save_checkpoint_steps=cfg.save_checkpoint_steps, # 每多少步保存一次模型参数
keep_checkpoint_max=cfg.keep_checkpoint_max # 最多保留的模型文件数量(防止磁盘占满)
)
# 定义模型保存回调
ckpoint_cb = ModelCheckpoint(
prefix=cfg.output_prefix, # 模型文件前缀名
directory=cfg.output_directory, # 模型保存目录
config=config_ck # 保存配置
)
7,模型训练
# 启动模型训练
print("============== Starting Training ==============")
model.train(
cfg.epoch_size, # 训练的总轮数
de_train, # 训练数据集
callbacks=[loss_cb, ckpoint_cb], # 训练过程中使用的回调函数
dataset_sink_mode=True # 启用数据集下沉模式(提升Ascend/GPU上的训练效率)
)
8,模型评估
# 使用测试集评估模型性能
metric = model.eval(de_test) # 计算测试集上的评估指标(这里为准确率)
print(metric) # 打印评估结果(如{'acc': 0.85}表示准确率85%)
加载模型
#加载模型
import os
CKPT = os.path.join(cfg.output_directory,cfg.output_prefix+'-'+str(cfg.epoch_size)+'_'+str(de_train.get_dataset_size())+'.ckpt')
net = Identification_Net(num_class=cfg.num_class, channel=cfg.channel, dropout_ratio=cfg.dropout_ratio)
load_checkpoint(CKPT, net=net)
model = Model(net)
验证推理
# 预测
class_names = {0:'daisy',1:'dandelion',2:'roses',3:'sunflowers',4:'tulips'}
test_ = de_test.create_dict_iterator().__next__()
test = Tensor(test_['image'], mindspore.float32)
predictions = model.predict(test)
predictions = predictions.asnumpy()
true_label = test_['label'].asnumpy()
#显示预测结果
for i in range(10):
p_np = predictions[i, :]
pre_label = np.argmax(p_np)
print('第' + str(i) + '个sample预测结果:', class_names[pre_label], ' 真实结果:', class_names[true_label[i]])
昇腾计算产业是基于昇腾系列(HUAWEI Ascend)处理器和基础软件构建的全栈 AI计算基础设施、行业应用及服务,https://devpress.csdn.net/organization/setting/general/146749包括昇腾系列处理器、系列硬件、CANN、AI计算框架、应用使能、开发工具链、管理运维工具、行业应用及服务等全产业链
更多推荐


所有评论(0)