【MindStudio训练营第一季】基于U-Net网络的图像分割的MindStudio实践

时间:2022-12-24 15:58:39

前情说明

本作业基于Windows版MindStudio 5.0.RC3,远程连接ECS服务器使用,ECS是基于官方分享的CANN6.0.RC1_MindX_Vision3.0.RC3镜像创建的。

基于ECS(Ascend310)的U-Net网络的图像分割

1. U-Net网络介绍:

U-Net模型基于二维图像分割。在2015年ISBI细胞跟踪竞赛中,U-Net获得了许多最佳奖项。论文中提出了一种用于医学图像分割的网络模型和数据增强方法,有效利用标注数据来解决医学领域标注数据不足的问题。U型网络结构也用于提取上下文和位置信息。

【MindStudio训练营第一季】基于U-Net网络的图像分割的MindStudio实践

[U-Net 论文]: Olaf Ronneberger, Philipp Fischer, Thomas Brox. "U-Net: Convolutional Networks for Biomedical Image Segmentation." conditionally accepted at MICCAI 2015. 2015.

2. ECS运行说明

我们的操作基本都在root用户下执行。

首先,修改bash,具体命令和结果如下。

【MindStudio训练营第一季】基于U-Net网络的图像分割的MindStudio实践

本项目支持MindStudio运行和终端运行。

(1)下载项目代码

下载链接:​​https://alexed.obs.cn-north-4.myhuaweicloud.com/unet_sdk.zip​

将项目文件unet_sdk.zip上传至华为云ECS弹性云服务器/root/目录下,并解压;或者下载到本地电脑,用MindStudio打开。
将之前unet_hw960_bs1.air模型放到/unet_sdk/model/目录下。

【MindStudio训练营第一季】基于U-Net网络的图像分割的MindStudio实践

项目文件结构

├── unet_sdk
├── README.md
├── data //数据集
│ ├── 1
│ │ ├──image.png //图片
│ │ ├──mask.png //标签
│ ...
├── model
│ ├──air2om.sh // air模型转om脚本
│ ├──xxx.air //air模型
│ ├──xxx.om //om模型
│ ├──aipp_unet_simple_opencv.cfg // aipp文件
├── pipeline
│ ├──unet_simple_opencv.pipeline // pipeline文件
├── main.py // 推理文件
├── run.sh // 执行文件
├── requirements.txt // 需要的三方库

(2) 模型转换

将unet_hw960_bs1.air模型转为昇腾AI处理器支持的.om格式离线模型,此处模型转换需要用到ATC工具。

昇腾张量编译器(Ascend Tensor Compiler,简称ATC)是昇腾CANN架构体系下的模型转换工具,它可以将开源框架的网络模型或Ascend IR定义的单算子描述文件(json格式)转换为昇腾AI处理器支持的.om格式离线模型。模型转换过程中可以实现算子调度的优化、权值数据重排、内存使用优化等,可以脱离设备完成模型的预处理。

​ATC参数概览​​:

【MindStudio训练营第一季】基于U-Net网络的图像分割的MindStudio实践


【MindStudio训练营第一季】基于U-Net网络的图像分割的MindStudio实践

(3) 运行脚本

运行脚本:

cd unet_sdk/model/   # 切换至模型存储目录
atc --framework=1 --model=unet_hw960_bs1.air --output=unet_hw960_bs1 --input_format=NCHW --soc_version=Ascend310 --log=error --insert_op_conf=aipp_unet_simple_opencv.cfg
  • 注意air模型转om只支持静态batch,这里batchsize=1。

参数说明:

 framework:原始框架类型。
 model:原始模型文件路径与文件名。
 output:转换后的离线模型的路径以及文件名。
 input_format:输入数据格式。
 soc_version:模型转换时指定芯片版本。
 log:显示日志的级别。
 insert_op_conf:插入算子的配置文件路径与文件名,这里使用AIPP预处理配置文件,用于图像数据预处理。

输出结果:

ATC run success,表示模型转换成功,得到unet_hw960_bs1.om模型。

【MindStudio训练营第一季】基于U-Net网络的图像分割的MindStudio实践

