diff --git "a/Ascend-PyTorch\347\246\273\347\272\277\346\216\250\347\220\206\346\214\207\345\257\274/PyTorch\347\246\273\347\272\277\346\216\250\347\220\206-FAQ.md" "b/Ascend-PyTorch\347\246\273\347\272\277\346\216\250\347\220\206\346\214\207\345\257\274/PyTorch\347\246\273\347\272\277\346\216\250\347\220\206-FAQ.md" index 521f3738395ea2d29253b369473bf771d80930b8..5a2f61dfae701307c5a24df34a5a1b92b8a35049 100644 --- "a/Ascend-PyTorch\347\246\273\347\272\277\346\216\250\347\220\206\346\214\207\345\257\274/PyTorch\347\246\273\347\272\277\346\216\250\347\220\206-FAQ.md" +++ "b/Ascend-PyTorch\347\246\273\347\272\277\346\216\250\347\220\206\346\214\207\345\257\274/PyTorch\347\246\273\347\272\277\346\216\250\347\220\206-FAQ.md" @@ -5,21 +5,24 @@ - [2.1 如何查看 `ONNX/om/pbtxt` 模型](#21-如何查看-onnxompbtxt-模型) - [2.2 `Exporting the operator {opname} to ONNX opset version {version} is not supported.`](#22-exporting-the-operator-opname-to-onnx-opset-version-version-is-not-supported) - [2.3 resize不支持5d输入的解决方案](#23-resize不支持5d输入的解决方案) + - [2.4 循环(LOOP)结构](#24-循环(LOOP)结构) - [3 OM离线推理失败问题汇总](#3-om离线推理失败问题汇总) - [3.1 找不到atc命令或找不到ascend动态库](#31-找不到atc命令或找不到ascend动态库) - [3.2 模型推理工具常见的错误&&解决方案](#32-模型推理工具常见的错误解决方案) - [3.3 msame和benchmark在多batch下推理区别](#33-msame和benchmark在多batch下推理区别) - [3.4 msame/benchmark推理提示实际输入和om输入size不一致](#34-msamebenchmark推理提示实际输入和om输入size不一致) - [3.5 benchmark工具报错`ERROR Check free memory less 0.256 rate now wait!`](#35-benchmark工具报错error-check-free-memory-less-0256-rate-now-wait) -- [4 精度调试常见问题](#4-精度调试常见问题) -- [5 性能优化常见问题](#5-性能优化常见问题) +- [4 精度相关问题](#4-精度相关问题) +- [5 性能相关问题](#5-性能相关问题) - [5.1 如何使用AIPP进行性能提升](#51-如何使用aipp进行性能提升) -- [5.2 GPU推理(trtexec)报错](#52-gpu推理trtexec报错) + - [5.2 GPU推理(trtexec)报错](#52-gpu推理trtexec报错) - [5.3 提升transpose的性能](#53-提升transpose的性能) + - [5.4 AICPU算子问题](#54-AICPU算子问题) # 1 介绍 本文目标读者为Ascend PyTorch模型离线推理开发者,用于指导开发者在昇腾服务器的CANN软件环境中,实现模型离线推理精度性能达标。这里仅列举模型离线推理中遇到的常见问题与解决方法,持续更新。 **FAQ上传格式** 尽量以文本方式呈现,方便索引查找 + - 标题 - 错误现象 - 原因分析 @@ -70,11 +73,11 @@ - 解决方案 使用 [MagicONNX工具](https://gitee.com/Ronnie_zheng/MagicONNX/tree/master) 进行改图,这里给出该问题的改图代码,更多功能详见[使用教程](https://gitee.com/Ronnie_zheng/MagicONNX/blob/master/docs/tutorials.md)和[API说明](https://gitee.com/Ronnie_zheng/MagicONNX/blob/master/docs/operations.md) + ```python import numpy as np from magiconnx import OnnxGraph - - + def modify(path): graph = OnnxGraph(path) resizes = graph.get_nodes("Resize") @@ -86,7 +89,7 @@ graph.add_initializer(f'shape_{node.name}', np.array(shapes[idx][0])) reshape1.inputs = [node.inputs[0], f'shape_{node.name}'] reshape1.outputs = [f'Reshape_{node.name}'] - + graph[node.inputs[-1]].value = np.array(shapes[idx][1]) out_name = node.outputs[0] node.set_input(0, f'Reshape_{node.name}') @@ -108,12 +111,56 @@ reshape3.outputs = [out_name] graph.save('modify.onnx') - + if __name__ == "__main__": modify('src.onnx') ``` +## 2.4 循环(LOOP)结构 + ++ 问题现象 + + 原始模型存在循环的Loop结构,导致静态模型节点不断堆叠,节点过多,onnx模型过大,无法打开。 + ++ 原因分析 + + 动态模型推理时,因为模型为动态编译,且Loop结构中,通常为重复调用相同的操作,不会涉及内存资源的累计。如下面的采样结构: + + ```python + def farthest_point_sample(xyz, npoint): + """ + Input: + xyz: pointcloud data, [B, N, 3] + npoint: number of samples + Return: + centroids: sampled pointcloud index, [B, npoint] + """ + device = xyz.device + B, N, C = xyz.shape + centroids = torch.zeros(B, npoint, dtype=torch.long).to(device) + distance = torch.ones(B, N).to(device) * 1e10 + farthest = torch.randint(0, N, (B,), dtype=torch.long).to(device) + batch_indices = torch.arange(B, dtype=torch.long).to(device) + # 采样过程 + for i in range(npoint): + centroids[:, i] = farthest + centroid = xyz[batch_indices, farthest, :].view(B, 1, 3) + dist = torch.sum((xyz - centroid) ** 2, -1) + mask = dist < distance + distance[mask] = dist[mask] + farthest = torch.max(distance, -1)[1] + return centroids + ``` + ++ 处理方案 + + 可采用两种方案: + + + 修改loop代码,一些简单的loop结构可以通过基本算子进行替换:如一些取值或则拼接操作可以通过indext/concat操作替换 + + 分离模型结构,遇到无法替换的loop结构,可以剥离loop结构到数据前处理或者后处理中,可参考案例:[PointNet++循环采样结构解决案例](https://gitee.com/wangjiangben_hw/ascend-pytorch-crowdintelligence-doc/blob/master/Ascend-PyTorch%E7%A6%BB%E7%BA%BF%E6%8E%A8%E7%90%86%E6%8C%87%E5%AF%BC/%E4%B8%93%E9%A2%98%E6%A1%88%E4%BE%8B/%E5%8A%9F%E8%83%BD%E6%89%93%E9%80%9A/PoinetNet++%E5%BE%AA%E7%8E%AF%E9%87%87%E6%A0%B7%E7%BB%93%E6%9E%84%E8%A7%A3%E5%86%B3%E6%A1%88%E4%BE%8B.md) + # 3 OM离线推理失败问题汇总 + ## 3.1 找不到atc命令或找不到ascend动态库 - 现象描述 ```shell @@ -222,9 +269,9 @@ bash build_local.sh ``` -# 4 精度调试常见问题 +# 4 精度相关问题 -# 5 性能优化常见问题 +# 5 性能相关问题 ## 5.1 如何使用AIPP进行性能提升 原理介绍可以参考[使能AIPP](https://support.huaweicloud.com/atctool-cann503alpha2infer/atlasatc_16_0016.html) - 使用方法 @@ -245,7 +292,7 @@ - 增加atc参数 在原有atc命令基础上增加 [--enable_small_channel=1](https://support.huaweicloud.com/atctool-cann503alpha2infer/atlasatc_16_0077.html) 和 [--insert_op_conf=path/to/insert_op.cfg](https://support.huaweicloud.com/atctool-cann503alpha2infer/atlasatc_16_0068.html#ZH-CN_TOPIC_0000001152734182) -# 5.2 GPU推理(trtexec)报错 +## 5.2 GPU推理(trtexec)报错 + 错误现象 @@ -276,8 +323,8 @@ 对于算子支持问题,默认采用以下两种解决方案: 1. 采用更高版本的trt版本(默认为trt7.xxx),如trt8 - 2. 基于onnxruntime进行onnx的离线推理得到性能 - 3. 基于2.方案仍然不生效,则基于在线推理得到性能 + 2. 基于onnxruntime进行onnx的离线推理得到性能 + 3. 基于2.方案仍然不生效,则基于在线推理得到性能 2. 内存限制 @@ -300,22 +347,22 @@ ```python import torch from torch import nn - + class SrcCode(nn.Module): def forward(self,x): y = x.expand(1024, 1024, 3).transpose(0, 1) return y - + class Optimizer(nn.Module): def forward(self,x): t = x.reshape(1024,1,3).repeat((1,1024,1)) return t - + src = SrcCode() opt = Optimizer() src.eval() opt.eval() - + input1 = torch.randn(1024,3) out = src(input1) out2 = opt(input1) @@ -330,3 +377,68 @@ 性能提升结果:整网性能提升270%,性能达标。 ![transpose_opt](./images/FAQ002_4.png) ![opt_profiling](./images/FAQ002_5.png) + +## 5.4 AICPU算子问题 + ++ 问题现象 + + + 算子不支持直接,转换模型错误: + + image-20211223152947663 + + + 性能问题: + + ![image-20211223154539348](./images/image-20211223154539348.png) + ++ 原因分析 + + 相关算子如果不支持某一格式时,算子将不再再AIcore侧进行调用,而是直接走AICPU,会造成一定性能损失,甚至模型转换的时候直接报错,常见如:INT64格式(AICORE默认不支持INT64格式) + ++ 处理方案 + + 可以通过改图规避,这里提供通用的转换INT64数据节点为INT32的方案,其他格式转换原理类似: + + ```python + import numpy as np + from magiconnx import OnnxGraph + + def value_to_int32(node): + node_value = node.value.copy() + if (node_value > MAXINT32).any(): + node_value[node_value>MAXINT32] = MAXINT32 + if (node_value < MININT32).any(): + node_value[node_value