MindStudio制作MindSpore TBE算子(二)算子测试
【摘要】 MindStudio制作MindSpore TBE算子(二)算子测试
在上一节中,成功制作了Mindspore的Add算子,具体可以查看MindStudio制作MindSpore TBE算子(一)算子制作,这一节,一起看看如何对算子进行测试。
建议参考以下内容一起食用:
算子代码实现
MindSpore框架TBE算子开发全流程
制作Mindspore的TBE流程中用于测试的是test_xxx_impl.py。
算子仿真验证
算子仿真验证是进行算子单元测试(UT测试),其中UT(Unit Test)是软件工程中常见的一种测试方式,目的是对代码中的最小可测试单元(如函数、类、模块)进行验证。针对 CANN 开发来说,UT 主要用于:
- 针对算子实现的单元级别功能测试
- 在真实或模拟环境中运行,验证算子输入输出是否符合预期可能包括边界情况、异常情况测试
特点:
- 以代码单元为测试对象(如 C++ 算子实现、Python 接口等)
- 关注 API 接口行为、异常处理、性能等
- 适用于 CI/CD 流程中的自动化测试
利用MindStudio执行UT测试
-
右键算子工程文件,点击New Case,创建 TBE UT CASE
-
选择测试的算子为新创建的addCustom算子,点击OK
-
生成了对应的test_xxx_impl.py文件
-
编辑对应的py文件,清理掉对应注释,
-
右击对应的python文件,执行TBE算子测试
-
如果这里出现报错
2025-02-10 20:32:17 Get case names failed.The file does not exist. /home/science/MindstudioProjects/Add_custom/out/addcustom_case.json
2025-02-10 20:32:17 Result of getting case name:Traceback (most recent call last):
File "/home/science/Ascend/ascend-toolkit/8.0.0/toolkit/python/site-packages/bin/op_ut_helper", line 20, in <module>
from absl import app
ModuleNotFoundError: No module named 'absl'
遇到这个报错是因为:如果 op_ut_helper 依赖的是 Ascend 自带的 Python,而安装 absl 时使用的是系统 Python,那么 op_ut_helper 可能找不到 absl。
解决方法有两种:
1. 在系统python下安装缺的包;
2. 利用anaconda的mindspore环境重新安装CANN
这里我推荐适应方法2
./Ascend-cann-toolkit_8.0.0_linux-x86_64.run --uninstall
./Ascend-cann-toolkit_8.0.0_linux-x86_64.run --install
解决这个问题之后,便可以选择测试例子
7. 执行测试用例
这里需要注意的是,需要选择的SOC核心为Ascend910芯片,这里我选择Ascend910Pro。
9. bug调整
报错信息:
Soc Version: Ascend910ProB
failed: [addcustom_impl] addcustom_impl_pre_static_test_addcustom_impl_auto_case_name_1 (Ascend910ProB), error msg: Failed,
Case File "/home/science/MindstudioProjects/Add_custom/testcases/ut/ops_test/test_addcustom_impl.py", line 16
Error trace:
Call op func failed, err_trace: Traceback (most recent call last):
File "/home/science/Ascend/ascend-toolkit/8.0.0/toolkit/python/site-packages/op_test_frame/ut/op_ut.py", line 873, in _call_op_func
op_func(*case_info.op_params, **addition_params)
File "/home/science/anaconda3/envs/mindspore/lib/python3.9/site-packages/mindspore/ops/op_info_register.py", line 298, in wrapped_function
return func(*args, **kwargs)
TypeError: addcustom_impl() missing 1 required positional argument: 'z'
------------------------------------------------------------------------
这里需要对之前的impl代码进行修改
addcustome_impl.py
from __future__ import absolute_import
from tbe import tvm
import tbe.dsl as tbe
from tbe.common.register import register_op_compute
from tbe.common.utils import shape_refine
from tbe.common.utils import shape_util
from tbe.common.utils import para_check
from functools import reduce
from mindspore.ops.op_info_register import op_info_register, TBERegOp, DataType
SHAPE_SIZE_LIMIT = 2147483648
@register_op_compute("addcustom")
def addcustom_compute(x, y):
"""
The compute function of the Addcustom implementation.
"""
# shape转为list
shape_x = shape_util.shape_to_list(x.shape)
shape_y = shape_util.shape_to_list(y.shape)
# shape_max取shape_x与shape_y的每个维度的大值
shape_x, shape_y, shape_max = shape_util.broadcast_shapes(shape_x, shape_y,
param_name_input1="input_x",
param_name_input2="input_y")
shape_size = reduce(lambda x, y: x * y, shape_max[:])
if shape_size > SHAPE_SIZE_LIMIT:
raise RuntimeError("the shape is too large to calculate")
# 将input_x的shape广播为shape_max
input_x = tbe.broadcast(x, shape_max)
input_y = tbe.broadcast(y, shape_max)
# 执行input_x + input_y
res = tbe.vadd(input_x, input_y)
return res
# 算子注册信息
# Define the kernel info of Addcustom
# 算子注册名称
addcustom_op_info = (TBERegOp("Addcustom") \
# 融合策略,这里选择不融合
.fusion_type("OPAQUE") \
.partial_flag(True) \
.async_flag(False) \
# 生成算子二进制名称
.binfile_name("addcustom.so") \
.compute_cost(10) \
.kernel_name("addcustom_impl") \
# 算子输入信息
.input(0, "x", False, "required", "all")\
.input(1, "y", False, "required", "all")\
.output(0, "z", False, "required", "all")\
# 数据格式名称
.dtype_format(DataType.F16_Default, DataType.F16_Default, DataType.F16_Default)\
.get_op_info())
# 算子的入口函数,描述了算子的编译过程
# Binding kernel info with the kernel implementation.
# 装饰器与算子注册信息绑定,执行后会注册到后端
@op_info_register(addcustom_op_info)
def addcustom_impl(x, y, z, kernel_name="addcustom_impl"):
"""
The entry function of the Addcustom implementation.
"""
# 获取算子输入tensor的shape与dtype
shape_x = x.get("shape")
shape_y = y.get("shape")
# 检验算子输入类型
check_tuple = ("float16")
input_data_type = x.get("dtype").lower()
para_check.check_dtype(input_data_type, check_tuple, param_name="input_x")
# shape_max取shape_x与shape_y的每个维度的最大值
shape_x, shape_y, shape_max = shape_util.broadcast_shapes(shape_x, shape_y,
param_name_input1="x",
param_name_input2="y")
# 如果shape的长度等于1,就直接赋值,如果shape的长度不等于1,做切片,将最后一个维度舍弃(按照内存排布,最后一个维度为1与没有最后一个维度的数据排布相同,例如2*3=2*3*1,将最后一个为1的维度舍弃,可提升后续的调度效率)
if shape_x[-1] == 1 and shape_y[-1] == 1 and shape_max[-1] == 1:
shape_x = shape_x if len(shape_x) == 1 else shape_x[:-1]
shape_y = shape_y if len(shape_y) == 1 else shape_y[:-1]
shape_max = shape_max if len(shape_max) == 1 else shape_max[:-1]
# 使用TVM的placeholder接口对输入tensor进行占位,返回一个tensor对象
data_x = tvm.placeholder(shape_x, name="data_1", dtype=input_data_type)
data_y = tvm.placeholder(shape_y, name="data_2", dtype=input_data_type)
with tvm.target.cce():
# 计算过程
res = addcustom_compute(data_x, data_y)
# 自动调度模块
sch = tbe.auto_schedule(res)
# 配置编译信息
config = {"print_ir": False,
"name": kernel_name,
"tensor_list": [data_x, data_y, res]}
tbe.build(sch, config)
# # 算子调用,测试算子计算正确性
# if __name__ == '__main__':
# input_output_dict = {"shape": (5, 6, 7),"format": "ND","ori_shape": (5, 6, 7),"ori_format": "ND", "dtype": "float16"}
# addcustom_impl(input_output_dict, input_output_dict, input_output_dict, kernel_name="add")
test_addcustom_impl.py
# # -*- coding:utf-8 -*-
import sys
import numpy as np
from op_test_frame.ut import BroadcastOpUT
# [TODO] change op_func_name here
ut_case = BroadcastOpUT("addcustom_impl", op_func_name="addcustom_impl")
# [TODO] coding expect function here
def calc_expect_func(input_x, input_y, output):
res = input_x["value"] + input_y["value"] # 计算加法
return [res, ]
# [TODO] coding cases here
ut_case.add_precision_case("all", {
"params": [
{"dtype": "float16", "format": "ND", "ori_format": "ND", "ori_shape": (32,), "shape": (32,), "param_type": "input"}, # input_x
{"dtype": "float16", "format": "ND", "ori_format": "ND", "ori_shape": (32,), "shape": (32,), "param_type": "input"}, # input_y
{"dtype": "float16", "format": "ND", "ori_format": "ND", "ori_shape": (32,), "shape": (32,), "param_type": "output"} # 添加输出参数
],
"calc_expect_func": calc_expect_func
})
- 测试结果
addcustom ut_impl start running...
Run command is:
export PATH=%%PYTHON_BIN%%:/home/science/Ascend/ascend-toolkit/8.0.0/atc/ccec_compiler/bin/:%%PYTHON_BIN%%:/home/science/Ascend/ascend-toolkit/8.0.0/compiler/ccec_compiler/bin/:/home/science/Ascend/ascend-toolkit/8.0.0/atc/bin/:/home/science/Ascend/ascend-toolkit/8.0.0/compiler/bin/:${PATH} && export PYTHONPATH=/home/science/MindstudioProjects/Add_custom/mindspore:/home/science/Ascend/ascend-toolkit/8.0.0/toolkit/python/site-packages:/home/science/Ascend/ascend-toolkit/8.0.0/atc/python/site-packages:/home/science/Ascend/ascend-toolkit/8.0.0/compiler/python/site-packages:${PYTHONPATH}:${PYTHONPATH} && export ADK_PATH=/home/science/Ascend/ascend-toolkit/8.0.0 && export LD_LIBRARY_PATH=/home/science/Ascend/ascend-toolkit/8.0.0/atc/lib64:/home/science/Ascend/ascend-toolkit/8.0.0/compiler/lib64:/home/science/Ascend/ascend-toolkit/8.0.0/toolkit/tools/simulator/Ascend910ProB/lib:${LD_LIBRARY_PATH} && export CAMODEL_LOG_PATH=/home/science/MindstudioProjects/Add_custom/out/model && export ASCEND_OPP_PATH=/home/science/Ascend/ascend-toolkit/8.0.0/opp && export PROJECT_PATH=/home/science/MindstudioProjects/Add_custom && export TVM_AICPU_OS_SYSROOT=/home/science/Ascend/ascend-toolkit/8.0.0/toolkit/toolchain/hcc/sysroot && export SIMULATOR_PATH=/home/science/Ascend/ascend-toolkit/8.0.0/toolkit/tools/simulator && unset LD_PRELOAD && rm -rf /home/science/MindstudioProjects/Add_custom/out/coverage_report/ut_impl && rm -rf /home/science/MindstudioProjects/Add_custom/out/model && mkdir -p -m750 /home/science/MindstudioProjects/Add_custom/out/model && rm -rf /home/science/MindstudioProjects/Add_custom/out/bin && mkdir -p -m750 /home/science/MindstudioProjects/Add_custom/out/bin && cd /home/science/MindstudioProjects/Add_custom/out/bin && /home/science/Ascend/ascend-toolkit/8.0.0/toolkit/python/site-packages/bin/op_ut_run --case_files=/home/science/MindstudioProjects/Add_custom/testcases/ut/ops_test --data_path=./data --simulator_data_path=/home/science/MindstudioProjects/Add_custom/out/model --simulator_lib_path=/home/science/Ascend/ascend-toolkit/8.0.0/toolkit/tools/simulator --simulator_mode=pv --soc_version=Ascend910ProB --cov_report=html --cov_report_path=/home/science/MindstudioProjects/Add_custom/out/coverage_report/ut_impl --case_name=addcustom_impl_pre_static_test_addcustom_impl_auto_case_name_1
run /home/science/MindstudioProjects/Add_custom ut test
===============================================================================
>>>> <<<<
>>>> Model Init Suc <<<<
>>>> <<<<
===============================================================================
[DRVSTUB_LOG] driver_queue.c:75 drvMoveTsReport:memcpy one report from TS to Driver stub successfully.
[DRVSTUB_LOG] driver_queue.c:75 drvMoveTsReport:memcpy one report from TS to Driver stub successfully.
[DRVSTUB_LOG] driver_queue.c:75 drvMoveTsReport:memcpy one report from TS to Driver stub successfully.
[DRVSTUB_LOG] driver_queue.c:61 drvMoveTsReport:taskReportQueue is empty
[DRVSTUB_LOG] driver_queue.c:75 drvMoveTsReport:memcpy one report from TS to Driver stub successfully.
[DRVSTUB_LOG] driver_queue.c:75 drvMoveTsReport:memcpy one report from TS to Driver stub successfully.
[DRVSTUB_LOG] driver_queue.c:61 drvMoveTsReport:taskReportQueue is empty
[DRVSTUB_LOG] driver_queue.c:75 drvMoveTsReport:memcpy one report from TS to Driver stub successfully.
[DRVSTUB_LOG] driver_queue.c:75 drvMoveTsReport:memcpy one report from TS to Driver stub successfully.
[DRVSTUB_LOG] driver_queue.c:75 drvMoveTsReport:memcpy one report from TS to Driver stub successfully.
[DRVSTUB_LOG] driver_queue.c:61 drvMoveTsReport:taskReportQueue is empty
[DRVSTUB_LOG] driver_queue.c:75 drvMoveTsReport:memcpy one report from TS to Driver stub successfully.
[DRVSTUB_LOG] driver_queue.c:75 drvMoveTsReport:memcpy one report from TS to Driver stub successfully.
[DRVSTUB_LOG] driver_queue.c:61 drvMoveTsReport:taskReportQueue is empty
[DRVSTUB_LOG] driver_queue.c:75 drvMoveTsReport:memcpy one report from TS to Driver stub successfully.
[DRVSTUB_LOG] driver_queue.c:61 drvMoveTsReport:taskReportQueue is empty
[INFO] model_api.cc:782 stopModel Model stopped successfully.
start run ops ut time: 2025-02-10 22:33:55.804219
[INFO] 2025-02-10 22:33:55.841581 [File "/home/science/Ascend/ascend-toolkit/8.0.0/toolkit/python/site-packages/op_test_frame/ut/op_ut_runner.py", line 366] multiprocess_run_args count: 2
[INFO] 2025-02-10 22:33:55.841770 [File "/home/science/Ascend/ascend-toolkit/8.0.0/toolkit/python/site-packages/op_test_frame/ut/op_ut_runner.py", line 369] process_num is 1, run cases one by one
[INFO] 2025-02-10 22:33:55.842073 [File "/home/science/Ascend/ascend-toolkit/8.0.0/toolkit/python/site-packages/op_test_frame/ut/op_ut_runner.py", line 205] start run: /home/science/MindstudioProjects/Add_custom/testcases/ut/ops_test/test_addcustom_impl.py
>>>> start run test case
[Ascend910ProB] addcustom_impl test start running...
addcustom_impl_pre_static_test_addcustom_impl_auto_case_name_1 (addcustom_impl) (precision) ... [INFO] 2025-02-10 22:34:01.097596 [File "/home/science/Ascend/ascend-toolkit/8.0.0/toolkit/python/site-packages/op_test_frame/runtime/rts_api.py", line 105] Load RTS shared library...
[INFO] 2025-02-10 22:34:01.098069 [File "/home/science/Ascend/ascend-toolkit/8.0.0/toolkit/python/site-packages/op_test_frame/runtime/rts_api.py", line 219] start load ascend simulator
[INFO] 2025-02-10 22:34:01.107970 [File "/home/science/Ascend/ascend-toolkit/8.0.0/toolkit/python/site-packages/op_test_frame/runtime/rts_api.py", line 231] Load ascend simulator success.
[INFO] 2025-02-10 22:34:02.181230 [File "/home/science/Ascend/ascend-toolkit/8.0.0/toolkit/python/site-packages/op_test_frame/runtime/rts_api.py", line 780] Runtime API call rtSetDevice() success.
[INFO] 2025-02-10 22:34:02.182355 [File "/home/science/Ascend/ascend-toolkit/8.0.0/toolkit/python/site-packages/op_test_frame/runtime/rts_api.py", line 780] Runtime API call rtStreamCreate() success.
[INFO] 2025-02-10 22:34:02.184036 [File "/home/science/Ascend/ascend-toolkit/8.0.0/toolkit/python/site-packages/op_test_frame/runtime/rts_api.py", line 780] Runtime API call rtMalloc() success.
[INFO] 2025-02-10 22:34:02.193498 [File "/home/science/Ascend/ascend-toolkit/8.0.0/toolkit/python/site-packages/op_test_frame/runtime/rts_api.py", line 780] Runtime API call rtMemcpy() success.
[INFO] 2025-02-10 22:34:02.194372 [File "/home/science/Ascend/ascend-toolkit/8.0.0/toolkit/python/site-packages/op_test_frame/runtime/rts_api.py", line 780] Runtime API call rtMalloc() success.
[INFO] 2025-02-10 22:34:02.195212 [File "/home/science/Ascend/ascend-toolkit/8.0.0/toolkit/python/site-packages/op_test_frame/runtime/rts_api.py", line 780] Runtime API call rtMemcpy() success.
[INFO] 2025-02-10 22:34:02.195873 [File "/home/science/Ascend/ascend-toolkit/8.0.0/toolkit/python/site-packages/op_test_frame/runtime/rts_api.py", line 780] Runtime API call rtMalloc() success.
[INFO] 2025-02-10 22:34:02.196505 [File "/home/science/Ascend/ascend-toolkit/8.0.0/toolkit/python/site-packages/op_test_frame/runtime/rts_api.py", line 780] Runtime API call rtMemset() success.
[INFO] 2025-02-10 22:34:02.197192 [File "/home/science/Ascend/ascend-toolkit/8.0.0/toolkit/python/site-packages/op_test_frame/runtime/rts_api.py", line 780] Runtime API call rtDevBinaryRegister() success.
[INFO] 2025-02-10 22:34:02.197720 [File "/home/science/Ascend/ascend-toolkit/8.0.0/toolkit/python/site-packages/op_test_frame/runtime/rts_api.py", line 780] Runtime API call rtFunctionRegister() success.
[INFO] 2025-02-10 22:34:02.206531 [File "/home/science/Ascend/ascend-toolkit/8.0.0/toolkit/python/site-packages/op_test_frame/runtime/rts_api.py", line 780] Runtime API call rtKernelLaunch() success.
[INFO] 2025-02-10 22:34:02.221129 [File "/home/science/Ascend/ascend-toolkit/8.0.0/toolkit/python/site-packages/op_test_frame/runtime/rts_api.py", line 780] Runtime API call rtStreamSynchronize() success.
[INFO] 2025-02-10 22:34:02.222081 [File "/home/science/Ascend/ascend-toolkit/8.0.0/toolkit/python/site-packages/op_test_frame/runtime/rts_api.py", line 780] Runtime API call rtMallocHost() success.
[INFO] 2025-02-10 22:34:02.222630 [File "/home/science/Ascend/ascend-toolkit/8.0.0/toolkit/python/site-packages/op_test_frame/runtime/rts_api.py", line 780] Runtime API call rtMemcpy() success.
[INFO] 2025-02-10 22:34:02.223189 [File "/home/science/Ascend/ascend-toolkit/8.0.0/toolkit/python/site-packages/op_test_frame/runtime/rts_api.py", line 780] Runtime API call rtFree() success.
[INFO] 2025-02-10 22:34:02.223564 [File "/home/science/Ascend/ascend-toolkit/8.0.0/toolkit/python/site-packages/op_test_frame/runtime/rts_api.py", line 780] Runtime API call rtFree() success.
[INFO] 2025-02-10 22:34:02.223956 [File "/home/science/Ascend/ascend-toolkit/8.0.0/toolkit/python/site-packages/op_test_frame/runtime/rts_api.py", line 780] Runtime API call rtFree() success.
[INFO] 2025-02-10 22:34:02.224431 [File "/home/science/Ascend/ascend-toolkit/8.0.0/toolkit/python/site-packages/op_test_frame/runtime/rts_api.py", line 780] Runtime API call rtStreamDestroy() success.
[INFO] 2025-02-10 22:34:02.244534 [File "/home/science/Ascend/ascend-toolkit/8.0.0/toolkit/python/site-packages/op_test_frame/runtime/rts_api.py", line 780] Runtime API call rtDeviceReset() success.
Error count: 0, Max atol error count: 0, Threshold count(rtol * data_size):0.032
ok
----------------------------------
run 1 tests, success: 1
>>>> end run test case, op_type:addcustom_impl cost time: 2
[INFO] 2025-02-10 22:34:02.248955 [File "/home/science/Ascend/ascend-toolkit/8.0.0/toolkit/python/site-packages/op_test_frame/ut/op_ut_runner.py", line 255] end run: /home/science/MindstudioProjects/Add_custom/testcases/ut/ops_test/test_addcustom_impl.py
/home/science/MindstudioProjects/Add_custom/out/bin/report/combine_rpt_path [] ['rpt_1_test_addcustom_impl.data']
load /home/science/MindstudioProjects/Add_custom/out/bin/report/combine_rpt_path/rpt_1_test_addcustom_impl.data success, case cnt: 1
========================================================================
------------------------------------------------------------------------
- test soc: [Ascend910ProB]
- test case count: 1
- success count: 1
- failed count: 0
- error count: 0
------------------------------------------------------------------------
Soc Version: Ascend910ProB
success: [addcustom_impl] addcustom_impl_pre_static_test_addcustom_impl_auto_case_name_1 (Ascend910ProB) (precision)
------------------------------------------------------------------------
========================================================================
end run ops ut time: 2025-02-10 22:34:02.266352
TBE TestRun Finished
Ut_Impl report index.html: http://localhost:63342/Add_custom/out/coverage_report/ut_impl/index.html?_ijt=laasfbagsbclwufgwngbqcposk
从报告中也可以看到,依然是有代码是UT测试中没有覆盖的内容,这也代表着我们需要进行更多更全面的测试用例编写。
【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
作者其他文章
评论(0)