模型转换成功之后,可以使用MindX SDK mxVision运行脚本,在Ascend 310上进行推理。

(4) MindX SDK mxVision 执行推理

MindX SDK文档请参考:​​https://support.huaweicloud.com/ug-vis-mindxsdk203/atlasmx_02_0051.html​

MindX SDK执行推理的业务流程:

通过stream配置文件,Stream manager可识别需要构建的element以及element之间的连接关系,并启动业务流程。Stream manager对外提供接口,用于向stream发送数据和获取结果,帮助用户实现业务对接。

plugin表示业务流程中的基础模块,通过element的串接构建成一个stream。buffer用于内部挂载解码前后的视频、图像数据,是element之间传递的数据结构,同时也允许用户挂载元数据(Metadata),用于存放结构化数据(如目标检测结果)或过程数据(如缩放后的图像)。

【MindStudio训练营第一季】基于U-Net网络的图像分割的MindStudio实践

MindX SDK基础概念介绍:

【MindStudio训练营第一季】基于U-Net网络的图像分割的MindStudio实践


【MindStudio训练营第一季】基于U-Net网络的图像分割的MindStudio实践

MindX SDK基础插件:

【MindStudio训练营第一季】基于U-Net网络的图像分割的MindStudio实践

MindX SDK业务流程编排:

Stream配置文件以json格式编写,用户必须指定业务流名称、元件名称和插件名称,并根据需要,补充元件属性和下游元件名称信息。

以下表格为本实验pipeline/unet_simple_opencv.pipeline文件及其对应的名称及描述:

【MindStudio训练营第一季】基于U-Net网络的图像分割的MindStudio实践


【MindStudio训练营第一季】基于U-Net网络的图像分割的MindStudio实践

pipeline/unet_simple_opencv.pipeline文件内容如下,可根据实际开发情况进行修改。

{
"unet_mindspore": {
"stream_config": {
"deviceId": "0"
},
"appsrc0": {
"props": {
"blocksize": "4096000"
},
"factory": "appsrc",
"next": "mxpi_imagedecoder0"
},
"mxpi_imagedecoder0": {
"props": {
"cvProcessor": "opencv",
"outputDataFormat": "BGR"
},
"factory": "mxpi_imagedecoder",
"next": "mxpi_imagecrop0"
},
"mxpi_imagecrop0": {
"props": {
"cvProcessor": "opencv",
"dataSource": "ExternalObjects"
},
"factory": "mxpi_imagecrop",
"next": "mxpi_imageresize0"
},
"mxpi_imageresize0": {
"props": {
"handleMethod": "opencv",
"resizeType": "Resizer_Stretch",
"resizeHeight": "960",
"resizeWidth": "960"
},
"factory": "mxpi_imageresize",
"next": "mxpi_tensorinfer0"
},
"mxpi_tensorinfer0": {
"props": {
"dataSource": "mxpi_imageresize0",
"modelPath": "model/unet_hw960_bs1_AIPP.om"
},
"factory": "mxpi_tensorinfer",
"next": "mxpi_dumpdata0"
},
"mxpi_dumpdata0": {
"props": {
"requiredMetaDataKeys": "mxpi_tensorinfer0"
},
"factory": "mxpi_dumpdata",
"next": "appsink0"
},
"appsink0": {
"props": {
"blocksize": "4096000"
},
"factory": "appsink"
}
}
}

(5) 修改modelPath

打开pipeline/unet_simple_opencv.pipeline文件,将"mxpi_tensorinfer0"元件的属性"modelPath"(模型导入路径)修改为模型转换后保存的om模型"model/unet_hw960_bs1.om"。

修改结果:

"modelPath": "model/unet_hw960_bs1.om"

modelPath修改完成之后,保存pipeline/unet_simple_opencv.pipeline文件。
StreamManagerApi:
StreamManagerApi文档请参考:
​https://support.huaweicloud.com/ug-vis-mindxsdk203/atlasmx_02_0320.html​​ StreamManagerApi用于对Stream流程的基本管理:加载流程配置、创建流程、向流程发送数据、获得执行结果、销毁流程。

