[{"data":1,"prerenderedAt":254},["ShallowReactive",2],{"content-query-iRHPWFxIx7":3},{"_path":4,"_dir":5,"_draft":6,"_partial":6,"_locale":7,"title":8,"description":9,"date":10,"cover":11,"type":12,"category":13,"body":14,"_type":248,"_id":249,"_source":250,"_file":251,"_stem":252,"_extension":253},"/technology-blogs/zh/3144","zh",false,"","基于MindSpore框架的深度学习模型在CV方向的应用--(3) ResNet50花卉图片分类实验","本实验将会利用一个开源数据集来帮助大家学习如何构建自己的图像识别模型。","2024-05-06","https://obs-mindspore-file.obs.cn-north-4.myhuaweicloud.com/file/2024/06/07/867fc572328a428d874d67f1b4ea9d24.png","technology-blogs","实践",{"type":15,"children":16,"toc":233},"root",[17,25,31,38,58,64,69,77,83,88,93,99,106,111,121,127,132,140,145,150,158,164,169,174,179,187,193,198,206,211,219,225],{"type":18,"tag":19,"props":20,"children":22},"element","h1",{"id":21},"基于mindspore框架的深度学习模型在cv方向的应用-3-resnet50花卉图片分类实验",[23],{"type":24,"value":8},"text",{"type":18,"tag":26,"props":27,"children":28},"p",{},[29],{"type":24,"value":30},"本实验将会利用一个开源数据集来帮助大家学习如何构建自己的图像识别模型。本实验会使用MindSpore来构建图像识别模型，实现花卉识别功能。",{"type":18,"tag":32,"props":33,"children":35},"h2",{"id":34},"_1实验目的",[36],{"type":24,"value":37},"1、实验目的",{"type":18,"tag":39,"props":40,"children":41},"ul",{},[42,48,53],{"type":18,"tag":43,"props":44,"children":45},"li",{},[46],{"type":24,"value":47},"掌握如何使用MindSpore进行ResNet50神经网络模型的开发。",{"type":18,"tag":43,"props":49,"children":50},{},[51],{"type":24,"value":52},"了解如何使用MindSpore进行花卉图片分类任务的训练。",{"type":18,"tag":43,"props":54,"children":55},{},[56],{"type":24,"value":57},"了解如何使用MindSpore进行花卉图片分类任务的测试。",{"type":18,"tag":32,"props":59,"children":61},{"id":60},"_2resnet模型介绍",[62],{"type":24,"value":63},"2、ResNet模型介绍",{"type":18,"tag":26,"props":65,"children":66},{},[67],{"type":24,"value":68},"ResNet50网络是2015年由微软实验室的何恺明提出，获得ILSVRC2015图像分类竞赛第一名。在ResNet网络提出之前，传统的卷积神经网络都是将一系列的卷积层和池化层堆叠得到的，但当网络堆叠到一定深度时，就会出现退化问题。下图是在CIFAR-10数据集上使用56层网络与20层网络训练误差和测试误差图，由图中数据可以看出，56层网络比20层网络训练误差和测试误差更大，随着网络的加深，其误差并没有如预想的一样减小。",{"type":18,"tag":26,"props":70,"children":71},{},[72],{"type":18,"tag":73,"props":74,"children":76},"img",{"alt":7,"src":75},"https://obs-mindspore-file.obs.cn-north-4.myhuaweicloud.com/file/2024/06/07/68a7e56839f2439a945fba19a2cf6100.png",[],{"type":18,"tag":32,"props":78,"children":80},{"id":79},"_3实验环境",[81],{"type":24,"value":82},"3、实验环境",{"type":18,"tag":26,"props":84,"children":85},{},[86],{"type":24,"value":87},"本案例支持win_x86和Linux系统，CPU/GPU/Ascend均可运行。",{"type":18,"tag":26,"props":89,"children":90},{},[91],{"type":24,"value":92},"如果在本地运行此实验，请参考《MindSpore环境搭建实验手册》在本地安装MindSpore。",{"type":18,"tag":32,"props":94,"children":96},{"id":95},"_4数据处理",[97],{"type":24,"value":98},"4、数据处理",{"type":18,"tag":100,"props":101,"children":103},"h3",{"id":102},"_41数据准备",[104],{"type":24,"value":105},"4.1数据准备",{"type":18,"tag":26,"props":107,"children":108},{},[109],{"type":24,"value":110},"该数据集是开源数据集，总共包括5种花的类型：分别是daisy（雏菊，633张），dandelion（蒲公英，898张），roses（玫瑰，641张），sunflowers（向日葵，699张），tulips（郁金香，799张），保存在5个文件夹当中，总共3670张，大小大概在230M左右。为了在模型部署上线之后进行测试，数据集在这里分成了flower_train和flower_test两部分。",{"type":18,"tag":112,"props":113,"children":115},"pre",{"code":114},"from download import download\n\n# 下载flower_photos训练数据集\nurl = \"https://ascend-professional-construction-dataset.obs.myhuaweicloud.com/deep-learning/flower_photos_train.zip\"\npath = download(url, \"./\", kind=\"zip\", replace=True)\n",[116],{"type":18,"tag":117,"props":118,"children":119},"code",{"__ignoreMap":7},[120],{"type":24,"value":114},{"type":18,"tag":100,"props":122,"children":124},{"id":123},"_42数据加载",[125],{"type":24,"value":126},"4.2数据加载",{"type":18,"tag":26,"props":128,"children":129},{},[130],{"type":24,"value":131},"导入相应的模块 os模块主要用于处理文件和目录，比如：获取当前目录下文件，删除制定文件，改变目录，查看文件大小等；MindSpore是目前业界最流行的深度学习框架，在图像，语音，文本，目标检测等领域都有深入的应用，也是该实验的核心，主要用于定义占位符，定义变量，创建卷积神经网络模型；numpy是一个基于python的科学计算包，在该实验中主要用来处理数值运算。",{"type":18,"tag":112,"props":133,"children":135},{"code":134},"# 字典访问，用来存储超参数\nfrom easydict import EasyDict as edict\n# os模块主要用于处理文件和目录\nimport os\n# 科学计算库\nimport numpy as np\n# 绘图库\nimport matplotlib.pyplot as plt\n\n# MindSpore库\nimport mindspore\n# 导入神经网络模块、环境设置模块、张量、模型导出、ops、模型加载等常见算子操作\nfrom mindspore import nn, Tensor, export, ops, load_checkpoint, load_param_into_net\n# 动量优化器\nfrom mindspore.nn import Momentum\n# 数据集处理模块\nimport mindspore.dataset as ds\n# 图像增强模块\nfrom mindspore.dataset import vision\n# 模型编译及模型保存设置\nfrom mindspore.train import Model, ModelCheckpoint, CheckpointConfig, LossMonitor\n# 损失值平滑处理\nfrom mindspore.amp import FixedLossScaleManager\n\n# 设置MindSpore的执行模式和设备\nmindspore.set_context(mode=mindspore.GRAPH_MODE, device_target=\"Ascend\")\n\ncfg = edict({\n    'data_path': 'flower_photos_train',   #训练数据集，如果是zip文件需要解压\n    'test_path':'flower_photos_test',     #测试数据集，如果是zip文件需要解压\n    'data_size': 3616,\n    'HEIGHT': 224,     # 图片高度\n    'WIDTH': 224,      # 图片宽度\n    '_R_MEAN': 123.68, # CIFAR10的均值\n    '_G_MEAN': 116.78,\n    '_B_MEAN': 103.94,\n    '_R_STD': 1,       # 自定义的标准差\n    '_G_STD': 1,\n    '_B_STD':1,\n    '_RESIZE_SIDE_MIN': 256, # 图像增强resize最小值\n    '_RESIZE_SIDE_MAX': 512,\n    \n    'batch_size': 32,   # 批次大小\n    'num_class': 5,     # 分类类别\n    'epoch_size': 3,  # 训练次数\n    'loss_scale_num':1024,\n    \n    'prefix': 'resnet-ai',          # 模型保存的名称\n    'directory': './model_resnet',  # 模型保存的路径\n    'save_checkpoint_steps': 10,    # 每隔10步保存ckpt\n})\n",[136],{"type":18,"tag":117,"props":137,"children":138},{"__ignoreMap":7},[139],{"type":24,"value":134},{"type":18,"tag":26,"props":141,"children":142},{},[143],{"type":24,"value":144},"读取数据集并预处理 数据读取并处理流程如下：",{"type":18,"tag":26,"props":146,"children":147},{},[148],{"type":24,"value":149},"MindSpore的mindspore.dataset提供了ImageFolderDataset函数，可以直接读取文件夹图片数据并映射文件夹名字为其标签(label)。这里我们使用ImageFolderDataset函数读取'daisy','dandelion','roses','sunflowers','tulips'数据。并将这五类标签映射为：{'daisy':0,'dandelion':1,'roses':2,'sunflowers':3,'tulips':4}，使用RandomCropDecodeResize、HWC2CHW、shuffle进行数据预处理。",{"type":18,"tag":112,"props":151,"children":153},{"code":152},"# 数据处理\ndef read_data(path,config,usage=\"train\"):\n    # 从目录中读取图像的源数据集。\n    dataset = ds.ImageFolderDataset(path,\n                                   class_indexing={'daisy':0,'dandelion':1,'roses':2,'sunflowers':3,'tulips':4})\n    trans = []\n    if usage == \"train\":\n        trans += [\n            vision.RandomCropDecodeResize((cfg.HEIGHT, cfg.WIDTH), (0.5, 1.0), (1.0, 1.0), max_attempts=100),\n            vision.RandomHorizontalFlip()\n        ]\n    else:\n        trans += [\n            vision.Decode(),\n            vision.Resize(cfg._RESIZE_SIDE_MIN),\n            vision.CenterCrop((cfg.HEIGHT, cfg.WIDTH))\n        ]\n\n    trans += [\n        vision.Normalize(mean=[cfg._R_MEAN, cfg._G_MEAN, cfg._B_MEAN], std=[cfg._R_STD, cfg._G_STD, cfg._B_STD]),\n        vision.HWC2CHW()\n    ]\n\n    # 数据映射操作\n    dataset = dataset.map(operations=trans,\n                            input_columns='image',\n                            num_parallel_workers=4)\n\n    # 对训练集做的批次处理\n    if usage == 'train':\n        dataset = dataset.shuffle(buffer_size=10000)  # 10000 as in imageNet train script\n        dataset = dataset.batch(cfg.batch_size, drop_remainder=True)\n    # 对测试集做的批次处理\n    else:\n        dataset = dataset.batch(1, drop_remainder=True)\n    \n    # 数据增强\n    dataset = dataset.repeat(1)\n    \n    dataset.map_model = 4\n\n    return dataset\n\n# 查看训练集和测试集的数量\nde_train = read_data(cfg.data_path,cfg,usage=\"train\")\nde_test = read_data(cfg.test_path,cfg,usage=\"test\")\nprint('训练数据集数量：',de_train.get_dataset_size()*cfg.batch_size) # get_dataset_size()获取批处理的大小。\nprint('测试数据集数量：',de_test.get_dataset_size())\n\ndata_next = de_train.create_dict_iterator(output_numpy=True).__next__()\nprint('通道数/图像长/宽：', data_next['image'][0,...].shape)\nprint('一张图像的标签样式：', data_next['label'][0])  # 一共5类，用0-4的数字表达类别。\n\nplt.figure()\nplt.imshow(data_next['image'][0,0,...])\nplt.colorbar()\nplt.grid(False)\nplt.show()\n",[154],{"type":18,"tag":117,"props":155,"children":156},{"__ignoreMap":7},[157],{"type":24,"value":152},{"type":18,"tag":32,"props":159,"children":161},{"id":160},"_5模型构建",[162],{"type":24,"value":163},"5、模型构建",{"type":18,"tag":26,"props":165,"children":166},{},[167],{"type":24,"value":168},"残差块（Residual Block） 将前面若干层的输出跳过中间层作为后几层的输入部分，也就是说后面特征层会有前几层的部分线性贡献。此种设计是为了克服随着网络层数加深而产生的学习效率变低和准确率无法有效提升的问题。",{"type":18,"tag":26,"props":170,"children":171},{},[172],{"type":24,"value":173},"瓶颈（BottleNeck）模块： 瓶颈（BottleNeck）模块，思路和Inception一样，通过1x1 conv来巧妙地缩减或扩张feature map维度从而使3x3 conv的filters数目不受外界即上一层输入的影响，自然它的输出也不会影响到下一层module。",{"type":18,"tag":26,"props":175,"children":176},{},[177],{"type":24,"value":178},"ResNet50模型构建 ResNet50有两个基本的块，分别名为Conv Block和Identity Block，其中Conv Block输入和输出的维度是不一样的，所以不能连续串联，它的作用是改变网络的维度；Identity Block输入维度和输出维度相同，可以串联，用于加深网络。",{"type":18,"tag":112,"props":180,"children":182},{"code":181},"\"\"\"ResNet.\"\"\"\n\n# 定义权重初始化函数\ndef _weight_variable(shape, factor=0.01):\n    init_value = np.random.randn(*shape).astype(np.float32) * factor\n    return Tensor(init_value)\n\n# 定义3X3卷积函数\ndef _conv3x3(in_channel, out_channel, stride=1):\n    weight_shape = (out_channel, in_channel, 3, 3)\n    weight = _weight_variable(weight_shape)\n    return nn.Conv2d(in_channel, out_channel,\n                     kernel_size=3, stride=stride, padding=0, pad_mode='same', weight_init=weight)\n\n# 定义1X1卷积层函数\ndef _conv1x1(in_channel, out_channel, stride=1):\n    weight_shape = (out_channel, in_channel, 1, 1)\n    weight = _weight_variable(weight_shape)\n    return nn.Conv2d(in_channel, out_channel,\n                     kernel_size=1, stride=stride, padding=0, pad_mode='same', weight_init=weight)\n\n# 定义7X7卷积层函数\ndef _conv7x7(in_channel, out_channel, stride=1):\n    weight_shape = (out_channel, in_channel, 7, 7)\n    weight = _weight_variable(weight_shape)\n    return nn.Conv2d(in_channel, out_channel,\n                     kernel_size=7, stride=stride, padding=0, pad_mode='same', weight_init=weight)\n\n# 定义Batch Norm层函数\ndef _bn(channel):\n    return nn.BatchNorm2d(channel, eps=1e-4, momentum=0.9,\n                          gamma_init=1, beta_init=0, moving_mean_init=0, moving_var_init=1)\n\n# 定义最后一层的Batch Norm函数\ndef _bn_last(channel):\n    return nn.BatchNorm2d(channel, eps=1e-4, momentum=0.9,\n                          gamma_init=0, beta_init=0, moving_mean_init=0, moving_var_init=1)\n\n# 定义全连接层函数\ndef _fc(in_channel, out_channel):\n    weight_shape = (out_channel, in_channel)\n    weight = _weight_variable(weight_shape)\n    return nn.Dense(in_channel, out_channel, has_bias=True, weight_init=weight, bias_init=0)\n\n# 构建残差模块\nclass ResidualBlock(nn.Cell):\n    expansion = 4  # conv2_x--conv5_x中，前两层的卷积核的个数是第三层（也就是输出通道）的4分之一。\n\n    def __init__(self, in_channel, out_channel, stride=1):\n        super(ResidualBlock, self).__init__()\n\n        # 前两层的卷积核个数等于输出通道的四分之一\n        channel = out_channel // self.expansion  \n        \n        # 第一层卷积\n        self.conv1 = _conv1x1(in_channel, channel, stride=1)\n        self.bn1 = _bn(channel)\n        # 第二层卷积\n        self.conv2 = _conv3x3(channel, channel, stride=stride)\n        self.bn2 = _bn(channel)\n        \n        # 第三层卷积，其中卷积核个数等于输出通道\n        self.conv3 = _conv1x1(channel, out_channel, stride=1)\n        self.bn3 = _bn_last(out_channel)\n        \n        # Relu激活层\n        self.relu = nn.ReLU()\n\n        self.down_sample = False\n        \n        # 当步长不为1、或输出通道不等于输入通道时，进行图像下采样，用来调整通道数\n        if stride != 1 or in_channel != out_channel:\n            self.down_sample = True\n        self.down_sample_layer = None\n        # 用1X1卷积调整通道数\n        if self.down_sample:\n            self.down_sample_layer = nn.SequentialCell([_conv1x1(in_channel, out_channel, stride), # 1X1卷积\n                                                        _bn(out_channel)])  # Batch Norm\n        # 加法算子\n        self.add = ops.Add()\n\n    # 构建残差块    \n    def construct(self, x): \n        # 输入\n        identity = x\n        \n        # 第一层卷积 1X1\n        out = self.conv1(x)\n        out = self.bn1(out)\n        out = self.relu(out)\n        \n        # 第二层卷积 3X3\n        out = self.conv2(out)\n        out = self.bn2(out)\n        out = self.relu(out)\n        \n        # 第三层卷积 1X1\n        out = self.conv3(out)\n        out = self.bn3(out)\n\n        # 改变网络的维度\n        if self.down_sample:\n            identity = self.down_sample_layer(identity)\n        \n        # 加上残差\n        out = self.add(out, identity)\n        # Relu激活\n        out = self.relu(out)\n\n        return out\n\n# 构建残差网络\nclass ResNet(nn.Cell):\n    # 输入参数为：残差块，残差块重复数，输入通道，输出通道，步长，图像类别数\n    def __init__(self, block, layer_nums, in_channels, out_channels, strides, num_classes):\n        super(ResNet, self).__init__()\n\n        # 报错信息，不用管\n        if not len(layer_nums) == len(in_channels) == len(out_channels) == 4:\n            raise ValueError(\"the length of layer_num, in_channels, out_channels list must be 4!\")\n\n        # 第一层卷积，卷积核7X7，输入通道3，输出通道64，步长2\n        self.conv1 = _conv7x7(3, 64, stride=2)\n        self.bn1 = _bn(64)\n        self.relu = ops.ReLU()\n        \n        # 3X3池化层，步长2\n        self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, pad_mode=\"same\")\n\n        # conv2_x残差块\n        self.layer1 = self._make_layer(block,\n                                       layer_nums[0],\n                                       in_channel=in_channels[0],\n                                       out_channel=out_channels[0],\n                                       stride=strides[0])\n        # conv3_x残差块\n        self.layer2 = self._make_layer(block,\n                                       layer_nums[1],\n                                       in_channel=in_channels[1],\n                                       out_channel=out_channels[1],\n                                       stride=strides[1])\n        # conv4_x残差块\n        self.layer3 = self._make_layer(block,\n                                       layer_nums[2],\n                                       in_channel=in_channels[2],\n                                       out_channel=out_channels[2],\n                                       stride=strides[2])\n        # conv5_x残差块\n        self.layer4 = self._make_layer(block,\n                                       layer_nums[3],\n                                       in_channel=in_channels[3],\n                                       out_channel=out_channels[3],\n                                       stride=strides[3])\n        # 均值算子\n        self.mean = ops.ReduceMean(keep_dims=True)\n        # Flatten层\n        self.flatten = nn.Flatten()\n        # 输出层\n        self.end_point = _fc(out_channels[3], num_classes)\n\n    # 输入参数为：残差块，残差块重复数，输入通道，输出通道，步长\n    def _make_layer(self, block, layer_num, in_channel, out_channel, stride):\n        # 搭建convn_x的残差块\n        \n        layers = []\n        \n        resnet_block = block(in_channel, out_channel, stride=stride)\n        layers.append(resnet_block)\n\n        for _ in range(1, layer_num):\n            resnet_block = block(out_channel, out_channel, stride=1)\n            layers.append(resnet_block)\n\n        return nn.SequentialCell(layers)\n    \n    # 构建 ResNet网络\n    def construct(self, x): \n        x = self.conv1(x)  # 第一层卷积7X7，步长为2\n        x = self.bn1(x)    # 第一层的Batch Norm\n        x = self.relu(x)   # Rule激活层\n        c1 = self.maxpool(x)  # 最大池化3X3，步长为2\n\n        c2 = self.layer1(c1) # conv2_x残差块\n        c3 = self.layer2(c2) # conv3_x残差块\n        c4 = self.layer3(c3) # conv4_x残差块\n        c5 = self.layer4(c4) # conv5_x残差块\n\n        out = self.mean(c5, (2, 3)) # 平均池化层\n        out = self.flatten(out)  # Flatten层\n        out = self.end_point(out)  # 输出层\n\n        return out\n\n# 构建ResNet50 网络\ndef resnet50(class_num=10):\n    return ResNet(ResidualBlock,    # 残差块\n                  [3, 4, 6, 3],  # 残差块数量\n                  [64, 256, 512, 1024],  # 输入通道\n                  [256, 512, 1024, 2048], # 输出通道\n                  [1, 2, 2, 2],  # 步长\n                  class_num) # 输出类别数\n\n# 构建ResNet101 网络\ndef resnet101(class_num=1001):\n    return ResNet(ResidualBlock,\n                  [3, 4, 23, 3],\n                  [64, 256, 512, 1024],\n                  [256, 512, 1024, 2048],\n                  [1, 2, 2, 2],\n                  class_num)\n",[183],{"type":18,"tag":117,"props":184,"children":185},{"__ignoreMap":7},[186],{"type":24,"value":181},{"type":18,"tag":32,"props":188,"children":190},{"id":189},"_6模型训练",[191],{"type":24,"value":192},"6、模型训练",{"type":18,"tag":26,"props":194,"children":195},{},[196],{"type":24,"value":197},"定义学习率函数 设定动态学习率，加速模型收敛。",{"type":18,"tag":112,"props":199,"children":201},{"code":200},"def get_lr(global_step, total_epochs, steps_per_epoch, lr_init=0.01, lr_max=0.1, warmup_epochs=5):\n    \n    lr_each_step = []\n    total_steps = steps_per_epoch * total_epochs\n    warmup_steps = steps_per_epoch * warmup_epochs\n    if warmup_steps != 0:\n        inc_each_step = (float(lr_max) - float(lr_init)) / float(warmup_steps)\n    else:\n        inc_each_step = 0\n    for i in range(int(total_steps)):\n        if i \u003C warmup_steps:\n            lr = float(lr_init) + inc_each_step * float(i)\n        else:\n            base = ( 1.0 - (float(i) - float(warmup_steps)) / (float(total_steps) - float(warmup_steps)) )\n            lr = float(lr_max) * base * base\n            if lr \u003C 0.0:\n                lr = 0.0\n        lr_each_step.append(lr)\n\n    current_step = global_step\n    lr_each_step = np.array(lr_each_step).astype(np.float32)\n    learning_rate = lr_each_step[current_step:]\n\n    return learning_rate\n",[202],{"type":18,"tag":117,"props":203,"children":204},{"__ignoreMap":7},[205],{"type":24,"value":200},{"type":18,"tag":26,"props":207,"children":208},{},[209],{"type":24,"value":210},"开始训练 完成数据预处理、网络定义、损失函数和优化器定义之后，开始模型训练。模型训练包含2层迭代，数据集的多轮迭代epoch和一轮数据集内按分组从数据集中抽取数据，输入网络计算得到损失函数，然后通过优化器计算和更新训练参数的梯度。",{"type":18,"tag":112,"props":212,"children":214},{"code":213},"import mindspore as ms\n# 构建ResNet50网络，输出类别数为5，对应5种花的类别\nnet = resnet50(class_num=cfg.num_class)\n\n# 设置Softmax交叉熵损失函数\nloss = nn.SoftmaxCrossEntropyWithLogits(sparse=True, reduction=\"mean\")\n\n# 设置动态学习率\ntrain_step_size = de_train.get_dataset_size()\nlr = Tensor(get_lr(global_step=0, total_epochs=cfg.epoch_size, steps_per_epoch=train_step_size))\n\n# 设置动量优化器\nopt = Momentum(net.trainable_params(), lr, momentum=0.9, weight_decay=1e-4, loss_scale=cfg.loss_scale_num)\n\n# 损失值平滑，解决训练过程中梯度过小的问题\nloss_scale = FixedLossScaleManager(cfg.loss_scale_num, False)\n\n# 模型编译，输入网络结构，损失函数，优化器，损失值平滑，以及模型评估标准\nmodel = Model(net, loss_fn=loss, optimizer=opt, loss_scale_manager=loss_scale, metrics={'acc'})\n\n# 定义用于训练的train_loop函数。\ndef train_loop(model, dataset, loss_fn, optimizer):\n    # 定义正向计算函数\n    def forward_fn(data, label):\n        logits = model(data)\n        loss = loss_fn(logits, label)\n        return loss\n\n    # 定义微分函数，使用mindspore.value_and_grad获得微分函数grad_fn,输出loss和梯度。\n    # 由于是对模型参数求导,grad_position 配置为None，传入可训练参数。\n    grad_fn = ms.value_and_grad(forward_fn, None, optimizer.parameters)\n\n    # 定义 one-step training函数\n    def train_step(data, label):\n        loss, grads = grad_fn(data, label)\n        optimizer(grads)\n        return loss\n\n    size = dataset.get_dataset_size()\n    model.set_train()\n    for batch, (data, label) in enumerate(dataset.create_tuple_iterator()):\n        loss = train_step(data, label)\n\n        if batch % 100 == 0:\n            loss, current = loss.asnumpy(), batch\n            print(f\"loss: {loss:>7f}  [{current:>3d}/{size:>3d}]\")\n\n# 定义用于测试的test_loop函数。\ndef test_loop(model, dataset, loss_fn):\n    num_batches = dataset.get_dataset_size()\n    model.set_train(False)\n    total, test_loss, correct = 0, 0, 0\n    for data, label in dataset.create_tuple_iterator():\n        pred = model(data)\n        total += len(data)\n        test_loss += loss_fn(pred, label).asnumpy()\n        correct += (pred.argmax(1) == label).asnumpy().sum()\n    test_loss /= num_batches\n    correct /= total\n    print(f\"Test: \\n Accuracy: {(100*correct):>0.1f}%, Avg loss: {test_loss:>8f} \\n\")\n\nfor t in range(cfg.epoch_size):\n    print(f\"Epoch {t+1}\\n-------------------------------\")\n    train_loop(net, de_train, loss, opt)\n    #ms.save_checkpoint(network, \"./save_direct.ckpt\")\n    test_loop(net, de_test, loss)\nprint(\"Done!\")\n",[215],{"type":18,"tag":117,"props":216,"children":217},{"__ignoreMap":7},[218],{"type":24,"value":213},{"type":18,"tag":32,"props":220,"children":222},{"id":221},"_7模型预测",[223],{"type":24,"value":224},"7、模型预测",{"type":18,"tag":112,"props":226,"children":228},{"code":227},"# 模型预测，从测试集中取10个样本进行测试，输出预测结果和真实标签\nclass_names = {0:'daisy',1:'dandelion',2:'roses',3:'sunflowers',4:'tulips'}\nfor i in range(10):\n    test_ = de_test.create_dict_iterator().__next__()\n    test = Tensor(test_['image'], mindspore.float32)\n    # 模型预测\n    predictions = model.predict(test)\n    predictions = predictions.asnumpy()\n    true_label = test_['label'].asnumpy()\n    # 显示预测结果\n    p_np = predictions[0, :]\n    pre_label = np.argmax(p_np)\n    print('第' + str(i) + '个sample预测结果：', class_names[pre_label], '   真实结果：', class_names[true_label[0]]) \n",[229],{"type":18,"tag":117,"props":230,"children":231},{"__ignoreMap":7},[232],{"type":24,"value":227},{"title":7,"searchDepth":234,"depth":234,"links":235},4,[236,238,239,240,245,246,247],{"id":34,"depth":237,"text":37},2,{"id":60,"depth":237,"text":63},{"id":79,"depth":237,"text":82},{"id":95,"depth":237,"text":98,"children":241},[242,244],{"id":102,"depth":243,"text":105},3,{"id":123,"depth":243,"text":126},{"id":160,"depth":237,"text":163},{"id":189,"depth":237,"text":192},{"id":221,"depth":237,"text":224},"markdown","content:technology-blogs:zh:3144.md","content","technology-blogs/zh/3144.md","technology-blogs/zh/3144","md",1776506126555]