-
初学者,按照HiQ教程测试了“基于Jupyter Notebook开发量子神经网络对鸢尾花进行分类”部分测试,发生如下错误求教,谢谢!
-
1. 昇腾AI全栈架构 1.1 昇腾AI全栈的四个大部分 应用使能层面,此层面通常包含用于部署模型的软硬件,例如API、SDK、部署平台,模型库等等。 AI框架层面,此层面包含用于构建模型的训练框架,例如华为的MindSpore、TensorFlow、Pytorch等。 异构计算架构,偏底层、偏通用的计算框架,用于针对上层AI框架的调用进行加速,力求向上支持多种AI框架,并在硬件上进行加速。 计算硬件,本层是AI计算的底座,有了强力的芯片及硬件设备,上层的加速才有实施的基础。2. 异构计算架构 CANN 华为公司面向计算机视觉、自然语言处理、推荐系统、类机器人等领域量身打造了基于“达芬奇(DaVinci)架构”的昇腾(Ascend)AI处理器,开启了智能之旅。为提升用户开发效率和释放昇腾AI处理器澎湃算力,同步推出针对AI场景的异构计算架构CANN(Compute Architecture for Neural Networks),CANN通过提供多层次的编程接口,以全场景、低门槛、高性能的优势,支持用户快速构建基于Ascend平台的AI应用和业务。昇腾AI异构计算架构(Compute Architecture for Neural Networks,CANN)被抽象成五层架构,如下图所示。2.1. 昇腾计算语言接口昇腾计算语言(Ascend Computing Language,AscendCL)接口是昇腾计算开放编程框架,是对低层昇腾计算服务接口的封装。它提供Device(设备)管理、Context(上下文)管理、Stream(流)管理、内存管理、模型加载与执行、算子加载与执行、媒体数据处理、Graph(图)管理等API库,供用户开发人工智能应用调用。2.2. 昇腾计算服务层本层主要提供昇腾计算库,例如神经网络(Neural Network,NN)库、线性代数计算库(Basic Linear Algebra Subprograms,BLAS)等;昇腾计算调优引擎库,例如算子调优、子图调优、梯度调优、模型压缩以及AI框架适配器。2.3. 昇腾计算编译引擎本层主要提供图编译器(Graph Compiler)和TBE(Tensor Boost Engine)算子开发支持。前者将用户输入中间表达(Intermediate Representation,IR)的计算图编译成NPU运行的模型。后者提供用户开发自定义算子所需的工具。2.4. 昇腾计算执行引擎本层负责模型和算子的执行,提供如运行时(Runtime)库(执行内存分配、模型管理、数据收发等)、图执行器(Graph Executor)、数字视觉预处理(Digital Vision Pre-Processing,DVPP)、人工智能预处理(Artificial Intelligence Pre-Processing,AIPP)、华为集合通信库(Huawei Collective Communication Library,HCCL)等功能单元。2.5. 昇腾计算基础层本层主要为其上各层提供基础服务,如共享虚拟内存(Shared Virtual Memory,SVM)、设备虚拟化(Virtual Machine,VM)、主机-设备通信(Host Device Communication,HDC)等。3. 昇腾计算语言接口AscendCLAscendCL(Ascend Computing Language,昇腾计算语言)是昇腾计算开放编程框架,是对底层昇腾计算服务接口的封装,它提供运行时资源(例如设备、内存等)管理、模型加载与执行、算子加载与执行、图片数据编解码/裁剪/缩放处理等API库,实现在昇腾CANN平台上进行深度学习推理计算、图形图像预处理、单算子加速计算等能力。简单来说,就是统一的API框架,实现对所有资源的调用。AscendCL的优势如下:1. 高度抽象:算子编译、加载、执行的API归一,相比每个算子一个API,AscendCL大幅减少API数量,降低复杂度。2. 向后兼容:AscendCL具备向后兼容,确保软件升级后,基于旧版本编译的程序依然可以在新版本上运行。3. 零感知芯片:一套AscendCL接口可以实现应用代码统一,多款昇腾处理器无差异。AscendCL的主要应用场景如下:1. 开发应用:用户可以直接调用AscendCL提供的接口开发图片分类应用、目标识别应用等。2. 供第三方框架调用:用户可以通过第三方框架调用AscendCL接口,以便使用昇腾AI处理器的计算能力。3. 供第三方开发lib库:用户还可以使用AscendCL封装实现第三方lib库,以便提供昇腾AI处理器的运行管理、资源管理等能力。
-
首先将resnet50_firstapp放入云主机的/home/HwHiAiUser/sample目录下并su - HwHiAiUser切换至HwHiAiUser账户。在已经将文件赋予运行权限后,运行模型转化,将原始模型转换为昇腾AI处理器能识别的*.om模型文件。设置环境变量说明: 如果执行脚本报错“ModuleNotFoundError: No module named 'PIL'”,则表示缺少Pillow库,请使用 pip3 install Pillow --user 命令安装Pillow库。需要安装python3环境,apt-get install python3-pip编译,然后运行,获得正确推测结果
-
使用OpenCV实现偏斜文档校正纸质文档扫描中经常会发生扫描出来的图像有一定角度的偏斜,对后期的文档信息化OCR提取造成很大的干扰,导致OCR识别准确率下降从而影响文档信息化的结果。这个时候可以使用OpenCV对文档进行纠偏,最常见的文本纠偏算法有两种,分别是基于FFT变换以后频率域梯度基于离散点求最小外接轮廓这两种方法各有千秋,相对来说,第二种方法得到的结果更加准确,第一种基于离散傅立叶变换求振幅的方法有时候各种阈值选择在实际项目中会有很大问题。基于FFT变换以后频率域梯度主要思路是先把图像转换为灰度图像,然后使用离散傅立叶变换得到图像在频率域空间的振幅,对其二值化之后,使用霍夫直线检测得到角度,然后根据角度完成旋转校正。代码实现如下:Mat src = imread("D:/vcprojects/images/rotate_text.png"); Mat gray, binary; cvtColor(src, gray, COLOR_BGR2GRAY); //expand input image to optimal size Mat padded; int m = getOptimalDFTSize(gray.rows); int n = getOptimalDFTSize(gray.cols); // on the border add zero values copyMakeBorder(gray, padded, 0, m - gray.rows, 0, n - gray.cols, BORDER_CONSTANT, Scalar::all(0)); Mat planes[] = { Mat_(padded), Mat::zeros(padded.size(), CV_32F) }; Mat complexI; // Add to the expanded another plane with zeros merge(planes, 2, complexI); // 离散傅立叶变换 dft(complexI, complexI); // 实部与虚部得到梯度图像 // planes[0] = Re(DFT(I), planes[1] = Im(DFT(I)) split(complexI, planes); magnitude(planes[0], planes[1], planes[0]); Mat magI = planes[0]; magI += Scalar::all(1); log(magI, magI); // crop the spectrum, if it has an odd number of rows or columns magI = magI(Rect(0, 0, magI.cols & -2, magI.rows & -2)); // rearrange the quadrants of Fourier image so that the origin is at the image center int cx = magI.cols / 2; int cy = magI.rows / 2; Mat q0(magI, Rect(0, 0, cx, cy)); // Top-Left - Create a ROI per quadrant Mat q1(magI, Rect(cx, 0, cx, cy)); // Top-Right Mat q2(magI, Rect(0, cy, cx, cy)); // Bottom-Left Mat q3(magI, Rect(cx, cy, cx, cy)); // Bottom-Right Mat tmp; // swap quadrants (Top-Left with Bottom-Right) q0.copyTo(tmp); q3.copyTo(q0); tmp.copyTo(q3); q1.copyTo(tmp); q2.copyTo(q1); tmp.copyTo(q2); // 归一化与阈值化显示 normalize(magI, magI, 0, 1.0, NORM_MINMAX); Mat dst; magI.convertTo(dst, CV_8UC1, 255, 0); threshold(dst, binary, 160, 255, THRESH_BINARY); // 霍夫直线 vector lines; Mat linImg = Mat::zeros(binary.size(), CV_8UC3); HoughLines(binary, lines, 1, (float)CV_PI / 180, 30, 0, 0); int numLines = lines.size(); float degree = 0.0; for (int l = 0; l { float rho = lines[l][0], theta = lines[l][1]; float offset = CV_PI / 12.0; if (abs(theta) > offset && abs(theta)< (CV_PI / 2.0- offset)) { printf("theta : %.2f ", theta); degree = (theta)*180-90; } Point pt1, pt2; double a = cos(theta), b = sin(theta); double x0 = a*rho, y0 = b*rho; pt1.x = cvRound(x0 + 1000 * (-b)); pt1.y = cvRound(y0 + 1000 * (a)); pt2.x = cvRound(x0 - 1000 * (-b)); pt2.y = cvRound(y0 - 1000 * (a)); line(linImg, pt1, pt2, Scalar(0, 255, 0), 3, 8, 0); } imshow("lines", linImg); // 旋转调整 Mat rot_mat = getRotationMatrix2D(Point(binary.cols/2, binary.rows/2), degree, 1); Mat rotated; warpAffine(src, rotated, rot_mat, src.size(), cv::INTER_CUBIC, 0, Scalar(255, 255, 255)); imshow("input", src); imshow("deskew-demo", rotated); imwrite("D:/deskew_text.png", rotated);基于离散点求最小外接轮廓其主要思路是先把图像二值化,得到一系列离散的前景像素点集合,然后利用轮廓的最小外接矩形函数,得到偏斜的矩形大小与角度,通过仿射变换完成校正。代码实现如下:Mat src = imread("D:/vcprojects/images/rotate_text.png"); Mat gray, binary; cvtColor(src, gray, COLOR_BGR2GRAY); threshold(gray, binary, 0, 255, THRESH_BINARY_INV | THRESH_OTSU); imshow("binary", binary); imwrite("D:/binary_text.png", binary); vector points; findNonZero(binary, points); RotatedRect box = minAreaRect(points); double angle = box.angle; if (angle < -45.) angle += 90.; printf("angle : %.2f ", angle); Point2f vertices[4]; box.points(vertices); for (int i = 0; i < 4; ++i) line(src, vertices[i], vertices[(i + 1) % 4], Scalar(0, 0, 255), 2); imshow("box", src); imwrite("D:/box_text.png", src); Mat rot_mat = getRotationMatrix2D(box.center, angle, 1); Mat rotated; warpAffine(src, rotated, rot_mat, src.size(), cv::INTER_CUBIC, 0, Scalar(255, 255, 255)); //bitwise_not(rotated, rotated); imshow("deskew-demo", rotated);运行结果原图最小外接矩形校正之后转自公众号:小白学视觉
-
利用监督学习(SL)的力量开发更有效的强化学习(RL)方法已经成为最近的一种趋势。为了解决稀疏奖励目标条件问题,我们提出了一种新的分阶段方法,即在线反馈学习和离线反馈学习交替进行。在在线阶段,我们执行RL训练并收集上线数据,而在离线阶段,我们对数据集中成功的轨迹执行SL。为了进一步提高样本效率,我们在在线阶段采用了额外的技术,包括减少任务生成更可行的轨迹和基于价值差异的内在奖励来缓解稀疏奖励问题。我们称这种整体算法为PhAsic自拟约简(PAIR)。在稀疏奖励目标条件机器人控制问题(包括具有挑战性的堆叠任务)上,PAIR大大优于非相位RL和相位SL基线。PAIR是第一个RL方法,它学习了从零开始堆叠6个立方体,只有0/1的成功奖励。https://www.zhuanzhi.ai/paper/007d9cb1ce12650d123764621e0b319d
-
概述本文研究的主要内容主要是针对大规模图像检索问题,提出基于深度哈希的机器学习算法,实现快速高效的图像检索。同时,针对单标签下细粒度相似性缺失的问题,引入多标签下的相似性度量,关注图像对之间细粒度层面的相似情况,提高检索的精度。并且,将设计的算法在华为公司开发的MindSpore框架中实现,应用到无人机遥感图像的检索任务中去。整体的技术路线如图1所示。图1 技术路线项目地址cid:link_1相关配置操作系统Ubuntu Server 18.04 64bitCUDA10.1环境MindSpore-gpu 1.5.1语言Python 3.7MLRSNet数据集本文使用的数据集为公开的多标签数据集MLRSNet,它包含109161个高分辨率遥感图像,这些图像被注释为46个类别,并且该类别中的样本图像数量从1500到3000不等。但是由于使用的服务器等条件限制,最终实验时选取了部分数据进行试验,标签数目不变。图像的固定大小为256×256具有各种像素分辨率的像素。此外,数据集中的每个图像都标记有60个预定义的类别标签中的几个,并且与每个图像相关联的标签的数量从1到13不等,下表中列出了与每个预定义标签关联的数据集中存在的图像数量。图2 MLRSNet数据集数据集下载地址:cid:link_0实现流程记录1.工作流程基于图像检索问题的框架,下图3展示了用于监督哈希码学习的深度哈希网络的流程图。该方法以成对图像标签形式接受输入图像的标签和相似性度量,并通过卷积神经网络来提取图像的高级特征和输出哈希编码。使用的卷积神经网络使用多个卷积池化层来执行图像提取,全连接层来近似最优降维表示,哈希层来生成q位哈希码。在该模型中,引入了一种交叉熵损失和均方误差损失结合在一起的成对相似度损失来保持相似学习,以保持细粒度的成对相似度,并采用一个量化损失对紧凑哈希编码施加约束。图3 基于多标签的软成对相似性的深度哈希图像检索框架2.图像哈希码相似性度量多标签图像检索在一定程度上能够关注到图像对之间细粒度层面上的相似性,返回更为相似的图像。因此,在深度哈希算法的基础上,本文引入了新的相似度定义方法——“软相似性度量”与“硬相似性度量”,“硬相似性”相当于单标签场景,表示完全相似或者完全不相似;“软相似性”用于关注细粒度层面的相似性,定义为连续的实值,数值越大则相似性越低。本文中,成对相似度被量化成百分比,用以表示“软相似性度量”,相似度值定义为成对标签向量的余弦距离,计算公式如下。3.损失函数为了高效的近邻搜索,需要在汉明空间中保持原始图像的语义相似度。针对“软相似性度量”与“硬相似性度量”的不同情况,分别使用两种不同的损失函数,并在最后加上正则项,进行两者的联合学习。4.实验结果
-
基于MindSpore框架的室内场景图像分割方法研究概述本文以华为最新国产深度学习框架Mindspore为基础,研究室内场景语义分割方法。本文基于注意力机制改进U-Net网络,并选取VGG16与ResNet50作为骨干网络,并且利用VGG16与ResNet50的预训练权重进行迁移学习。整体的技术路线如图1所示。 图1(技术路线图)项目地址cid:link_1相关配置名称配置信息NPUAscend910操作系统Ubuntu 20.04编译器Python3.7框架MindSpore1.6NYU-V2数据集本文利用公开数据集NYU-V2作为实验数据集,选取该数据集被标注的RGB图片用于训练和测试。作为常用的语义分割数据集,NYU-V2面向各种类型任务,选取的数据是由微软的 RGB摄像机记录的各种室内场景图片组成,其中共有464个不同的室内场景、1449张图片、894个类别标签。由于在NYU-V2数据集中,接近70%的数据集标签由前10类标签组成,所以本文选取该数据集室内场景的主要语义类别:墙壁(wall)、地板(floor)、橱柜(cabinet)、床(bed)、椅子(chair)、沙发(sofa)、桌子(table)、门(door)、窗户(window)、书柜(bookshelf)作为训练分割的语义类别,NYU-V2数据集中其他类别归为背景(background)类数据集下载地址:NYU Depth V2 « Nathan SilbermanNYU Depth V2 « Nathan Silberman实现流程记录1、基于U-Net网络实现室内场景语义分割模型U-Net是由Ronneberger 等人在2015年构建的一种完全对称的U型结构神经网络。参考华为官方gitee仓库的modelzoo克隆至本地,找到research/cv/unet目录,在此代码基础上进行修改。在原有U-Net模型的基础上,本文将输入图片的大小统一归为512×512,便于网络的卷积计算。本文实现的U-Net网络结构如图2所示。2、模型权重文件转换MindSpore采用ModelCheckpoint对象保存模型参数到CheckPoint文件(简称ckpt文件),由于MindSpore目前没有VGG16和ResNet50的相关预训练模型,导致本文在迁移学习的过程中无法直接使用MindSpore官方提供的预训练权重。PyTorch上采用pth文件保存模型参数且与MindSpore在保存模型参数的机制上不同,无法直接采用PyTorch上的预训练权重加载到MindSpore中。本文在查阅了MindSpore与PyTorch相关文档后,成功编写了将pth模型文件转换为ckpt模型文件的脚本。经过实际训练发现该脚本切实有效的解决了MindSpore中预训练模型缺失的问题。3、优化器的选择优化器运用在神经网络的反向传播中,通过引导损失函数的参数向正确的方向更新适当的大小,使得损失函数的值能够到达全局最优。其中最为重要的两个部分是优化方向和步长。本文选取Adam作为模型训练的优化器,Adam是SGD、AdsGrad等优化器的集大成者,能够有效控制学习率步长和梯度方向。本文由于运用到了迁移学习故将整个训练分为两个阶段。第一阶段冻结骨干网络预训练权重,将主要资源运用在扩张路径上,从而缩短训练时间,节约训练资源。第二阶段解冻骨干网络的参数,让网络中的所有参数参与训练。通过冻结训练后再解冻可以加快训练效率同时防止骨干网络的参数权值被破坏,从而获得更好的训练效果。结果展示图像的预测结果示例定量结果比较
-
多进程转MindRecord背景信息MindRecord数据在MindSpore中读取性能更优,推荐用户将其他格式的数据集转换为MindRecord格式。经验总结利用multiprocessing.Pool接口,实现多进程运行。将Cifar10图片格式数据集,转换成MindRecord格式,并进行性能对比。与单进程方式相比,多进程中需进行如下配置(具体差异详见代码附件):total_data_length = len(os.listdir(os.path.join(argv.data_define_path, argv.path)))part_num = math.ceil(total_data_length / argv.multi_num)left = total_data_length % part_numif left == 0: left = part_numtotal_index_with_length = []for i in range(argv.multi_num - 1): total_index_with_length.append([i * part_num, part_num])total_index_with_length.append([(argv.multi_num - 1) * part_num, left])pool_list = []for i, index_with_length in enumerate(total_index_with_length): pool_list.append((argv, index_with_length[0], index_with_length[1], i))with Pool(processes=argv.multi_num) as pool: pool.map(process_single_writer, pool_list)其中argv.multi_num为进程数;process_single_writer和单进程中的转换方式相同;pool_list为每个进程传入参数。注:当数据集较大时,推荐在训练环境中利用训练环境机器的本地SSD(开发环境中使用EFS会影响数据转换性能),并选用8卡规格进行转换(若选用1卡的规格,CPU/内存/SSD空间(一共3.3T) 都只会被分到1/8 )。需要注意的是8卡任务会起8次脚本导致重复转换,可以通过RANK_ID来控制,使仅有一个脚本正常执行;性能对比:多进程转MindRecord: 8886.35imgs/sec ; 单进程转MindRecord:2133.79imgs/sec一个Epoch最后一个Batch的数据不足背景信息一个Epoch的迭代次数=图片总数/Batch Size,如果不能整除,就会出现最后一个Batch的数据不足。目前如果Batch Size数据不足会报错。经验总结如果迭代一个Epoch的末尾训练报错结束,可以检查是否该问题导致的,可以通过如下配置规避drop_remainder=true代码示例如下:import mindspore.dataset as ds# data is an instance of Dataset object# declare an apply_func function which returns a Dataset objectdef apply_func(ds): ds = ds.batch(2, drop_remainder=true) return ds# use apply to call apply_funcdata = data.apply(apply_func)TFRecord数据读取背景信息TFRecord数据文件是一种将图像数据和标签统一存储的二进制文件,能更好的利用内存,在TensorFlow中快速的复制,移动,读取,存储等。经验总结TFRecord的读取FP32图片数据使用tostring保存为TFRecord,若直接使用TFRecordDataset读取为UINT8格式,而MindSpore中暂时缺少tf.decode_raw这样类似功能的算子,需要自己手动进行数据转化,转化代码如下:def trans_dtype(data, target): trans_to_float32 = lambda x: np.frombuffer(np.ndarray.tobytes(x), dtype=np.float32) input_size = 128 data = np.reshape(trans_to_float32(data), (input_size, input_size, 10)) target = np.reshape(trans_to_float32(target), (input_size, input_size, 10)) return data, targettfdataset = tfdataset.map(input_columns=['data', 'target'], operations=trans_dtype)自动生成Schema与预先定义Schema训练数据含有两批不同大小的数据(Key值不同),如A中包含{a,b,c}3种Key及其值,B种包含{a,b,c,d}4种Key及其值,目前训练任务中只需要两批数据中{a,b}2种Key及其值即可。 以读取TFRecord为例:DATA #A+Btfdataset = de.TFRecordDataset(dataset_files=DATA) # (1)DATA #B+Atfdataset = de.TFRecordDataset(dataset_files=DATA) # (2)以上两种写法中,(2)写法会报错。其关键在于DATA的构造,在读取数据过程中,如果不进行Schema的定义,MindSpore会在读取第一个数据的时候根据读取到的数据本身自行定义Schema。所以如果先读取B类数据,自动生成的Schema会包含{a,b,c,d}4个Key,而之后读取A类数据的时候得不到key=d的值,此时便会报错。所以较为恰当的做法是事先在程序中定义好Schema,如:DATA # B+A或A+Bschema = de.Schema()schema.add_column('a')schema.add_column('b')tfdataset = de.TFRecordDataset(dataset_files=DATA, schema=schema)NHWC到NCHW的转化数据读入时是NHWC的形式,需转化为NCHW的形式送入网络data = data.transpose(2,0,1)target = target.transpose(2,0,1) # (1)import mindspore.transforms.py_transforms as Ttransforms = T.ComposeOp([T.HWC2CHW()])tfdataset = tfdataset.map(input_columns='target', operations=())tfdataset = tfdataset.map(input_columns='data', operations=transforms()) # (2)得到的数据Shape是正确的,但是数据会被打乱,图片写出不正常;(2)使用T.HWC2CHW()则可以得到Shape正确数据顺序正确的图片,图片写出正常。MindData数据处理流程推荐顺序背景信息MindData包含的数据处理操作包括Repeat、Batch、Shuffle、Map和Zip,一般训练过程中都会用到Repeat、Batch、Shuffle和Map的操作。经验总结在实际使用过程中,需要组合使用这几个操作时,为达到最优性能,推荐按照如下顺序:数据集加载并shuffle -> Map -> Batch -> Repeat。 原因是shuffle操作需要填充足够数据之后才会往下走,如果是先Load和Map的话,Shuffle很容易受到Map的阻塞导致Pipeline无法并行处理。示例代码如下:import mindspore.dataset as dsimport mindspore.dataset.transforms.vision.py_transforms as transformsDATA_DIR = "custom_dataset_dir/"imagefolder_dataset = ds.ImageFolderDatasetV2(dataset_dir, shuffle=True)resize_op = transforms.Resize(size=(500,500))# map()dataset.map(input_columns="image", operations=resize_op)# batch()dataset = dataset.batch(32, drop_remainder=True)# repeat()dataset = dataset.repeat(10)数据分布式方式背景信息PyTorch的数据分布式方式是ddp(distributeddataparallel)或者dp(dataparallel),而MindSpore的数据分布式方式是ddp(distributeddataparallel)。经验总结内容dp和ddp的区别就是数据集是集中在一台机器还是分发到每台机器。差别是用户对batchsize的设置,如果是dp,batchsize=total_batchsize。如果是ddp,batchsize=per_gpu_batch。因此MindSpore的batchsize=per_gpu_batch。
-
MindSpore保存的模型文件转换为PyTorch中的模型文件输入 MindSpore的ckpt文件,以ResNet-18为例,MindSpore的网络结构和PyTorch保持一致,转完之后可直接加载进网络,这边参数只用到bn和conv2d,若有其他层MindSpore和PyTorch名称不一致,需要同样的修改名称。作用:方便和PyTorch训练结果对比如果不确定自己训练的结果是不是正确(MindSpore的前向目前可能存在问题),可转到PyTorch上跑前向看看转换脚本:from mindspore.train.serialization import load_checkpointimport torchdef mindspore2pytorch(ckpt_name='res18_ms.ckpt'): par_dict = load_checkpoint(ckpt_name) state_dict = {} state_dict_useless = ['global_step', 'learning_rate', 'beta1_power', 'beta2_power'] for name in par_dict: parameter = par_dict[name].data if name in state_dict_useless or name.startswith('moment1.') or name.startswith('moment2.'): pass else: print('========================ms_name:', name ) if name.endswith('.beta'): name = name[:name.rfind('.beta')] name = name + '.bias' elif name.endswith('.gamma'): name = name[:name.rfind('.gamma')] name = name + '.weight' elif name.endswith('.moving_mean'): name = name[:name.rfind('.moving_mean')] name = name + '.running_mean' elif name.endswith('.moving_variance'): name = name[:name.rfind('.moving_variance')] name = name + '.running_var' print('========================py_name:', name ) state_dict[name] = torch.from_numpy(parameter.asnumpy()) ###torch.save({'state_dict' : state_dict}, 'res18_py.pth')PyTorch保存的模型文件转换为MindSpore中的模型文件输入 PyTorch的pth文件,以ResNet-18为例,MindSpore的网络结构和PyTorch保持一致,转完之后可直接加载进网络,这边参数只用到BN和Conv2D,若有其他层MindSpore和PyTorch名称不一致,需要同样的修改名称。作用:有的网络训练的时候必须加载一些预训练权重,将PyTorch的预训练权重转到MindSpore支持的格式。转换脚本:from mindspore.train.serialization import save_checkpointfrom mindspore import Tensorimport torchdef pytorch2mindspore(ckpt_name='res18_py.pth'): par_dict = torch.load(ckpt_name, map_location=torch.device('cpu')) new_params_list = [] for name in par_dict: param_dict = {} parameter = par_dict[name] print('========================py_name',name) if name.endswith('normalize.bias'): name = name[:name.rfind('normalize.bias')] name = name + 'normalize.beta' elif name.endswith('normalize.weight'): name = name[:name.rfind('normalize.weight')] name = name + 'normalize.gamma' elif name.endswith('.running_mean'): name = name[:name.rfind('.running_mean')] name = name + '.moving_mean' elif name.endswith('.running_var'): name = name[:name.rfind('.running_var')] name = name + '.moving_variance' print('========================ms_name',name) param_dict['name'] = name param_dict['data'] = Tensor(parameter.numpy()) new_params_list.append(param_dict) save_checkpoint(new_params_list, 'res18_ms.ckpt')详细代码内容请见附件
-
问题一开发人员在多张网络使用dropout算子时,dropout算子中seed1值会有变化,可能会导致产生调试精度差异。创建简单示例import numpy as npimport mindspore.ops as opsfrom mindspore import Tensor, contextfrom mindspore.ops import operations as Pimport mindspore.nn as nnimport mindspore#保存数据context.set_context(mode=context.GRAPH_MODE, device_target="Ascend")class PrintDemo1(nn.Cell): def __init__(self): super(PrintDemo1, self).__init__() self.conv1 = nn.Conv2d(in_channels=1, out_channels=6, kernel_size=4, stride=1 ,has_bias=False, weight_init='normal', pad_mode='valid') self.conv2 = nn.Conv2d(in_channels=6, out_channels=2, kernel_size=2, pad_mode="valid") self.conv3 = nn.Conv2d(in_channels=2, out_channels=6, kernel_size=2, pad_mode="valid") self.dropout = nn.Dropout(keep_prob=0.6) def construct(self, input_data): x = self.conv1(input_data) x = self.dropout(x) x = self.conv2(x) x = self.conv3(x) return x class PrintDemo2(nn.Cell): def __init__(self): super(PrintDemo2, self).__init__() self.conv1 = nn.Conv2d(in_channels=1, out_channels=6, kernel_size=4, stride=1 ,has_bias=False, weight_init='normal', pad_mode='valid') self.conv2 = nn.Conv2d(in_channels=6, out_channels=2, kernel_size=2, pad_mode="valid") self.conv3 = nn.Conv2d(in_channels=2, out_channels=6, kernel_size=2, pad_mode="valid") self.dropout = nn.Dropout(keep_prob=0.6) def construct(self, input_data): x = self.conv1(input_data) x = self.dropout(x) x = self.conv2(x) x = self.conv3(x) return xmindspore.set_seed(123)def test(): input_data = Tensor(np.ones([1, 1, 32, 32]), mindspore.float32) net1 = PrintDemo1() net2 = PrintDemo2() net1(input_data) net2(input_data) return net1(input_data), net2(input_data)test()代码分析在以上示例代码中我们设置了一个全局seed=123,nn.Dropout源码中打印dropout中seed0与seed1,发现两次打印出seed0一致,而seed1有变化,具体打印结果如下图:问题二BN中的moving_mean和moving_variance不更新。经验总结内容在网络定义之后要加上set_train(),加上之后bn为训练模式才会更新moving_mean和moving_variance。示例如下:backbone = get_backbone(args)criterion = get_loss(args)train_net = BuildTrainNetwork(network, criterion, args)train_net.set_train()问题三MindData数据预处理中有用到c_transforms.Resize,该算子实现与torch_transforms.Resize实现不一致。经验总结内容MindData的第三方库和PyTorch的第三方库不一样(MindData使用的是OpenCV),因此c_transforms.Resize和torch_transforms.Resize的输出相比有点误差是正常的,不影响使用。问题四DUMP_train图没有某些算子的数据,因此网络进行精度调测的时候,经常要查看DUMP图中的算子信息。经验总结内容该问题可能是算子名过长导致的(算子名通过网络的脚本定义类名嵌套组合而成),需要设置如下参数:context.set_context(reserve_class_name_in_scope=False)详细代码信息请参考附件文件。
-
MindInsight主要功能介绍MindInsight详细功能介绍请参考MindInsight性能调试。MindInsight主页面包括主要功能的概览信息:迭代轨迹、算子耗时统计、数据准备、时间线、调优助手。迭代轨迹:展示了每个迭代各个阶段的性能信息:包括迭代间隙、前向反向、迭代拖尾以及每个all_reduce的信息。下方展示各个阶段的变化趋势。算子耗时统计:通过类型、详细信息两个维度展示AICORE和AICPU算子耗时统计信息。数据准备:性能分析分为两部分:1、迭代间隙数据处理分析;2、数据处理pipeline分析。迭代间隙阶段:下图展示了迭代间隙阶段执行的操作的流程,通过分析队列中数据的情况判断出现性能问题的步骤。数据处理阶段:分析用于已经定位到了该阶段的问题时,定位其中哪个算子存在问题,通过各个算子之间的队列的使用率,判断前面的算子能否提供足够的数据到队列中供下一个算子使用。时间线:展示了算子在各个stream上的起止时刻,执行顺序、算子间隙、allreduce信息,从详细的粒度展示算子执行情况。用户可参考下图,进行算子分析(常用的为MindData阶段分析和算子性能分析)。案例问题分析问题1:迭代间隙过长通过迭代轨迹发现,迭代间隙过长:问题分析1.迭代间隙过长,通常因为数据处理过程导致,进入数据处理阶段分析。2.主机队列几乎为空,判定是数据处理算子问题,进入数据处理pipeline查看具体问题。3.当算子左边连接的Queue使用率都比较高,右边连接的Queue使用率比较低时,该算子可能是性能瓶颈:图中红框内数据可以看出,map操作过程中的队列使用率高,而右边连接的队列使用率较低,判断map中的数据处理过程存在性能瓶颈。4.分析map中数据处理相关代码:发现数据处理进程数为默认值1,可以尝试调整数据处理进程数。5.分析map中数据处理相关代码:发现存在c_transform和py_transform混用的问题,降低了训练性能。措施1:调整数据处理进程数调整数据处理进程数为8:if do_train: cifar_ds = ds.Cifar10Dataset(dataset_dir=data_home, num_parallel_workers=8, shuffle=True, usage='train')else: cifar_ds = ds.Cifar10Dataset(dataset_dir=data_home, num_parallel_workers=8, shuffle=False, usage='test')cifar_ds = cifar_ds.map(operations=transform_label, num_parallel_workers=8, python_multiprocessing=True, input_columns="label")cifar_ds = cifar_ds.map(operations=transform_data, num_parallel_workers=8, python_multiprocessing=True, python_multiprocessing=True, input_columns="image")cifar_ds = cifar_ds.batch(batch_size, num_parallel_workers=8, drop_remainder=True)修改后,重新训练,将训练后代码继续做profiling,发现迭代间隙明显缩短。性能对比: 改进前:1100imgs/sec 改进后: 2150imgs/sec措施2:避免c_transform和py_transform混用数据处理过程中发现存在c_transform和py_transform混用的情况:if do_train: # Transformation on train datatransform_data = py_trans.Compose([ CV.RandomCrop((32, 32), (4, 4, 4, 4)), py_vision.ToPIL(), py_vision.RandomHorizontalFlip(), CV.Rescale(rescale, shift), CV.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010)), CV.HWC2CHW() ])else: # Transformation on validation data transform_data = py_trans.Compose([ CV.Rescale(rescale, shift), CV.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010)), CV.HWC2CHW() ]) cifar_ds = cifar_ds.map(operations=transform_data, input_columns="image")将数据处理过程中代码进行如下修改:if do_train: # Transformation on train data transform_data = C.Compose([ CV.RandomCrop((32, 32), (4, 4, 4, 4)), CV.RandomHorizontalFlip(), CV.Rescale(rescale, shift), CV.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010)), CV.HWC2CHW()]) else: # Transformation on validation data transform_data = C.Compose([ CV.Rescale(rescale, shift), CV.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010)), CV.HWC2CHW()])cifar_ds = cifar_ds.map(operations=transform_data, input_columns="image")修改后,重新训练,将训练后代码继续做profiling。迭代间隙有所缩短。性能对比: 改进前:2150imgs/sec 改进后: 2250imgs/sec经过这两步优化,迭代间隙由原来的77.5027ms减少到17.0623ms,有明显改善。问题2:数据队列为空继续分析优化后的Profiler数据,发现数据准备中的主机队列几乎为空:问题分析进入数据处理pipeline查看具体问题。2.如红框所示,数据处理过程中的队列使用率高。对于最右侧的算子,如果其左边所有Queue的使用率都比较高,该算子可能是性能瓶颈。而此处最右侧算子为框架自动插入算子,因此判断数据下发存在性能瓶颈,应提升数据从Host传输到Device的速度。措施3:采用数据下沉模式采用数据下沉模式,实现整图下沉到Device执行,避免Host-Device频繁交互,减小了数据传输开销。将Model.train接口中dataset_sink_mode值设为True,即可采用数据下沉模式。model.train(..., dataset_sink_mode=True, sink_size=steps_per_epoch_train)修改后,重新训练,将训练后代码继续做profiling,发现主机队列为空比例大大下降。数据处理过程中的队列使用率明显降低。性能对比: 改进前:2250imgs/sec 改进后: 2350imgs/sec问题3:前向+反向时间较长继续分析优化后的Profiler数据,由迭代轨迹看出,前反向时间相对较长,可能存在优化空间:措施4:使用混合精度使用混合精度可以加速训练,减少前反向时间。修改高阶API代码中的Model接口,将amp_level设置成"O3",网络将采用FP16进行训练。net = Model(net, loss, opt, metrics=metrics, amp_level="O3")修改后,重新训练,将训练后代码继续做profiling。发现前反向时间明显减少。性能对比: 改进前:2350imgs/sec 改进后: 3500imgs/sec经过以上优化,训练性能得到明显提升。由初始的1100imgs/sec,改进到3500imgs/sec。详细代码请参考附件文件。
-
本文介绍如何在ModelArts开发环境中收集profiler以及按需开启profiler进行性能调试。一、开发环境训练脚本收集profiler数据为了收集神经网络的性能数据,需要在训练脚本中添加MindSpore Profiler相关接口。1.set_context之后,初始化网络、以及初始化HCCL之前,需要初始化MindSpore Profiler对象。2.在训练结束后,调用Profiler.analyse()停止性能数据收集并生成性能分析结果。样例代码如下:from mindspore.profiler import Profilerfrom mindspore import Modelcontext.set_context(mode=context.GRAPH_MODE, device_target=args.device_target)SAVE_PATH = "./profile"# Init Profiler and SummaryCollector# Data directory should be placed under SAVE_PATH.profiler_output_path = SAVE_PATH + "mindspore_profile"profiler = Profiler(output_path=profiler_output_path)# Train ModelModel.train()# Profiler endprofiler.analyse()注:output_path为生成profiler数据路径,若未指定该路径,profiler数据将自动在当前目录下生成data文件夹并将profiler数据保存至此。二、按需收集profiler进行性能调试开启Profiler数据采集,可以按条件开启Profiler1、按Step收集Profiler数据样例代码如下:class 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() # 开启Profiler数据采集,可以按条件开启Profiler。 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() # 停止Profiler,可以按条件停止Profiler。 def end(self, run_context): self.profiler.analyse()......start_step = 2stop_step = 5profiler_data = StopAtEpoch(start_step, stop_step)model.train(..., callbacks=[..., profiler_data])2、按Epoch收集Profiler数据样例代码如下:class StopAtEpoch(Callback): def __init__(self, start_epoch, stop_epoch): super(StopAtEpoch, 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 epoch_num == self.start_epoch: self.profiler.start() # 开启Profiler数据采集,可以按条件开启Profiler。 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() # 停止Profiler,可以按条件停止Profiler。 def end(self, run_context): self.profiler.analyse()......start_epoch = 2stop_epoch = 5profiler_data = StopAtEpoch(start_epoch, stop_epoch)model.train(..., callbacks=[..., profiler_data])三、运行脚本启动命令:python MindSpore_1P_profiler.py data_path=xxx在开发环境的Terminal中运行脚本,运行结束后,生成的Profiling数据存放在SAVE_PATH中。注:按需收集profiler性能调试不支持自定义数据保存路径,故在程序运行结束后会默认将profiler数据保存到当前目录下data文件中。注意事项:1.训练加推理过程暂不支持性能调试,目前支持单独训练或推理的性能调试。2.Ascend性能调试暂不支持动态shape场景、多子图场景和控制流场景。详细代码请参加附件。
-
本文给大家介绍几种常用的性能调优方法。调整数据处理进程数MindSpore Data中的某些算子接收num_parallel_workers参数,该参数设置了算子使用的线程数。根据物理内核的数量和目标系统的负载,增加管道中num_parallel_workers的值,可以提高性能。对于任何包含计算密集型Tensor运算(比如Decode)的Map算子而言,尤其如此。使用默认数据处理进程数(为1):if do_train: cifar_ds = ds.Cifar10Dataset(dataset_dir=data_home, shuffle=True, usage='train')else: cifar_ds = ds.Cifar10Dataset(dataset_dir=data_home, shuffle=False, usage='test')cifar_ds = cifar_ds.map(operations=transform_label, input_columns="label")cifar_ds = cifar_ds.map(operations=transform_data, input_columns="image")cifar_ds = cifar_ds.batch(batch_size, drop_remainder=True)调整数据处理进程数为2:if do_train: cifar_ds = ds.Cifar10Dataset(dataset_dir=data_home, num_parallel_workers=2, shuffle=True, usage='train')else: cifar_ds = ds.Cifar10Dataset(dataset_dir=data_home, num_parallel_workers=2, shuffle=False, usage='test')cifar_ds = cifar_ds.map(operations=transform_label, num_parallel_workers=2, python_multiprocessing=True, input_columns="label")cifar_ds = cifar_ds.map(operations=transform_data, num_parallel_workers=2, python_multiprocessing=True, python_multiprocessing=True, input_columns="image")cifar_ds = cifar_ds.batch(batch_size, num_parallel_workers=2, drop_remainder=True)运行后性能对比:使用默认数据处理进程数:2200 imgs/sec ;调整数据处理进程数为2:2300 imgs/sec使用MindRecord格式加载数据目前MindSpore Data支持的特定格式数据集为:MindRecord。使用MindRecord格式的加载数据性能更优。MindRecord数据加载流程:import mindspore.dataset as dsCV_FILE_NAME = "./cifar10.mindrecord"cifar_ds = ds.MindDataset(dataset_file=CV_FILE_NAME,columns_list=["data","label"], shuffle=True)运行后性能对比: 自定义数据集加载cifar10:850 imgs/sec;MindRecord格式加载cifar10:2200 imgs/sec加载数据集时shuffle数据集加载时shuffle,算子可以在生成输出Tensor之前对数据进行内部shuffle。与在管道中使用显式shuffle算子相比,这种内部shuffle通常会带来更好的性能。管道中使用显式shuffle:import mindspore.dataset as dsDATA_DIR = "./cifar-10-batches-bin/"cifar_ds = ds.Cifar10Dataset(DATA_DIR, usage='train')cifar_ds = cifar_ds.shuffle(buffer_size=10000)加载数据集时shuffle:import mindspore.dataset as dsDATA_DIR = "./cifar-10-batches-bin/"cifar_ds = ds.Cifar10Dataset(DATA_DIR, shuffle=True, usage='train')运行后性能对比:本样例未见明显性能收益混合精度混合精度训练方法是通过混合使用单精度和半精度数据格式来加速深度神经网络训练的过程,同时保持了单精度训练所能达到的网络精度。混合精度训练能够加速计算过程,同时减少内存使用和存取,并使得在特定的硬件上可以训练更大的模型或batch size。运行后性能对比:高阶API: 2200 imgs/sec ;高阶API混合精度: 3300 imgs/sec 低阶API: 2000 imgs/sec ;低阶API混合精度: 3200 imgs/sec数据下沉采用数据集的下沉模式,即训练计算下沉到硬件平台中执行,数据下沉可以优化训练性能。将Model.train接口中dataset_sink_mode 值设为True,即可采用数据下沉模式。数据未下沉:model.train(..., dataset_sink_mode=False, ...)数据下沉:model.train(..., dataset_sink_mode=True, sink_size=steps_per_epoch_train)注:低阶API不支持数据下沉,若想实现数据下沉请使用Model.train接口进行训练。运行后性能对比:数据未下沉:2000 imgs/sec;数据下沉:2200 imgs/sec避免c_transform和py_transform混用c_transform是在C++内维护buffer管理,py_transform是在python内维护buffer管理。因为python和C++切换的性能成本,建议不要混用算子,否则会降低训练性能。c_transform和py_transform混用:if do_train: # Transformation on train datatransform_data = py_trans.Compose([ CV.RandomCrop((32, 32), (4, 4, 4, 4)), py_vision.ToPIL(), py_vision.RandomHorizontalFlip(), CV.Rescale(rescale, shift), CV.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010)), CV.HWC2CHW() ])else: # Transformation on validation data transform_data = py_trans.Compose([ CV.Rescale(rescale, shift), CV.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010)), CV.HWC2CHW() ]) cifar_ds = cifar_ds.map(operations=transform_data, input_columns="image")c_transform和py_transform未混用:if do_train: # Transformation on train data transform_data = C.Compose([ CV.RandomCrop((32, 32), (4, 4, 4, 4)), CV.RandomHorizontalFlip(), CV.Rescale(rescale, shift), CV.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010)), CV.HWC2CHW()]) else: # Transformation on validation data transform_data = C.Compose([ CV.Rescale(rescale, shift), CV.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010)), CV.HWC2CHW()])cifar_ds = cifar_ds.map(operations=transform_data, input_columns="image")运行后性能对比:c_transform和py_transform混用:1100 imgs/sec; c_transform和py_transform未混用:2200 imgs/sec多map合并单map数据预处理时,Map算子可以接收Tensor算子列表,并将按顺序应用所有的这些算子。与为每个Tensor算子使用单独的Map算子相比,可以获得更好的性能。多map数据预处理:randomcrop_op = CV.RandomCrop((32, 32), (4, 4, 4, 4))randomhorizontalflip_op = CV.RandomHorizontalFlip()rescale_op = CV.Rescale(rescale, shift)normalize_op = CV.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010))hwc2chw_op = CV.HWC2CHW()if do_train: cifar_ds = cifar_ds.map(operations=[randomcrop_op], input_columns="image") cifar_ds = cifar_ds.map(operations=[randomhorizontalflip_op], input_columns="image")cifar_ds = cifar_ds.map(operations=[rescale_op], input_columns="image")cifar_ds = cifar_ds.map(operations=[normalize_op], input_columns="image")cifar_ds = cifar_ds.map(operations=[hwc2chw_op], input_columns="image")else:cifar_ds = cifar_ds.map(operations=[rescale_op], input_columns="image")cifar_ds = cifar_ds.map(operations=[normalize_op], input_columns="image")cifar_ds = cifar_ds.map(operations=[hwc2chw_op], input_columns="image")合并成单map数据预处理:if do_train: # Transformation on train data transform_data = C.Compose([ CV.RandomCrop((32, 32), (4, 4, 4, 4)), CV.RandomHorizontalFlip(), CV.Rescale(rescale, shift), CV.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010)), CV.HWC2CHW()])else: # Transformation on validation data transform_data = C.Compose([ CV.Rescale(rescale, shift), CV.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010)), CV.HWC2CHW()])cifar_ds = cifar_ds.map(operations=transform_data, input_columns="image")运行后性能对比:本样例未见明显性能收益融合算子MindSpore Data提供某些融合算子,这些算子将两个或多个算子的功能聚合到一个算子中。 与它们各自组件的流水线相比,这种融合算子提供了更好的性能。一个很好的融合算子是RandomCropDecodeResizeOp,它执行解码,然后对任意给定的Tensor进行随机裁剪和大小调整。用户可以查看算子API文档查看是否有相应融合算子替代现有算子,以获得更好性能。自动数据加速MindSpore提供了一种自动数据调优的工具——Dataset AutoTune,用于在训练过程中根据环境资源的情况自动调整数据处理管道的并行度,最大化利用系统资源加速数据处理管道的处理速度。在整个训练的过程中,Dataset AutoTune模块会持续检测当前训练性能瓶颈处于数据侧还是网络侧。如果检测到瓶颈在数据侧,则将进一步对数据处理管道中的各个算子(如GeneratorDataset、map、batch此类数据算子)进行参数调整。详细代码请点击附件进行下载
-
一、概述混合精度训练方法是通过混合使用单精度和半精度数据格式来加速深度神经网络训练的过程,同时保持了单精度训练所能达到的网络精度。混合精度训练能够加速计算过程,同时减少内存使用和存取,并使得在特定的硬件上可以训练更大的模型或batch size。MindSpore混合精度典型的计算流程如下图所示:1、参数以FP32存储;2、正向计算过程中,遇到FP16算子,需要把算子输入和参数从FP32 cast成FP16进行计算;3、将Loss层设置为FP32进行计算;4、反向计算过程中,首先乘以Loss Scale值,避免反向梯度过小而产生下溢;5、FP16参数参与梯度计算,其结果将被cast回FP32;6、除以Loss scale值,还原被放大的梯度;7、判断梯度是否存在溢出,如果溢出则跳过更新,否则优化器以FP32对原始参数进行更新。二、使用场景由于混合精度能带来加速计算,减少内存占用的优势,因此用户在遇到以下情况可以考虑使用混合精度:1、内存资源不足;2、训练速度较慢。三、使用条件本文档是针对以下两类使用场景的的用户:1、即将启动MindSpore训练代码迁移任务,并对MindSpore有基础了解;2、已完成MindSpore训练代码迁移任务,即有可使用的MindSpore训练代码。四、使用样例1、MindSpore高阶API使用混合精度MindSpore在mindspore.Model接口中做了封装,方便用户调用。具体实现步骤与编写普通训练代码过程没有区别。只需要在Model中设置混合精度相关参数,如amp_level, loss_scale_manager, keep_batchnorm_fp32。修改高阶API代码中的Model接口,将amp_level设置成"O3",网络将采用混合精度进行训练。net = Model(net, loss, opt, metrics=metrics, amp_level="O3")2、MindSpore低阶API使用混合精度MindSpore低阶API使用混合精度,只需在MindSpore低阶API代码构造模型步骤中,将网络设置成混合精度进行训练。下面对比两者构造模型的区别。MindSpore低阶API代码中构造模型:class BuildTrainNetwork(nn.Cell): '''Build train network.''' def __init__(self, my_network, my_criterion, train_batch_size, class_num): super(BuildTrainNetwork, self).__init__() self.network = my_network self.criterion = my_criterion self.print = P.Print() # Initialize self.output self.output = mindspore.Parameter(Tensor(np.ones((train_batch_size, class_num)), mindspore.float32), requires_grad=False) def construct(self, input_data, label): output = self.network(input_data) # Get the network output and assign it to self.output self.output = output loss0 = self.criterion(output, label) return loss0class TrainOneStepCellV2(TrainOneStepCell): def __init__(self, network, optimizer, sens=1.0): super(TrainOneStepCellV2, self).__init__(network, optimizer, sens=1.0) def construct(self, *inputs): weights = self.weights loss = self.network(*inputs) # Obtain self.network from BuildTrainNetwork output = self.network.output sens = P.Fill()(P.DType()(loss), P.Shape()(loss), self.sens) # Get the gradient of the network parameters grads = self.grad(self.network, weights)(*inputs, sens) grads = self.grad_reducer(grads) # Optimize model parameters loss = F.depend(loss, self.optimizer(grads)) return loss, output model_constructed = BuildTrainNetwork(net, loss_function, TRAIN_BATCH_SIZE, CLASS_NUM)model_constructed = TrainOneStepCellV2(model_constructed, opt)MindSpore低阶API混合精度代码中构造模型:class BuildTrainNetwork(nn.Cell): '''Build train network.''' def __init__(self, my_network, my_criterion, train_batch_size, class_num): super(BuildTrainNetwork, self).__init__() self.network = my_network self.criterion = my_criterion self.print = P.Print() # Initialize self.output self.output = mindspore.Parameter(Tensor(np.ones((train_batch_size, class_num)), mindspore.float32), requires_grad=False) def construct(self, input_data, label): output = self.network(input_data) # Get the network output and assign it to self.output self.output = output loss0 = self.criterion(output, label) return loss0class TrainOneStepCellV2(TrainOneStepCell): '''Build train network.''' def __init__(self, network, optimizer, sens=1.0): super(TrainOneStepCellV2, self).__init__(network, optimizer, sens=1.0) def construct(self, *inputs): weights = self.weights loss = self.network(*inputs) # Obtain self.network from BuildTrainNetwork output = self.network.output sens = P.Fill()(P.DType()(loss), P.Shape()(loss), self.sens) # Get the gradient of the network parameters grads = self.grad(self.network, weights)(*inputs, sens) grads = self.grad_reducer(grads) # Optimize model parameters loss = F.depend(loss, self.optimizer(grads)) return loss, output def build_train_network_step2(network, optimizer, loss_fn=None, level='O0', **kwargs): """ Build the mixed precision training cell automatically. """ amp.validator.check_value_type('network', network, nn.Cell) amp.validator.check_value_type('optimizer', optimizer, nn.Optimizer) amp.validator.check('level', level, "", ['O0', 'O2', 'O3', "auto"], amp.Rel.IN) if level == "auto": device_target = context.get_context('device_target') if device_target == "GPU": level = "O2" elif device_target == "Ascend": level = "O3" else: raise ValueError( "Level `auto` only support when `device_target` is GPU or Ascend.") amp._check_kwargs(kwargs) config = dict(amp._config_level[level], **kwargs) config = amp.edict(config) if config.cast_model_type == mstype.float16: network.to_float(mstype.float16) if config.keep_batchnorm_fp32: amp._do_keep_batchnorm_fp32(network) if loss_fn: network = amp._add_loss_network(network, loss_fn, config.cast_model_type) if amp._get_parallel_mode() in (amp.ParallelMode.SEMI_AUTO_PARALLEL, amp.ParallelMode.AUTO_PARALLEL): network = amp._VirtualDatasetCell(network) loss_scale = 1.0 if config.loss_scale_manager is not None: loss_scale_manager = config.loss_scale_manager loss_scale = loss_scale_manager.get_loss_scale() update_cell = loss_scale_manager.get_update_cell() if update_cell is not None: # only cpu not support `TrainOneStepWithLossScaleCell` for control flow. if not context.get_context("enable_ge") and context.get_context("device_target") == "CPU": raise ValueError("Only `loss_scale_manager=None` and " "`loss_scale_manager=FixedLossScaleManager`" "are supported in current version. If you use `O2` option," "use `loss_scale_manager=None` or `FixedLossScaleManager`") network = TrainOneStepCellV2(network, optimizer) return network network = TrainOneStepCellV2(network, optimizer) return network model_constructed = BuildTrainNetwork(net, loss_function, TRAIN_BATCH_SIZE, CLASS_NUM)model_constructed = build_train_network_step2(model_constructed, opt, level="O3")五、性能对比相比全精度训练,使用混合精度后,获得了可观的性能提升。低阶API: 2000 imgs/sec ;低阶API混合精度: 3200 imgs/sec高阶API: 2200 imgs/sec ;高阶API混合精度: 3300 imgs/sec详细代码请见附件。
-
一、简介首先MindSpore Data提供了简洁、丰富的数据读取、处理、增强等功能;同时使用读取数据的流程,主要分为三步(使用和PyTorch中数据读取方式类似): 数据集加载 - 根据数据格式,选择最简单、高效的数据集加载方式; 数据增强 - 使用几何变换、颜色变换、旋转、平移、缩放等基本图像处理技术来扩充数据集;数据处理 - 对数据集做repeat、batch、shuffle、map、zip等操作。二、使用说明1、数据集加载首先加载要使用的数据集,根据实际使用的数据集格式,从以下三种数据集读取方式选取一种即可:常用标准数据集:例如 ImageNet、MNIST、CIFAR-10、VOC等;特定格式数据集 :特定存储格式的数据,例如:MindRecord;自定义数据集:数据组织形式自定义的数据集。2.1 常用数据集加载目前已经支持的常用数据集有:MNIST, CIFAR-10, CIFAR-100, VOC, ImageNet, CelebA。如果使用以上开源数据集或者已经将所使用的数据整理为以上标准数据集格式,可以直接使用如下方法加载数据集。以CIFAR-10为例:import mindspore.dataset as dsDATA_DIR = "./cifar-10-batches-bin/"cifar_ds = ds.Cifar10Dataset(DATA_DIR)数据集加载好之后,就可以调用接口create_dict_iterator()创建迭代器读取数据,后面两种方式同理。for data in cifar_ds.create_dict_iterator():# In CIFAR-10 dataset, each dictionary of data has keys "image" and "label". print(data["image"]) print(data["label"])2.2 特定格式数据集加载目前支持的特定格式数据集为:MindRecord。MindRecord格式的数据读取性能更优,推荐用户将数据转换为MindRecord格式。转换示例如下:from mindspore.mindrecord import Cifar10ToMRcifar10_path = "./cifar-10-batches-py"mindrecord_path = "./cifar10.mindrecord"cifar10_transformer = Cifar10ToMR(cifar10_path, mindrecord_path)cifar10_transformer.transform(["label"])MindRecord数据加载:import mindspore.dataset as dsCV_FILE_NAME = "./cifar10.mindrecord"cifar_ds = ds.MindDataset(dataset_file=CV_FILE_NAME,columns_list=["data","label"], shuffle=True)2.3 自定义数据集加载提供的自定义数据集加载方式为:GeneratorDataset接口。GeneratorDataset接口需要自己实现一个生成器,生成训练数据和标签,适用于较复杂的任务。GeneratorDataset()需要传入一个生成器,生成训练数据。import mindspore.dataset as dsclass Dataset: def __init__(self, image_list, label_list): super(Dataset, self).__init__() self.imgs = image_list self.labels = label_list def __getitem__(self, index): img = Image.open(self.imgs[index]).convert('RGB') return img, self.labels[index] def __len__(self): return len(self.imgs)class MySampler(): def __init__(self, dataset): self.__num_data = len(dataset) def __iter__(self): indices = list(range(self.__num_data)) return iter(indices)dataset = Dataset(save_image_list, save_label_list)sampler = MySampler(dataset)cifar_ds = ds.GeneratorDataset(dataset, column_names=["image", "label"], sampler=sampler, shuffle=True)以上例子中 dataset是一个生成器,产生image和label。2、数据增强提供 c_transforms 和 py_transforms 两个模块来供用户完成数据增强操作,两者的对比如下:模块名称实现优缺点c_transforms基于C++的OpenCV实现性能较高py_transforms基于Python的PIL实现性能较差,但是可以自定义增强函数使用建议:如果不需要自定义增强函数,并且c_transforms中有对应的实现,建议使用c_transforms模块。2.1 c_transforms模块目前c_transforms接口包括两部分:mindspore.dataset.transforms.c_transforms和mindspore.dataset.vision.c_transforms。使用方法:1.定义好数据增强函数:把多个增强函数加入到一个list中,并调用Compose封装;2.调用dataset.map()函数,将定义好的函数或算子作用于指定的数据列。示例代码如下:import mindspore.dataset as dsimport mindspore.dataset.vision.c_transforms as CV_transformsimport mindspore.dataset.transforms.c_transforms as C_transformsDATA_DIR = "./cifar-10-batches-bin/"cifar_ds = ds.Cifar10Dataset(DATA_DIR, shuffle=True, usage='train')#定义增强函数列表transforms_list = C_transforms.Compose[ CV_transforms.RandomCrop((32, 32), (4, 4, 4, 4)),CV_transforms.RandomHorizontalFlip(),CV_transforms.Rescale(rescale, shift),CV_transforms.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010)),CV_transforms.HWC2CHW()]#调用map()函数cifar_ds = cifar_ds.map(operations=transforms_list, input_columns="image")其中,input_columns为指定要做增强的数据列,operations为定义的增强函数。2.2 py_transforms模块py_transforms接口也包括两部分mindspore.dataset.transforms.py_transforms和mindspore.dataset.vision.py_transforms。使用方法:和c_transforms模块中的使用方法类似。示例代码如下:import mindspore.dataset as dsimport mindspore.dataset.vision.py_transforms as py_visionimport mindspore.dataset.transforms.py_transforms as py_transformsDATA_DIR = "./cifar-10-batches-bin/"cifar_ds = ds.Cifar10Dataset(DATA_DIR, shuffle=True, usage='train')transform_list = py_transforms.Compose([ py_vision.ToPIL(), py_vision.RandomCrop((32, 32), (4, 4, 4, 4)), py_vision.RandomHorizontalFlip(), py_vision.ToTensor(), py_vision.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010))])cifar_ds = cifar_ds.map(operations=transforms_list, input_columns="image")使用py_transforms自定义增强函数:自定义增强函数可参考MindSpore源码中的py_transforms_util.py脚本。下面以RandomBrightness为例,说明自定义增强算子的定义方式:#自定义增强函数定义class RandomBrightness(object): """ Randomly adjust the brightness of the input image. Args: brightness (float): Brightness adjustment factor (default=0.0). Returns: numpy.ndarray, image. """ def __init__(self, brightness=0.0): self.brightness = brightness def __call__(self, img): alpha = random.uniform(-self.brightness, self.brightness) return (1-alpha) * img自定义算子的调用和py_transforms_util.py中的算子调用没有区别。3、数据处理数据处理操作有:zip、shuffle、map、batch、repeat。数据处理操作说明zip合并多个数据集shuffle混洗数据map将函数和算子作用于指定列数据batch将数据分批,每次迭代返回一个batch的数据repeat对数据集进行复制一般训练过程中都会用到shuffle、map、batch、repeat,如下示例:import mindspore.dataset as dsimport mindspore.dataset.vision.c_transforms as CV_transformsimport mindspore.dataset.transforms.c_transforms as C_transformsDATA_DIR = "./cifar-10-batches-bin/"cifar_ds = ds.Cifar10Dataset(DATA_DIR, shuffle=True, usage='train')transform_list = C.Compose([ CV.RandomCrop((32, 32), (4, 4, 4, 4)), CV.RandomHorizontalFlip(), CV.Rescale(rescale, shift), CV.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010)), CV.HWC2CHW()])# map()cifar_ds.map(input_columns="image", operations=transforms_list)# batch()cifar_ds = cifar_ds.batch(batch_size, drop_remainder=True)# repeat()cifar_ds = cifar_ds.repeat(repeat_num)在实际使用过程中,需要组合使用这几个操作时,为达到最优性能,推荐按照如下顺序: 数据集加载并shuffle -> map -> batch -> repeat。以下简单介绍一下数据处理函数的使用方法:3.1数据集加载与shuffle方式一:加载数据集时shuffleimport mindspore.dataset as dsDATA_DIR = "./cifar-10-batches-bin/"cifar_ds = ds.Cifar10Dataset(DATA_DIR, shuffle=True, usage='train')方式二:加载数据集后shuffleimport mindspore.dataset as dsDATA_DIR = "./cifar-10-batches-bin/"cifar_ds = ds.Cifar10Dataset(DATA_DIR, usage='train')cifar_ds = cifar_ds.shuffle(buffer_size=10000)参数说明:buffer_size:buffer_size越大,混洗程度越大,时间消耗更大3.2 map:func = lambda x : x*2cifar_ds = cifar_ds.map(input_columns="data", operations=func)参数说明:input_columns:函数作用的列数据operations:对数据做操作的函数3.3 batchcifar_ds = cifar_ds.batch(batch_size=32, drop_remainder=True, num_parallel_workers=4)参数说明:drop_remainder:舍弃最后不完整的batchnum_parallel_workers: 用几个线程来读取数据3.4 repeatcifar_ds = cifar_ds.repeat(count=2)参数说明:count: 数据集复制数量3.5 zipimport mindspore.dataset as dsDATA_DIR_1 = "custom_dataset_dir_1/"DATA_DIR_2 = "custom_dataset_dir_2/"imagefolder_dataset_1 = ds.ImageFolderDatasetV2(DATA_DIR_1)imagefolder_dataset_2 = ds.ImageFolderDatasetV2(DATA_DIR_2)imagefolder_dataset = ds.zip((imagefolder_dataset_1, imagefolder_dataset_2))详细代码请见附件。
推荐直播
-
OpenHarmony应用开发之网络数据请求与数据解析
2025/01/16 周四 19:00-20:30
华为开发者布道师、南京师范大学泰州学院副教授,硕士研究生导师,开放原子教育银牌认证讲师
科技浪潮中,鸿蒙生态强势崛起,OpenHarmony开启智能终端无限可能。当下,其原生应用开发适配潜力巨大,终端设备已广泛融入生活各场景,从家居到办公、穿戴至车载。 现在,机会敲门!我们的直播聚焦OpenHarmony关键的网络数据请求与解析,抛开晦涩理论,用真实案例带你掌握数据访问接口,轻松应对复杂网络请求、精准解析Json与Xml数据。参与直播,为开发鸿蒙App夯实基础,抢占科技新高地,别错过!
回顾中 -
Ascend C高层API设计原理与实现系列
2025/01/17 周五 15:30-17:00
Ascend C 技术专家
以LayerNorm算子开发为例,讲解开箱即用的Ascend C高层API
回顾中
热门标签