这里用到的StreamManagerApi有:

  • InitManager:初始化一个StreamManagerApi。
  • CreateMultipleStreams:根据指定的配置创建多个Stream。
  • SendData:向指定Stream上的输入元件发送数据(appsrc)。
  • GetResult:获得Stream上的输出元件的结果(appsink)
  • DestroyAllStreams:销毁所有的流数据。

main.py文件内容如下,可根据实际开发情况进行修改。

import argparse
import base64
import json
import os

import cv2
import numpy as np
from StreamManagerApi import *
import MxpiDataType_pb2 as MxpiDataType

x0 = 2200 # w:2200~4000; h:1000~2800
y0 = 1000
x1 = 4000
y1 = 2800
ori_w = x1 - x0
ori_h = y1 - y0

def _parse_arg():
parser = argparse.ArgumentParser(description="SDK infer")
parser.add_argument("-d", "--dataset", type=str, default="data/",
help="Specify the directory of dataset")
parser.add_argument("-p", "--pipeline", type=str,
default="pipeline/unet_simple_opencv.pipeline",
help="Specify the path of pipeline file")
return parser.parse_args()


def _get_dataset(dataset_dir):
img_ids = sorted(next(os.walk(dataset_dir))[1])
for img_id in img_ids:
img_path = os.path.join(dataset_dir, img_id)
yield img_path


def _process_mask(mask_path):
# 手动裁剪
mask = cv2.imread(mask_path, cv2.IMREAD_GRAYSCALE)[y0:y1, x0:x1]
return mask


def _get_stream_manager(pipeline_path):
stream_mgr_api = StreamManagerApi()
ret = stream_mgr_api.InitManager() #初始化stream
if ret != 0:
print(f"Failed to init Stream manager, ret={ret}")
exit(1)

with open(pipeline_path, 'rb') as f:
pipeline_content = f.read()

ret = stream_mgr_api.CreateMultipleStreams(pipeline_content) # 创建stream
if ret != 0:
print(f"Failed to create stream, ret={ret}")
exit(1)
return stream_mgr_api


def _do_infer_image(stream_mgr_api, image_path):
stream_name = b'unet_mindspore' # 与pipeline中stream name一致
data_input = MxDataInput()
with open(image_path, 'rb') as f:
data_input.data = f.read()

# 插入抠图的功能,扣1800*1800大小
roiVector = RoiBoxVector()
roi = RoiBox()
roi.x0 = x0
roi.y0 = y0
roi.x1 = x1
roi.y1 = y1
roiVector.push_back(roi)
data_input.roiBoxs = roiVector

unique_id = stream_mgr_api.SendData(stream_name, 0, data_input) # 向指定Stream上的输入元件发送数据(appsrc)
if unique_id < 0:
print("Failed to send data to stream.")
exit(1)

infer_result = stream_mgr_api.GetResult(stream_name, unique_id) # 获得Stream上的输出元件的结果(appsink)
if infer_result.errorCode != 0:
print(f"GetResult error. errorCode={infer_result.errorCode},"
f"errorMsg={infer_result.data.decode()}")
exit(1)
# 用dumpdata获取数据
infer_result_data = json.loads(infer_result.data.decode())
content = json.loads(infer_result_data['metaData'][0]['content'])

tensor_vec = content['tensorPackageVec'][0]['tensorVec'][1] # 1是argmax结果
data_str = tensor_vec['dataStr']
tensor_shape = tensor_vec['tensorShape']
argmax_res = np.frombuffer(base64.b64decode(data_str), dtype=np.float32).reshape(tensor_shape)
np.save("argmax_result.npy", argmax_res)

tensor_vec = content['tensorPackageVec'][0]['tensorVec'][0] # 0是softmax结果
data_str = tensor_vec['dataStr']
tensor_shape = tensor_vec['tensorShape']
softmax_res = np.frombuffer(base64.b64decode(data_str), dtype=np.float32).reshape(tensor_shape)
np.save("softmax_result.npy", softmax_res)

return softmax_res # ndarray

