模块导入

# 基础工具库:文件路径与字典操作
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.float32mstype.int64 等)。
  • 作用:在数据转换、网络定义中指定数据类型,确保计算一致性。
(5)mindspore.common.initializer.TruncatedNormal
  • 功能:截断正态分布初始化器,用于神经网络权重参数的初始化。
  • 特点:生成落在均值附近一定范围内的随机数,避免权重过大或过小影响训练。
(6)mindspore.nn 模块
  • 功能:MindSpore 的神经网络模块,提供常用网络层(如 Conv2d、Linear)、损失函数(如 CrossEntropyLoss)、优化器(如 Adam)等。
  • 作用:用于搭建深度学习模型的核心组件。
(7)mindspore.train 相关模块
  • Model:封装了模型的训练、评估流程,简化训练接口。
  • 回调函数(ModelCheckpointCheckpointConfigLossMonitorTimeMonitor):
    • ModelCheckpoint:保存模型 checkpoint(参数文件)。
    • CheckpointConfig:配置 checkpoint 的保存策略(如保存频率、最大数量)。
    • LossMonitor:监控训练过程中的损失值变化。
    • TimeMonitor:记录每个 epoch 的训练时间。
  • load_checkpointload_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]]) 

Logo

昇腾计算产业是基于昇腾系列(HUAWEI Ascend)处理器和基础软件构建的全栈 AI计算基础设施、行业应用及服务,https://devpress.csdn.net/organization/setting/general/146749包括昇腾系列处理器、系列硬件、CANN、AI计算框架、应用使能、开发工具链、管理运维工具、行业应用及服务等全产业链

更多推荐