• [算子使用] 深夜:在?我用本地环境pytest带你玩自定义算子
    # 深夜:在?我用本地环境pytest带你玩自定义算子# module1:# 多玩法Python调试框架pytest## 初学入门  大家好python通用测试框架的是unittest+HTMLTestRunner,这段时间看到了pytest文档,发现这个框架和丰富的plugins很好用,所以来学习下pytest.!(https://gitee.com/qmckw/pic/raw/master/PicGO-updata-img/6536777-74124be4a6b0a5fe.png)pytest是一个非常成熟的全功能的Python测试框架,主要有以下几个特点:- 简单灵活,容易上手- 支持参数化- 能够支持简单的单元测试和复杂的功能测试,还可以用来做selenium/appnium等自动化测试、接口自动化测试(pytest+requests)- pytest具有很多第三方插件,并且可以自定义扩展,比较好用的如pytest-selenium(集成selenium)、pytest-html(完美html测试报告生成)、pytest-rerunfailures(失败case重复执行)、pytest-xdist(多CPU分发)等- 测试用例的skip和xfail处理- 可以很好的和jenkins集成- report框架----allure 也支持了pytest安装pytest:```bashpip install -U pytest```验证安装的版本:```bashpytest --version```**pytest documentation中的例子:****例1:**首先我们找一个目录,新建文件夹Pytest,然后新建test_sample.py,输入以下内容。```pythonimport pytest# content of test_sample.pydef func(x): return x + 1def test_answer(): assert func(3) == 5```!(https://bbs-img.huaweicloud.com/data/forums/attachment/forum/202201/18/114545gr6ho9hehtncvw71.png)如上图,在目录栏输入cmd(也可以直接在IDE中运行):!(https://bbs-img.huaweicloud.com/data/forums/attachment/forum/202201/18/114624lghvpswonf2vouvq.png)回车,打开命令行,输入“pytest”。!(https://bbs-img.huaweicloud.com/data/forums/attachment/forum/202201/18/114753vrlxpnlyvh9wzkq7.png)pytest返回一个错误报告,因为func(3)不返回5。**例子2:**当需要编写多个测试样例的时候,我们可以将其放到一个测试类当中,新建一个目录test,在目录下新建test_class.py,输入一下内容:```pythonclass TestClass: def test_one(self): x = "this" assert 'h' in x def test_two(self): x = "hello" assert hasattr(x, 'check') ```pytest -q test_class.py结果:!(https://bbs-img.huaweicloud.com/data/forums/attachment/forum/202201/18/115240qbepcno8g6auhhjq.png)从测试结果中可以看到,该测试共执行了两个测试样例,一个失败一个成功。同样,我们也看到失败样例的详细信息,和执行过程中的中间结果。-q即-quiet,作用是减少冗长,具体就是不再展示pytest的版本信息。**如何编写pytest测试样例**通过上面2个实例,我们发现编写pytest测试样例非常简单,只需要按照下面的规则:- 测试文件以test_开头(以_test结尾也可以)- 测试类以Test开头,并且不能带有 **init** 方法- 测试函数以test_开头- 断言使用基本的assert即可## 运行模式   Pytest的多种运行模式,让测试和调试变得更加得心应手,下面介绍5种常用的模式。需要注意的是,运行测试的文件是有命名的要求的,否则需要额外的命令行指示。pytest命令会找当前目录及其子目录中的所有test_*.py 或 *_test.py格式的文件以及以test开头的方法或者class,不然就会提示找不到可以运行的case了。**1.运行后生成测试报告(htmlReport)**安装pytest-html:```bashpip install -U pytest-html```运行模式:```bashpytest --html=report.html```!(https://bbs-img.huaweicloud.com/data/forums/attachment/forum/202201/18/115629woajemqbne3rhmra.png)我们可以看到,目录下生成了html文件,点开看看:报告效果:!(https://bbs-img.huaweicloud.com/data/forums/attachment/forum/202201/18/115749rv8u9guwzaguz64g.png)我们可以看到排版非常整洁的错误报告,在以上报告中可以清晰的看到测试结果和错误原因,定位问题很容易。**2.运行指定的case**  当我们写了较多的cases时,如果每次都要全部运行一遍,无疑是很浪费时间的,通过指定case来运行就很方便了。测试用例,新建test2目录,目录下新建test_se.py文件:```pythonclass TestClassOne(object): def test_one(self): x = "this" assert 't'in x def test_two(self): x = "hello" assert hasattr(x, 'check')class TestClassTwo(object): def test_one(self): x = "iphone" assert 'p'in x def test_two(self): x = "apple" assert hasattr(x, 'check')```运行模式:模式1:直接运行test_se.py文件中的所有cases:```csspytest test_se.py```!(https://bbs-img.huaweicloud.com/data/forums/attachment/forum/202201/18/120306v141jf69i3moggiq.png)模式2:运行test_se.py文件中的TestClassOne这个class下的两个cases:```csspytest test_se.py::TestClassOne```!(https://bbs-img.huaweicloud.com/data/forums/attachment/forum/202201/18/120341dbske4jvkarxahy0.png)模式3:运行test_se.py文件中的TestClassTwo这个class下的test_one:```csspytest test_se.py::TestClassTwo::test_one```> 注意:定义class时,需要以T开头,不然pytest是不会去运行该class的。!(https://bbs-img.huaweicloud.com/data/forums/attachment/forum/202201/18/120407rbpdj3qfutjbyimy.png)我们可以看到,三者的用时是递减的。**3.多进程运行cases**  当cases量很多时,运行时间也会变的很长,如果想缩短脚本运行的时长,就可以用多进程来运行。安装pytest-xdist:```bashpip install -U pytest-xdist```运行模式:```bashpytest test_se.py -n NUM```其中NUM填写并发的进程数。!(https://bbs-img.huaweicloud.com/data/forums/attachment/forum/202201/18/120809nfbrdchpgpfshd2t.png)对比最开始,我们这次用两个进程花了0.93s,一个进程花了0.83s,一百个进程花了十多秒。在我们测试代码量不大的情况下,多进程没有什么优势。!(https://bbs-img.huaweicloud.com/data/forums/attachment/forum/202201/18/121017johttctkzpnupzcx.png)**4.重试运行cases**  在做接口测试时,有事会遇到503或短时的网络波动,导致case运行失败,而这并非是我们期望的结果,此时可以就可以通过重试运行cases的方式来解决。安装pytest-rerunfailures:```bashpip install -U pytest-rerunfailures```运行模式:```bashpytest test_se.py --reruns NUM```NUM填写重试的次数。!(https://bbs-img.huaweicloud.com/data/forums/attachment/forum/202201/18/121319axoqbgnlyvytighw.png)**5.显示print内容**  在运行测试脚本时,为了调试或打印一些内容,我们会在代码中加一些print内容,但是在运行pytest时,这些内容不会显示出来。如果带上-s,就可以显示了。运行模式:```bashpytest test_se.py -s```  另外,pytest的多种运行模式是可以叠加执行的,比如说,你想同时运行4个进程,又想打印出print的内容。可以用:```bashpytest test_se.py -s -n 4```# module2:# pytest带你玩转mindspore自定义算子有关算子的前置知识,请阅读官网的参考文档:[MindSpore算子](https://www.mindspore.cn/docs/programming_guide/zh-CN/r1.5/operators_classification.html)当开发网络遇到内置算子不足以满足需求时,你可以利用MindSpore的Python API和C++ API方便快捷地扩展CPU端的自定义算子。自定义算子分为三步- 算子原语:定义了算子在网络中的前端接口原型,也是组成网络模型的基础单元,主要包括算子的名称、属性(可选)、输入输出名称、输出shape推理方法、输出dtype推理方法等信息。- 算子实现:利用框架提供的C++ API,结合算子具体特性实现算子内部计算逻辑。- 算子信息:描述CPU算子的基本信息,如算子名称、支持的输入输出类型等。它是后端做算子选择和映射时的依据。下面我们以自定义`Transpose`算子为例,介绍自定义算子和利用pytest进行测试。## 注册算子原语算子的原语是一个继承于`PrimitiveWithInfer`的子类,其类型名称即是算子名称。CPU算子原语定义在`mindspore/ops/operations`路径下,根据算子类型选择适合的文件,接口定义如下:- 属性由构造函数`__init__`的入参定义。本用例的算子没有init属性,因此`__init__`没有额外的入参。- 输入输出的名称通过`init_prim_io_names`函数定义。- 输出Tensor的shape和dtype(数据类型对象,可以参考本人这篇[文章](https://blog.csdn.net/weixin_54227557/article/details/122557619))检验在`__infer__`函数中实现。以`Transpose`算子原语为例,给出如下示例代码,这里用到了装饰器语法糖。`Transpose`算子原语中参数“perm”作为输入传入,但是在解析时元组类型的“perm”实际被认为是算子的属性。```pythonfrom mindspore.ops import PrimitiveWithInferclass Transpose(PrimitiveWithInfer): """ The definition of the Transpose primitive. """ @prim_attr_register def __init__(self): """Initialize Transpose""" self.init_prim_io_names(inputs=['x', 'perm'], outputs=['output']) def __infer__(self, x, perm): x_shape = x['shape'] p_value = perm['value'] if len(x_shape) != len(p_value): raise ValueError('The dimension of x and perm must be equal.') out_shapes = [] for i in p_value: out_shapes.append(x_shape) out = {'shape': tuple(out_shapes), 'dtype': x['dtype'], 'value': None} return out```## 实现CPU算子和注册算子信息(此处仅供简单了解,详见官网)### 实现CPU算子通常一个CPU算子的实现,需要编写一个头文件和一个源文件,文件路径为`mindspore/ccsrc/backend/kernel_compiler/cpu`,如果算子的逻辑实现是通过调用第三方库`MKL-DNN`,则放在子目录`mkldnn`下。详细介绍请参考[oneMKL](https://github.com/oneapi-src/oneMKL)和[oneDNN](https://github.com/oneapi-src/oneDNN) 。算子的头文件中包括算子的注册信息和类的声明。算子类继承于`CPUKernel`父类,重载`InitKernel`和`Launch`两个成员函数。算子的源文件是类的实现,主要是重载InitKernel和Launch两个函数,InitKernel中`AnfRuntimeAlgorithm`类中的函数实现了各种对算子节点的操作,`shape_`表示算子第1个输入的shape,`axis_`表示算子的属性perm。> `AnfRuntimeAlgorithm`类的详细内容可参考MindSpore源码中[mindspore/ccsrc/backend/session/anf_runtime_algorithm.h](https://gitee.com/mindspore/mindspore/blob/r1.5/mindspore/ccsrc/backend/session/anf_runtime_algorithm.h)下的声明。源文件中`Launch`函数首先依次获取每个输入输出的地址,然后根据`axis_`变换维度,把值赋给输出地址指向的空间。这里对实现过程就不详细阐述了。### 注册算子信息算子信息是指导后端选择算子实现的关键信息,`MS_REG_CPU_KERNEL`中第一个参数是注册算子的名称,和原语中算子名称一致,第二个参数依次指明每个输入输出的类型,最后一个参数是算子实现的类名。`Transpose`算子注册代码如下:```MS_REG_CPU_KERNEL(Transpose, KernelAttr().AddInputAttr(kNumberTypeFloat32).AddOutputAttr(kNumberTypeFloat32), TransposeCPUFwdKernel);```> 算子信息中定义输入输出信息的个数和顺序、算子实现中的输入输出信息的个数和顺序、算子原语中输入输出名称列表的个数和顺序,三者要完全一致。## 编译MindSpore写好自定义CPU算子后,需要重新编译安装MindSpore,具体请参考[安装文档](https://gitee.com/mindspore/docs/blob/r1.5/install/mindspore_cpu_install_source.md)。## 使用自定义CPU算子并用pytest测试编译并安装完成后,自定义CPU算子可以通过导入原语直接使用。下面以`Transpose`的单算子网络测试为例进行说明。在`test_transpose.py`文件中定义网络。```pythonimport numpy as npimport mindspore.nn as nnimport mindspore.context as contextfrom mindspore import Tensorimport mindspore.ops as opscontext.set_context(mode=context.GRAPH_MODE, device_target="CPU")class Net(nn.Cell): def __init__(self): super(Net, self).__init__() self.transpose = ops.Transpose() def construct(self, data): return self.transpose(data, (1, 0))def test_net(): x = np.arange(2 * 3).reshape(2, 3).astype(np.float32) transpose = Net() output = transpose(Tensor(x)) print("output: ", output)```执行用例(**这里我们可以看到,利用pytest是测试其中一个类中的一个函数,并且均以test_开头,可以回到上文的pytest用法复习一下**):```bashpytest -s test_transpose.py::test_net```执行结果:```output: [[0, 3] [1, 4] [2, 5]]```!(https://bbs-img.huaweicloud.com/data/forums/attachment/forum/202201/18/125450wm5ycxa7pr32rzve.png)我们把报告输出html:```bashpytest --html=report.html -s test_transpose.py::test_net```可以查看html报告。## 定义算子反向传播函数如果算子要支持自动微分,需要在其原语中定义其反向传播函数(bprop)。你需要在bprop中描述利用正向输入、正向输出和输出梯度得到输入梯度的反向计算逻辑。反向计算逻辑可以使用内置算子或自定义反向算子构成。定义算子反向传播函数时需注意以下几点:- bprop函数的入参顺序约定为正向的输入、正向的输出、输出梯度。若算子为多输出算子,正向输出和输出梯度将以元组的形式提供。- bprop函数的返回值形式约定为输入梯度组成的元组,元组中元素的顺序与正向输入参数顺序一致。即使只有一个输入梯度,返回值也要求是元组的形式。例如,`Transpose`的反向原语为:```pythonimport mindspore as msimport mindspore.ops as opsfrom mindspore.ops._grad.grad_base import bprop_gettersfill = ops.Fill()invert_permutation = ops.InvertPermutation()transpose = ops.Transpose()@bprop_getters.register(ops.Transpose)def get_bprop_transpose(self): """Generate bprop for Transpose""" def bprop(x, perm, out, dout): return transpose(dout, invert_permutation(perm)), fill(ms.int32, (len(perm), ), 0) return bprop```- `Transpose`反向算子中用到了`InvertPermutation`算子,该算子和`Transpose`算子开发一样,需要有算子的原语,注册,实现等完整的流程。在`test_transpose.py`文件中加入一下内容,定义反向用例。```pythonimport mindspore.ops as opsclass Grad(nn.Cell): def __init__(self, network): super(Grad, self).__init__() self.grad = ops.GradOperation(sens_param=True) self.network = network def construct(self, input_data, sens): gout = self.grad(self.network)(input_data, sens) return goutdef test_grad_net(): x = np.arange(2 * 3).reshape(2, 3).astype(np.float32) sens = np.arange(2 * 3).reshape(3, 2).astype(np.float32) grad = Grad(Net()) dx = grad(Tensor(x), Tensor(sens)) print("dx: ", dx.asnumpy())```执行用例:```bashpytest -s test_transpose.py::test_grad_net```执行结果:```dx: [[0. 2. 4.] [1. 3. 5.]]```!(https://bbs-img.huaweicloud.com/data/forums/attachment/forum/202201/18/130016xhbwpu5qju2dieua.png)## 开源代码[qmckw/CPUcustom_opByPytest (gitee.com)](https://gitee.com/qmckw/cpucustom_op-by-pytest)## 参考资料(https://links.jianshu.com/go?to=https%3A%2F%2Fdocs.pytest.org%2Fen%2Flatest%2Fcontents.html)好用的Pytest单元测试框架(《51测试天地》四十九(下)- 44)(https://links.jianshu.com/go?to=http%3A%2F%2Fwww.cnblogs.com%2Fsparkling-ly%2Fcategory%2F851617.html)(https://links.jianshu.com/go?to=https%3A%2F%2Fblog.csdn.net%2Fliuchunming033%2Farticle%2Fcategory%2F3193659)[MindSpore参考文档](https://www.mindspore.cn/docs/programming_guide/zh-CN/r1.5/index.html)
  • [执行问题] 使用混合精度报错
    【功能模块】MindSpore 1.5.0Ascend 910【操作步骤&问题现象】我在进行单机多卡的训练,根据文档,在设置模型时,opt_level设置为O3,代码如下:model = Model(model, criterion, optimizer, amp_level='O3')原先的代码如下:model = Model(model, criterion, optimizer)添加混合精度后,训练时报错,已经确认,是添加混合精度训练导致报错,报错日志如下:现在先尝试一下O2
  • [其他] 混合模型简介
    混合模型(hybrid model)是几种不同模型组合而成的一种模型。它允许一个项目能沿着最有效的路径发展。也可定义为由固定效应和随机效应(随机误差除外)两部分组成的统计分析模型。如由几个高斯分布混合起来的模型叫高斯混合模型,几个线性模型混合在一起的模型叫线性混合模型。一般的,被模拟的系统几乎不可能按照一种模式一步一步地进行,会受到很多外界因素的干扰。而混合模型能够适应不同的系统和不同情况的需要而提出一种灵活多样的动态方法。混合模型分为分析、综合、运行和废弃四个阶段,各阶段的重叠为设计员提出了模型选择。    混合模型是一个统计模型,包含fixed effects和random effects两种效应的混合。    在统计学中,混合模型是代表一个大群体中存在子群体的概率模型,不要求被观察的数据集认同个人观察属于哪个子群体. 一般,混合模型符合代表大群体观察结果的概率分布的混合分布. 然而,当有关问题的混合分布关系到大群体到其子群体的起源性质时,混合模型常被用来做统计推断,关于小群体的性质,而没有子群体的认同信息。有些方法实现混合模型的步骤涉及到做子群体认同归属的假设到个人观察结果(或者子群体的权重), 在这种情况下这些步骤可以看着是一类非监督学习或者聚类过程. 并不是所有的推断过程都会涉及这些步骤。混合模型不应该与组合数据的模型混淆, 比如说 数据的一部分的和被约束到一个常数上。固定效应模型    应用前提是假定全部研究结果的方向与效应大小基本相同,即各独立研究的结果趋于一致,一致性检验差异无显著性。因此,固定效应模型用于各独立研究间无差异,或差异较小的研究。固定效应模型指实验结果只想比较每一自变量项之特定类目或类别的差异及其与其他自变项之特定类目或类别间交互效果,而不想依此推论到同一自变项未包含在内的其他类目或类别的实验设计。随机效应模型    随机效应模型是经典的线性模型的一种推广,就是把原来固定的回归系数看作是随机变量,一般都是假设来自正态分布。如果模型里一部分系数是随机的,另外一些是固定的,一般就叫做混合模型。随机效应有压缩的功能,而且可以使模型的自由度df变小。这个简单的结果对高维数据分析的发展起到了至关重要的作用。事实上,随机效应模型就是一个带惩罚项penalty的一个线性模型,引入正态随机效应就等价于增加一个二次惩罚。著名的岭回归ridge regression就是一个二次惩罚,它的提出解决了当设计矩阵不满秩时最小二乘估计LSE无法计算的问题,并提高了预测能力 [3]  。因此,引入随机效应或者二次惩罚就可以处理当参数个数p大于观测个数n的情形,这是在分析高维数据时必须面对的问题。当然,二次惩罚还有一些特点,如:计算简便,能选择相关的predictor,对前面的几个主成分压缩程度较小等。    混合模型的特点是:无论对任何个体和界面,回归系数α和β都相同。如果模型是正确假定的,解释变量与误差项不相关,即cov(X(i,t),ε(i,t))=0,那么无论是N趋于无穷还是T趋于无穷,模型参数的混合最小二乘估计量pooled OLS都是一致估计量。
  • [执行问题] 求助:windows本地安装MindSpore1.5,CPU训练时报错
    windows安装MindSpore1.5,利用MindStudio--python3.7.5,本地CPU训练,DeepLabv3,数据集voc2012(不混合SBD数据集);参考gitee上帖子:models: Models of MindSpore - Gitee.com参数如下:--data_file=D:\code\models-master\official\cv\deeplabv3\src\data\preprocess\MindRecoder_train0--device_target=CPU--train_dir=./ckpt--train_epochs=20--batch_size=8--crop_size=513--base_lr=0.015--lr_type=cos--min_scale=0.5--max_scale=2.0--ignore_label=255--num_classes=21--model=deeplab_v3_s16--ckpt_pre_trained=D:\code\models-master\official\cv\deeplabv3\model\resnet101_ascend_v120_imagenet2012_official_cv_bs32_acc78.ckpt--save_steps=3--keep_checkpoint_max=200问题:batch_size初始设为32,16都报错内存不足;后调整为8,但训练几步后报错,提示如下:
  • [执行问题] 【mindspore1.5】【自动问答模型】模型训练失败
    【功能模块】mindspore1.5版本【操作步骤&问题现象】在根据自动问答使用手册在mindspore1.5的版本进行训练时出现runtime的错误。【截图信息】【日志信息】(可选,上传日志内容或者附件)
  • [安装] 【mindspore】【训练】请问是否支持在Ascend710上训练?mindspore在Ascend710上训练检查报错
    【功能模块】训练【操作步骤&问题现象】1、按照mindspore官网的安装步骤2、执行 mindspore.run_check() 报错【截图信息【日志信息】(可选,上传日志内容或者附件)
  • [执行问题] 分布式训练报错
    【功能模块】MindSpore 1.5.0Ascend 910【操作步骤&问题现象】在按文档教程进行分布式训练时(单机多卡),出现如下报错。运行模式为图模式,部分初始化代码如下:context.set_context(mode=context.GRAPH_MODE, device_target=config.device, device_id=int(os.environ["DEVICE_ID"]))config.device_id = int(os.environ["DEVICE_ID"])init()context.set_auto_parallel_context(parallel_mode=ParallelMode.AUTO_PARALLEL, gradients_mean=False)
  • [其他干货] 如何通俗易懂的描述机器学习的流程?
    1.3 数据预处理数据预处理,其实就是对数据进行清理、数据整理或普通数据处理。指对数据进行各种检查和校正过程,以纠正缺失值、拼写错误、使数值正常化/标准化以使其具有可比性、转换数据(如对数转换)等问题。例如对图像进行resize成统一的大小或者分辨率。 数据的质量将对机器学习算法模型的质量好坏产生很大的影响。因此,为了达到最好的机器学习模型质量,传统的机器学习算法流程中,其实很大一部分工作就是在对数据进行分析和处理。一般来说,数据预处理可以轻松地占到机器学习项目流程中80%的时间,而实际的模型建立阶段和后续的模型分析大概仅占到剩余的20%。1.4 数据分割训练集 & 测试集在机器学习模型的开发流程中,希望训练好的模型能在新的、未见过的数据上表现良好。为了模拟新的、未见过的数据,对可用数据进行数据分割,从而将已经处理好的数据集分割成2部分:训练集合测试集。第一部分是较大的数据子集,用作训练集(如占原始数据的80%);第二部分通常是较小的子集,用作测试集(其余20%的数据)。接下来,利用训练集建立预测模型,然后将这种训练好的模型应用于测试集(即作为新的、未见过的数据)上进行预测。根据模型在测试集上的表现来选择最佳模型,为了获得最佳模型,还可以进行超参数优化。训练集 & 验证集 & 测试集另一种常见的数据分割方法是将数据分割成3部分:1)训练集,2)验证集和3)测试集。训练集用于建立预测模型,同时对验证集进行评估,据此进行预测,可以进行模型调优(如超参数优化),并根据验证集的结果选择性能最好的模型。验证集的操作方式跟训练集类似。不过值得注意的是,测试集不参与机器学习模型的建立和准备,是机器学习模型训练过程中单独留出的样本集,用于调整模型的超参数和对模型的能力进行初步评估。通常边训练边验证,这里的验证就是用验证集来检验模型的初步效果。交叉验证实际上数据是机器学习流程中最宝贵的,为了更加经济地利用现有数据,通常使用N倍交叉验证,将数据集分割成N个。在这样的N倍数据集中,其中一个被留作测试数据,而其余的则被用作建立模型的训练数据。通过反复交叉迭代的方式来对机器学习流程进行验证。这种交叉验证的方法在机器学习流程中被广泛的使用,但是深度学习中使用得比较少哈。1.5 机器学习算法建模下面是最有趣的部分啦,数据筛选和处理过程其实都是很枯燥乏味的,现在可以使用精心准备的数据来建模。根据taget变量(通常称为Y变量)的数据类型,可以建立一个分类或回归模型。机器学习算法机器学习算法可以大致分为以下三种类型之一:监督学习:是一种机器学习任务,建立输入X和输出Y变量之间的数学(映射)关系。这样的(X、Y)对构成了用于建立模型的标签数据,以便学习如何从输入中预测输出。 无监督学习:是一种只利用输入X变量的机器学习任务。X变量是未标记的数据,学习算法在建模时使用的是数据的固有结构。 强化学习:是一种决定下一步行动方案的机器学习任务,它通过试错学习(trial and error learning)来实现这一目标,努力使reward回报最大化。参数调优传说中的调参侠主要干的就是这个工作啦。超参数本质上是机器学习算法的参数,直接影响学习过程和预测性能。由于没有万能的超参数设置,可以普遍适用于所有数据集,因此需要进行超参数优化。以随机森林为例。在使用randomForest时,通常会对两个常见的超参数进行优化,其中包括mtry和ntree参数。mtry(maxfeatures)代表在每次分裂时作为候选变量随机采样的变量数量,而ntree(nestimators)代表要生长的树的数量。另一种在10年前仍然非常主流的机器学习算法是支持向量机SVM。需要优化的超参数是径向基函数(RBF)内核的C参数和gamma参数。C参数是一个限制过拟合的惩罚项,而gamma参数则控制RBF核的宽度。调优通常是为了得出超参数的较佳值集,很多时候不要去追求找到超参一个最优值,其实调参侠只是调侃调侃,真正需要理解掌握算法原理,找到适合数据和模型的参数就可以啦。特征选择特征选择从字面上看就是从最初的大量特征中选择一个特征子集的过程。除了实现高精度的模型外,机器学习模型构建最重要的一个方面是获得可操作的见解,为了实现这一目标,能够从大量的特征中选择出重要的特征子集非常重要。特征选择的任务本身就可以构成一个全新的研究领域,在这个领域中,大量的努力都是为了设计新颖的算法和方法。从众多可用的特征选择算法中,一些经典的方法是基于模拟退火和遗传算法。除此之外,还有大量基于进化算法(如粒子群优化、蚁群优化等)和随机方法(如蒙特卡洛)的方法。性能指标如何知道训练出来的机器学习模型表现好或坏?就是使用性能评价指标(metrics),一些常见的评估分类性能的指标包括准确率(AC)、灵敏度(SN)、特异性(SP)和马太相关系数(MCC)。回归最简单的回归模式,可以通过以下简单等式很好地总结:Y = f(X)。其中,Y对应量化输出变量,X指输入变量,f指计算输出值作为输入特征的映射函数(从机器学习模型中得到)。上面的回归例子公式的实质是,如果X已知,就可以推导出Y。一旦Y被计算(预测)出来,一个流行的可视化方式是将实际值与预测值做一个简单的散点图,如下图所示。对回归模型的性能进行评估,以评估拟合模型可以准确预测输入数据值的程度。评估回归模型性能的常用指标是确定系数(R²)。此外,均方误差(MSE)以及均方根误差(RMSE)也是衡量残差或预测误差的常用指标。下面是机器学习算法的主要流程:主要从1)数据集准备、2)数据预处理、3)数据分割、4)定义神经网络模型,5)训练网络。深度学习不需要我们自己去提取特征,而是通过神经网络自动对数据进行高维抽象学习,减少了特征工程的构成,在这方面节约了很多时间。但是同时因为引入了更加深、更复杂的网络模型结构,所以调参工作变得更加繁重啦。例如:定义神经网络模型结构、确认损失函数、确定优化器,最后就是反复调整模型参数的过程。MindSpore官方资料GitHub : https://github.com/mindspore-ai/mindsporeGitee : https : //gitee.com/mindspore/mindspore官方QQ群 : 486831414
  • [技术干货] MindSpore性能调试(Ascend)1
    在Ascend AI处理器上使用MindSpore Profiler进行性能调试。流程准备训练脚本,并在训练脚本中调用性能调试接口,接着运行训练脚本。启动MindInsight,并通过启动参数指定summary-base-dir目录(summary-base-dir是Profiler所创建目录的父目录),例如训练时Profiler创建的文件夹绝对路径为/home/user/code/data,则summary-base-dir设为/home/user/code。启动成功后,根据IP和端口访问可视化界面在训练列表找到对应训练,点击性能分析,即可在页面中查看训练性能数据首先准备脚本:set_context之后,初始化网络、以及初始化HCCL之前,需要初始化MindSpore Profiler对象。调用Profiler.analyse()停止性能数据收集并生成性能分析结果。Profiler可以通过start_profile参数控制是否基于step(epoch)开启、关闭收集性能数据。对于图模式的数据下沉模式,只有在每个epoch结束后才有机会告知CANN开启和停止,因此对于数据下沉模式,需要基于epoch开启和关闭。正常正常情况下,代码如下:import numpy as npfrom mindspore import nn, contextfrom mindspore import Modelimport mindspore.dataset as dsfrom mindspore.profiler import Profilerclass Net(nn.Cell):    def __init__(self):        super(Net, self).__init__()        self.fc = nn.Dense(2, 2)    def construct(self, x):        return self.fc(x)def generator():    for i in range(2):        yield (np.ones([2, 2]).astype(np.float32), np.ones([2]).astype(np.int32))def train(net):    optimizer = nn.Momentum(net.trainable_params(), 1, 0.9)    loss = nn.SoftmaxCrossEntropyWithLogits(sparse=True)    data = ds.GeneratorDataset(generator, ["data", "label"])    model = Model(net, loss, optimizer)    model.train(1, data)if __name__ == '__main__':    context.set_context(mode=context.GRAPH_MODE, device_target="Ascend")    # Init Profiler    # Note that the Profiler should be initialized after context.set_context and before model.train    # If you are running in parallel mode on Ascend, the Profiler should be initialized before HCCL    # initialized.    profiler = Profiler(output_path = './profiler_data')    # Train Model    net = Net()    train(net)    # Profiler end    profiler.analyse()图模式:对于非数据下沉,需要基于step开启代码如下:from mindspore.profiler.callback import Callbackclass StopAtStep(Callback):    def __init__(self, start_step, stop_step):        super(StopAtStep, self).__init__()        self.start_step = start_step        self.stop_step = stop_step        self.profiler = Profiler(start_profile=False)    def step_begin(self, run_context):        cb_params = run_context.original_args()        step_num = cb_params.cur_step_num        if step_num == self.start_step:            self.profiler.start()    def step_end(self, run_context):        cb_params = run_context.original_args()        step_num = cb_params.cur_step_num        if step_num == self.stop_step:            self.profiler.stop()    def end(self, run_context):        self.profiler.analyse()对于数据下沉,需要基于epoch开启class StopAtEpoch(Callback):    def init(self, start_epoch, stop_epoch):        super(StopAtStep, self).init()        self.start_epoch = start_epoch        self.stop_epoch = stop_epoch        self.profiler = Profiler(start_profile=False)    def epoch_begin(self, run_context):        cb_params = run_context.original_args()        epoch_num = cb_params.cur_epoch_num        if step_num == self.start_epoch:          self.profiler.start()    def epoch_end(self, run_context):        cb_params = run_context.original_args()        epoch_num = cb_params.cur_epoch_num        if epoch_num == self.stop_epoch:            self.profiler.stop()    def end(self, run_context):        self.profiler.analyse()————————————————原文链接:https://blog.csdn.net/JIAJIA14754545/article/details/121856792
  • [技术干货] 【MindSpore】实现保存最优模型
    1. 功能描述:MindSpore训练模型时,实现保存最优模型。2. 实现保存最优模型功能简介:在面对复杂网络时,往往需要进行几十甚至几百次的epoch训练。在训练之前,很难掌握在训练到第几个epoch时,模型的精度能达到满足要求的程度,所以经常会采用一边训练的同时,在相隔固定epoch的位置对模型进行精度验证,并保存相应的模型,等训练完毕后,通过查看对应模型精度的变化就能迅速地挑选出相对最优的模型。流程如下:1) 定义回调函数EvalCallBack,实现同步进行训练和验证。2) 定义训练网络并执行。3) 将不同epoch下的模型精度绘制出折线图并挑选最优模型。3. 原因分析:MindSpore在训练模型时,保存最后一个ckpt可能精度不达标。4. 解决方案:apply_eval函数,用来验证模型的精度。定义回调函数EvalCallBack:模型验证def apply_eval(eval_param):eval_model = eval_param['model']eval_ds = eval_param['dataset']metrics_name = eval_param['metrics_name']res = eval_model.eval(eval_ds)return res[metrics_name]我们自定义一个数据收集的回调类EvalCallBack,用于实现下面两种信息:4.1 训练过程中,每一个epoch结束之后,训练集的损失值和验证集的模型精度。4.2 保存精度最高的模型。class EvalCallBack(Callback):  """  回调类,获取训练过程中模型的信息  """  def __init__(self, eval_function, eval_param_dict, interval=1, eval_start_epoch=1, save_best_ckpt=True,               ckpt_directory="./", besk_ckpt_name="best.ckpt", metrics_name="acc"):      super(EvalCallBack, self).__init__()      self.eval_param_dict = eval_param_dict      self.eval_function = eval_function      self.eval_start_epoch = eval_start_epoch      if interval < 1:          raise ValueError("interval should >= 1.")      self.interval = interval      self.save_best_ckpt = save_best_ckpt      self.best_res = 0      self.best_epoch = 0      if not os.path.isdir(ckpt_directory):          os.makedirs(ckpt_directory)      self.best_ckpt_path = os.path.join(ckpt_directory, besk_ckpt_name)      self.metrics_name = metrics_name删除ckpt文件    def remove_ckpoint_file(self, file_name):        os.chmod(file_name, stat.S_IWRITE)        os.remove(file_name)每一个epoch后,打印训练集的损失值和验证集的模型精度,并保存精度最好的ckpt文件    def epoch_end(self, run_context):        cb_params = run_context.original_args()        cur_epoch = cb_params.cur_epoch_num        loss_epoch = cb_params.net_outputs        if cur_epoch >= self.eval_start_epoch and (cur_epoch - self.eval_start_epoch) % self.interval == 0:            res = self.eval_function(self.eval_param_dict)            print('Epoch {}/{}'.format(cur_epoch, num_epochs))            print('-' * 10)            print('train Loss: {}'.format(loss_epoch))            print('val Acc: {}'.format(res))            if res >= self.best_res:                self.best_res = res                self.best_epoch = cur_epoch                if self.save_best_ckpt:                    if os.path.exists(self.best_ckpt_path):                        self.remove_ckpoint_file(self.best_ckpt_path)                    save_checkpoint(cb_params.train_network, self.best_ckpt_path)训练结束后,打印最好的精度和对应的epochdef end(self, run_context):    print("End training, the best {0} is: {1}, the best {0} epoch is {2}".format(self.metrics_name, self.best_res, self.best_epoch), flush=True)训练和评估运行下面代码,开始模型训练。train_ds =  create_dataset(train_data_path)val_ds = create_dataset(val_data_path)eval_param_dict = {"model":model,"dataset":val_ds,"metrics_name":"Accuracy"}eval_cb = EvalCallBack(apply_eval, eval_param_dict,)训练模型model.train(num_epochs,train_ds, callbacks=[eval_cb, TimeMonitor()], dataset_sink_mode=True)结果:Epoch 1/20train Loss: 0.47486544val Acc: 0.8333333333333334epoch time: 8439.054 ms, per step time: 140.651 msEpoch 2/20train Loss: 0.20464368val Acc: 0.8333333333333334epoch time: 3805.755 ms, per step time: 63.429 msEpoch 3/20train Loss: 0.3345307val Acc: 0.9166666666666666epoch time: 3721.042 ms, per step time: 62.017 msEpoch 4/20train Loss: 0.7761406val Acc: 0.8333333333333334epoch time: 3302.892 ms, per step time: 55.048 msEpoch 5/20train Loss: 0.3566268val Acc: 0.9epoch time: 3375.371 ms, per step time: 56.256 msEpoch 6/20train Loss: 0.13434622val Acc: 0.9333333333333333epoch time: 4012.532 ms, per step time: 66.876 msEpoch 7/20train Loss: 0.20843573val Acc: 0.85epoch time: 3357.198 ms, per step time: 55.953 msEpoch 8/20train Loss: 0.96780926val Acc: 0.95epoch time: 3628.576 ms, per step time: 60.476 msEpoch 9/20train Loss: 1.4824448val Acc: 0.8666666666666667epoch time: 3403.053 ms, per step time: 56.718 msEpoch 10/20train Loss: 0.11375467val Acc: 0.9166666666666666epoch time: 3293.931 ms, per step time: 54.899 msEpoch 11/20train Loss: 0.14315866val Acc: 0.8833333333333333epoch time: 3308.482 ms, per step time: 55.141 msEpoch 12/20train Loss: 0.13462222val Acc: 0.95epoch time: 3922.425 ms, per step time: 65.374 msEpoch 13/20train Loss: 0.46668455val Acc: 0.8666666666666667epoch time: 3366.989 ms, per step time: 56.116 msEpoch 14/20train Loss: 0.18877655val Acc: 0.9166666666666666epoch time: 3301.854 ms, per step time: 55.031 msEpoch 15/20train Loss: 0.30053577val Acc: 0.9epoch time: 3218.894 ms, per step time: 53.648 msEpoch 16/20train Loss: 0.19290532val Acc: 0.8166666666666667epoch time: 3241.427 ms, per step time: 54.024 msEpoch 17/20train Loss: 0.00813961val Acc: 0.8833333333333333epoch time: 3317.892 ms, per step time: 55.298 msEpoch 18/20train Loss: 0.09142441val Acc: 0.8166666666666667epoch time: 3365.341 ms, per step time: 56.089 msEpoch 19/20train Loss: 0.89299583val Acc: 0.9epoch time: 3441.966 ms, per step time: 57.366 msEpoch 20/20train Loss: 0.29071262val Acc: 0.8166666666666667epoch time: 3269.289 ms, per step time: 54.488 msEnd training, the best acc is: 0.95, the best acc epoch is 12使用精度最好的模型对验证集进行可视化预测。visualize_model('best.ckpt', val_ds)1结果:————————————————原文链接:https://blog.csdn.net/qingshuibaifen/article/details/121610933
  • [技术干货] MindSpore(Ascend)训练DeepLabV3+
    MindSpore(Ascend)训练DeepLabV3+说明:本文记录了使用MindSpore框架在Atlas 300T训练卡上训练DeepLabV3+的过程,参考:https://gitee.com/mindspore/models/tree/master/official/cv/deeplabv3plus1. 描述DeepLab是一系列图像语义分割模型,DeepLabv3+通过encoder-decoder进行多尺度信息的融合,同时保留了原来的空洞卷积和ASSP层, 其骨干网络使用了Resnet模型,提高了语义分割的健壮性和运行速率。2. 前提条件开发环境:Ascend910 + MindSpore1.3.0(安装教程:https://www.mindspore.cn/install)Python依赖: opencv-python、numpy、pillow3. 数据集Pascal VOC 2012(https://www.kaggle.com/huanghanchina/pascal-voc-2012)Semantic Boundaries Dataset(http://home.bharathh.info/pubs/codes/SBD/download.html)4. 模型训练4.1 获取源代码克隆MindSpore Gitee仓库开源代码:https://gitee.com/mindspore/models/tree/master/official/cv/deeplabv3plus4.2 数据集预处理数据集目录:└─Dataset    ├─VOC2012    │   ├──Annotations    │   ├──...    │    └─benchmark_RELEASE        ├──dataset        ├──...根据readme提示处理数据集:进入tools目录:cd /deeplabv3plus/src/tools获取训练数据清单:python3 get_dataset_list.py --data_dir=Dataset#执行完成后会在Dadaset目录下生成voc_train_lst.txt、voc_val_lst.txt、vocaug_train_lst.txt三个文件将数据集转换为MindRecord:#三个数据清单都需要执行一次python3 get_dataset_mindrecord.py --data_root=/home/wesley/dataset/VOC2012/ \--data_lst=/home/wesley/dataset/voc_train_lst.txt \--dst_path=../../mindrecord/voc_train.mindrecord \--num_shards=1 \--shuffle=True4.3 开始训练4.3.1 准备预训练Backbone:resnet101_ascend_v120_imagenet2012_official_cv_bs32_acc78.ckpt4.3.2 单卡训练:执行train.py脚本即可,命令如下,参数(在train.py中查看描述)可根据实际情况修改:    python3 train.py --data_file=./mindrecord/vocaug_train.mindrecord \    --train_dir=./ckpt/ \    --train_epochs=200 \    --batch_size=32 \    --crop_size=513 \    --base_lr=0.015 \    --lr_type=cos \    --min_scale=0.5 \    --max_scale=2.0 \    --ignore_label=255 \    --num_classes=21 \    --model=DeepLabV3plus_s16 \    --ckpt_pre_trained=./resnet101_bs32_acc78.ckpt \    --save_steps=1500 \    --keep_checkpoint_max=200 >log 2>&1 &训练日志信息:4.3.3 多卡训练:通过script目录下的脚本启动8卡训练(由于多卡没有环境,未做测试)1、使用vocaug_train数据集训练s16,微调ResNet-101预训练模型,修改run_distribute_train_s16_r1.sh脚本参数部分如下,然后执行:bash run_distribute_train_s16_r1.shtrain_path=../deeplabv3plus/train/ #训练结果输出路径train_code_path=../deeplabv3plus/ #代码路径python3 ${train_code_path}/train.py --train_dir=${train_path}/ckpt  \--data_file=./mindrecord/vocaug_train.mindrecord  \--train_epochs=300  \--batch_size=32  \--crop_size=513  \--base_lr=0.08  \--lr_type=cos  \--min_scale=0.5  \--max_scale=2.0  \--ignore_label=255  \--num_classes=21  \--model=DeepLabV3plus_s16  \--ckpt_pre_trained=./resnet101_bs32_acc78.ckpt  \--is_distributed  \--save_steps=410  \--keep_checkpoint_max=200 >8p_log_1 2>&1 &2、 使用vocaug_train数据集训练s8,微调上一步的模型,修改run_distribute_train_s8_r1.sh脚本参数部分如下,然后执行:bash run_distribute_train_s8_r1.shtrain_path=../deeplabv3plus/train2/train_code_path=../deeplabv3plus/python3 ${train_code_path}/train.py --train_dir=${train_path}/ckpt  \--data_file=./mindrecord/vocaug_train.mindrecord  \--train_epochs=800  \--batch_size=16  \--crop_size=513  \--base_lr=0.02  \--lr_type=cos  \--min_scale=0.5  \--max_scale=2.0  \--ignore_label=255  \--num_classes=21  \--model=DeepLabV3plus_s8  \--loss_scale=2048  \--ckpt_pre_trained=./train/ckpt/DeepLabV3plus_s16-34_45.ckpt--is_distributed  \--save_steps=820  \--keep_checkpoint_max=200 >8p_log_2 2>&1 &3、使用voc_train数据集训练s8,微调上一步的模型,修改run_distribute_train_s8_r2.sh脚本参数部分如下,然后执行:bash run_distribute_train_s8_r2.shtrain_path=../deeplabv3plus/train2/train_code_path=../deeplabv3plus/python3 ${train_code_path}/train.py --train_dir=${train_path}/ckpt  \--data_file=./mindrecord/voc_train.mindrecord  \--train_epochs=300  \--batch_size=16  \--crop_size=513  \--base_lr=0.008  \--lr_type=cos  \--min_scale=0.5  \--max_scale=2.0  \--ignore_label=255  \--num_classes=21  \--model=DeepLabV3plus_s8  \--loss_scale=2048  \--ckpt_pre_trained=./train/ckpt/DeepLabV3plus_s8-34_45.ckpt  \--is_distributed  \--save_steps=110  \--keep_checkpoint_max=200 >8p_log_3 2>&1 &5. 模型评估通过eval.py脚本和训练保存的ckpt文件进行模型评估:python3 eval.py --data_root=/home/wesley/dataset  \--data_lst=/home/wesley/dataset/voc_val_lst.txt  \--batch_size=32  \--crop_size=513  \--ignore_label=255  \--num_classes=21  \--model=DeepLabV3plus_s16  \--scales=1.0  \--freeze_bn  \--ckpt_path=./train/ckpt/DeepLabV3plus_s16-34_45.ckpt >./eval_log 2>&1 &————————————————原文链接:https://blog.csdn.net/HsiehVe/article/details/121512129
  • [技术干货] 利用MindSpore复现ICCV2021 Best Paper Swin Trasnformer
    经过长达一个月的复现,终于成功利用MindSpore复现了SwinTransformer在imagenet上的分类精度,中间踩过很多的坑,这个帖子就作为复现SwinTransformer的记录贴,希望能对大家复现2021年这种充满训练Trick的论文有所帮助。复现着复现着突然Swin就拿了最佳论文了,当时感觉也非常有意思,突然就在复现ICCV2021的最佳论文了,模型的效果的确很炸裂。博客所有的相关代码已经上传到我的码云修改完成后代码将会合入MindSpore的model的models主仓,有需要的同学可以自取。数据篇——数据增强由于SwinTransformer源码是基于PyTorch和timm完成的,其中的AutoAugment虽然是基本基于PIL库实现的,但是由于MindSpore本身图像库接口和timm和PyTorch存在一定的区别,非常不易自己实现。因此笔者选择将timm的相关数据增强代码复制到MindSpore中并且基于numpy对其中PyTorch的一部分完整修改,同时也可以认为相当于是MindSpore的dataset扩充了一个可以即插即用的AutoAugment,相关的接口和PyTorch完全统一(反正也是cv来的),可以作为未来复现此类论文的一个基本模板,代码见我的仓库swin_transformer/data/data_utils文件夹模型篇——混合精度混合精度训练方法是通过混合使用单精度和半精度数据格式来加速深度神经网络训练的过程,同时保持了单精度训练所能达到的网络精度。混合精度训练能够加速计算过程,同时减少内存使用和存取,并使得在特定的硬件上可以训练更大的模型或batchsize。这里我们主要针对MindSpore的混合精度和PyTorch(Apex)混合精度的区别做一些说明。这里应该倒过来看,在笔者从模型训练、数据、性能角度都匹配了原基于PyTorch的SwinTransformer后,模型在10轮的时候会比同期PyTorch低1-2个点,这让人非常疑惑,因此最后联想到了混合精度。(不确定最后能不能靠O2跑到,一次三天实在等不起,就选择还是尽量同步源码了)下面的理解是我基于MindSpore源码得到的,如果有错误希望指正。首先是关于运算模式的一些定义:O0:纯FP32训练,可以作为accuracy的baseline;O1:混合精度训练(推荐使用),根据黑白名单自动决定使用FP16(GEMM, 卷积)还是FP32(Softmax)进行计算。O2:“几乎FP16”混合精度训练,不存在黑白名单,除了BatchNorm,几乎都是用FP16计算。O3:纯FP16训练,很不稳定,但是可以作为speed的baseline;MindSpore拥有了O0、O2和O3,但是O1是缺省的,对于O2和O3,唯一的区别就是BN层是fp32还是fp16,那就是说如果不使用BN层的大多数ViT,O2和O3是一样的。知道了这个区别之后,我们了解到Apex库中有对于fp16和fp32在O1模式下的名单,见list可以看到,实际在O1模式下,softmax、layernorm这类对精度影响较大的模块都会被保留在fp32,因此我们也选择将这些模块保存在fp32,进一步同步PyTorch。关于转fp32和fp16的操作,选择直接去抄mindspore的amp.py文件:print(f"=> using amp_level {args.amp_level}")# 转换fp16net.to_float(mstype.float16)print(f"=> change {args.arch} to fp16")# 转换fp32,反正swin就用了几个nn.Conv2d,主要还是nn.Dense,我就索性转fp32了cell_types = (nn.GELU, nn.Softmax, nn.Conv2d, nn.Conv1d, nn.BatchNorm2d, nn.LayerNorm)_do_keep_fp32(net, cell_types)print(f"=> cast {cell_types} to fp32 back")class OutputTo16(nn.Cell):    "Wrap cell for amp. Cast network output back to float16"    def __init__(self, op):        super(OutputTo16, self).__init__(auto_prefix=False)        self._op = op    def construct(self, x):        return F.cast(self._op(x), mstype.float16)def _do_keep_fp32(network, cell_types):    cells = network.name_cells()    change = False    for name in cells:        subcell = cells[name]        if subcell == network:            continue        elif isinstance(subcell, cell_types):            network._cells[name] = OutputTo16(subcell.to_float(mstype.float32))            change = True        else:            # 这里是递归调用            _do_keep_fp32(subcell, cell_types)    if isinstance(network, nn.SequentialCell) and change:        network.cell_list = list(network.cells()经过手动的MindSpore的O1模式转换后,十轮同期的精度正常了,然后可以放心往下跑了。模型篇——性能调优相对于V100 GPU来说,MindSpore基于CANN,拥有更加优秀的矩阵计算算法,这点非常赞,同时MindSpore的on-device执行 - MindSpore master documentation可以极大的提高数据加载和模型运行的效率。相应的,目前让人感觉最深刻的就是MindSpore目前对于索引的优化可以说是相当不靠谱了,一旦模型中出现大量的索引算子,整个模型是性能会急剧下滑,甚至单步训练时长可能是同等条件下V100GPU的四五倍。这里举几个例子,希望可以作为目前Ascend910性能瓶颈经典的几个坑:例1 qkv范式的不同写法"""qkv注意力写法1"""self.qkv = nn.Dense(in_channels=dim, out_channels=dim * 3, has_bias=qkv_bias)qkv = ops.Reshape()(self.qkv(x), (B_, N, 3, self.num_heads, C // self.num_heads))qkv = ops.Transpose()(qkv, (2, 0, 3, 1, 4))q, k, v = qkv[0]*self.scale, qkv[1], qkv[2]"""qkv注意力写法2"""self.q = nn.Dense(in_channels=dim, out_channels=dim, has_bias=qkv_bias)self.k = nn.Dense(in_channels=dim, out_channels=dim, has_bias=qkv_bias)self.v = nn.Dense(in_channels=dim, out_channels=dim, has_bias=qkv_bias)q = ops.Reshape()(self.q(x), (B_, N, self.num_heads, C // self.num_heads))k = ops.Reshape()(self.k(x), (B_, N, self.num_heads, C // self.num_heads))k = ops.Transpose()(k, (0, 1, 3, 2))v = ops.Reshape()(self.v(x), (B_, N, self.num_heads, C // self.num_heads))这两种方法是目前最主流的self attention范式,在Ascend910上,强烈要求使用写法2。虽然这两者得到的最后解决是相同的,但是由于写法1用到了索引操作(哪怕的qkv[0]这么一点),在SwinTransformer上swin_tiny模型的单步训练时长会白白增加100ms最后(大约从600ms左右到700ms+),性能差距非常大。例2 用reshape和Transpose代替一部分典型索引"""写法1"""x0 = x[:, 0::2, 0::2, :]  # B H/2 W/2 Cx1 = x[:, 1::2, 0::2, :]  # B H/2 W/2 Cx2 = x[:, 0::2, 1::2, :]  # B H/2 W/2 Cx3 = x[:, 1::2, 1::2, :]  # B H/2 W/2 Cx = torch.cat([x0, x1, x2, x3], -1)  # B H/2 W/2 4*Cx = x.view(B, -1, 4 * C)  # B H/2*W/2 4*C"""写法2"""x = P.Reshape()(x, (B, self.H_2, 2, self.W_2, 2, self.dim))x = P.Transpose()(x, (0, 1, 3, 4, 2, 5))x = P.Reshape()(x, (B, self.H2W2, self.dim_mul_4))很容易可以理解,两者都是做了一个类似于反上采样和PixelShuffle的操作,将像素重排,这个形式的非常规则的,而且输入输出数量也是相同的。在这种情况下,切记要使用同等的reshape操作,这个操作在这个模型使用较多的情况下,可以为模型再一次节约大量的时间,swin_tiny节约了大概150ms/step容易知道,当kernel_size=strides的unfold的时候,也推荐之后这种方式,此处略过。例3 用矩阵乘法代替索引"""写法1"""a = [1, 2, 3]index = 2a => 3"""写法2"""a = [1, 2, 3]index = 2one_hot_index = [0, 0, 1] # predefinea dot one_hot_index.T => 3这里由于篇幅问题,不拿SwinTransformer的代码做说明(参见relative_position_index的使用处),简单说就是在索引固定的情况下,使用onehot和矩阵乘法来代替索引,只要索引够多,这种方法能为模型性能做很大贡献。关于如何使用MindSpore的Profiler的性能调试工具,可以参见我的师兄的帖子【昇腾众智】RetinaFace_ResNet50模型的910训练+310推理模型篇——模型训练关于如何使用MindSpore进行自定义训练,可以参考我的博客如何实现MindSpore自定义训练这里主要对之前的博客留下来的问题进行一些解决(感觉昱峰哥提的建议,深受启发):异构并行训练异构并行训练方法是通过分析图上算子内存占用和计算密集度,将内存消耗巨大或适合CPU逻辑处理的算子切分到CPU子图,将内存消耗较小计算密集型算子切分到硬件加速器子图,框架协同不同子图进行网络训练,使得处于不同硬件且无依赖关系的子图能够并行进行执行的过程。首先是关于异构并行计算方面的优化:驱动源自MindSpore的这句话:在盘古或GPT3大模型训练过程中,优化器状态占用了大量内存,进而限制了可训练的模型规模。使用优化器异构,将优化器指定到CPU上执行,可以极大扩展可训练模型规模。结合这两句话,我们很容易意识到,模型的权重保存和更新正好非常符合这种内存大且运算少的特性,之前那种将grad_sum和zero_op放在显存中运算是不合理的,我们要将这种运算都放在CPU里面去,为模型节约宝贵的显存,因此在这里我们对之前的操作进行一些优化:不再自己重写TrainOneStepCell,而是从nn.TrainOneStepWithLossScaleCell继承(这个Cell包含了自动过滤overflow的梯度),减少实际的代码量,特别是关于分布式运算的管理。将_sum_op和_clear_op全部丢到CPU里面去,根据异构计算中的模板即可assignadd = P.AssignAdd()assignadd.add_prim_attr("primitive_target", "CPU")进一步的,考虑到在保存最后的权重的会包括grad_sum和zeros权重,这样子加上原来的optimizer包含的权重,相当于存了四个模型的大小权重,有什么方法可以优化呢?我们可以去除zeros权重:_sum_op = C.MultitypeFuncGraph("grad_sum_op")assignadd = P.AssignAdd()assignadd.add_prim_attr("primitive_target", "CPU")# 相当于执行a -= a,a减去自己就可以得到0self.hyper_map(F.partial(_sum_op), self._grad_sum, -self._grad_sum)配合上clip_grad_norm,我们成功的从数据和模型都对原来基于PyTorch的SwinTransformer进行了全方位的复现,然后就该去ModelArts进行训练了~ 冲冲冲ModelArts使用篇ModelArts 是面向开发者的一站式 AI 开发平台,为机器学习与深度学习提供海量数据预处理及交互式智能标注、大规模分布式训练、自动化模型生成,及端-边-云模型按需部署能力,帮助用户快速创建和部署模型,管理全周期 AI 工作流。上面的介绍摘自华为云的官方,也就当个大概的介绍,大家可以将这个理解成一个高效的深度学习平台吧。首先简单介绍一个华为云ModelArts使用的感受:快:不知道是由于Ascend910ProA和Ascend910B的不同,相同的代码在ModelArts跑起来就是比线下的910B服务器要快100ms/step左右。猜想有可能是因为云服务器环境稳定,或者就是传说中的ModelArts对分布式运算做了特定优化。开销大:V100八卡需要195一小时,Ascend910八卡155一小时,SwinTransformer一跑就是3天,1w代金券直接走了 T T难入门,入门后很方便:要不是本地的910NPU资源不够,内心一直是很抗拒使用云服务器的,因为当时缺少合适的文档,官网的教程还误导了我,导致学习成本极高。后来在自己的摸索下,终于解决了其中的坑点,直到后来群里才发了使用文档才发现坑白踩了。这里推荐一份很详细的文档,来自东北大学的一位老兄,写的非常详细:【ModelArts】鹏城云脑实验平台(华为云ModelArts)使用教程解决完之后就可以安心训练,并且可以保存训练参数,启动训练只需要动动鼠标,再也不用敲命令行写脚本了!论文当时拿他的权重跑出来是81.15%,复现了一个月,终于到了,果然这种论文还是得各种同步作者的操作~。这一个月踩了各种MindSpore的坑,感觉自己更懂MindSpore了。————————————————原文链接:https://blog.csdn.net/qq_31768873/article/details/120904231
  • [技术干货] MindSpore应用梯度累积算法
    概述本教程介绍梯度累积的训练方式,目的是为了解决由于内存不足导致某些大型网络无法训练大Batch_size的问题。传统的训练方式是每次计算得到loss和梯度后,直接用所得梯度对参数进行更新。与传统的训练方式不同,梯度累积引入Mini-batch的概念,首先对每个Mini-batch的数据计算loss和梯度,但不立即更新模型参数,而是先对所得梯度进行累加,然后在指定数量(N)个Mini-batch之后,用累积后的梯度更新网络参数。下次训练前清空过往累积梯度后重新累加,如此往复。最终目的是为了达到跟直接用N*Mini-batch数据训练几乎同样的效果。本篇教程将分别介绍在单机模式和并行模式下如何实现梯度累积训练。梯度下降算法大致分为三种1. 批量梯度下降(Batch Gradient Descent,BGD)2. 批量梯度下降(Batch Gradient Descent,BGD)3. 小批量梯度下降(Mini-Batch Gradient Descent,MBGD)单机模式在单机模式下,主要通过将训练流程拆分为正向反向训练、参数更新和累积梯度清理三个部分实现梯度累积。这里以MNIST作为示范数据集,自定义简单模型实现梯度累积需要如下几个步骤。首先要导入需要的文库:代码如下:import argparseimport osfrom collections.abc import Iterableimport mindspore.nn as nnfrom mindspore import ParameterTuplefrom mindspore import context, DatasetHelper, save_checkpointfrom mindspore.nn import Cellimport mindspore.ops as opsfrom model_zoo.official.cv.lenet.src.dataset import create_datasetfrom model_zoo.official.cv.lenet.src.lenet import LeNet5加载数据集:利用MindSpore的dataset提供的MnistDataset接口加载MNIST数据集,此部分代码由model_zoo中lenet目录下的dataset.py导入。得到定义训练模型:通过mini_steps控制每次更新参数前的累加次数。达到累加次数后进行参数更新和 累加梯度变量清零。代码如下:class GradientAccumulation:    def __init__(self, network, loss_fn, optimizer):        self._network = network        self._loss_fn = loss_fn        self._optimizer = optimizer        params = self._optimizer.parameters        self._grad_sum = params.clone(prefix="grad_sum", init='zeros')        self._zeros = params.clone(prefix="zeros", init='zeros')        self._train_forward_backward = self._build_train_forward_backward_network()        self._train_optim = self._build_train_optim()        self._train_clear = self._build_train_clear()    @staticmethod    def _transform_callbacks(callbacks):        """Transform callback to a list."""        if callbacks is None:            return []        if isinstance(callbacks, Iterable):            return list(callbacks)        return [callbacks]    def _build_train_forward_backward_network(self):        """Build forward and backward network"""        network = self._network        network = nn.WithLossCell(network, self._loss_fn)        loss_scale = 1.0        network = TrainForwardBackward(network, self._optimizer, self._grad_sum, loss_scale).set_train()        return network    def _build_train_optim(self):        """Build optimizer network"""        network = TrainOptim(self._optimizer, self._grad_sum).set_train()        return network    def _build_train_clear(self):        """Build clear network"""        network = TrainClear(self._grad_sum, self._zeros).set_train()        return network    def train_process(self, epoch, train_dataset, mini_steps=None):        """        Training process. The data would be passed to network directly.        """        dataset_helper = DatasetHelper(train_dataset, dataset_sink_mode=False, epoch_num=epoch)        for i in range(epoch):            step = 0            for k, next_element in enumerate(dataset_helper):                loss = self._train_forward_backward(*next_element)                if (k + 1) % mini_steps == 0:                    step += 1                    print("epoch:", i + 1, "step:", step, "loss is ", loss)                    self._train_optim()                    self._train_clear()            train_dataset.reset()        save_checkpoint(self._train_forward_backward, "gradient_accumulation.ckpt", )训练并保存模型调用网络、优化器及损失函数,然后自定义GradientAccumulation的train_process接口,进行模型训练if __name__ == "__main__":    parser = argparse.ArgumentParser(description='MindSpore Grad Cumulative Example')    parser.add_argument('--device_target', type=str, default="GPU", choices=['GPU'],                        help='device where the code will be implemented (default: GPU)')    parser.add_argument('--data_path', type=str, default="./Data",                        help='path where the dataset is saved')    args = parser.parse_args()    context.set_context(mode=context.GRAPH_MODE, device_target=args.device_target)    ds_train = create_dataset(os.path.join(args.data_path, "train"), 32)    net = LeNet5(10)    net_loss = nn.SoftmaxCrossEntropyWithLogits(sparse=True, reduction="mean")    net_opt = nn.Momentum(net.trainable_params(), 0.01, 0.9)    model = GradientAccumulation(net, net_loss, net_opt)    print("============== Starting Training ==============")    model.train_process(10, ds_train, mini_steps=4)————————————————原文链接:https://blog.csdn.net/JIAJIA14754545/article/details/121856735
  • [技术干货] MindSpore之Faster_rcnn
    前一阵子参加了华为的多目标检测比赛 link,尝试通过 faster_rcnn 算法定位和分类病理图像中的癌细胞。MindSpore 是华为的 AI 框架,支持华为自研的Ascend芯片。MindSpore目前不支持macOS,不过组织方提供了华为云作为训练平台。以下将分享使用mindspore及华为云的经验。Notebook首先可以从mindspore官方的 gitee 上下载faster_rcnn模型, 注意原先的model_zoo已经被移至model 仓库,同时还可以这里 link 下载在imageNeth上预训练的模型,我选择的是resnet_50。接下来使用华为云的model_art新建notebook。有多种设置可以进行选择,我使用的是mindspore1.2.1-cuda10.1和Ascend. 这个笔记本跟google colab类似但功能更加强大,你可以在上面新建jupyter notebook,打开ternimal, 查看json,csv文件(文件查看器的功能很棒)等等。 将需要用的文件保存在work文件夹下,包括先前下载的faster_rcnn和预训练模型。按照faster_rcnn下的readme文件执行代码,首先应该修改default_config.yaml, 根据你使用的数据集更改coco_classes和num_classes。这一步在readme文件中省略了,但是会影响模型的结构和训练的效率。接下来对预训练的模型进行处理python convert_checkpoint.py --ckpt_file=1ckpt_file为到预训练的模型的路径。这步之后会得到所需要的backbone.ckpt。下一步是处理自己的数据集,新建txt文件,每行是按空间分割的图像标注,格式如下0000001.jpg 0,259,401,459,7,0 35,28,324,201,2,0 0,30,59,80,2,01第一列是图像的相对路径【不需要写成train2017/0000001.jpg】,其余为[xmin,ymin,xmax,ymax,class,is_crowd]格式的框继续修改default_config.yaml,save_checkpoint_epochs修改成10(notebook上的空间有限,设为1可能在几十个epoch后出现disk存储空间不够用),更改anno_path和image_dir。执行bash run_standalone_train_ascend.sh [COCO_ROOT] [MINDRECORD_DIR]。PRETRAINED_MODEL为backbone.ckpt的路径。BACKBONE=resnet_v1.5_50,COCO_ROOT不需要,MINDRECORD_DIR设成想要存放MINDRECORD的路径。MINDRECORD类似tensorflow的tfrecord。注意:第一个epoch涉及图的生成会比较慢执行bash run_eval_ascend.sh [VALIDATION_JSON_FILE] [CHECKPOINT_PATH] [COCO_ROOT] [MINDRECORD_DIR]。CHECKPOINT_PATH为训练得到的faster_rcnn-12_50.ckpt 。如果只想看在训练集上的结果,[VALIDATION_JSON_FILE]可以直接使用annotations/train.txt ,[COCO_ROOT] [MINDRECORD_DIR]保持不变。下载生成的results.pkl.bbox,进行可视化可以看到结果不是很理想,可能是训练次数不够多的问题。#可视化的代码with open(anno_path,"r") as f:    imgs= for line in f.readlines()]with open(anno_path,"r") as f:    annotations=get_annotation(f)with open(pred_path,"r") as fp:    pred_res=json.load(fp)id2img=dict(zip(range(1,len(imgs)+1),imgs))for kk in id2img:    # draw image    df=pd.DataFrame(pred_res)    image_path=id2img[kk]    f = Image.open(image_path)     img_np = np.asarray(f ,dtype=np.float32)    fig = plt.figure()    ax = fig.add_subplot(1,1,1)    ax.imshow(img_np.astype(np.uint8))    # draw prediction    df_group=df.groupby('image_id')    df_i=df_group.get_group(kk)    for box_index in range(len(df_i)):        boxes=df_i.iloc        ymin=boxes["bbox"][0]        xmin=boxes["bbox"][1]        ymax=boxes["bbox"][2]        xmax=boxes["bbox"][3]        ax.add_patch(plt.Rectangle((xmin,ymin),(xmax-xmin),(ymax-ymin),fill=False,edgecolor='red', linewidth=1))        # draw ground truth    annotation=annotations[kk]    for anno in annotation:        xmin=anno[0]        ymin=anno[1]        xmax=anno[2]        ymax=anno[3]        ax.add_patch(plt.Rectangle((xmin,ymin),(xmax-xmin),(ymax-ymin),fill=False,edgecolor='blue', linewidth=1))        labels = []    plt.show()    breakOBS & Algorithm一般来说,在notebook上完成debug后,就进入到实际的训练的环节,这一步需要执行上百个epoch,通常用ModelArts上的Algorithm和training job来完成。接下来介绍如何使用OBS以及如何在ModelArts上创建Algorithm进行训练。整个过程分成三步将代码和模型上传OBS。在执行bash run_standalone_train_ascend.sh时,会在script下新建train文件夹。只需要上传此文件夹和faster_rcnn-12_50.ckpt即可。其中default_config和train.py需要进行一些修改。default_config: 将data_url,label_url,metadata_url设定成数据集的位置#Train.py: 在训练前对数据集进行处理def parse_data():    data_path = './dataset/'     if not os.path.exists(data_path):        mox.file.copy_parallel(src_url=config.data_url, dst_url=data_path)    label_path = './labels.csv'     if not os.path.exists(label_path):        mox.file.copy_parallel(src_url=config.label_url, dst_url=label_path)    metadata_path = './metadata.csv'     if not os.path.exists(metadata_path):        mox.file.copy_parallel(src_url=config.metadata_url, dst_url=metadata_path)        os.mkdir("./train/")    os.mkdir("./eval/")    os.mkdir("./annotations/")    file = open('./annotations/train.txt','w')    file.close()    data_path = './dataset/images/'             image_files, image_anno_dict = filter_valid_data(label_path, data_path)    metadata_df = pd.read_csv(metadata_path)    train_test_split = 1    split_at = len(image_files)*train_test_split    for idx, image_name in enumerate(image_files):        image_path = os.path.join(data_path, image_name + '.bmp')        image_metadata = metadata_df[metadata_df.image_id == image_name].iloc[0]        w = image_metadata.width        h = image_metadata.height        image_anno_dict[:,[0,2]] *= w        image_anno_dict[:,[1,3]] *= h        bool_matrix = image_anno_dict[:,4:] == 1        classes=[]        categs=np.arange(4)        for row in bool_matrix:            classes.append(get_categ(categs[row]))        if len(classes)!=len(image_anno_dict):            print("warning")        annos = np.array(image_anno_dict,dtype=np.int32)        if idx < split_at:            ty="train"        else:            ty="test"            break        shutil.move(image_path,f"./{ty}/")        save_anno(image_name+ '.bmp',annos,classes,ty)        with open("./annotations/train.txt","r") as f:        print(f.readlines()[0])    mox.file.copy_parallel(src_url="./annotations", dst_url=config.mindrecord_dir)    config.anno_path="./annotations/train.txt"    config.image_dir="./train/"这里会通过Moxing框架进行一些文件的拷贝【image source: Mindsporechallenge】​ 创建algorithm注意:需要保存的文件,为其设定路径时,一定要放在output path mapping configuration里设定training job这里不需要像之前使用bash来跑了【当然也可以,但是需要通过python来调用bash,然后bash在调用python, 还不如直接使用python】对华为产品的体验:notebook挺好用的,它同时有三个功能,file explorer, jupyter notebook, ternimal,但是对下载文件的大小有限制。Algorithm中对input_rul和ouput_url进行区分,如果不小心把保留文件的路径设成input_url就会无法保留。OBS啥的还是比较麻烦,上传文件有个数限制,下载文件似乎不能批量下载。文件没有查看功能,而且不好移动到别的文件夹。在notebook上得到的checkpoint,需要先下载下来(好像不能超过100M?),再保存到OBS里,相当于重新弄了一遍。对初上手来说,需要比较多的尝试。————————————————原文链接:https://blog.csdn.net/Aren8/article/details/120932635
  • [技术干货] MindSpore简介
    MindSpore可以做模型的自动切分这一点让人印象深刻。当然,还有很多特点,比如自动微分、支持动态图+静态图,等等。如果希望了解更多,请看MindSpore官网:MindSpore​www.mindspore.cn/对于个人来讲,去年便对MindSpore有简单了解,做过一些其与TensorFlow、PyTorch的对比分析。因为此前尚未开源,只能基于公开的文档做调研而已。而三月底,在HDC大会时,华为正式开源了MindSpore的源码和相应的文档。因而有机会实际拿来运行看看,本文将介绍如何在Windows平台安装和搭建MindSpore,同时训练一个小的网络(LeNet)。安装MindSpore截至今天,MindSpore官网建议的安装操作系统为EulerOS和Ubuntu,并不包括Windows。而不幸的是我的这台Lenovo游戏主机是Windows 10的系统。仔细了下文档,发现实际上MindSpore是支持Windows平台的[1],只不过只能以CPU的模式运行(暂时不支持Windows平台的GPU)。如果希望尝试MindSpore对GPU的支持,需要使用Ubuntu系列或者华为的EulerOS(这也不是本文的重点)。下面进入安装的正题。安装Anaconda非常推荐使用Anaconda作为Python虚拟环境的管理。你可以去Anaconda官网下载,一路Next即可。如果遇到问题,可适当参考这里。由于Anaconda的安装过程简单直观,这里不详述了。创建MindSpore的Python Env目前MindSpore仅仅支持Python 3.7.5,下面创建的pyhton env就叫做mindspore:conda create -n mindspore python=3.7.5安装MindSpore下载MindSpore的whl文件,下载地址见这里,目前只有一个0.1.0的版本mindspore-0.1.0-cp37-cp37m-win_amd64.whl在mindspore这个python env里执行:conda activate mindspore # 此时你应该在mindspore-0.1.0-cp37-cp37m-win_amd64.whl这个文件的目录里pip install mindspore-0.1.0-cp37-cp37m-win_amd64.whl注意,这里很多同学反应安装过程很慢,甚至有失败的情况,基本都是网络惹得祸。因为安装上面的whl文件时会按照一些依赖的libraries,如果你的pip是默认源的话,在国内的网络下载时可能遇到问题的。一个解决办法是重试(yes, just retry),另一个办法是把pip源切换为国内的源,比如清华源。具体方法见这里:Tsinghua Open Source Mirror​mirror.tuna.tsinghua.edu.cn/help/pypi/正在上传…重新上传取消​一个临时的办法可以是:pip install -i https://pypi.tuna.tsinghua.edu.cn/simple mindspore-0.1.0-cp37-cp37m-win_amd64.whl验证Spore安装是否成功python>>> import mindspore as ms>>> print(ms.__version__)# 如果成功,上面应该打印 0.1.0训练一个LeNet华为官方已经在其MindSpore Doc这个Repo里内置了一些examples,比如LeNet。直接Fork吧:git clone https://github.com/mindspore-ai/docs.git如果你和我一样懒,仅仅下载lenet.py也可以,路径如下:https://github.com/mindspore-ai/docs/blob/master/tutorials/tutorial_code/lenet.py训练LeNet因为这个代码里默认使用的训练设备为Ascend,所以需要手动设置一下--device_target为CPU:python lenet.py --device_target CPUMindSpore用LeNet训练MNIST大约十几秒就可以跑完一个Epoch了:******Downloading the MNIST dataset******============== Starting Training ==============epoch: 1 step: 1, loss is 2.3008137epoch: 1 step: 2, loss is 2.299688epoch: 1 step: 3, loss is 2.309444epoch: 1 step: 4, loss is 2.3006275epoch: 1 step: 5, loss is 2.3028035epoch: 1 step: 6, loss is 2.302422epoch: 1 step: 7, loss is 2.3067183epoch: 1 step: 8, loss is 2.3057096epoch: 1 step: 9, loss is 2.3042586epoch: 1 step: 10, loss is 2.303799.........epoch: 1 step: 1870, loss is 0.15847126epoch: 1 step: 1871, loss is 0.12955114epoch: 1 step: 1872, loss is 0.15605931epoch: 1 step: 1873, loss is 0.28985676epoch: 1 step: 1874, loss is 0.14183074epoch: 1 step: 1875, loss is 0.05726877============== Starting Testing ============================ Accuracy:{'Accuracy': 0.9625400641025641} ==============看看Accuracy,已经到96.25%,还可以~我们观察一下这个目录,会看到同时还保存了模型文件(.ckpt和.meta)还有train、val时的pb文件,具体待后面再讲。04/25/2020  12:21 PM           494,155 checkpoint_lenet-1_1875.ckpt04/25/2020  12:20 PM            15,033 checkpoint_lenet-graph.meta04/25/2020  02:36 PM             4,831 ms_output_0eval.pb04/25/2020  02:36 PM            15,878 ms_output_0train.pb避坑指南也许在上面你会遇到MNIST数据集下载的问题。以我自己为例,在电信的宽带下载MNIST几乎是龟速,实在没法忍,想起此前在其他Repo下载过这个数据集的几个gz文件。于是copy进lenet.py里定义的路径:train_path = "./MNIST_Data/train/"test_path = "./MNIST_Data/test/"需要注意的是需要分别copy train-*到./MNIST_Data/train, t10k-*到./MNIST_Data/test如果你之前没下载过,你可以直接在这里下载下面这个link的MNIST_DATA的压缩包,解压到lenet.py的同级目录即可:https://gitee.com/loveunk/mindspore/blob/master/example/_lenet_demo/MNIST_Data.zip————————————————原文链接:https://blog.csdn.net/weixin_54227557/article/details/121237191
总条数:3885 到第
上滑加载中