# 自定义dice系数和iou函数
def _calculate_accuracy(infer_image, mask_image):
mask_image = cv2.resize(mask_image, infer_image.shape[1:3])
mask_image = mask_image / 255.0
mask_image = (mask_image > 0.5).astype(np.int)
mask_image = (np.arange(2) == mask_image[..., None]).astype(np.int)

infer_image = np.squeeze(infer_image, axis=0)
inter = np.dot(infer_image.flatten(), mask_image.flatten())
union = np.dot(infer_image.flatten(), infer_image.flatten()) + \
np.dot(mask_image.flatten(), mask_image.flatten())

single_dice = 2 * float(inter) / float(union + 1e-6)
single_iou = single_dice / (2 - single_dice)
return single_dice, single_iou


def main(_args):
dice_sum = 0.0
iou_sum = 0.0
cnt = 0
stream_mgr_api = _get_stream_manager(_args.pipeline)
for image_path in _get_dataset(_args.dataset):
infer_image = _do_infer_image(stream_mgr_api, os.path.join(image_path, 'image.png')) # 抠图并且reshape后的shape,1hw
mask_image = _process_mask(os.path.join(image_path, 'mask.png')) # 抠图后的shape, hw
dice, iou = _calculate_accuracy(infer_image, mask_image)
dice_sum += dice
iou_sum += iou
cnt += 1
print(f"image: {image_path}, dice: {dice}, iou: {iou}")
print(f"========== Cross Valid dice coeff is: {dice_sum / cnt}")
print(f"========== Cross Valid IOU is: {iou_sum / cnt}")
stream_mgr_api.DestroyAllStreams() # 销毁stream

if __name__ == "__main__":
args = _parse_arg()
main(args)

run.sh文件内容如下,可根据实际开发情况进行修改。参考SDK软件包sample脚本,需要按照实际路径修改各个环境变量路径。

set -e

CUR_PATH=$(cd "$(dirname "$0")" || { warn "Failed to check path/to/run.sh" ; exit ; } ; pwd)

# Simple log helper functions
info() { echo -e "\033[1;34m[INFO ][MxStream] $1\033[1;37m" ; }
warn() { echo >&2 -e "\033[1;31m[WARN ][MxStream] $1\033[1;37m" ; }

#export MX_SDK_HOME=${CUR_PATH}/../../..
export LD_LIBRARY_PATH=${MX_SDK_HOME}/lib:${MX_SDK_HOME}/opensource/lib:${MX_SDK_HOME}/opensource/lib64:/usr/local/Ascend/ascend-toolkit/latest/acllib/lib64:${LD_LIBRARY_PATH}
export GST_PLUGIN_SCANNER=${MX_SDK_HOME}/opensource/libexec/gstreamer-1.0/gst-plugin-scanner
export GST_PLUGIN_PATH=${MX_SDK_HOME}/opensource/lib/gstreamer-1.0:${MX_SDK_HOME}/lib/plugins

#to set PYTHONPATH, import the StreamManagerApi.py
export PYTHONPATH=$PYTHONPATH:${MX_SDK_HOME}/python

python3 main.py
exit 0

(6) 运行脚本

激活mxVision环境变量(本作业无需此步骤):

. /root/mxVision/set_env.sh

运行脚本:

cd /root/unet_sdk/  # 切换至推理脚本目录
bash run.sh

运行截图如下:

【MindStudio训练营第一季】基于U-Net网络的图像分割的MindStudio实践

通过MindStudio运行,会自动上传代码到预设路径,并执行,运行结果如下:

【MindStudio训练营第一季】基于U-Net网络的图像分割的MindStudio实践

MindStudio专家系统工具

专家系统工具当前支持专家系统自有知识库和生态知识库对模型/算子进行性能分析,支持性能调优一键式闭环实现一键式性能问题优化能力。

专家系统自有知识库当前提供的功能:基于Roofline模型的算子瓶颈识别与优化建议、基于Timeline的AI CPU算子优化、算子融合推荐、TransData算子识别和算子优化分析。

