!68951 Fix custom op doc

Merge pull request !68951 from zichun_ye/code_docs_custom_master
This commit is contained in:
i-robot 2024-04-30 10:11:24 +00:00 committed by Gitee
commit c92a7b17fd
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
2 changed files with 75 additions and 95 deletions

View File

@ -13,21 +13,83 @@ mindspore.ops.Custom
.. note::
不同自定义算子的函数类型func_type支持的平台类型不同。每种类型支持的平台如下
- "hybrid": ["Ascend", "GPU", "CPU"].
- "akg": ["Ascend", "GPU", "CPU"].
- "tbe": ["Ascend"].
- "hybrid": ["GPU", "CPU"].
- "akg": ["GPU", "CPU"].
- "aot": ["GPU", "CPU"].
- "pyfunc": ["CPU"].
- "julia": ["CPU"].
- "aicpu": ["Ascend"].
当运行在ge后端时通过 `CustomRegOp` 生成"aicpu"和"tbe"类型的自定义算子的算子信息,通过 `custom_info_register` 将算子信息绑定到"tbe"类型的自定义算子的 `func` 上,然后将"aicpu"类型的自定义算子的算子信息以及"tbe"类型的自定义算子的 `func` 实现保存在一个或多个文件里,并且将这些文件保存在一个单独的目录里,在网络运行前将此目录的绝对路径设置到环境变量"MS_DEV_CUSTOM_OPP_PATH"。
参数:
- **func** (Union[function, str]) - 自定义算子的函数表达。
- function如果 `func` 是函数类型,那么 `func` 应该是一个Python函数它描述了用户定义的操作符的计算逻辑。该函数可以是以下之一
1. AKG操作符实现函数可以使用ir builder/tvm compute/hybrid语法。
2. 纯Python函数。
3. 使用Hybrid DSL编写的带有装饰器的内核函数。
- 字符串:如果 `func` 是字符串类型,那么 `str` 应该是包含函数名的文件路径。当 `func_type` 是"aot"或"julia"时,可以使用这种方式。
1. 对于"aot"
目前"aot"支持GPU/CPU仅Linux平台。"aot"意味着提前编译在这种情况下Custom直接启动用户定义的"xxx.so"文件作为操作符。用户需要提前将手写的"xxx.cu"/"xxx.cc"文件编译成"xxx.so",并提供文件路径和函数名。
- "xxx.so"文件生成:
1) GPU平台给定用户定义的"xxx.cu"文件(例如"{path}/add.cu"使用nvcc命令进行编译例如"nvcc --shared -Xcompiler -fPIC -o add.so add.cu")。
2) CPU平台给定用户定义的"xxx.cc"文件(例如"{path}/add.cc"使用g++/gcc命令进行编译例如"g++ --shared -fPIC -o add.so add.cc")。
- 定义"xxx.cc"/"xxx.cu"文件:
"aot"是一个跨平台的标识符。"xxx.cc"或"xxx.cu"中定义的函数具有相同的参数。通常,该函数应该像这样:
.. code-block::
int func(int nparam, void **params, int *ndims, int64_t **shapes, const char **dtypes, void *stream, void *extra)
参数:
- `nparam(int)` : 输入和输出的总数假设操作符有2个输入和3个输出那么 `nparam=5`
- `params(void **)` : 输入和输出指针的数组指针;输入和输出的指针类型为 `void *` 假设操作符有2个输入和3个输出那么第一个输入的指针是 `params[0]` ,第二个输出的指针是 `params[3]`
- `ndims(int *)` : 输入和输出维度数的数组指针;假设 `params[i]` 是一个1024x1024的张量`params[j]` 是一个77x83x4的张量那么 `ndims[i]=2` `ndims[j]=3`
- `shapes(int64_t **)` : 输入和输出形状( `int64_t *` )的数组指针;第 `i` 个输入的第 `j` 个维度的大小是 `shapes[i][j]` (其中 `0<=j<ndims[i]` );假设 `params[i]` 是一个2x3的张量`params[j]`是一个3x3x4的张量那么 `shapes[i][0]=2` `shapes[j][2]=4`
- `dtypes(const char **)` : 输入和输出类型( `const char *` )的数组指针;(例如:"float32"、"float16"、"float"、"float64"、"int"、"int8"、"int16"、"int32"、"int64"、"uint"、"uint8"、"uint16"、"uint32"、"uint64"、"bool"
- `stream(void *)` : 流指针仅在CUDA文件中使用。
- `extra(void *)` : 用于进一步扩展。
返回值int:
- 0: 如果这个AOT内核成功执行MindSpore将继续运行。
- 其他值: MindSpore将引发异常并退出。
示例:详见 `tests/st/ops/graph_kernel/custom/aot_test_files/` 中的详细信息。
- 在Custom中使用
.. code-block::
Custom(func="{dir_path}/{file_name}:{func_name}", ...)
例如Custom(func="./reorganize.so:CustomReorganize", out_shape=[1], out_dtype=mstype.float32, "aot")
2. 对于"julia"
目前,"julia"仅支持CPU仅限Linux平台。对于julia它使用JIT编译器即时编译器并且julia支持C API来调用julia代码。自定义功能可以直接将用户定义的"xxx.jl"文件作为一个操作符来启动。用户需要编写一个包含模块和函数的"xxx.jl"文件,并提供该文件的路径以及模块名称和函数名称。
示例:详情见 `tests/st/ops/graph_kernel/custom/julia_test_files/`
- 在Custom中使用
.. code-block::
Custom(func="{dir_path}/{file_name}:{module_name}:{func_name}",...)
例如Custom(func="./add.jl:Add:add", out_shape=[1], out_dtype=mstype.float32, "julia")
- **out_shape** (Union[function, list, tuple]) - 自定义算子的输入的形状或者输出形状的推导函数。默认值: ``None``
- **out_dtype** (Union[function, :class:`mindspore.dtype`, tuple[:class:`mindspore.dtype`]]) - 自定义算子的输入的数据类型或者输出数据类型的推导函数。默认值: ``None``
- **func_type** (str) - 自定义算子的函数类型,必须是[ ``"hybrid"`` , ``"akg"`` , ``"tbe"`` , ``"aot"`` , ``"pyfunc"`` , ``"julia"`` , ``"aicpu"`` ]中之一。默认值: ``"hybrid"``
- **func_type** (str) - 自定义算子的函数类型,必须是[ ``"hybrid"`` , ``"akg"`` , ``"aot"`` , ``"pyfunc"`` , ``"julia"``]中之一。默认值: ``"hybrid"``
- **bprop** (function) - 自定义算子的反向函数。默认值: ``None``
- **reg_info** (Union[str, dict, list, tuple]) - 自定义算子的算子注册信息。默认值: ``None``

View File

@ -172,19 +172,11 @@ class Custom(ops.PrimitiveWithInfer):
.. note::
The supported platforms are determined by the input `func_type`. The supported platforms are as follows:
- "hybrid": supports ["Ascend", "GPU", "CPU"].
- "akg": supports ["Ascend", "GPU", "CPU"].
- "tbe": supports ["Ascend"].
- "hybrid": supports ["GPU", "CPU"].
- "akg": supports ["GPU", "CPU"].
- "aot": supports ["GPU", "CPU"].
- "pyfunc": supports ["CPU"].
- "julia": supports ["CPU"].
- "aicpu": supports ["Ascend"].
If run on ge backend, use `CustomRegOp` to generate the registration information of "aicpu" and "tbe" operator,
use `custom_info_register` to bind the registration information to the `func` of the "tbe" operator,
then save the registration information of "aicpu" operator and the `func` implementation of "tbe" operator to
a file or separate files, keep these files in a separate directory, and set the absolute path of this directory
to environment variable "MS_DEV_CUSTOM_OPP_PATH" before running the network.
Args:
func (Union[function, str]):
@ -193,9 +185,8 @@ class Custom(ops.PrimitiveWithInfer):
computation logic of a user defined operator. The function can be one of the following:
1. A AKG operator implementation function, which can use ir builder/tvm compute/hybrid grammar.
2. A TBE operator implementation function.
3. A pure python function
4. An kernel decorated function written by the Hybrid DSL.
2. A pure python function
3. An kernel decorated function written by the Hybrid DSL.
- str: If func is of str type, then str should be a path of file along with a function name.
This could be used when func_type is "aot" or "julia".
@ -299,18 +290,7 @@ class Custom(ops.PrimitiveWithInfer):
func_type (str): The implementation type of `func`, should be one of
[ ``"hybrid"`` , ``"akg"`` , ``"tbe"`` , ``"aot"`` , ``"pyfunc"`` , ``"julia"`` , ``"aicpu"`` ].
Each `func_type` only supports specific platforms(targets). Default: ``"hybrid"`` .
The supported platforms of `func_type`:
- ``"hybrid"``: supports ["Ascend", "GPU", "CPU"].
- ``"akg"``: supports ["Ascend", "GPU", "CPU"].
- ``"tbe"``: supports ["Ascend"].
- ``"aot"``: supports ["GPU", "CPU"].
- ``"pyfunc"``: supports ["CPU"].
- ``"julia"``: supports ["CPU"].
- ``"aicpu"``: supports ["Ascend"].
[ ``"hybrid"`` , ``"akg"`` , ``"aot"`` , ``"pyfunc"`` , ``"julia"`` ].
bprop (function): The back propagation function of `func`. Default: ``None`` .
reg_info (Union[str, dict, list, tuple]): Represents the registration information(reg info) of `func` with
@ -343,7 +323,7 @@ class Custom(ops.PrimitiveWithInfer):
or the attributes of `func` differs in different targets.
Supported Platforms:
``Ascend`` ``GPU`` ``CPU``
``GPU`` ``CPU``
Examples:
>>> import numpy as np
@ -372,68 +352,6 @@ class Custom(ops.PrimitiveWithInfer):
>>> # the result will be a 16 * 16 tensor with all elements 2
>>> print(output.shape)
(16, 16)
>>> # Example, func_type = "tbe"
>>> square_with_bias_op_info = CustomRegOp() \
... .fusion_type("OPAQUE") \
... .attr("bias", "required", "float") \
... .input(0, "x") \
... .output(0, "y") \
... .dtype_format(DataType.F32_Default, DataType.F32_Default) \
... .dtype_format(DataType.F16_Default, DataType.F16_Default) \
... .target("Ascend") \
... .get_op_info()
>>>
>>> @custom_info_register(square_with_bias_op_info)
... def square_with_bias(input_x, output_y, bias=0.0, kernel_name="square_with_bias"):
... import te.lang.cce
... from te import tvm
... from topi.cce import util
...
... shape = input_x.get("shape")
... dtype = input_x.get("dtype").lower()
...
... shape = util.shape_refine(shape)
... data = tvm.placeholder(shape, name="data", dtype=dtype)
...
... with tvm.target.cce():
... res0 = te.lang.cce.vmul(data, data)
... res = te.lang.cce.vadds(res0, bias)
... sch = te.lang.cce.auto_schedule(res)
...
... config = {"print_ir": False,
... "name": kernel_name,
... "tensor_list": [data, res]}
...
... te.lang.cce.cce_build_code(sch, config)
>>>
>>> def test_tbe():
... square_with_bias = ops.Custom(square_with_bias, out_shape=lambda x, _: x, \
... out_dtype=lambda x, _: x, func_type="tbe")
... res = self.square_with_bias(input_x, 1.0)
... return res
>>>
>>> # Example, func_type = "aicpu"
>>> resize_bilinear_op_info = CustomRegOp("ResizeBilinear") \
... .fusion_type("OPAQUE") \
... .input(0, "input", "required") \
... .output(1, "output", "required") \
... .attr("align_corners", "required", "bool") \
... .attr("cust_aicpu", "optional", "str", "aicpu_kernels") \
... .dtype_format(DataType.F32_Default, DataType.F32_Default) \
... .dtype_format(DataType.F16_Default, DataType.F32_Default) \
... .target("Ascend") \
... .get_op_info()
>>>
>>> @custom_info_register(resize_bilinear_op_info)
... def resize_bilinear_aicpu():
... return
>>>
>>> def test_aicpu(x):
... resize_bilinear_op = ops.Custom(resize_bilinear_aicpu, out_shape=[1, 1, 9, 9], \
... out_dtype=mstype.float32, func_type="aicpu")
... res = resize_bilinear_op(x, True, "aicpu_kernels")
... return res
>>>
>>> # Example, func_type = "aot"
>>> def test_aot(x, y, out_shapes, out_types):
... program = ops.Custom("./reorganize.so:CustomReorganize", out_shapes, out_types, "aot")