• [模型训练] Say Hello to MindSpore——基于LeNet5的手写数字识别案例复现ModelArts和WSL2+GPU
    基于LeNet5的手写数字识别实验介绍LeNet5 + MNIST被誉为深度学习领域的“Hello world”。本实验主要介绍使用MindSpore在MNIST手写数字数据集上开发和训练一个LeNet5模型,并验证模型精度。今天就给大家做一个简简单单的模型案例复现,详情均可以阅读官网参考文档。实验准备数据集准备MNIST是一个手写数字数据集,训练集包含60000张手写数字,测试集包含10000张手写数字,共10类。MNIST数据集的官网:THE MNIST DATABASE。• 方式一,从MNIST官网下载如下4个文件到本地并解压:train-images-idx3-ubyte.gz: training set images (9912422 bytes)train-labels-idx1-ubyte.gz: training set labels (28881 bytes)t10k-images-idx3-ubyte.gz: test set images (1648877 bytes)t10k-labels-idx1-ubyte.gz: test set labels (4542 bytes)• 方式二,从华为云OBS中下载MNIST数据集 并解压。• 方式三(推荐),使用ModelArts训练作业/Notebook时,可以拷贝他人共享的OBS桶内的数据集,方法详见适配训练作业、数据拷贝。脚本准备从课程gitee仓库 上下载本实验相关脚本。将脚本和数据集组织为如下形式:lenet5├── MNIST│ ├── test│ │ ├── t10k-images-idx3-ubyte│ │ └── t10k-labels-idx1-ubyte│ └── train│ ├── train-images-idx3-ubyte│ └── train-labels-idx1-ubyte└── main.py创建OBS桶使用ModelArts训练作业/Notebook时,需要使用华为云OBS存储实验脚本和数据集,可以参考快速通过OBS控制台上传下载文件 了解使用OBS创建桶、上传文件、下载文件的使用方法(下文给出了操作步骤)。提示: 华为云新用户使用OBS时通常需要创建和配置“访问密钥”,可以在使用OBS时根据提示完成创建和配置。也可以参考获取访问密钥并完成ModelArts全局配置 获取并配置访问密钥。打开OBS控制台 ,点击右上角的“创建桶”按钮进入桶配置页面,创建OBS桶的参考配置如下:• 区域:华北-北京四• 数据冗余存储策略:单AZ存储• 桶名称:全局唯一的字符串• 存储类别:标准存储• 桶策略:公共读• 归档数据直读:关闭• 企业项目、标签等配置:免上传文件点击新建的OBS桶名,再打开“对象”标签页,通过“上传对象”、“新建文件夹”等功能,将脚本和数据集上传到OBS桶中。上传文件后,查看页面底部的“任务管理”状态栏(正在运行、已完成、失败),确保文件均上传完成。若失败请:• 参考上 传对象 大小限制/切换上 传方式 ,• 参考上 传对象 失败常见原因 。• 若无法解决请新建工单 ,产品类为“对象存储服务”,问题类型为“桶和对象相关”,会有技术人员协助解决。实验步骤(ModelArts训练作业)ModelArts提供了训练作业服务,训练作业资源池大,且具有作业排队等功能,适合大规模并发使用。使用训练作业时,如果有修改代码和调试的需求,有如下三个方案:1. 在本地修改代码后重新上传;2. 使用PyCharm ToolKit 配置一个本地Pycharm+ModelArts的开发环境,便于上传代码、提交训练作业和获取训练日志。3. 在ModelArts上创建Notebook,然后设置Sync OBS功能 ,可以在线修改代码并自动同步到OBS中。因为只用Notebook来编辑代码,所以创建CPU类型最低规格的Notebook就行。适配训练作业创建训练作业时,运行参数会通过脚本传参的方式输入给脚本代码,脚本必须解析传参才能在代码中使用相应参数。如data_url和train_url,分别对应数据存储路径(OBS路径)和训练输出路径(OBS路径)。脚本对传参进行解析后赋值到args变量里,在后续代码里可以使用。import argparseparser = argparse.ArgumentParser()parser.add_argument('--data_url', required=True, default=None, help='Location of data.')parser.add_argument('--train_url', required=True, default=None, help='Location of training outputs.')args, unknown = parser.parse_known_args()MindSpore暂时没有提供直接访问OBS数据的接口,需要通过ModelArts自带的moxing框架与OBS交互。• 方式一,拷贝自己账户下OBS桶内的数据集至执行容器。• import moxing• # src_url形如's3://OBS/PATH',为OBS桶中数据集的路径,dst_url为执行容器中的路径• moxing.file.copy_parallel(src_url=args.data_url, dst_url='MNIST/')• 方式二(推荐),拷贝他人共享的OBS桶内的数据集至执行容器,前提是他人账户下的OBS桶已设为公共读/公共读写。若在创建桶时桶策略为私有,请参考配置标准桶策略 修改为公共读/公共读写。• import moxing• moxing.file.copy_parallel(src_url="s3://share-course/dataset/MNIST/", dst_url='MNIST/')• 方式三(不推荐),先关联他人私有账户,再拷贝他人账户下OBS桶内的数据集至执行容器,前提是已获得他人账户的访问密钥、私有访问密钥、OBS桶-概览-基本信息-Endpoint。• import moxing• # 设置他人账户的访问密钥, ak:Access Key Id, sk:Secret Access Key, server:endpoint of obs bucket• moxing.file.set_auth(ak='Access Key', sk='Secret Access Key', server="obs.cn-north-4.myhuaweicloud.com")• moxing.file.copy_parallel(src_url="s3://share-course/dataset/MNIST/", dst_url='MNIST/')创建训练作业可以参考使用常用框架训练模型 来创建并启动训练作业(下文给出了操作步骤)。打开ModelArts控制台-训练管理-训练作业 ,点击“创建”按钮进入训练作业配置页面,创建训练作业的参考配置:• 算法来源:常用框架->Ascend-Powered-Engine->MindSpore• 代码目录:选择上述新建的OBS桶中的lenet5目录,用obs browser+上传• 启动文件:选择上述新建的OBS桶中的lenet5目录下的main.py,快速创建算法• 数据来源:数据存储位置->选择上述新建的OBS桶中的lenet5目录下的MNIST目录• 训练输出位置:选择上述新建的OBS桶中的lenet5目录并在其中创建output目录• 作业日志路径:同训练输出位置• 规格:Ascend:1*Ascend 910• 其他均为默认•  启动并查看训练过程:1. 点击提交以开始训练;2. 在训练作业列表里可以看到刚创建的训练作业,在训练作业页面可以看到版本管理;3. 点击运行中的训练作业,在展开的窗口中可以查看作业配置信息,以及训练过程中的日志,日志会不断刷新,等训练作业完成后也可以下载日志到本地进行查看;4. 参考实验步骤(ModelArts Notebook),在日志中找到对应的打印信息,检查实验是否成功。5. epoch: 1 step: 1875, loss is 1.93937336. epoch: 2 step: 1875, loss is 0.046494857. epoch: 3 step: 1875, loss is 0.067324838. [WARNING] SESSION(168,ffff0ffff1e0,python):2022-02-10-19:52:59.136.619 [mindspore/ccsrc/backend/session/ascend_session.cc:1806] SelectKernel] There are 4 node/nodes used reduce precision to selected the kernel!9. Metrics: {'loss': 0.07129916341009682, 'acc': 0.9781650641025641}实验步骤(ModelArts Notebook)ModelArts Notebook资源池较小,且每个运行中的Notebook会一直占用Device资源不释放,不适合大规模并发使用(不使用时需停止实例,以释放资源)。创建Notebook可以参考创建并打开Notebook 来创建并打开Notebook(下文给出了操作步骤)。打开ModelArts控制台-开发环境-Notebook ,点击“创建”按钮进入Notebook配置页面,创建Notebook的参考配置:• 计费模式:按需计费• 名称:notebook-lenet5• 工作环境:公共镜像->Ascend+ARM算法开发和训练基础镜像,AI引擎预置TensorFlow和MindSpore• 资源池:公共资源• 类型:Ascend• 规格:单卡1*Ascend 910• 存储位置:对象存储服务(OBS)->选择上述新建的OBS桶中的lenet5文件夹(此为旧版操作,新版有所变更,请看下面详细叙述)• 自动停止:打开->选择1小时后(后续可在Notebook中随时调整)将数据添加到并行文件系统中创建完成后,添加数据存储,将数据挂载到data目录下即可。打开Notebook后,选择MindSpore环境作为Kernel。导入模块导入MindSpore模块和辅助模块,设置MindSpore上下文,如执行模式、设备等。import os# os.environ['DEVICE_ID'] = '0'import mindspore as msimport mindspore.context as contextimport mindspore.dataset.transforms.c_transforms as Cimport mindspore.dataset.vision.c_transforms as CVfrom mindspore import nnfrom mindspore.train import Modelfrom mindspore.train.callback import LossMonitorcontext.set_context(mode=context.GRAPH_MODE, device_target='Ascend') # Ascend, CPU, GPU数据处理在使用数据集训练网络前,首先需要对数据进行预处理,如下:def create_dataset(data_dir, training=True, batch_size=32, resize=(32, 32),rescale=1/(255*0.3081), shift=-0.1307/0.3081, buffer_size=64):data_train = os.path.join(data_dir, 'train') # train setdata_test = os.path.join(data_dir, 'test') # test setds = ms.dataset.MnistDataset(data_train if training else data_test)ds = ds.map(input_columns=["image"], operations=[CV.Resize(resize), CV.Rescale(rescale, shift), CV.HWC2CHW()])ds = ds.map(input_columns=["label"], operations=C.TypeCast(ms.int32))# When `dataset_sink_mode=True` on Ascend, append `ds = ds.repeat(num_epochs) to the endds = ds.shuffle(buffer_size=buffer_size).batch(batch_size, drop_remainder=True)return ds对其中几张图片进行可视化,可以看到图片中的手写数字,图片的大小为32x32。import matplotlib.pyplot as pltds = create_dataset('data/lenet/lenet5/MNIST', training=False)#修改为挂载路径即可data = ds.create_dict_iterator(output_numpy=True).get_next()images = data['image']labels = data['label']for i in range(1, 5):plt.subplot(2, 2, i)plt.imshow(images[i][0])plt.title('Number: %s' % labels[i])plt.xticks([])plt.show()定义模型定义LeNet5模型class LeNet5(nn.Cell):def __init__(self):super(LeNet5, self).__init__()self.conv1 = nn.Conv2d(1, 6, 5, stride=1, pad_mode='valid')self.conv2 = nn.Conv2d(6, 16, 5, stride=1, pad_mode='valid')self.relu = nn.ReLU()self.pool = nn.MaxPool2d(kernel_size=2, stride=2)self.flatten = nn.Flatten()self.fc1 = nn.Dense(400, 120)self.fc2 = nn.Dense(120, 84)self.fc3 = nn.Dense(84, 10)def construct(self, x):x = self.relu(self.conv1(x))x = self.pool(x)x = self.relu(self.conv2(x))x = self.pool(x)x = self.flatten(x)x = self.fc1(x)x = self.fc2(x)x = self.fc3(x)return x训练使用MNIST数据集对上述定义的LeNet5模型进行训练。训练策略如下表所示,可以调整训练策略并查看训练效果,要求验证精度大于95%。batch sizenumber of epochslearning rateoptimizer3230.01Momentum 0.9def train(data_dir, lr=0.01, momentum=0.9, num_epochs=3):ds_train = create_dataset(data_dir)ds_eval = create_dataset(data_dir, training=False)net = LeNet5()loss = nn.loss.SoftmaxCrossEntropyWithLogits(sparse=True, reduction='mean')opt = nn.Momentum(net.trainable_params(), lr, momentum)loss_cb = LossMonitor(per_print_times=ds_train.get_dataset_size())model = Model(net, loss, opt, metrics={'acc', 'loss'})# dataset_sink_mode can be True when using Ascendmodel.train(num_epochs, ds_train, callbacks=[loss_cb], dataset_sink_mode=False)metrics = model.eval(ds_eval, dataset_sink_mode=False)print('Metrics:', metrics)train('data/lenet/lenet5/MNIST/')#此处我们修改为自己的挂载路径即可 训练完成。实验步骤(本地CPU/GPU/Ascend)MindSpore还支持在本地CPU/GPU/Ascend环境上运行,如Windows/Ubuntu x64笔记本,NVIDIA GPU服务器,以及Atlas Ascend服务器等。在本地环境运行实验前,需要先参考安装教程配置环境。在Windows/Ubuntu x64笔记本上运行实验:# 编辑main.py 将第15行的context设置为`device_target='CPU'或者'GPU'python main.py --data_url=.\MNIST#拷贝到当前文件夹,也可自定义路径。实验小结本实验展示了如何使用MindSpore进行手写数字识别,以及开发和训练LeNet5模型。通过对LeNet5模型做几代的训练,然后使用训练后的LeNet5模型对手写数字进行识别,识别准确率大于95%。即LeNet5学习到了如何进行手写数字识别。
  • [安装经验] MindSpore入门--基于GPU服务器安装MindSpore 1.5.0
    # MindSpore Install On GPU Server > 基于GPU服务器安装MindSpore 1.5.0 本文开发环境如下: > - Ubuntu Server 20.04 x86_64 > - Python 3.8.10 > - Cuda 11.1.0 > - RTX 3090 * 4 > - MindSpore 1.5.0 本文主要内容如下: >- 系统安装(略过) >- GPU环境配置 >- Mindspore安装及测试 >- Mindspore Serving安装及测试 >- 问题 >- 参考 ## 0. 系统安装 > `Ubuntu Server 20.04`安装过程略 ## 1. GPU环境配置 ### 1.1 NVIDIA驱动配置 > 注意事项: > > - NVIDIA驱动版本:NVIDIA-Linux-x86_64-470.86.run > - 关于dkms:由于采用run格式文件安装,未避免系统内核升级重启后,需要重新安装驱动,这里引入dkms模块。 ```shell sudo apt install dkms wget -c https://cn.download.nvidia.com/XFree86/Linux-x86_64/470.86/NVIDIA-Linux-x86_64-470.86.run chmod a+x NVIDIA-Linux-x86_64-470.86.run sudo ./NVIDIA-Linux-x86_64-470.86.run ``` 具体安装过程如下图1.1所示。 ![](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/202202/10/143929dsepoq1p9yqi50d0.gif)图1.1 NVIDIA驱动安装过程安装完成后,使用命令`nvidia-smi`查看是否安装成功。如果安装成功,会输入类似如下内容。 ```shell +-----------------------------------------------------------------------------+ | NVIDIA-SMI 470.86 Driver Version: 470.86 CUDA Version: 11.4 | |-------------------------------+----------------------+----------------------+ | GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC | | Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. | | | | MIG M. | |===============================+======================+======================| | 0 NVIDIA GeForce ... Off | 00000000:24:00.0 Off | N/A | | 30% 34C P0 103W / 350W | 0MiB / 24268MiB | 0% Default | | | | N/A | +-------------------------------+----------------------+----------------------+ | 1 NVIDIA GeForce ... Off | 00000000:41:00.0 Off | N/A | | 30% 35C P0 107W / 350W | 0MiB / 24268MiB | 0% Default | | | | N/A | +-------------------------------+----------------------+----------------------+ | 2 NVIDIA GeForce ... Off | 00000000:81:00.0 Off | N/A | | 30% 34C P0 103W / 350W | 0MiB / 24268MiB | 0% Default | | | | N/A | +-------------------------------+----------------------+----------------------+ | 3 NVIDIA GeForce ... Off | 00000000:E1:00.0 Off | N/A | | 30% 34C P0 103W / 350W | 0MiB / 24268MiB | 0% Default | | | | N/A | +-------------------------------+----------------------+----------------------+ +-----------------------------------------------------------------------------+ | Processes: | | GPU GI CI PID Type Process name GPU Memory | | ID ID Usage | |=============================================================================| | No running processes found | +-----------------------------------------------------------------------------+ ``` ### 1.2 CUDA环境配置 #### 1.2.1 安装CUDA ```shell wget https://developer.download.nvidia.com/compute/cuda/11.1.0/local_installers/cuda_11.1.0_455.23.05_linux.run chmod a+x cuda_11.1.0_455.23.05_linux.run sudo ./cuda_11.1.0_455.23.05_linux.run ``` 具体安装过程如下图1.2所示。 ![](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/202202/10/144021oxv0n47jiw4gcpdv.gif)图1.2 CUDA 11.1.0 安装过程安装成功后输出如下内容: ```shell =========== = Summary = =========== Driver: Not Selected Toolkit: Installed in /usr/local/cuda-11.1/ Samples: Not Selected Please make sure that - PATH includes /usr/local/cuda-11.1/bin - LD_LIBRARY_PATH includes /usr/local/cuda-11.1/lib64, or, add /usr/local/cuda-11.1/lib64 to /etc/ld.so.conf and run ldconfig as root To uninstall the CUDA Toolkit, run cuda-uninstaller in /usr/local/cuda-11.1/bin ***WARNING: Incomplete installation! This installation did not install the CUDA Driver. A driver of version at least .00 is required for CUDA 11.1 functionality to work. To install the driver using this installer, run the following command, replacing with the name of this run file: sudo .run --silent --driver Logfile is /var/log/cuda-installer.log ``` #### 1.2.2 配置环境变量 > 添加`CUDA`环境变量的常规方法添加在`/etc/profile`或用户目录下的`.bashrc`文件中,这样每次登陆终端便会自动生效。 > > 如果需要在多个深度学习框架之间切换,且各个框架需要的`CUDA`环境不同时,上述方面即为不方便。 > > 因此,本文将`CUDA`添加到特定的bash文件中,需要使用某个`CUDA`环境时,直接`source`即可。 ```shell vim ~/env_cuda_11.1.0.sh ``` 使用上述命令在用户目录下创建`bash`文件,写入如下内容。 > 注意:`bash`文件名可以自定义。 ```shell #!/bin/bash # cuda 11.1.0 ########################### ## cuda 11.1.0 ## ########################### export PATH="/usr/local/cuda-11.1/bin:$PATH" export LD_LIBRARY_PATH="/usr/local/cuda-11.1/lib64:$LD_LIBRARY_PATH" ``` 如果要使用本文`CUDA`环境,只需要执行以下命令即可。 ```shell source ~/env_cuda_11.1.0.sh ``` 使用`nvcc -V`命令检测`CUDA`环境是否生效。生效后输出如下内容。 ```shell nvcc: NVIDIA (R) Cuda compiler driver Copyright (c) 2005-2020 NVIDIA Corporation Built on Tue_Sep_15_19:10:02_PDT_2020 Cuda compilation tools, release 11.1, V11.1.74 Build cuda_11.1.TC455_06.29069683_0 ``` ### 1.3 cuDNN环境配置 > 注意事项:`cuDNN`文件下载需要注册NVIDIA账号。 从`cuDNN`官网下载相应包,并上传到服务器。需要下载的文件如下图所示。 ![](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/202202/10/144341zasa1wnlwyqlhzwo.png) 然后使用如下命令进行安装。 ```shell tar -zxvf cudnn-11.1-linux-x64-v8.0.5.39.tgz cd cuda sudo cp include/*.h /usr/local/cuda-11.1/include/ sudo cp -d lib64/libcudnn* /usr/local/cuda-11.1/lib64/ ``` 如果需要查看解压内容,可在解压后`cuda`目录下使用命令`tree`。 ```shell . ├── include │   ├── cudnn_adv_infer.h │   ├── cudnn_adv_train.h │   ├── cudnn_backend.h │   ├── cudnn_cnn_infer.h │   ├── cudnn_cnn_train.h │   ├── cudnn.h │   ├── cudnn_ops_infer.h │   ├── cudnn_ops_train.h │   └── cudnn_version.h ├── lib64 │   ├── libcudnn_adv_infer.so -> libcudnn_adv_infer.so.8 │   ├── libcudnn_adv_infer.so.8 -> libcudnn_adv_infer.so.8.0.5 │   ├── libcudnn_adv_infer.so.8.0.5 │   ├── libcudnn_adv_train.so -> libcudnn_adv_train.so.8 │   ├── libcudnn_adv_train.so.8 -> libcudnn_adv_train.so.8.0.5 │   ├── libcudnn_adv_train.so.8.0.5 │   ├── libcudnn_cnn_infer.so -> libcudnn_cnn_infer.so.8 │   ├── libcudnn_cnn_infer.so.8 -> libcudnn_cnn_infer.so.8.0.5 │   ├── libcudnn_cnn_infer.so.8.0.5 │   ├── libcudnn_cnn_train.so -> libcudnn_cnn_train.so.8 │   ├── libcudnn_cnn_train.so.8 -> libcudnn_cnn_train.so.8.0.5 │   ├── libcudnn_cnn_train.so.8.0.5 │   ├── libcudnn_ops_infer.so -> libcudnn_ops_infer.so.8 │   ├── libcudnn_ops_infer.so.8 -> libcudnn_ops_infer.so.8.0.5 │   ├── libcudnn_ops_infer.so.8.0.5 │   ├── libcudnn_ops_train.so -> libcudnn_ops_train.so.8 │   ├── libcudnn_ops_train.so.8 -> libcudnn_ops_train.so.8.0.5 │   ├── libcudnn_ops_train.so.8.0.5 │   ├── libcudnn.so -> libcudnn.so.8 │   ├── libcudnn.so.8 -> libcudnn.so.8.0.5 │   ├── libcudnn.so.8.0.5 │   └── libcudnn_static.a └── NVIDIA_SLA_cuDNN_Support.txt ``` ### 1.4 NCCL环境配置 > 注意事项: > > - 如果非多GPU环境,可跳过本步骤。 > > - `NCCL`文件下载需要注册NVIDIA账号。 从`NCCL`官网下载相应包,并上传到服务器。需要下载的文件如下图所示。 ![](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/202202/10/144114y5oijmwvmn4xi21p.png) 然后使用如下命令进行安装。 ```shell tar -xvf nccl_2.8.4-1+cuda11.1_x86_64.txz cd nccl_2.8.4-1+cuda11.1_x86_64 sudo cp include/*.h /usr/local/cuda-11.1/include/ sudo cp -d -r lib/* /usr/local/cuda-11.1/lib64/ ``` 如果需要查看解压内容,可在解压后`nccl_2.8.4-1+cuda11.1_x86_64`目录下使用命令`tree`。 ```shell . ├── include │   ├── nccl.h │   └── nccl_net.h ├── lib │   ├── libnccl.so -> libnccl.so.2 │   ├── libnccl.so.2 -> libnccl.so.2.8.4 │   ├── libnccl.so.2.8.4 │   ├── libnccl_static.a │   └── pkgconfig │   └── nccl.pc └── LICENSE.txt ``` ### 1.5 TensorRT环境配置 > 注意事项: > > - 如果不使用`MindSpore Serving`推理服务,可跳过本步骤。 > > - 本文采用tar文件安装方式,需要先注册NVIDIA账号下载相应文件。 从`TensorRT`官网下载相应包,并上传到服务器。需要下载的文件如下图所示。 ![](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/202202/10/144219cx7r9uhbipppqscn.png) 然后使用如下命令进行安装。 - 基础依赖库安装。 ```shell tar zxvf TensorRT-7.2.2.3.Ubuntu-18.04.x86_64-gnu.cuda-11.1.cudnn8.0.tar.gz mkdir ~/tensorrt mv TensorRT-7.2.2.3 ~/tensorrt/ ``` 在1.2.2中的`env_cuda_11.1.0.sh`文件中增加`tensorrt`环境。内容如下。 ```shell # ${TensorRT-path}为变量,需要替换为你的真实目录。 # 例如:LD_LIBRARY_PATH=/home/ubuntu/tensorrt/TensorRT-7.2.2.3/lib:$LD_LIBRARY_PATH export LD_LIBRARY_PATH=${TensorRT-path}/lib>:$LD_LIBRARY_PATH ``` - python包安装 > 建议:在完成Mindspore虚拟环境创建并激活后安装 ```shell cd ~/tensorrt/TensorRT-7.2.2.3/ pip3 install python/tensorrt-7.2.2.3-cp38-none-linux_x86_64.whl pip3 install uff/uff-0.6.9-py2.py3-none-any.whl pip3 install graphsurgeon/graphsurgeon-0.4.5-py2.py3-none-any.whl pip3 install onnx_graphsurgeon/onnx_graphsurgeon-0.2.6-py2.py3-none-any.whl ``` ## 2. MindSpore安装及测试 #### 2.1 安装`Python`基础环境 > 如果已经安装,可跳过本步骤。 ```shell sudo apt update sudo apt install python3 python3-dev python3-pip sudo pip3 install virtualenv ``` 可以使用`python3 -V`命令检查安装的`python`版本。本文版本信息如下。 ```shell Python 3.8.10 ``` #### 2.2. 安装`MindSpore` - 创建虚拟环境 ```shell virtualenv -p python3 env_mindspore_1.5.0 ``` 输出内容如下 ```shell created virtual environment CPython3.8.10.final.0-64 in 292ms creator CPython3Posix(dest=/mnt/data_0301_12t/xingchaolong/home/pyenvs/env_mindspore_1.5.0, clear=False, no_vcs_ignore=False, global=False) seeder FromAppData(download=False, pip=bundle, setuptools=bundle, wheel=bundle, via=copy, app_data_dir=/home/xingchaolong/.local/share/virtualenv) added seed packages: pip==21.3.1, setuptools==58.3.0, wheel==0.37.0 activators BashActivator,CShellActivator,FishActivator,NushellActivator,PowerShellActivator,PythonActivator ``` - 激活虚拟环境 ```shell source env_mindspore_1.5.0/bin/activate ``` - 激活`CUDA`环境 ```shell source ~/env_cuda_11.1.0.sh ``` - 安装`mindspore` ```shell pip3 install https://ms-release.obs.cn-north-4.myhuaweicloud.com/1.5.0/MindSpore/gpu/x86_64/cuda-11.1/mindspore_gpu-1.5.0-cp38-cp38-linux_x86_64.whl --trusted-host ms-release.obs.cn-north-4.myhuaweicloud.com -i https://pypi.tuna.tsinghua.edu.cn/simple ``` #### 2.3 测试`Mindspore` 使用如下命令测试是否安装成功。 ```shell python3 -c "import mindspore;mindspore.run_check()" ``` 如果安装成功,输出如下内容。 ```shell MindSpore version: 1.5.0 The result of multiplication calculation is correct, MindSpore has been installed successfully! ``` ## 3. MindSpore Serving安装及测试 > 注意事项: > > - MindSpore Serving目前并未安装成功,以下步骤仅供参考。 #### 3.1 安装`MindSpore Serving` ```shell pip3 install https://ms-release.obs.cn-north-4.myhuaweicloud.com/1.5.0/Serving/x86_64/mindspore_serving-1.5.0-cp38-cp38-linux_x86_64.whl --trusted-host ms-release.obs.cn-north-4.myhuaweicloud.com -i https://pypi.tuna.tsinghua.edu.cn/simple ``` #### 3.2 测试`MindSpore Serving` ```shell python3 -c "from mindspore_serving import server" ``` 如果没有报错,则表示安装成功。 ## 4. 总结 本文介绍了Ubuntu Server 20.04环境下,基于英伟达GPU硬件配置相关环境,安装MindSpore及对其测试。 ## 问题 - MindSpore Serving测试时出现以下问题 ```shell free(): invalid pointer Aborted (core dumped) ``` 目前官方已修复该问题。 ## 参考 - [DKMS简介](http://abcdxyzk.github.io/blog/2020/09/21/kernel-dkms/) - [TensorRT安装](https://docs.nvidia.com/deeplearning/tensorrt/install-guide/index.html#installing-tar) - [安装MindSpore](https://www.mindspore.cn/install) - [安装MindSpore Serving](https://www.mindspore.cn/serving/docs/zh-CN/r1.5/serving_install.html)
  • [安装经验] Jetson Nano源码编译MindSpore 1.6 GPU版编译的再次尝试(连载中)
    在各位大大的支持下,张小白带着一颗不服输的心,开始了继Nvidia Jetson Nano B01初体验(一)https://bbs.huaweicloud.com/blogs/330158Nvidia Jetson Nano B01初体验(二)https://bbs.huaweicloud.com/blogs/330177Nvidia Jetson Nano B01初体验(三)https://bbs.huaweicloud.com/blogs/330290之后的另一次尝试。
  • [安装经验] Jetson Nano源码编译MindSpore 1.6 GPU版编译记录
    本文摘自 原创作品:Nvidia Jetson Nano B01初体验(3)https://bbs.huaweicloud.com/blogs/330290(十七)再次探索:源码编译MindSpore 1.6.0当张小白向群里诉苦说,MindSpore没有GPU+aarch64版本的时候,小口鸟大大的哥哥月月鸟大大指出了一条康庄大道:尽管张小白一百万个不情愿,还是觉得跟着大大的方向是没错的。所以开玩笑归开玩笑,迈向披荆斩棘的道路中,总要遵循灯塔或者看一下交通标志灯。。先看了一下32G TF卡的剩余空间:还有13G可用,按理说应该是够了(够折腾的了)。那就开干吧。参考 https://bbs.huaweicloud.com/blogs/198349  张小白上次源码编译V1.0的时候还是在一年半前。查看编译所需的环境要求:(1)gcc 7.3.0当前是7.5.0,从张小白以前的经验来看,7.5应该也是可以的。(2)gmp 6.1.2 在上一篇博客中已经安装过了:此处不再赘述。(3)Python 3.9.0 这个进入vitualenv环境就可以了。我们可以另外创建一个给源码编译用。virtualenv -p ~/.pyenv/versions/3.9.0/bin/python mindspore-sourcesource ~/mindspore-source/bin/activate(4)cmake 大于3.18.3够了。(5)patch 大于2.5wget http://ftp.gnu.org/gnu/patch/patch-2.5.4.tar.gztar zxvf patch-2.5.4.tar.gz./configuremake -j8sudo make install -j8patch --version够了。(6)flex 大于2.5.35wget https://github.com/westes/flex/releases/download/v2.6.4/flex-2.6.4.tar.gztar zxvf flex-2.6.4.tar.gz./configuremake -j8coredump了!可能是交换分区不够,改为make (不带-j参数)编译试试。一样的结果。小技巧:如何给Nano增加虚拟内存:那看看如何增加虚拟内存吧!free -msudo fallocate -l 4G /var/swapfilesudo chmod 600 /var/swapfilesudo mkswap /var/swapfilesudo swapon /var/swapfilesudo bash -c 'echo "/var/swapfile swap swap defaults 0 0" >> /etc/fstab'free -m再试一遍吧:make -j8sudo make install -j8一样的。换个方式呢?sudo apt-get install flexflex --version真是多此一举啊。。但是这个问题好奇怪,怎么会编译不过去呢?张小白百思不得其解。(7)wheel 大于0.32.0pip3 install wheel==0.32.0其实已经有了wheel.还原吧!pip3 install wheel==0.37.1(8)openssl 大于1.1.1wget https://github.com/openssl/openssl/archive/OpenSSL_1_1_1g.tar.gztar -zxvf OpenSSL_1_1_1g.tar.gz./config --prefix=/usr/local/opensslmake -j8sudo make install -j8编辑 ~/.bashrc,追加一行:export OPENSSL_ROOT_DIR=/usr/local/opensslsource ~/.bashrc 使其生效。当然需要再回到virtualenv环境:source ~/mindspore-source/bin/activate(9)NUMA大于2.0.11sudo apt-get install libnuma-dev(10)下载mindspore源码:git clone https://gitee.com/mindspore/mindspore.git -b r1.6(11)开始编译(遇到Python找不到的问题)bash build.sh -e gpu -j12好像是老问题了。换成virtualenv 3.7.5 的环境试试呢?deactivatevirtualenv -p ~/.pyenv/versions/3.7.5/bin/python mindspore-source375source ~/mindspore-source375/bin/activatebash build.sh -e gpu -j12好像依然如此。(12)源码编译Python3.7.5还是先源码编译 Python3.7.5吧!wget https://www.python.org/ftp/python/3.7.5/Python-3.7.5.tgztar -xzf Python-3.7.5.tgz进入Python-3.7.5目录后./configure --prefix=/usr/local/python3.7.5 --with-openssl=/usr/local/openssl --enable-sharedmake -j 12sudo make install -j 12export PATH=/usr/local/python3.7.5/bin:$HOME/.local/bin:$PATHpython -c "from distutils.sysconfig import get_python_inc; print(get_python_inc())"python -c "import distutils.sysconfig as sysconfig; print(sysconfig.get_config_var('LIBDIR'))"(13)再次尝试解决Python找不到的问题张小白突然想起当年编译的时候遇到的坑:https://bbs.huaweicloud.com/forum/forum.php?mod=viewthread&tid=80520&ordertype=2&page=4唉,看来还是得这样操作才行。跟踪build.sh代码:是执行到了 ./scripts/build/build_mindspore.sh打开这个shell加上ENABLE_GITEE=ON参数,让其走gitee而不是github修改对应的CMakeLists.txt文件:强行让其不执行find_package.编辑 cmake/check_requirements.cmake(14)解决gmp找不到的问题再来一遍:bash build.sh -e gpu -j12终于没报python3.7.5找不到的错了,报了gmp找不到的错。那就装gmp吧。sudo apt-get install -y build-essential m4 libgmp-dev libmpfr-dev libmpc-dev(15)再次编译再来!bash build.sh -e gpu -j12终于开始编译了。。。。。。。。。。。。好像还在编译依赖库,耐心等待吧。毕竟以前github更慢。在编译flatbuffers包的时候,突然中断了:老革命遇到了新问题。。在build_mindspore.sh中增加参数试试:再次执行,好像还是一样的错:(16)源码安装gcc7.3.0CMAKE_CXX_COMPILER报错,张小白总感觉是gcc 7.5.0的编译器有问题,要不试一试 gcc7.3.0?df -h感觉32G的TF卡快不够用了。wget http://ftp.gnu.org/gnu/gcc/gcc-7.3.0/gcc-7.3.0.tar.gztar -xzf gcc-7.3.0.tar.gzcd gcc-7.3.0./configure --enable-checking=release --enable-languages=c,c++ --disable-multilib。。make -j 12 sudo make install -j 12先备份一下gcc7.5,再将软链接指向gcc7.3cd /usr/binsudo mv gcc gcc7.5sudo mv g++ g++7.5sudo ln -s /usr/local/bin/gcc gccsudo ln -s /usr/local/bin/g++ g++gcc --versiong++ --version这次编译完之后,df -h看来要清理一下,否则mindspore会没有足够的空间编译的。(17)再再次编译再来,因为前面有很多是用gcc 7.5.0编译的,现在全改为gcc 7.3.0编译吧,清空代码仓目录,重新下载重新编译吧!rm -rf ~/mindsporegit clone https://gitee.com/mindspore/mindspore.git -b r1.6vi ~/mindspore/scripts/build/build_mindspore.sh箭头所示的两行都加上-DENABLE_GITEE=ON,让它不要走恐怖的github。。bash build.sh -e gpu -j12。。。。。。。。。。。正当张小白满怀欣喜的准备收工的时候,突然:CUDA报错“No CMAKE_CUDA_COMPILER”度娘了一把,这个报错是PATH缺少cuda的路径造成的。然后查看了下现在的PATH:难道 .bashrc中定义的路径在编译过程中被去掉了?重新 source ~/.bashrc后,检查PATH含了 /usr/local/cuda/bin的路径后,重新编译:bash build.sh -e gpu -j12报了pybind11_add_module错。难道是pybind11没装?装下看看:sudo pip3 install -i https://pypi.tuna.tsinghua.edu.cn/simple/  pybind11并不是,pybind11已经有了。再试一次bash build.sh -e gpu -j12,结果跟前面一样(其实啥也没新装肯定是这样了)。再检查错误日志中提到的CMakeList.txt:难道不是缺pybind11,而是缺_ms_mpi的包?是因为openmpi没装吗?装一下试试:wget https://download.open-mpi.org/release/open-mpi/v4.0/openmpi-4.0.3.tar.gztar -xvzf openmpi-4.0.3.tar.gzcd openmpi-4.0.3./configuremake -j12sudo make install -j12whereis openmpi再次编译:bash build.sh -e gpu -j12BUG依旧在,几度夕阳红。看了一下安装依赖:貌似就剩下NCCL没装了。感觉安装这个是没用的。暂时搞不定了。。。在论坛提了问题贴:https://bbs.huaweicloud.com/forum/thread-179083-1-1.html结果得到的专家答复如下:这个就很尴尬了。。。看来MindSpore团队也没空管我的问题。。。。唉。。。就这样吧。
  • [API使用] nn.Conv3d
    【功能模块】【操作步骤&问题现象】  请问nn.Con3d 可以在GPU使用吗? 我看API是支持的,但是我在华为云上创建了一个GPU环境,然后试了一下好像不行,要Ascend【截图信息】【日志信息】(可选,上传日志内容或者附件)
  • [安装] 【mindspore】【mindspore1.6安装】conda安装gpu版本验证失败
    【功能模块】mindspore-gpu安装【操作步骤&问题现象】1、window wsl2安装了Ubuntu18.042、安装了支持wsl的显卡驱动3、在miniconda中新建了python3.9.0的虚拟环境4、使用conda install mindspore-gpu=1.6.0 cudatoolkit=10.1 -c mindspore -c conda-forge命令安装mindspore,未报错5、验证是否安装成功报错6、ImportError: libcudnn.so.7: cannot open shared object file: No such file or directory【截图信息】【日志信息】(可选,上传日志内容或者附件)
  • [技术干货] JEDEC发布HBM3标准:速率提升一倍
     JEDEC 今天宣布,将发布其高带宽内存 (HBM) DRAM 标准的下一版本:JESD238 HBM3。HBM3 是一种创新方法,用于提高在更高带宽、更低功耗和单位面积容量对解决方案的市场成功至关重要的应用中使用的数据处理速率,包括图形处理和高性能计算和服务器。  据介绍,新 HBM3 的主要属性包括:  将经过验证的 HBM2 架构扩展到更高的带宽,将 HBM2 一代的每针数据速率提高一倍,并定义高达 6.4 Gb/s 的数据速率,相当于每台设备 819 GB/s;  将独立通道的数量从 8 个(HBM2)增加到 16 个;每个通道有两个伪通道,HBM3 实际上支持 32 个通道;  支持 4 高、8 高和 12 高 TSV 堆栈,并为将来扩展至 16 高 TSV 堆栈做好准备;  支持基于每个内存层 8Gb 到 32Gb 的各种密度,设备密度从 4GB(8Gb 4 高)到 64GB(32Gb 16 高);第一代 HBM3 设备预计将基于 16Gb 存储层;  为了满足市场对高平台级 RAS(可靠性、可用性、可维护性)的需求,HBM3 引入了强大的、基于符号的片上 ECC,以及实时错误报告和透明度;  通过在主机接口上使用低摆幅 (0.4V) 信号和较低 (1.1V) 工作电压来提高能效;  “凭借其增强的性能和可靠性属性,HBM3 将支持需要巨大内存带宽和容量的新应用,”NVIDIA 技术营销总监兼 JEDEC HBM 小组委员会主席 Barry Wagner 说。  “HBM3 将使行业达到更高的性能阈值,提高可靠性并降低能耗,”美光 高性能内存和网络副总裁兼总经理 Mark Montierth 说。“在与 JEDEC 成员合作开发此规范时,我们利用美光在提供先进内存堆叠和封装解决方案方面的悠久历史来优化市场领先的计算平台。”  “随着 HPC 和 AI 应用的不断进步,对更高性能和更高能效的需求比以往任何时候都增长得更快。随着当前 HBM3 JEDEC 标准的发布,SK hynix很高兴能够为我们的客户提供具有当今现有最高带宽和最佳能效的存储器,并通过采用增强的 ECC 方案增加了稳健性。SK 海力士很自豪能成为 JEDEC 的一员,因此很高兴能够继续与我们的行业合作伙伴一起建立强大的 HBM 生态系统,并为我们的客户提供 ESG 和 TCO 价值”,SK海力士DRAM产品企划副总裁Uksong Kang 说。  “十多年来, Synopsys一直是 JEDEC 的积极贡献者,帮助推动 HBM3、DDR5 和 LPDDR5 等最先进的内存接口在一系列新兴应用中的开发和采用,”Synopsys 的 IP 战略的营销高级副总裁 John Koeter 说。“Synopsys HBM3 IP 和验证解决方案已被领先客户采用,可加速将这一新接口集成到高性能 SoC 中,并支持开发具有最大内存带宽和能效的多芯片系统级封装设计。”他接着说。  人工智能推动 HBM 增长  高带宽内存 (HBM) 正变得越来越主流。随着最新迭代的规范获得批准,生态系统中的供应商正准备确保它可以实施,以便客户可以开始设计、测试和部署系统。  人工智能 (AI) 的大规模增长和多样性意味着 HBM 并不适合小众市场。它甚至变得更便宜了,但它仍然是一种优质内存,需要专业知识才能实施。作为 3D 堆叠 DRAM 的内存接口,HBM 通过堆叠多达 8 个 DRAM 裸片和可选的基础裸片(包括缓冲电路和测试逻辑),在显着小于 DDR4 或 GDDR5 的外形尺寸中实现更高的带宽,同时使用更少的功耗。  与所有内存一样,HBM 每次迭代都会在性能改进和功耗方面取得进步。三星电子内存产品规划团队的首席工程师 Jinhyun Kim 表示,从 HBM2 迁移到 HBM3 时,一个关键的变化是将数据传输速率从 3.2/3.6Gbps 提高到 6.4Gbps,每个引脚的性能将提高 100%。  第二个根本变化是最大容量从 16GB (8H) 增加到 24GB (12H) 50%。最后,HBM3 将片上纠错码作为行业标准实现,这提高了系统可靠性,Kim 说。“这对于下一代人工智能和机器学习系统至关重要。”  HBM 的本质是你不能简单地取出 HBM2 并用最新最好的替代它,但每一代新一代 HBM 都包含许多改进,与最新最好的 GPU 和 ASIC 的发布相吻合,Kim 说。多年来,三星不断更新其 HBM 产品组合,在每次参与之前,都将当前和下一代 HBM 产品的生命周期与主要合作伙伴的需求保持一致。“这有助于完全满足向后兼容性的需求,”他说。  设计人员将不得不适应利用 HBM3,Kim 表示,这是支持系统架构的理想解决方案,可解决 AI/ML 数据集日益复杂和大小的问题,并指出 HBM2 中每个堆栈的最大带宽为 409GB/s。“使用 HBM3,带宽已跃升至 819GB/s,而每个 HBM 堆栈的最大密度将增加到 24GB,以便管理更大的数据集。”  这些变化使系统设计人员能够扩展受密度限制限制的各种应用程序的可访问性。“我们将看到 HBM3 的采用从通用 GPU 和 FPGA 通过基于 DRAM 的缓存和 HPC 系统中的 CPU 扩展到主内存,”他说。  Kim 说,AI/ML 推理的主流化可以说是 HBM 的主流化。“不乏新的用例、应用程序和工作负载,推动了下一代 HPC 和数据中心对 AI/ML 计算能力的需求。”  Objective Analysis 的首席分析师 Jim Handy 表示,人工智能一直是 GPU 中 HBM 的主要驱动力。“GPU 和 AI 加速器对带宽有着令人难以置信的渴望,而 HBM 将它们带到了他们想去的地方。” 有时 HBM 最经济实惠,即使它过去的成本是 DRAM 的六倍——尽管现在它已经下降到大约三倍。  “使用 HBM 的应用程序需要如此多的计算能力,因此 HBM 确实是唯一的方法,”Handy 说。如果你尝试用 DDR 来做这件事,你最终将不得不拥有多个处理器而不是只有一个处理器来完成相同的工作,而且处理器成本最终会超过你在 DRAM 中节省的成本。”  人工智能的一个特点是它大量使用矩阵操作,Handy 说,当 GPU 明显优于使用标准 x86 架构时,人工智能变得更便宜,进化的下一步是采用 FPGA 来访问到专用处理器。由于 AI 需要如此多的带宽,GPU 和 FPGA 一直在整合 HBM。  HBM 的一个关键特性是不可能拔出 HBM2 并用 HBM3 替换它,因为它是焊接而不是插座,但系统设计人员应该能够轻松地进行转换,Handy。“这几乎是 HBM2E 和早期版本的线性发展。”
  • [执行问题] 在GPU-PYNATIVE/ CPU-GRAPH_MODE 与 GPU-GRAPH_MODE 执行不一致
    【功能模块】GPU -GRAPH_MODE 与 GPU-PYNATIVE/ CPU-GRAPH_MODE 输出不一致【操作步骤&问题现象】1、CPU 的 GRAPH_MODE 能够正常运行, 并且每轮 step 都可以调用 CallBack2、GPU 的PYNATIVE_MODE 下能够正常运行3、GPU的GRAPH_MODE  存在三个问题    1.  input 0 of cnode is not a value node   (这在cpu 的 graph_mode 下 并没有出现这一警告)    2.  step 间隔数不为1    3.  loss  为 nan 想请教一下,在不同的设备与 mode下如何才能保证结果的一致性, dataset的sink mode 会不会在不同设备上有不同的效果【截图信息】1. CPU GRAPH_MODE2. GPU GRAPH MODE3. GPU PYNATIVE【日志信息】(可选,上传日志内容或者附件)
  • [安装] ubuntu18.04上安装gpu版本 验证安装时卡住
    【功能模块】【操作步骤&问题现象】安装以后运行验证就卡住不动了,用代码验证在最后print输出时也是卡住不动【截图信息】
  • [分布式] mindspore在gpu上进行单机分布式训练, 仅一块GPU被利用
    【训练环境】Ubuntu16.04+Docker18.09.1在官网提供的MindSpore1.3镜像(OpneMPI4.0.3/NCCL2.7.8)中运行训练代码GPU: V100*8【问题】使用MPI做单机多卡训练时, nvidia-smi显示仅一块GPU计算, 其他GPU内存被少量占用当contex的mode参数设置为GRAPH_MODE时,不能在训练中修改optimizer的learning rate,这是否符合设计意图,如何实现此功能?关键调用代码如下:
  • [分布式] mindspore GPU分布式训练报错
    【功能模块】代码见附件报错:跑的4卡请问改如何解决【操作步骤&问题现象】1、2、【截图信息】【日志信息】(可选,上传日志内容或者附件)
  • [资产园地] 人脸检测-RetinaFace 支持Pytorch, GPU训练, 支持CPU,GPU推理
    描述RetinaFace(人脸检测/Pytorch)注:本算法支持多卡训练、单卡混合精度训练,但在多卡情况下不支持混合精度1. 概述此模型基于RetinaFace: Single-stage Dense Face Localisation in the Wild中提出的模型结构实现,该算法会载入在WiderFace 上的预训练模型,在用户数据集上做迁移学习。我们提供了训练代码和可用于训练的模型,用于实际场景的微调训练。训练后生成的模型可直接在ModelArts平台部署成在线服务。人脸检测的评估手段一般使用mAP指标,详细说明请参考:https://github.com/Cartucho/mAP本算法的其他信息如下表所示:项目说明参考论文RetinaFace: Single-stage Dense Face Localisation in the Wild使用框架Pytorch-1.4.0训练集WIDERFACE 中的 WIDER_train训练总epoch数100训练batch_size使用混合精度单卡训练,batch_size=16训练硬件及耗时单卡v100,O1混合精度,训练大约31小时测试集WIDERFACE 中的WIDER_val推理硬件及速度CPU 10.3s/pic ,GPU2080ti 0.5s/pic–1.5s/pic ,modelarts平台V100 GPU:3226张图片总共耗时24分钟(target_size = 1600,max_size = 2150)输入图像尺寸训练:1024*1024 推理:target_size = 1600,max_size = 2150(保证图片等比例缩放,使用最小一条边缩放到target_size的缩放比例;如果此时最大边超过了max_size,则使用最大边缩放到max_size的缩放比例)原论文准确率RetinaFace-R50 Easy 96.5, Medium 95.6, Hard 90.4本算法准确率RetinaFace-R50 Easy 95.52, Medium 94.43, Hard 90.062、训练2.1. 算法基本信息任务类型:人脸检测支持的框架引擎:PyTorch-1.4.0-python3.6算法输入:存储在OBS上的数据集,必须按照WIDERFACE 数据集的格式进行存储,详情请查看下文第4节案例指导WIDERFACE 预训练模型,在WIDERFACE 上的mAP是 Easy 95.52, Medium 94.43, Hard 90.06算法输出:用于Pytorch推理的pth模型,CPU推理速度:10.3s/pic GPU2080ti推理速度:0.5s/pic–1.5s/pic ,modelarts平台V100 GPU:3226张图片总共耗时24分钟(target_size = 1600,max_size = 2150)2.2. 训练参数说明名称默认值类型是否必填是否可修改描述data_urldata/WIDERFACE/WIDER_trainstring是是训练或者评估输入的数据集 (如果使用文件夹形式的数据,则填写该文件夹在OBS上的访问路径;如果使用zip压缩包形式的数据,则填写该压缩包的父目录在OBS上的访问路径)train_urloutput/string是是训练或者评估结果输出路径data_formatzipstring否是可选值zip(上传数据为zip压缩包)或者dir(上传数据为目录形式),压缩包和目录的具体格式请查看下面《ModelArts AI市场算法RetinaFace使用指导》所附连接networkresnet50string否是模型的backbone网络,可选值 mobile0.25 、resnet50 或者resnet152num_workers1int否是数据加载的worker数量lr0.001string否是训练的初始学习率momentum0.9string否是优化器的动量系数load_weightweight/best_model.pthstring否是可加载的预训练模型,当eval=True时,该参数为必填项 ;默认值是以resnet50为backbone在WiderFace数据集上的预训练模型,该预训练模型已经包含在本算法中weight_decay0.0005string否是优化器中的正则化权重衰减量gamma0.1string否是分段衰减学习率中每次学习率衰减的比例(new_lr=lr*gamma),仅当use_cosine_decay=False该参数有效img_size1024int否是训练数据的分辨率confidence_threshold0.02string否是nms时的置信度阈值nms_threshold0.4string否是nms时的IOU阈值num_gpu1int否是当num_gpu=1时,使用单个GPU训练;当num_gpu>1时,使用机器上所有的GPU进行训练batch_size16int否是训练时的batch_size,可根据GPU的显存进行调整epoch100int否是训练的epoch数量use_backboneTruestring否是训练时是否使用backbone网络在ImageNet数据集上的预训练参数use_mixedTruestring否是是否使用混合精度进行训练,使用混合精度一定程度上可以降低显存消耗,也可能提高训练速度amp_levelO1string否是混合精度的设置,可选值:O0,O1,O2,O3warmup_epoch10int否是训练开始时,使用warmup学习率的epoch数量,warmup_epoch=-1表示不使用warmupdecay150int否是分段衰减学习率的第一次学习率降低的epoch数,仅当use_cosine_decay=False时有效decay280int否是分段衰减学习率的第二次学习率降低的epoch数,仅当use_cosine_decay=False时有效use_cosine_decayTruestring否是是否使用余弦衰减学习率,设置为False则使用分段衰减学习率optimizersgdstring否是sgd 或者 adam优化器evalFalsestring否是eval=True,则进行评估;eval=False进行训练2.3. 训练输出文件训练完成后的输出文件如下:|- RetinaFace_Resnet50_Final.pth |- deploy_scripts |- model |- data |- layers |- models |- retinaface_utils |- config.json |- customize_service.py |- save_model.pth3. GPU/CPU推理元模型来源 选择 保存在OBS上的对应路径下的deploy_scripts文件夹。注意:推理配置文件model/config.json中的runtime字段为pytorch1.4-python3.6,表示该模型可同时在CPU或GPU运行。4. 案例指导本算法的详细使用方法,请查看《ModelArts AI Gallery算法RetinaFace使用指导》。交付交付方式华为云ModelArts交付区域华北-北京一、华北-北京四、华东-上海一、华南-广州、亚太-**
  • [技术干货] AIOT时代的编程语言、编译器与指令集架构:机遇、挑战与技术分享
    本次分享来自遇见未来系列讲座——与曾建江老师探讨AIOT时代的编程语言、编译器与指令集架构:机遇、挑战与展望。编译器、编程语言以及指令集架构都是一个软件生态的根基,此次给大家介绍软件生态根基上的语言编译器以及指令集架构,有哪些机遇挑战以及一些最新的技术课题。B站视频:https://www.bilibili.com/video/BV17C4y1a74c一 趋势与挑战(一) 处理器发展趋势软件都是在处理器上执行的,首先我们看下处理器的发展。下图[1]统计了从70年代中期开始到2018年,执行软件的微处理器的发展趋势。它从几个维度统计了这些处理器的发展:微处理器发展趋势(1970-2020)1. 晶体管的数量(橙色所示):依据40多年前提出的摩尔定律,晶体管数量一直在提升。此外2018年业界发布了一个很有意思的芯片——Cerebras的芯片,该芯片晶体管数量远远超出这个趋势图里面的范畴,是一个非常惊人的数字:1.2万亿个晶体管(当然这不是商用上非常经济的设计)。但是可以看到在用来运行软件的处理器中,所包含晶体管的数量还是持续追随着摩尔定律在增长。2. 单线程(单核)的性能(蓝色所示):这里的单核性能指的是当前单核能够提供的整数计算性能。从40年前开始,性能几乎还是能够沿着摩尔定律的发展而持续地提升。但是从21世纪特别是21世纪10年代开始,单核性能的发展几乎停滞了,或者说是发展缓慢。发展缓慢意味着用来运行软件的单个处理器的性能提升,从10年前开始就是非常有限的。3. 频率(绿色所示):频率的趋势更加平缓,从2000年开始,就没有跟随摩尔定律,这里有工艺限制的因素,很大原因是物理实现上的限制。频率的走缓几乎是更早于性能的走缓。这里蓝色性能和绿色频率的差别意味着芯片开发者或者架构开发者做出了非常大的努力,让处理器在频率不增长的情况下,能够持续地为软件性能提升提供贡献,这是非常不容易的一件事情。4. 处理器的功耗(红色所示):几乎从2000年开始,处理器功耗就不再大规模增长了。这里有个非常重要的原因是芯片的物理分装有相应的物理限制,从单位的物理分装里能够散发出来的热量是有限的。据统计,按照能量密度来算,处理器上运行软件所耗费的能量,能量密度已经超过了核反应堆。这是一个非常惊人的情况,所以从功耗上来说,微处理器能够耗散的功耗,已经达到了目前工艺或者说现在生产的极限。明显从很早开始,电池以及功耗就开始限制我们微处理器的发展。5. 处理器核数(黑色所示):处理器核数的增长从05年左右开始,跟随着摩尔定律中晶体管数量的逐步增长,单个芯片上所集成的处理器核数变得越来越多,几乎是和晶体管数量同步的发展趋势,意味着未来所使用的芯片里集成的核会更多。那这些核是不是都在做一个有意义的事情?下面我们来看下这些核本身的形态是怎样发展的。有个论断[2]是通用计算的时代结束了,回顾我们刚才讲的趋势,从2000年初开始,性能提升已经开始逐步走缓。如何获取更多的性能,这里有一个非常重要的趋势,就是处理器在变得越来越专用,专用是指如何进行处理器的定制化以及专用化的设计,通过对计算本身并行的特征,以及它的访存内存使用的特征,来发掘计算的模式里是否有利用定制化的硬件,来提升特定模式计算的性能,或者是降低所使用的功耗的手段,这种叫做定制化。最典型的例子是现在非常热的AI处理器,比如现在华为手机里集成的达芬奇 AI芯片,就是定制化的设计。为了让应用跑得更快,现在采取了更多的手段。如下图所示,蓝色这块区域就是用定制化的设计来提升应用的性能,降低完成计算所需要的功耗。(二) 指令集架构的演进实现定制化,这里又回到处理器,用来实现软件或者运行软件非常重要的软件和硬件的接口,叫做指令集。如下图所示,这是一个比较传统的指令集的分类。指令集从60年代的复杂指令集(Complex Instruction Set Computer, CISC)开始发展,到70年代有了精简指令集(reduced instruction set computer, RISC)的分类。一直到80年代开始,业界开始探索一种称为超长指令集(Very Long Instruction Word,VLIW)的指令级并行架构。90年代时还有非常多不同种类的指令集存在。指令集架构的演进但随着时间的演变,到今天为止,市面上现在主流用到的指令集已经不多了,非常多指令集已停止发展。留在市面上的还有一些特定领域的大型机的指令集。通用指令集领域的话,有Intel X86指令集、IBM power指令集和SPARC指令集。但是手机上主要是用ARM 指令集,还有最近比较热的RISC-V 指令集,可数的就这几种。指令集在处理器发展上所起到的最重要的作用,就是让软件和硬件实现他们的界面以及交互。现存的通用指令集有这样的趋势:这些不同的指令集,会相互借鉴、相互汲取各自设计上的优点。举个例子,Intel X86指令集,虽然是一个复杂指令集的设计,但是一些具体指令汲取了很多RISC的设计概念,包括它内部的实现,借用了一些 RISC指令集的设计理念;IBM Power指令集,照说它应该是一个精简指令集的架构,但随着 Power指令集的逐步发展,内部也引入了指令组合的概念。指令组合从逻辑上来看,其设计思想与超长指令集VLIW有些接近,思路上是相通的。一直到今天为止,现在市面上能够用到的指令集,虽然还是各自有多样化,但是种类已经减少了,此外它的设计也不再严格区分复杂指令集、精简指令集以及超长指令集,有相互借鉴发展的趋势。(三) 处理器架构与编译技术的演进为了让软件能够变成用指令集描述的指令序列,编译器在此过程中起到了非常关键的作用。随着架构的发展,我们来看下编译器和架构是怎样的演进路径。处理器架构与编译技术的演进2000年以前,大部分处理器都是单核的,所以当时单核优化是编译器以及编译技术的重点。面向不同的指令集,编译技术也在不停演进及发展,比如说循环优化、指针分析、数据重组,面向单核的编译优化等是在该时期发展的。可以看到,编译器本身的优化,是和处理器的实现紧密相关的。随着多核处理器的发展(如果大家还记得前面多核处理器的发展趋势是从2000年到2010年中开始的),编译优化逐渐转向了多核优化的方向。多核处理器中,芯片的性价比(performance/dollar)是一个非常重要的衡量指标。也就是说当单核性能提升到了一定程度时,不得不通过多核来提升整个芯片的性能,然后让软件通过多核架构来获取更进一步的性能提升。到10年代中期,多核的优化又变成了重点。随着技术的持续发展,2010年以后性能提升逐步走向异构的优化(或者叫做超异构的优化)。和多核不同,异构的多核就是处理器的形态从通用的CPU转向了GPU以及现在的AI芯片这样专用的设计。前面也提到了一个趋势是说通用计算的时代已经结束了,现在已经处于异构计算(或者定制化计算)的时代。在这个时代,处理器的形态非常多:DSP、GPU、AI, 甚至于FPGA,像这样不同种类的核在一个系统里协同工作,对整个系统开发或者系统的架构也产生了非常大的挑战。(四) 超异构时代软件开发趋势对于编译优化,问题是这么多不同指令的软件,如何在一个系统里进行协作,让它们能够把整个系统的晶体管利用起来,来做有意义的(或者说是有效的)计算。进一步来看,在现在的异构以及超异构架构时代(或者说是后摩尔时代)整个芯片架构走向异构,快速演进的芯片和高复杂度的应用,对软件开发效率以及兼容性提出了前所未有的挑战。业界提到现在是软件灾难(software disaster)的时代:因为有这么多核,怎样让一份软件能够在不同芯片上运行起来。David Patterson与John Hennessy指出“The easy ride of software is over”:在异构计算时代,想要完全释放出异构芯片的计算能力,程序员必须既懂上层应用算法,又懂底层硬件模型,才能写出高效高质量代码,未来的编程工作会比现在更复杂。业界趋势下图[3]显示了过去40年来的处理器性能。按照目前的速度,标准处理器基准测试的性能在2038年之前不会翻一番。处理器性能(1980-2015)1. 不同领域的计算需要越来越多的异构资源。我们举个例子,现在的天河-2(这是一个大型机的例子)里面集成了intel Phi 芯片,也有通用的处理器。此外还有GPU的集群,在GPU集群里也集成了大量GPU核,但CPU的软件是不能够运行在GPU上的,如何让这两者协同起来,就是一个非常巨大的挑战。2. 出现面向特定领域定制的体系结构(DSA)。这里再给大家介绍下TPU,TPU是谷歌推出的针对AI计算的处理器,该处理单元于2015年首次部署,目前为超过10亿人提供服务。它运行深度神经网络(DNN)的速度是类似技术中当代CPU和GPU的15到30倍,能效是当代CPU和GPU的30到80倍,该处理器使用的是自己的指令集。我们现在所在的超异构时代是针对领域定制的架构,也就是说在超异构时代,异构走向了根据领域定制的趋势,不再是仅有CPU和GPU甚至于以后的XPU(X PU指该处理器定制设计用途未知)。开发者痛点从软件开发者角度来看,软件如何为这么多的处理器架构开发,有几个问题是容易遇到的。1. 开发效率问题不同的处理器其实是有自己的开发技巧的,比如DSP有DSP的优化技巧,GPU有GPU的优化套路,FPGA有自己专用的开发语言。普通开发者在上层应用算法和底层硬件模型无法做到两者皆懂,无法利用芯片能力实现程序性能的提升。如何让这些软件高效地为不同处理器架构进行开发,这是软件开发者需要解决或面对的问题。此外,目前缺乏有效的轻量化实时编译方案,无法做到运行时代码生成。2. 兼容性问题a) 异构处理器核之间的兼容性:怎么理解呢?就是我写一份软件,这款软件是否可以跑在其他不同的处理器上。如果这个程序下载了或完成开发以后,可以不经过任何修改,直接一份可执行的程序就可以在不同的处理器上运行,这就是二进制的兼容。二进制的兼容性在异构处理器时代非常难,芯片快速演进,开发者针对多芯片需要多次开发,代码移植成本很高。b) 源代码的兼容性:在当前时代里,源码兼容性是一个非常大的挑战。体系结构层出不穷,开发者无法通过DSL语言,快速适配多形态芯片进行迭代式开发。举个例子,英伟达GPU的开发,通用GPU的计算开发是使用专用的OpenCL编程语言来进行的。针对不同的GPU,虽然能够用同一种编程语言完成针对不同GPU的软件开发,但是并不能够保证在不同的GPU上性能都是一致的、都是最高的。这就导致了软件在进行移植时,在不能保证二进制兼容性的情况下,能够保证代码的兼容性。但是如果保证了代码的兼容性,对性能的可移植性又不能够满足,所以在这个过程当中,软件移植的成本是非常高的。这也是当前超异构时代软件编程一个非常重要的问题。这里总结一下就是产能Productivity、性能Performance、可移植性Portability的3P问题。超异构时代软件开发趋势如何解决3P问题(Productivity、Performance、Portability),支撑快速演进的芯片可编程性和解决软件兼容性问题,助力开发者实现高质量快速编程,降低代码迁移成本,下面介绍从开发者视角看到的如何对现在超异构时代软件进行开发的趋势(并不是解决方案)。1. 声明式开发:所见即所得的交互式编程。针对普通的应用开发,比如现在手机上比较热门的APP开发,有声明式开发的趋势,那这里的趋势是什么样的?针对手机这种界面型的开发,有一种称为所见即所得的交互式编程。所见即所得这个词原来是用在文本编辑里面的,大家经常使用Word的话,应该知道Word中你在屏幕上打出来是什么样的字,在打印机上打印出来就是什么样。这就叫做所见即所得的文本编辑。这里所见即所得的交互式编程是指:手机终端的应用开发者,在写代码的时候就能够在当前环境内直接看到它未来应用所呈现的样子。比如苹果公司基于SwiftUI开发的AppKit、UIKit、TVUIKit、WatchKit。“UI即代码、代码即UI”的可视化编程理念一直是一种趋势,提供新UI开发机制,所见即所得的实时预览、多端预览、提升UI开发体验和效率是声明式开发的关键挑战。2. 协同式开发:多人协作/端云协同编程。我们认为未来这会是一个比较重要的趋势,所谓协同式开发是和现在软件工程规模非常相关的一个问题。在一个小的软件项目里,可能有5-10位开发者,但是大规模的软件开发,经常有上百个开发者在同一个项目里开发,这时对软件开发提出非常大的挑战:如何让这么大规模的团队同时高效地开发,避免冲突?不同于结对编程,协同式开发使开发者能一起工作,同时保留多人信息,并与他人实时协作编辑和调试,提供新开发模式,即时安全共享项目,联合调试,实现多设备体验一致是协同式开发的关键挑战。3. 智慧化开发:AI辅助编程/AI可视化编程。把重复的劳动交给工具,让开发者专注于逻辑、业务的编写,智能化编程应用而生。智慧化开发的意思是在写代码时会有一些代码提示。原来传统的IDE所实现的代码提示是一种代码逻辑的提示。未来在异构时代,有一个很重要的问题:我们所写的代码对性能会有什么样的影响?传统的开发过程是很难在写代码的时候界面就给出一些性能的预估。未来通过智慧化编程,开发者在代码开发过程当中就能够看到代码的性能预估以及潜力。此外在安全方面,如果代码有一些安全漏洞,在软件开发前期就能解决。面向新创新场景,解决软件工程效率问题和AI编程领域可视化调试和性能分析问题是智慧化编程的关键挑战。代码补全在向智能、深度的方向发展二 产业案例接下来通过编译器和编程语言在昇腾产品里的应用案例给大家介绍下,现在编译器和编程语言技术是如何在产品中发挥作用。2019年9月18日HC2019,副董事长胡厚崑宣布,AI基础软件59.8s完成ResNet-50@imageNet模型训练,超越原世界纪录10s,并现场展示基于MindSpore实现10.02s内20万天体识别,成功发布全球最快的AI训练集群Atlas 900。为了实现这样的世界纪录,编译器在其中贡献了一些非常关键的技术。1. Super Kernel优化技术:在二进制层面实现算子Kernel融合调度,最大化减少TS调度Kernel开销,Resnet50训练E2E性能提升2~3s,助力整体性能突破60s。该技术所解决的是编译性能(应用软件最终编译出来的软件的性能)问题。这对于编译(最终的软件)来说是非常关键的。如果没有该技术,软件所运行的速度突破60秒还是一个非常大的问题。2. 并行编译、ccache优化(Compiler cache的优化):库上CCE算子构建时间从15min+降到4min,提升构建速度3倍。该技术从编译的角度来看,解决的是编译时间的问题:如何把需要编译构建的软件尽快编译出来。从开发的视角来看,大家都不愿意写了一行代码然后要花一小时进行编译。但有时候因为软件上的依赖关系,如果是在非常底层的代码里进行了一次改动,有可能会需要把整个工程进行重构。这个时候,全工程的全量重构的时间就会非常影响开发效率,上述提到的技术就是用于解决这样的开发效率问题。3. 算子优化编译和代码生成:突破循环优化、同步算法、内存复用、多核多batch等优化技术,数量级提升TBE算子性能,TBE成为D算子开发的统一框架。这也是用于解决性能问题。在整个昇腾的案例里面,希望大家记住的是两点:编译在这里解决的,第一个是性能的问题,第二个是开发时间/编译时间的问题。三 技术案例互动分享到这里大家可能会好奇:像这样的编译技术是如何来实现的?接下来就通过一些技术的案例分享给大家讲解。(一) 编译器和编程语言的设计和实现中关注的问题深入到具体单点技术之前,先来看下编译器和编程语言的设计和实现中关注的问题。设计中主要关注如下三点:1. 表达力强现在C的编译器可能很少,C语言应该是底层还在使用。我想本科有可能还会教授C语言编程这门课,但是 AI领域已经进入到大量使用Python语言的阶段。为什么呢?这里有一个很重要的问题,在上层语言中,Python语言对于AI领域的表达能力是比C语言更强的。也就是说在进行编程语言的设计或实现时,会想如何更加容易地描述计算或应用业务的逻辑。只有非常容易描述这些计算以及业务的逻辑,开发者才能够更加高效地把想实现的功能描述出来。2. 容易使用在语言层面,当你想用一个语言来进行表达的时候,语言好学与否,也是需要考虑的一个非常重要的问题。如何让语言变得更加容易使用:好学、好写、好读,还有不容易出错。3. 不易出错、代码安全不容易出错也是在语言设计上非常重要的一个考量,在设计一门语言时,需要注意这个语言是否会让开发者写出一个错误的逻辑,在这点上有可能一些早期的语言做的不是很好,但是新的这些语言在不易出错这个功能上会考虑的更多一些。因为在现在这个万物互联的时代有太多的程序要写,如果很容易出错,程序员会觉得用这个语言太麻烦。然后现在在很多设备的编程上,代码安全也是非常重要的考量,这等于说是在进行软件开发时,使用的语言会有很多的考量,那在实现的过程当中,编译器就是把语言实现,让芯片能够看懂并且执行的工具。而在实现中,为了让芯片看懂并执行,需要关注如下三点:首先是上述商用产品案例中关注的两个问题:一个是性能问题,如何通过编译,让软件运行时间尽可能短。另一个是占用资源少的问题,占用资源少的话可以省出空间资源,编译出来的软件不要太大,比如大家不希望自己下载一个小小的记事本软件,就要占用整个手机的存储空间。在这个过程当中编译器所要完成的目标就是让编译出来的程序越小越好,占用的资源越少越好。其次是平台无关性,如何让我的软件可以在尽可能多的平台上能够运行。举个例子,做APK或者说做移动APP开发的同学,有可能写了一个程序,但是这个程序应用APP无法在所有型号手机上运行,这是非常现实的问题。现在谷歌的应用市场,以及华为的应用市场里,已经有非常多的应用程序了。这些应用开发者所面临的问题是开发一个程序以后,能否让这个应用程序在尽可能多的不同手机上运行,因为只有让程序在尽可能多的不同型号手机上运行,才可能获取更多的用户,这个手机应用才有可能去变现。平台无关性对于开发者来说是最现实的问题。(二) 编译的基本过程上述编译器和编程语言的设计和实现中关注的问题又是如何通过编译过程来解决的?下面给大家介绍下整个编译器编译的基本过程,看它是如何一步步把我们前面讲到的编程语言变成可执行代码的。语言的问题是由上层设计来解决的,和芯片相关的这部分实现就是通过编译器完成的。和芯片相关的部分有:一是怎么让编程语言编译到我们的执行环境上,二是怎么让编译出的代码尽可能跑得快,还要跨平台。(因为时间受限,我在这里做一些大致的介绍,不具体深入。)首先大家知道,我们现在所写的源程序是字符串的形式,字符串本质上是一些文本,它是可以打印出来的,但编译器无法理解这些文本本身的意义是什么。举个简单的例子,像古埃及的文字,现在有许多语言学家正在研究它,对于语言学家而言,这些古埃及的文字也是一些符号构成的文本,我们不能一下就弄懂这些文本到底是什么意思,得需要仔细地翻译。类似的,编译器把源程序文本变成处理器可以理解的二进制格式的过程也是一个翻译的过程。编译的基本过程翻译的第一步是词法语法解析的过程。程序的源代码通常是英文字母、数字和一些其它符号构成的文本。词法分析就是要识别出哪个或者哪几个连续的符号是一个词。多个词又构成了句子。检查句子是否通顺,就需要语法检查了。如果句子也通顺了,看句子表达的意思对不对,前后是否衔接连贯,就是语义检查了。如果经过语法检查,语义检查,句子通顺,意思也没有问题。那么编译器就对目前解析的结果生成一个中间的表示,我们叫它抽象语法树。生成中间表示是一个非常重要的点,往后不同的编译器就会有不同的方式去执行。下面进一步给大家介绍这三种执行方式的差别。解释执行、编译执行及字节码虚拟机的形象解释第一种是解释执行。所谓解释执行就是把程序告诉编译器所要执行的这些逻辑放到可以执行的工具上运行,该工具可以运行这些逻辑。好比同声翻译,你说一句,我翻译一句。解释执行就是你翻译一句,我理解这句意思后就去执行这一句。这样的方式比较灵活但不是很高效。第二种是编译执行。这种方式下编译器会把源程序完整编译成机器能够直接执行的二进制代码,然后再由用户或者其它程序调用执行。在这种编译的过程中,编译器会进行各种性能,资源占用等方面的优化,使得生成的程序性能和大小更优。编译执行是一种静态的,我们称它为静态是因为它是一次性编译生成的。它的特点是程序跑得快,相比而言,解释执行这样的方式就显得非常低效。第三种就是字节码虚拟机执行。字节码虚拟机执行是介于解释执行和编译执行之间的一种方式。Java实现了这样的运行方式。Java的编译器把程序源代码编译成了字节码的格式,然后通过虚拟机来执行(稍微澄清下,这里的虚拟机不是通常意义上的安装虚拟操作系统的虚拟机,而是用来运行字节码的虚拟机)。虚拟机执行还有另一种方式,就是把字节码实时编译成机器码,然后由硬件直接执行。这种方式会比通过虚拟机执行要快,但仍然没有直接在硬件上执行快。(三) 编译优化案例下面为大家介绍两个编译优化的案例。1. Auto-Tuning这里分析一个案例:在静态编译的过程中,如何改善已经编译出来的程序性能。该技术名为Auto-Tuning,也就是自动调优。举个例子,有个优化技术是循环展开。编译器为生成的代码在循环体末尾加一个跳转指令跳转到循环体开始,从而再次进行循环体的执行。这种跳转不利于处理器高效运行。循环展开就是把循环体多复制几分,比如说循环体一共要运行4次,编译器就复制4份相同的代码,中间没有任何跳转,那么执行效率就会比原来的高。通常的静态编译,通过一次编译,把源代码编译成二进制文件,在这个过程中软件要达到性能更优会有一些障碍。有统计数据显示,工业上用到的编译器有上百个参数,这些参数如何设置,如何互相组合,都有不同的策略,通过一次编译而获取更优的性能还是很难的。另一方面,我们的软件要在不同的处理器上运行,不同的处理器指令集不同,各种指令执行效率都有差异,通过一次编译而获取在多个处理器上达到较优性能的效果也是很难的。Auto-Tuning技术,是为了让整个编译策略更优、更友好地适配运行环境。它有3个组件:编译器,Search Driver, Profiler。下图是Auto-Tuning编译的流程图。Auto-Tuning编译技术整体流程在左边的黄色源代码,经过中间绿色的词法、语法、语义分析和优化等步骤最终生成黄色的可执行文件,在开启Auto-Tuning后,过程中除了正常操作外还会把编译过程中应用到的需要调整的参数都完全暴露给外面的控制程序,就是前面提到的Search Driver。接下来为了解编译完成的程序的性能到底如何,我们需要把这个程序运行在执行平台上,可以是硬件平台,或者是仿真的平台。程序运行过程中会生成体现性能的一些指标,包括热点代码、指令的执行效率、内存访问是否高效等。这些指标会提供给第三个组件——Profiler。Profiler会评估当前这个程序执行是否高效,感知程序在执行过程中是否有瓶颈,是否还有更好的优化空间。在Profiler给出进一步的优化建议后,开始再次编译、运行和评估。整个过程相当于在编译器的整个参数调优空间里进行搜索,这也是Search Driver组件名称的来由。从理论上来说这是一个NP完备的问题,计算量非常大。采用这个技术,我们认为可以达到一个相对优的编译的解,这就是Auto-Tuning技术。2. 128比特位宽原子操作指令优化案例另一种提升程序性能的手段是通过指令来对软件应用进行优化,该案例讲的是如何使用一个128比特位宽的原子操作指令来优化数据库的应用,举一反三,你也可以通过特定场景的问题驱动指令集的设计。数据库有大量数据在多个核上运行,而现在的处理器有很多的核,比如鲲鹏有64-128个核,甚至以后会更多。现代数据库例如PostgreSQL等在高并发业务场景下,均采用预写日志系统(Write Ahead Logging)对事务进行提交和记录。总体思想为数据文件的修改必须发生在这些修改已经记录在日志文件中之后,因此在生成该事务提交的日志记录时 ,需要原子性的预留数据写入磁盘的全局位置信息,否则在并发情况下后台线程会将数据写到错误的地址上。通过原子锁完成位置信息的预留,会引入跨CPU访存延迟、Cache一致性代价等问题引起的性能瓶颈。全局位置信息包括一个64位起始地址和一个64位的结束地址,若想通过Lock-Free无锁操作完成位置信息的预留,则需引入双寄存器原子指令。使用双寄存器原子指令原子性完成全局位置信息预留(示例代码如下),多个lock-free线程可以同时访问同一数据而不产生数据竞争或者损坏,同时某个线程在执行数据访问时挂起不会阻碍其他的线程继续执行。cas: ldxp x7, x6, [x8] # 使用ldxp指令读取全局位置信息 eor x7, x7, x2 # 判断Start Position x7是否等于期望值x2 eor x6, x6, x3 # 判断End Position x6是否等于期望值x3 orr x6, x7, x6 # 判断Start & End Position是否均保留有效 cbnz x6, fail # 若无效,则其他线程已修改 stxp w7, x4, x5, [x8] # 反之有效,stxp指令更新全局位置信息 cbnz w7, cas # 若写入失败,则重新尝试 fail: # 位置保留失败,根据程序逻辑执行指令这里的LDXP/STXP指令用以执行一对通用寄存器的原子存储操作,指令语义如下所示:LDXP , , [<Xn|SP>] // Load Exclusive Pair of Registers STXP , , , [<Xn|SP>] // Store Exclusive Pair of registersLDXP:从Memory中读取一对双字数据到目标寄存器Xt1,Xt2中,同时对Memory地址注册一个监控保留状态。STXP:有条件的将Xt1,Xt2一对双字字数据写入到Memory中,仅当此地址的监控保留状态有效时才执行成功,如果STXP执行成功,将零值写入Ws。如果STXP执行失败,将非零值写入Ws。在我们的实验中,上述优化为某数据库的Measured tpmTOTAL性能提升10%。四 挑战课题接下来讲我们这个领域里有哪些挑战的课题,这些课题想解决的问题是什么样的。1.通用语言扩展机制研究,以及新型AI编程语言的设计和实现AI编程以及AI语言的研究一直是我们团队关注的重点,我们要解决如何提升AI编程的体验和效率,充分发挥硬件的潜力,最大化AI程序的性能。例如基于昇腾芯片,如何让AI编程更高效、性能更优。这方面的课题内容是构建一套面向AI算法开发的编程语言,实现语言原生自动微分、动静态图融合、稀疏矩阵编程等核心技术。对于通用编程语言,如何扩充现有编程语言和编译器能力,如何构建嵌入式领域的相关语言(eDSL),还有快速满足各种应用场景的定制需求。这方面的课题内容是探索和构建通用编程语言各种可扩展机制的设计和实现:包括但不限于元编程、跨语言互操作、eDSL及其类型系统、可扩展编译器框架。2.基于开放体系架构下的DSA设计与编译工具链技术研究领域定制架构(Domain Specific Architecture DSA)是计算机架构的发展趋势,针对应用领域定制的软硬件架构,解决摩尔定律无法持续的危机,在硬件变化基本稳定的情况下通过领域定制架构持续提升软件性能。现在是超异构的时代,未来的架构,芯片的专用性会越来越强。在数据中心、AI&视觉计算等不同的场景下,随着业务性能的需要,例如数据库查询性能、HPC算法能力等需求下,专用架构、专用芯片的使用会越来越多。基于这样的趋势,如何设计与研发相对应的编译工具链也是一个挑战课题。课题内容具体如下所示:1)DSA设计:突破已有计算机架构的限制,利用RISC-V等开放架构,设计特定场景的软硬件系统,如视觉分析,AI计算,图形处理,HPC计算等;2)DSA编译优化自动化:高级语言到汇编指令之间的转换需手工开发编译器翻译。当前大量DSA的出现,让编译优化的开发成为瓶颈,需要探索新的方法;3)DSA高效建模:对DSA快速构建性能模型,通过仿真,FPGA原型等手段,快速评估DSA设计效果;3. 对AI芯片编译器技术的研究AI芯片支持全场景,包括不同的芯片规格,需要在端、边、云场景下发挥出极致算力,对编译技术有较高挑战。面临不同场景下算法的侧重不同,芯片SOC级别的内存带宽不同,计算单元的算力不同以及上层框架的要求不同等问题,需要挑战编程语言表达完备性、优化技术如何实现、如何进行POLYHEDRAL循环优化、超轻量在线编译、多场景性能优化、融合算子最优切分策略求解、计算单元最优调度等业界难题。4. 面向应用的统一IR(公共中间表示)的研究多核和异构是未来计算系统的发展趋势,从应用角度看,多种业务融合、互相协同开发和调优的需求会逐渐增加。从硬件来看,如何协同多种算力高效执行是一个挑战课题,特别是在人工智能领域出现了越来越多的IR(编译器中间表示),彼此之间互相割裂无法统一优化和调试。在新硬件架构下,如何利用整体算力来完成应用的高效执行已经成为一个挑战的课题。我们需要确定一个统一的异构编程语言、探索出一个方便易用的异构编程框架、开发相应的编译优化技术及运行时支持,给开发者提供易用性的同时充分挖掘硬件潜力。同时本课题瞄准支持多语言公共表示和抽象,支持多层 IR同时也支持其他IR和中间语言,实现跨语言高效互通,为全程序优化打下基础;提供一个可沉淀不同领域优化技术的公共基础设施、动静态各种优化技术模块化,并可按不同场景需要自适应自组合,如在昇腾AI领域,支持更好的算子融合优化。通过该课题研究,达成多编程语言支持,降低 “语言墙” 开销,构建业界领先的编译优化基础设施(含传统应用和AI模型算法),并支持更多功能(如程序分析、安全检测)。今天的课题介绍就到这里了。以上是我给初学者的建议和分享,谢谢。参 考[1] https://www.karlrupp.net/2018/02/42-years-of-microprocessor-trend-data/[2] https://www.nextplatform.com/2019/02/05/the-era-of-general-purpose-computers-is-ending/[3] https://dl.acm.org/doi/fullHtml/10.1145/3154484原文转载自毕昇编译-AIOT时代的编程语言、编译器与指令集架构:机遇、挑战与技术分享扫码关注毕昇编译公众号
  • [分布式] GPU上运行Mindspore程序出现OOM
    【功能模块】【操作步骤&问题现象】能够在单张GPU上成功运行模型,但是在单机多卡训练时,保持batchsize不变,随着训练进行,会出现显卡内存不足的问题(OOM)1、使用mpirun运行多卡训练,运行代码为mpirun --allow-run-as-root -n $DEVICE_NUM python train_mindspore.py --config_path $CONFIG_PATH --device_num $DEVICE_NUM> train.log 2>&1 &【截图信息】【日志信息】(可选,上传日志内容或者附件)
  • [活动体验] 通过配置模型提供Servable
    通过配置模型提供Servable概述MindSpore Serving当前仅支持Ascend 310、Ascend 910和Nvidia GPU环境。MindSpore Serving的Servable提供推理服务,包含两种类型。一种是推理服务来源于单模型,一种是推理服务来源于多模型组合,多模型组合正在开发中。模型需要进行配置以提供Serving推理服务。本文将说明如何对单模型进行配置以提供Servable,以下所有Servable配置说明针对的是单模型Servable,Serving客户端简称客户端。以ResNet-50作为样例介绍如何配置模型提供Servable。相关概念预处理和后处理模型提供推理能力,模型的每个输入和输出的数据类型、数据长度、Shape是固定的。如果客户端发来的数据不能直接满足模型输入要求,需要通过预处理转化为满足模型输入的数据。 如果模型的输出不直接提供给客户端,需要通过后处理转化为所需的输出数据。以下图是resnet50 Servable数据流程图,描述了图像数据从Serving客户端通过网络传输到Serving,Serving进行预处理、推理和后处理,最后向Serving客户端返回结果:针对Resnet50推理模型,客户端发来的数据为jpg、png等格式的图片,预期返回图片的分类。Resnet模型输入为经过图片Decode、Resize、Normalize等操作产生的Tensor,输出为每个类别的得分Tensor。需要通过预处理将图片转化为满足模型输入的Tensor,通过后处理返回得分最大的类别名称或者前5类别名称及其得分。在不同的场景下,如果来自客户端的数据输入组成、结构或类型不同,可以提供不同的预处理。如果对模型的输出也有不同的要求,可以提供不同的后处理。比如上述resnet50 Servable,针对返回得分最大的类别名称还是前5类别名称及其得分这两种场景提供了两个后处理。方法上述的resnet Servable提供了classify_top5和classify_top1两个方法(Method)。classify_top5输入为image,输出为label和score,返回前5的分类名称和得分。classify_top1预处理和classify_top5一致,而后处理不同,输入为image,输出为label,返回最大得分的分类名称。一个Servable可提供一个或多个方法,Servable的名称和方法的名称标记了Serving提供的一个服务,每个方法对客户端提供的数据进行可选的预处理,接着进行模型推理,对模型的推理结果进行可选的后处理,最后将需要的结果返回给客户端。Servable包含如下内容:指定可选的预处理和可选的后处理;定义方法输入、预处理、模型、后处理、方法输出之间的数据流,前者可作为后者的输入。比如方法输出的值可来源于方法输入、预处理、模型或后处理;指定方法名,使客户端可以通过方法名指定使用的方法;指定方法的输入和输出名称,使客户端可以通过名称来指定输入、获取输出。实例每次请求可包括一个或多个实例,每个实例之间相互独立,结果互不影响。比如一张图片返回一个分类类别,三张独立的图片独立返回三个分类类别模型配置以Resnet50模型为例,模型配置文件目录结果如下图所示:•目录resnet50指示Servable的名称。通过servable_config.py配置Servable,其中包括预处理和后处理定义、模型声明、方法定义。目录1和2表示版本1和版本2的模型,模型版本为正整数,从1开始,数字越大表示版本越新。resnet50_1b_cifar10.mindir为模型文件,Servable启动会加载对应版本的模型文件。预处理和后处理定义预处理和后处理定义方式例子如下:代码如下:import numpy as npimport mindspore.dataset.vision.c_transforms as VC# cifar 10idx_2_label = ['airplane', 'automobile', 'bird', 'cat', 'deer', 'dog', 'frog', 'horse', 'ship', 'truck']def preprocess_eager(image):"""Define preprocess, input is image numpy, return preprocess result.Return type can be numpy, str, bytes, int, float, or bool.Use MindData Eager, this image processing can also use other image processing library,likes numpy, PIL or cv2 etc."""image_size = 224mean = [0.4914 * 255, 0.4822 * 255, 0.4465 * 255]std = [0.2023 * 255, 0.1994 * 255, 0.2010 * 255]decode = VC.Decode()resize = VC.Resize([image_size, image_size])normalize = VC.Normalize(mean=mean, std=std)hwc2chw = VC.HWC2CHW()image = decode(image)image = resize(image)image = normalize(image)image = hwc2chw(image)return imagedef postprocess_top1(score):"""Define postprocess. This example has one input and one output.The input is the numpy tensor of the score, and the output is the label str of top one."""max_idx = np.argmax(score)return idx_2_label[max_idx]def postprocess_top5(score):"""Define postprocess. This example has one input and two outputs.The input is the numpy tensor of the score. The first output is the str joined by labels of top five,and the second output is the score tensor of the top five."""idx = np.argsort(score)[::-1][:5] # top 5ret_label = [idx_2_label[i] for i in idx]ret_score = score[idx]return ";".join(ret_label), ret_score预处理和后处理定义格式相同,入参为每个实例的输入数据。输入数据为文本时,入参为str对象;输入数据为其他数据类型,包括Tensor、Scalar number、Bool、Bytes时,入参为numpy对象。通过return返回实例的处理结果,return返回的每项数据可为numpy、Python的bool、int、float、str、或bytes数据对象。模型声明resnet50 Servabale模型声明示例代码如下所示:代码如下:from mindspore_serving.server import registerresnet_model = register.declare_model(model_file="resnet50_1b_cifar10.mindir", model_format="MindIR", with_batch_dim=True)其中declare_model入参model_file指示模型的文件名称;model_format指示模型的模型类别,当前Ascend310环境支持OM和MindIR两种模型类型,Ascend910和GPU环境仅支持MindIR模型类型。如果模型输入和输出第1维度不是batch维度,需要设置参数with_batch_dim=False,with_batch_dim默认为True。设置with_batch_dim为True,主要针对处理图片、文本等包含batch维度的模型。假设batch_size=2,当前请求有3个实例,共3张图片,会拆分为2次模型推理,第1次处理2张图片返回2个结果,第2次对剩余的1张图片进行拷贝做一次推理并返回1个结果,最终返回3个结果。另外,对于一个模型,假设其中一个输入是数据输入,包括batch维度信息,另一个输入为模型配置信息,没有包括batch维度信息,此时在设置with_batch_dim为True基础上,设置额外参数without_batch_dim_inputs指定没有包括batch维度信息的输入信息。 例如:代码如下from mindspore_serving.server import register# Input1 indicates the input shape information of the model, without the batch dimension information.# input0: [N,3,416,416], input1: [2]yolov_model = register.declare_model(model_file="yolov3_darknet53.mindir", model_format="MindIR",with_batch_dim=True, without_batch_dim_inputs=1)对于分布式模型,与非分布式单模型配置相比仅声明方法不同,需要使用mindspore_serving.server.distributed.declare_servable,其中入参rank_size表示模型推理使用的device个数,stage_size表示流水线的段数代码如下:from mindspore_serving.server import distributedmodel = distributed.declare_servable(rank_size=8, stage_size=1, with_batch_dim=False)方法定义方法定义的例子如下:代码如下:from mindspore_serving.server import register@register.register_method(output_names=["label"])def classify_top1(image): # pipeline: preprocess_eager/postprocess_top1, model"""Define method `classify_top1` for servable `resnet50`.The input is `image` and the output is `label`."""x = register.add_stage(preprocess_eager, image, outputs_count=1)x = register.add_stage(resnet_model, x, outputs_count=1)x = register.add_stage(postprocess_top1, x, outputs_count=1)return x@register.register_method(output_names=["label", "score"])def classify_top5(image):"""Define method `classify_top5` for servable `resnet50`.The input is `image` and the output is `label` and `score`. """x = register.add_stage(preprocess_eager, image, outputs_count=1)x = register.add_stage(resnet_model, x, outputs_count=1)label, score = register.add_stage(postprocess_top5, x, outputs_count=2)return label, score上述代码在Servable resnet50定义了classify_top1和classify_top5方法,其中方法classify_top1入参为image,出参为label,方法classify_top5入参为image,出参为label和score。即,Servable方法的入参由Python方法的入参指定,Servable方法的出参由register_method的output_names指定。另外方法定义中:add_stage指示了使用的预处理、模型和后处理,以及它们的输入。return指示了方法的返回数据,可以是方法的输入或者add_stage的输出,和register_method的output_names参数对应。用户在客户端使用Servable某个方法提供的服务时,需要通过入参名称指定对应输入的值,通过出参名称识别各个输出的值。比如客户端访问方法classify_top5:代码如下:import osfrom mindspore_serving.client import Clientdef read_images():"""Read images for directory test_image"""image_files = []images_buffer = []for path, _, file_list in os.walk("./test_image/"):for file_name in file_list:image_file = os.path.join(path, file_name)image_files.append(image_file)for image_file in image_files:with open(image_file, "rb") as fp:images_buffer.append(fp.read())return image_files, images_bufferdef run_classify_top5():"""Client for servable resnet50 and method classify_top5"""client = Client("localhost:5500", "resnet50", "classify_top5")instances = []image_files, images_buffer = read_images()for image in images_buffer:instances.append({"image": image}) # input `image`result = client.infer(instances)for file, result_item in zip(image_files, result): # result for every imagelabel = result_item["label"] # result `label`score = result_item["score"] # result `score`print("file:", file)print("label result:", label)print("score result:", score)if __name__ == '__main__':run_classify_top5()