生态知识库的专家系统性能调优功能:由生态开发者使用Python编程语言进行开发,用户通过调用专家系统提供的接口,对生态开发者提供的模型/算子进行性能分析。

MindStudio IDE当前版本仅支持的生态知识库创建功能,可以在上面完成生态知识库代码开发,暂不支持对生态知识库的专家系统分析功能。性能调优一键式闭环提供一键式性能问题分析和优化能力,有效提升用户性能分析和优化效率。

下面介绍如何使用专家系统工具对模型和算子进行性能瓶颈识别并输出优化建议。

1. 单击菜单栏“Ascend > Advisor”,弹出专家系统工具界面 。如图所示。

【MindStudio训练营第一季】基于U-Net网络的图像分割的MindStudio实践

2. 单击上图界面左上角红框中的按钮,打开专家系统配置界面,各参数配置示例如图所示。

【MindStudio训练营第一季】基于U-Net网络的图像分割的MindStudio实践

各参数具体说明如下:

【MindStudio训练营第一季】基于U-Net网络的图像分割的MindStudio实践

3. 配置完成后单击“Start”启动分析。

之后开始运行,如图所示,具体时间与网络情况有关。

【MindStudio训练营第一季】基于U-Net网络的图像分割的MindStudio实践

运行完成后,会自动跳转到如下图所示界面。

【MindStudio训练营第一季】基于U-Net网络的图像分割的MindStudio实践

这里的Model Performance Report是模型性能的总结报告。根据该页面,可以知道模型性能是好是坏,也可以知道模型的吞吐率和运行时间,AI Core的利用率,Tiling策略是否合理,部分字段说明如下所示,具体可参见​​https://www.hiascend.com/document/detail/zh/mindstudio/50RC3/msug/msug_000285.html。​

【MindStudio训练营第一季】基于U-Net网络的图像分割的MindStudio实践

从上述截图的分析结果可以看出我们所用的U-Net模型的芯片利用率是偏低的,甚至可以说是很差,有很大的优化的空间。下面我们来详细分析。

【MindStudio训练营第一季】基于U-Net网络的图像分割的MindStudio实践

先来看根据总体性能数据汇总计算得出的Model Performance,显示为Bad,情况不乐观啊。接着看看汇总信息。

【MindStudio训练营第一季】基于U-Net网络的图像分割的MindStudio实践

可以看到Cube吞吐量Cube Throughput约393 GOps,Vector吞吐量Vector Throughput约0.89 GOps,AI Core执行时间88712us,任务执行时间177183us,平均BlockDim利用率Avg BlockDim Usage,算子执行时的平均核心数,数值为1,这反映了反映芯片利用情况,考虑到我们ECS的Ascend 310总计2个AI Core,且由系统自动调度,这里为1还可以接收。但下面的数据可难看了。

【MindStudio训练营第一季】基于U-Net网络的图像分割的MindStudio实践

如图所示,芯片利用率Chip Utilization。按照规则,80为优,显示为绿色;小于80则为差,显示为红色。根据Pipeline Bound的数值计算得出。而我们这里直接为0了。再看Cube利用率Cube Ratio约为0.41,Vector利用率Vector Ratio约为0.29,Scalar利用率Scalar Ratio约为0.26,还有优化空间,而MTE1瓶颈、MTE2瓶颈、MTE3瓶颈都还不小。特别是MTE2瓶颈,约为0.39。下面接着看。

【MindStudio训练营第一季】基于U-Net网络的图像分割的MindStudio实践

来看内存读入量的数据切片策略Tiling Strategy为5.23,情况糟糕。根据规则,数值达到80为优,显示为绿色;小于80则为差,显示为红色。这是根据Memory Redundant的数值计算得出。同时,可以看到真实内存读入量Real Memory Input(GB)约为1.44GB,真实内存写出量Real Memory Output(GB)约为0.60GB,都在可用范围内。

接下来进入Computational Graph Optimization界面,如图红框所示两处都可以,二者就是简版和精装版的区别了。在这里,我们可以看到计算图优化,算子融合推荐功能专家系统分析建议,会分行展示可融合的算子。

【MindStudio训练营第一季】基于U-Net网络的图像分割的MindStudio实践

先来看看需要进行UB融合的算子,点击算子,会自动跳转相应的计算图,既直观又方便啊。同时我们看到可融合算子的执行时间Fusion Operator Duration达到了约9585us,接近10ms了,算是比较大了。本模型没有AIPP融合推荐和L2Cache融合推荐。

【MindStudio训练营第一季】基于U-Net网络的图像分割的MindStudio实践

我们直接看TransData算子融合推荐,如图所示。该算子执行持续时间在2.5ms左右,也不算小了,也是一个值得优化的地方啊。

【MindStudio训练营第一季】基于U-Net网络的图像分割的MindStudio实践

但遗憾的是本次Roofline页面(基于Roofline模型的算子瓶颈识别与优化建议功能输出结果)和Model Graph Optimization页面(基于Timeline的AICPU算子优化功能输出结果)都没什么结果展示,具体分别如下图所示。

【MindStudio训练营第一季】基于U-Net网络的图像分割的MindStudio实践

这里提个建议,看了下运行日志(显示了这一句[ERROR] Analyze model(RooflineModel) failed, please check dfx log.),Roofline之所以没有结果显示,可能是Roofline运行失败,不过这个日志有点太简洁了,不太友好,也没有给出 dfx log的具体路径或位置,哪怕弹出一个链接给用户,让用户去自行查找呢,这都没有,感觉界面不太友好啊。

专家系统提供对推理模型和算子的性能瓶颈分析能力并输出专家建议,但实际性能调优还需用户自行修改,不能做到性能调优一键式闭环。而性能调优一键式闭环提供一键式性能问题分析和优化能力,有效提升用户性能分析和优化效率。同时,性能调优一键式闭环当前实现生态知识库ONNX模型的部分推理场景瓶颈识别和自动化调优能力。

但这需要准备待优化的ONNX模型文件(.onnx)以及ONNX模型经过ATC转换后的OM模型文件(.om),而我们这次是.air模型转om模型,虽然可以获得onnx模型,但太麻烦了,我们这次就不尝试了。

这里再提个建议,性能调优一键式闭环还需要下载ONNX模型调优知识库,我按照文档(文档链接:​​https://www.hiascend.com/document/detail/zh/mindstudio/50RC3/msug/msug_000303.html)中提供Link跳转下载(如下图所示),未能找到文档后续所说的KnowledgeBase​​ Configuration知识库配置文件echosystem.json。不知道是不是我的问题,建议工程师看看,验证一下。

【MindStudio训练营第一季】基于U-Net网络的图像分割的MindStudio实践

MindStudio Profiling工具

Profiling作为专业的昇腾AI任务性能分析工具,其功能涵盖AI任务运行时关键数据采集和性能指标分析。熟练使用Profiling,可以快速定位性能瓶颈,显著提升AI任务性能分析的效率。

下面介绍使用Profiling工具采集性能数据并作简单的性能数据分析。

1. 更换python链接(可选)

这里先给大家排下雷,如果大家遇到如下报错,那么按照下面的操作修复下就行了,报错信息如下图所示:

【MindStudio训练营第一季】基于U-Net网络的图像分割的MindStudio实践

个人认为,这应该是本地电脑没安装Python或者安装了,但是没有添加到系统Path,以致无法调用,这应该Profiling需要在Windows上调用Python做一些操作,但无法调用Python导致的。那么我们只要安装Python的时候,选择添加到Path,或者已经安装Python的同学,将Python添加到Path,最终使得能够在Windows终端下直接调用Python即可。最终效果示例如下:

【MindStudio训练营第一季】基于U-Net网络的图像分割的MindStudio实践

此外,因为ECS终端默认启动的Python是/usr/bin/python,而在ECS默认是Python2直接运行程序会报错,而我们需要用Python3,所以需要重新链接符号,具体流程为:删除python链接文件-->>新建链接文件到python3,下面是操作步骤:

【MindStudio训练营第一季】基于U-Net网络的图像分割的MindStudio实践

那么有人可能就要问了,为什么是/usr/local/python3.9.5/bin/python3呢?因为我们在通过MindStudio直接在远程ECS上运行的时候,就是用的这个啊,来张图看看:

【MindStudio训练营第一季】基于U-Net网络的图像分割的MindStudio实践

这里提个建议,我之前运行会报错,详情见​​https://www.hiascend.com/forum/thread-0229107014330773104-1-1.html,连着两天重启,试了好几次,就是不行,后来又试了一次,突然就可以了,感觉很奇怪,莫明其妙地报错,莫名其秒地好了,这给我一种IDE很不稳定的感觉。建议优化一下,提升下稳定性。​

2. 执行Profiling采集

(1)单击菜单栏“Ascend > System Profiler > New Project”,弹出Profiling配置窗口 。

【MindStudio训练营第一季】基于U-Net网络的图像分割的MindStudio实践

配置“Project Properties”,配置工程名称“Project Name”和选择工程路径“Project Location”。单击“Next”进入下一步。

(2)进入“Executable Properties”配置界面。

【MindStudio训练营第一季】基于U-Net网络的图像分割的MindStudio实践

(3)进入“Profiling Options”配置界面,配置项按默认配置

【MindStudio训练营第一季】基于U-Net网络的图像分割的MindStudio实践

完成上述配置后单击窗口右下角的“Start”按钮,启动Profiling。工程执行完成后,MindStudio自动弹出Profiling结果视图。

【MindStudio训练营第一季】基于U-Net网络的图像分割的MindStudio实践

先来看下全量迭代耗时数据,在Timeline视图下查看Step Trace数据迭代耗时情况,识别耗时较长迭代进行分析。注意,可选择导出对应迭代Timeline数据,单击耗时较长迭代按钮

【MindStudio训练营第一季】基于U-Net网络的图像分割的MindStudio实践


弹出对话框,单击“Yes”导出对应迭代Timeline数据。如图所示,如果最初看不见,建议将鼠标放到图上,之后滑动放大,就能看见了。

【MindStudio训练营第一季】基于U-Net网络的图像分割的MindStudio实践

还可以查看迭代内耗时情况:存在较长耗时算子时,可以进一步找算子详细信息辅助定位;存在通信耗时或调度间隙较长时,分析调用过程中接口耗时。如图所示。

【MindStudio训练营第一季】基于U-Net网络的图像分割的MindStudio实践

在界面下方还能查看对应的算子统计表:查看迭代内每个AICORE和AICPU算子的耗时及详细信息,进一步定位分析算子的Metrics指标数据,分析算子数据搬运、执行流水的占比情况,识别算子瓶颈点。

【MindStudio训练营第一季】基于U-Net网络的图像分割的MindStudio实践

此外,这里还能查看组件接口耗时统计表:查看迭代内AscendCL API和Runtime API的接口耗时情况,辅助分析接口调用对性能的影响。

【MindStudio训练营第一季】基于U-Net网络的图像分割的MindStudio实践

这个要说一下,限于屏幕大小,上述这次数据的完整展示,可能需要放大或缩小,或者调整某些部分大小,这些操作很卡顿,操作起来没什么反应,仿佛这个界面卡死了,可用性差,用户体验不好,建议优化一下。

我们可以看到下图中这个Op的Task Wait Time要9.895us,而其他Op基本为0,所以可以考虑试试能不能减少这个Wait Time,从而提升性能。

【MindStudio训练营第一季】基于U-Net网络的图像分割的MindStudio实践

这里说一下,上图中这个Op Name很长,我需要将这栏横向拉伸很长才能完整显示,这有点麻烦,我本来想将鼠标悬停此处,让其自动显示完整名称,但好像不行,能否考虑加一下这个悬停显示全部内容的操作,否则我要先拉伸看,之后再拉回去看其他,比较麻烦。

还记得之前我们在专家系统工具那时提到的MTE2瓶颈相比之下有些大(约0.39)嘛?这里从下图看到Mte2时间较长,约3.7ms,说一下,mte2类型指令应该是DDR->AI Core搬运类指令,这里我们量化一下看看,如下图所示,AI Core时间约为6.8ms,但Task Duration约12.5ms,几乎翻倍了,说明我们Task只有约一半时间是真正用于AI Core计算,很明显很多时间被浪费了。

【MindStudio训练营第一季】基于U-Net网络的图像分割的MindStudio实践


【MindStudio训练营第一季】基于U-Net网络的图像分割的MindStudio实践

说明这一点还是比较值得优化的。而各个工具之间也是可以相互辅助,相互验证更好地帮助我们定位问题。下面我们再看看,先确认下Timeline颜色配置调色板,如下图所示。而我们之前看到的Timeline基本是绿色,未见黄色或红色,估计没什么优化空间了。还是优先做明显地值得优化地点吧,这也算抓大放小吧。

【MindStudio训练营第一季】基于U-Net网络的图像分割的MindStudio实践

好了,我们再看点其他的,比如Analysis Summary,这里展示了比较详细的软硬件信息,比如Host Computer Name、Host Operating System等,还有我们ECS上用的CPU的详细信息,包括型号、逻辑核心数量等,令我感兴趣的是,还有Ascend 310的信息,包括AI Core数量2, AI CPU数量4,Control CPU数量4,Control CPU Type为ARMv8_Cortex_A55,以及一个TS CPU,很详细了,很好地展示了Ascend 310的内部硬件信息,更有助于我们了解这款处理器。

【MindStudio训练营第一季】基于U-Net网络的图像分割的MindStudio实践

同时,再来看看Baseline Comparison吧。

【MindStudio训练营第一季】基于U-Net网络的图像分割的MindStudio实践

总的来说,MindStudio提供了Host+Device侧丰富的性能数据采集能力和全景Timeline交互分析能力,展示了Host+Device侧各项性能指标,帮助用户快速发现和定位AI应用、芯片及算子的性能瓶颈,包括资源瓶颈导致的AI算法短板,指导算法性能提升和系统资源利用率的优化。MindStudio支持Host+Device侧的资源利用可视化统计分析,具体包括Host侧CPU、Memory、Disk、Network利用率和Device侧APP工程的硬件和软件性能数据。
通过Profiling性能分析工具前后两次对网络应用推理的运行时间进行分析,并对比两次执行时间可以得出结论,可以帮助我们去验证替换函数或算子后,是否又性能提升,是否提升了推理效率。此外,还可以帮助我们挑选应该优先选择的网络模型,或者测试自定义算子是否达到最优性能,是否还存在优化空间等等,还是挺有用的。

MindStudio精度比对工具

1. 定义

为了帮助开发人员快速解决算子精度问题,需要提供自有实现的算子运算结果与业界标准算子运算结果之间进行精度差异对比的工具。

2. 功能

提供Tensor比对能力,包含余弦相似度、欧氏相对距离、绝对误差(最大绝对误差、平均绝对误差、均方根误差)、相对误差(最大相对误差、平均相对误差、累积相对误差)、KL散度、标准差算法比对维度。

总结

  1. MindStudio的安装过于繁琐

暂不谈Linux下的安装和配置,以本次的Windows下MindSutido搭配远程ECS使用来说,Windows下除了要安装MindStudio安装包,还要安装Python依赖,安装MinGW依赖,以及安装CMake等,太麻烦了。能否做成一键安装,毕竟这是个IDE,感觉使用其他IDE都是一键安装,就算有其他依赖,一般也是在IDE内部根据需要,自行选择安装即可,这个MindStudio可麻烦了,安装的依赖还很分散。

  1. 还是性能问题,性能优化不好

Windows下MindStudio的CPU、内存等资源占用很大,远大于其他类型IDE(比如PyCharm、IntelliJ IEDA等),而且还卡顿,这还是远程连接ECS使用,可就是这样,感觉本地电脑也快起飞了,远不如PyCharm、IntelliJ IEDA等使用起来顺畅,感觉是软件优化不行,如果是全部在物理机上运行,可能资源开销就更大了,这也太增加负载了,如果是这样,IDE的可视化操作意义就不大了,很多操作不如在终端执行,将更多资源留给更有用的地方。