已合并
修改ROIAlignGrad readme文档及examples #1315
SimonZzz创建于 16 天前
修改ROIAlignGrad readme文档及examples #1315
已合并
SimonZzz创建于 16 天前
2 个文件变更+439-2
@@ -13,14 +13,143 @@
13 13 
14## 功能说明14## 功能说明
15 15 
16-ROIAlignGrad是ROIAlign算子的反向传播算子。ROIAlign是一种池化操作,用于从非均匀尺寸的特征图中提取固定尺寸的ROI(Region of Interest)特征。反向传播负责将输出梯度按正向传播时的双线性插值权重分配回输入特征图。16+- 算子功能:ROIAlignGrad是ROIAlign算子的反向传播算子。ROIAlign是一种池化操作,用于从非均匀尺寸的特征图中提取固定尺寸的ROI(Region of Interest)特征。反向传播负责将输出梯度按正向传播时的双线性插值权重分配回输入特征图。
17+ 
18+- 计算公式:
19+ 
20+ 对于每个ROI的每个bin中的每个采样点 $(y, x)$,通过双线性插值计算其4个邻居像素 $(y_{low}, x_{low})$、$(y_{low}, x_{high})$、$(y_{high}, x_{low})$、$(y_{high}, x_{high})$ 的插值权重:
21+ 
22+ $$
23+ l_y = y - y_{low}, \quad l_x = x - x_{low}, \quad h_y = 1 - l_y, \quad h_x = 1 - l_x
24+ $$
25+ 
26+ $$
27+ w_1 = h_y \cdot h_x, \quad w_2 = h_y \cdot l_x, \quad w_3 = l_y \cdot h_x, \quad w_4 = l_y \cdot l_x
28+ $$
29+ 
30+ 将每个采样点的梯度 $\frac{\partial L}{\partial y}$ 按权重累加到4个邻居像素:
31+ 
32+ $$
33+ \text{xdiff}[b, c, y_{low}, x_{low}] += \frac{1}{count} \cdot \frac{\partial L}{\partial y} \cdot w_1
34+ $$
35+ 
36+ $$
37+ \text{xdiff}[b, c, y_{low}, x_{high}] += \frac{1}{count} \cdot \frac{\partial L}{\partial y} \cdot w_2
38+ $$
39+ 
40+ $$
41+ \text{xdiff}[b, c, y_{high}, x_{low}] += \frac{1}{count} \cdot \frac{\partial L}{\partial y} \cdot w_3
42+ $$
43+ 
44+ $$
45+ \text{xdiff}[b, c, y_{high}, x_{high}] += \frac{1}{count} \cdot \frac{\partial L}{\partial y} \cdot w_4
46+ $$
47+ 
48+ 其中 $b$ 为batch索引,$c$ 为通道索引,$count = roi\_bin\_grid\_h \times roi\_bin\_grid\_w$ 为该bin的采样点总数。
49+ 
50+## 参数说明
51+ 
52+<table style="undefined;table-layout: fixed; width: 1005px"><colgroup>
53+ <col style="width: 170px">
54+ <col style="width: 170px">
55+ <col style="width: 352px">
56+ <col style="width: 213px">
57+ <col style="width: 100px">
58+ </colgroup>
59+ <thead>
60+ <tr>
61+ <th>参数名</th>
62+ <th>输入/输出/属性</th>
63+ <th>描述</th>
64+ <th>数据类型</th>
65+ <th>数据格式</th>
66+ </tr></thead>
67+ <tbody>
68+ <tr>
69+ <td>ydiff</td>
70+ <td>输入</td>
71+ <td>反向传播梯度输入,shape为(N, C, pooled_height, pooled_width)。</td>
72+ <td>FLOAT</td>
73+ <td>ND</td>
74+ </tr>
75+ <tr>
76+ <td>rois</td>
77+ <td>输入</td>
78+ <td>ROI坐标,shape为(N, 5),每行格式为[batch_idx, roi_x1, roi_y1, roi_x2, roi_y2]。</td>
79+ <td>FLOAT</td>
80+ <td>ND</td>
81+ </tr>
82+ <tr>
83+ <td>rois_n</td>
84+ <td>输入(可选)</td>
85+ <td>每个batch中有效ROI的数量,shape为(B,)。当前计算中未使用。</td>
86+ <td>INT32</td>
87+ <td>ND</td>
88+ </tr>
89+ <tr>
90+ <td>xdiff_shape</td>
91+ <td>属性(必选)</td>
92+ <td>输出特征图的shape,即正向输入特征图的shape,格式为[B, C, H, W],必须为4元素正整数列表。</td>
93+ <td>ListInt</td>
94+ <td>-</td>
95+ </tr>
96+ <tr>
97+ <td>pooled_height</td>
98+ <td>属性(必选)</td>
99+ <td>ROI输出特征图的高度。</td>
100+ <td>Int</td>
101+ <td>-</td>
102+ </tr>
103+ <tr>
104+ <td>pooled_width</td>
105+ <td>属性(必选)</td>
106+ <td>ROI输出特征图的宽度。</td>
107+ <td>Int</td>
108+ <td>-</td>
109+ </tr>
110+ <tr>
111+ <td>spatial_scale</td>
112+ <td>属性(必选)</td>
113+ <td>特征图相对于原图的缩放比例。</td>
114+ <td>Float</td>
115+ <td>-</td>
116+ </tr>
117+ <tr>
118+ <td>sample_num</td>
119+ <td>属性(可选)</td>
120+ <td>每个bin的采样次数。默认值为2,0表示自动计算(取ceil(roi_size / pooled_size))。</td>
121+ <td>Int</td>
122+ <td>-</td>
123+ </tr>
124+ <tr>
125+ <td>roi_end_mode</td>
126+ <td>属性(可选)</td>
127+ <td>
128+ <ul style="margin-top: 0; margin-bottom: 0; padding-left: 2ch;">
129+ <li>0:无对齐。</li>
130+ <li>1:TF偏移模式(x2/y2 += spatial_scale,roi_w/roi_h取max(., 1.0))。</li>
131+ <li>2:PyTorch对齐模式(x1/y1/x2/y2 -= 0.5)。</li>
132+ <li>3:MMDetection对齐模式(同2)。</li>
133+ </ul>
134+ 默认值为1。
135+ </td>
136+ <td>Int</td>
137+ <td>-</td>
138+ </tr>
139+ <tr>
140+ <td>xdiff</td>
141+ <td>输出</td>
142+ <td>输入特征图的梯度,shape为(B, C, H, W)。</td>
143+ <td>FLOAT</td>
144+ <td>ND</td>
145+ </tr>
146+ </tbody></table>
17 147 
18## 约束说明148## 约束说明
19 149 
20- 仅支持float32数据类型。150- 仅支持float32数据类型。
21- ydiff和xdiff为4维ND格式,rois为2维ND格式。151- ydiff和xdiff为4维ND格式,rois为2维ND格式。
22- xdiff_shape属性必须为4元素正整数列表。152- xdiff_shape属性必须为4元素正整数列表。
23-- 多个采样点映射到同一输入像素时使用原子加累加(非确定性计算)。
24- 空tensor(shape含0维)时返回全零梯度。153- 空tensor(shape含0维)时返回全零梯度。
25 154 
26## 调用说明155## 调用说明
@@ -28,3 +157,4 @@ ROIAlignGrad是ROIAlign算子的反向传播算子。ROIAlign是一种池化操
28| 调用方式 | 调用样例 | 说明 |157| 调用方式 | 调用样例 | 说明 |
29|----------|----------|------|158|----------|----------|------|
30| aclnn 接口调用 | [test_aclnn_roi_align_v2_backward_l2](examples/test_aclnn_roi_align_v2_backward.cpp) | 通过[aclnnRoiAlignV2Backward](./docs/aclnnRoiAlignV2Backward.md)接口方式调用RoiAlignGrad算子。 |159| aclnn 接口调用 | [test_aclnn_roi_align_v2_backward_l2](examples/test_aclnn_roi_align_v2_backward.cpp) | 通过[aclnnRoiAlignV2Backward](./docs/aclnnRoiAlignV2Backward.md)接口方式调用RoiAlignGrad算子。 |
160+| 图模式 | [test_geir_roi_align_grad](examples/test_geir_roi_align_grad.cpp) | 通过[算子IR](op_graph/roi_align_grad_proto.h)构图方式调用RoiAlignGrad算子。 |
@@ -0,0 +1,307 @@
1+/**
2+ * Copyright (c) 2026 Huawei Technologies Co., Ltd.
3+ * This program is free software, you can redistribute it and/or modify it under the terms and conditions of
4+ * CANN Open Software License Agreement Version 2.0 (the "License").
5+ * Please refer to the License for details. You may not use this file except in compliance with the License.
6+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
7+ * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
8+ * See LICENSE in the root of the software repository for the full text of the License.
9+ */
10+ 
11+/* Generated By CANNBot */
12+ 
13+#include <iostream>
14+#include <fstream>
15+#include <string.h>
16+#include <stdint.h>
17+#include <vector>
18+#include <string>
19+#include <map>
20+#include "assert.h"
21+ 
22+#include "graph.h"
23+#include "types.h"
24+#include "tensor.h"
25+#include "ge_error_codes.h"
26+#include "ge_api_types.h"
27+#include "ge_api.h"
28+#include "array_ops.h"
29+#include "ge_ir_build.h"
30+ 
31+#include "experiment_ops.h"
32+#include "nn_other.h"
33+#include "../op_graph/roi_align_grad_proto.h"
34+ 
35+#define FAILED -1
36+#define SUCCESS 0
37+ 
38+using namespace ge;
39+using std::map;
40+using std::string;
41+using std::vector;
42+#define ADD_INPUT(intputIndex, intputName, intputDtype, inputShape) \
43+ vector<int64_t> placeholder##intputIndex##_shape = inputShape; \
44+ auto placeholder##intputIndex = op::Data("placeholder" + intputIndex).set_attr_index(0); \
45+ TensorDesc placeholder##intputIndex##_desc = TensorDesc(ge::Shape(placeholder##intputIndex##_shape), FORMAT_ND, \
46+ intputDtype); \
47+ placeholder##intputIndex##_desc.SetPlacement(ge::kPlacementHost); \
48+ placeholder##intputIndex##_desc.SetFormat(FORMAT_ND); \
49+ Tensor tensor_placeholder##intputIndex; \
50+ ret = GenOnesData(placeholder##intputIndex##_shape, tensor_placeholder##intputIndex, \
51+ placeholder##intputIndex##_desc, intputDtype, 2); \
52+ if (ret != SUCCESS) { \
53+ printf("%s - ERROR - [XIR]: Generate input data failed\n", GetTime().c_str()); \
54+ return FAILED; \
55+ } \
56+ placeholder##intputIndex.update_input_desc_x(placeholder##intputIndex##_desc); \
57+ input.push_back(tensor_placeholder##intputIndex); \
58+ graph.AddOp(placeholder##intputIndex); \
59+ add1.set_input_##intputName(placeholder##intputIndex); \
60+ add1.update_input_desc_##intputName(placeholder##intputIndex##_desc); \
61+ inputs.push_back(placeholder##intputIndex);
62+ 
63+#define ADD_OUTPUT(outputIndex, outputName, outputDtype, outputShape) \
64+ TensorDesc outputName##outputIndex##_desc = TensorDesc(ge::Shape(outputShape), FORMAT_ND, outputDtype); \
65+ add1.update_output_desc_##outputName(outputName##outputIndex##_desc);
66+ 
67+string GetTime()
68+{
69+ time_t timep;
70+ time(&timep);
71+ char tmp[64];
72+ strftime(tmp, sizeof(tmp), "%Y-%m-%d %H:%M:%S,000", localtime(&timep));
73+ return tmp;
74+}
75+ 
76+uint32_t GetDataTypeSize(DataType dt)
77+{
78+ uint32_t dilation = 1;
79+ uint32_t oneByte = 1;
80+ uint32_t twoByte = 2;
81+ uint32_t fourByte = 4;
82+ uint32_t eightByte = 8;
83+ 
84+ if (dt == ge::DT_FLOAT) {
85+ dilation = fourByte;
86+ } else if (dt == ge::DT_FLOAT16) {
87+ dilation = twoByte;
88+ } else if (dt == ge::DT_BF16) {
89+ dilation = twoByte;
90+ } else if (dt == ge::DT_INT16) {
91+ dilation = twoByte;
92+ } else if (dt == ge::DT_UINT16) {
93+ dilation = twoByte;
94+ } else if (dt == ge::DT_INT32) {
95+ dilation = fourByte;
96+ } else if (dt == ge::DT_UINT32) {
97+ dilation = fourByte;
98+ } else if (dt == ge::DT_INT64) {
99+ dilation = eightByte;
100+ } else if (dt == ge::DT_UINT64) {
101+ dilation = eightByte;
102+ } else if (dt == ge::DT_INT8) {
103+ dilation = oneByte;
104+ }
105+ return dilation;
106+}
107+ 
108+int32_t GenOnesDataFloat32(vector<int64_t> shapes, Tensor& input_tensor, TensorDesc& input_tensor_desc, float value)
109+{
110+ input_tensor_desc.SetRealDimCnt(shapes.size());
111+ size_t size = 1;
112+ for (uint32_t i = 0; i < shapes.size(); i++) {
113+ size *= shapes[i];
114+ }
115+ uint32_t byteSizeFloat32 = 4;
116+ uint32_t data_len = size * byteSizeFloat32;
117+ float* pData = new (std::nothrow) float[size];
118+ if (pData == nullptr) {
119+ return FAILED;
120+ }
121+ 
122+ for (size_t i = 0; i < size; ++i) {
123+ *(pData + i) = value;
124+ }
125+ input_tensor = Tensor(input_tensor_desc, (uint8_t*)pData, data_len);
126+ delete[] pData;
127+ return SUCCESS;
128+}
129+ 
130+int32_t GenOnesData(vector<int64_t> shapes, Tensor& input_tensor, TensorDesc& input_tensor_desc, DataType data_type,
131+ int value)
132+{
133+ input_tensor_desc.SetRealDimCnt(shapes.size());
134+ size_t size = 1;
135+ for (uint32_t i = 0; i < shapes.size(); i++) {
136+ size *= shapes[i];
137+ }
138+ uint32_t data_type_size = GetDataTypeSize(data_type);
139+ uint32_t data_len = size * data_type_size;
140+ uint8_t* pData = new (std::nothrow) uint8_t[data_len];
141+ if (pData == nullptr) {
142+ return FAILED;
143+ }
144+ if (data_type == ge::DT_FLOAT) {
145+ float fval = static_cast<float>(value);
146+ for (size_t i = 0; i < size; ++i) {
147+ memcpy(pData + i * data_type_size, &fval, data_type_size);
148+ }
149+ } else {
150+ for (size_t i = 0; i < size; ++i) {
151+ memcpy(pData + i * data_type_size, &value, data_type_size);
152+ }
153+ }
154+ input_tensor = Tensor(input_tensor_desc, pData, data_len);
155+ delete[] pData;
156+ return SUCCESS;
157+}
158+ 
159+int32_t WriteDataToFile(string bin_file, uint64_t data_size, uint8_t* inputData)
160+{
161+ FILE* fp = fopen(bin_file.c_str(), "w");
162+ if (fp == nullptr) {
163+ printf("WriteDataToFile: failed to open file %s\n", bin_file.c_str());
164+ return FAILED;
165+ }
166+ fwrite(inputData, sizeof(uint8_t), data_size, fp);
167+ fclose(fp);
168+ return SUCCESS;
169+}
170+ 
171+int CreateOppInGraph(DataType inDtype, std::vector<ge::Tensor>& input, std::vector<Operator>& inputs,
172+ std::vector<Operator>& outputs, Graph& graph)
173+{
174+ Status ret = SUCCESS;
175+ // 自定义代码:添加单算子定义到图中
176+ auto add1 = op::ROIAlignGrad("roi_align_grad1");
177+ 
178+ std::vector<int64_t> ydiffShape = {2, 3, 7, 7};
179+ std::vector<int64_t> roisShape = {2, 5};
180+ 
181+ add1.set_attr_xdiff_shape({1, 3, 14, 14});
182+ add1.set_attr_pooled_width(7);
183+ add1.set_attr_pooled_height(7);
184+ add1.set_attr_spatial_scale(0.5f);
185+ add1.set_attr_sample_num(2);
186+ add1.set_attr_roi_end_mode(1);
187+ 
188+ ADD_INPUT(1, ydiff, inDtype, ydiffShape);
189+ ADD_INPUT(2, rois, inDtype, roisShape);
190+ 
191+ ADD_OUTPUT(1, xdiff, inDtype, ({1, 3, 14, 14}));
192+ 
193+ outputs.push_back(add1);
194+ // 添加完毕
195+ return SUCCESS;
196+}
197+ 
198+int main(int argc, char* argv[])
199+{
200+ const char* graph_name = "tc_ge_irrun_test";
201+ Graph graph(graph_name);
202+ std::vector<ge::Tensor> input;
203+ 
204+ printf("%s - INFO - [XIR]: Start to initialize ge using ge global options\n", GetTime().c_str());
205+ std::map<AscendString, AscendString> global_options = {{"ge.exec.deviceId", "0"}, {"ge.graphRunMode", "1"}};
206+ Status ret = ge::GEInitialize(global_options);
207+ if (ret != SUCCESS) {
208+ printf("%s - INFO - [XIR]: Initialize ge using ge global options failed\n", GetTime().c_str());
209+ return FAILED;
210+ }
211+ printf("%s - INFO - [XIR]: Initialize ge using ge global options success\n", GetTime().c_str());
212+ 
213+ std::vector<Operator> inputs{};
214+ std::vector<Operator> outputs{};
215+ 
216+ if (argc < 2) {
217+ printf("Usage: %s <arg>\n", argv[0]);
218+ return FAILED;
219+ }
220+ std::cout << argv[1] << std::endl;
221+ 
222+ DataType inDtype = DT_FLOAT;
223+ 
224+ std::cout << inDtype << std::endl;
225+ 
226+ ret = CreateOppInGraph(inDtype, input, inputs, outputs, graph);
227+ if (ret != SUCCESS) {
228+ printf("%s - ERROR - [XIR]: Create Opp In Graph failed\n", GetTime().c_str());
229+ return FAILED;
230+ }
231+ 
232+ if (!inputs.empty() && !outputs.empty()) {
233+ graph.SetInputs(inputs).SetOutputs(outputs);
234+ }
235+ 
236+ std::map<AscendString, AscendString> build_options = {
237+ 
238+ };
239+ printf("%s - INFO - [XIR]: Start to create ir session using build options\n", GetTime().c_str());
240+ ge::Session* session = new Session(build_options);
241+ 
242+ if (session == nullptr) {
243+ printf("%s - ERROR - [XIR]: Create ir session using build options failed\n", GetTime().c_str());
244+ return FAILED;
245+ }
246+ printf("%s - INFO - [XIR]: Create ir session using build options success\n", GetTime().c_str());
247+ printf("%s - INFO - [XIR]: Start to add compute graph to ir session\n", GetTime().c_str());
248+ 
249+ std::map<AscendString, AscendString> graph_options = {
250+ 
251+ };
252+ uint32_t graph_id = 0;
253+ ret = session->AddGraph(graph_id, graph, graph_options);
254+ 
255+ printf("%s - INFO - [XIR]: Session add ir compute graph to ir session success\n", GetTime().c_str());
256+ printf("%s - INFO - [XIR]: dump graph to txt\n", GetTime().c_str());
257+ std::string file_path = "./dump";
258+ aclgrphDumpGraph(graph, file_path.c_str(), file_path.length());
259+ printf("%s - INFO - [XIR]: Start to run ir compute graph\n", GetTime().c_str());
260+ std::vector<ge::Tensor> output;
261+ ret = session->RunGraph(graph_id, input, output);
262+ if (ret != SUCCESS) {
263+ printf("%s - INFO - [XIR]: Run graph failed\n", GetTime().c_str());
264+ delete session;
265+ GEFinalize();
266+ return FAILED;
267+ }
268+ printf("%s - INFO - [XIR]: Session run ir compute graph success\n", GetTime().c_str());
269+ 
270+ int input_num = input.size();
271+ for (int i = 0; i < input_num; i++) {
272+ std::cout << "input " << i << " dtype : " << input[i].GetTensorDesc().GetDataType() << std::endl;
273+ string input_file = "./tc_ge_irrun_test_0008_npu_input_" + std::to_string(i) + ".bin";
274+ uint8_t* input_data_i = input[i].GetData();
275+ int64_t input_shape = input[i].GetTensorDesc().GetShape().GetShapeSize();
276+ std::cout << "this is " << i << "th input, input shape size =" << input_shape << std::endl;
277+ uint32_t data_size = input_shape * GetDataTypeSize(input[i].GetTensorDesc().GetDataType());
278+ WriteDataToFile((const char*)input_file.c_str(), data_size, input_data_i);
279+ }
280+ 
281+ int output_num = output.size();
282+ for (int i = 0; i < output_num; i++) {
283+ std::cout << "output " << i << " dtype : " << output[i].GetTensorDesc().GetDataType() << std::endl;
284+ string output_file = "./tc_ge_irrun_test_0008_npu_output_" + std::to_string(i) + ".bin";
285+ uint8_t* output_data_i = output[i].GetData();
286+ int64_t output_shape = output[i].GetTensorDesc().GetShape().GetShapeSize();
287+ std::cout << "this is " << i << "th output, output shape size =" << output_shape << std::endl;
288+ uint32_t data_size = output_shape * GetDataTypeSize(output[i].GetTensorDesc().GetDataType());
289+ WriteDataToFile((const char*)output_file.c_str(), data_size, output_data_i);
290+ }
291+ 
292+ ge::AscendString error_msg = ge::GEGetErrorMsgV2();
293+ std::string error_str(error_msg.GetString());
294+ std::cout << "Error message: " << error_str << std::endl;
295+ ge::AscendString warning_msg = ge::GEGetWarningMsgV2();
296+ std::string warning_str(warning_msg.GetString());
297+ std::cout << "Warning message: " << warning_str << std::endl;
298+ printf("%s - INFO - [XIR]: Precision is ok\n", GetTime().c_str());
299+ printf("%s - INFO - [XIR]: Start to finalize ir graph session\n", GetTime().c_str());
300+ ret = ge::GEFinalize();
301+ if (ret != SUCCESS) {
302+ printf("%s - INFO - [XIR]: Finalize ir graph session failed\n", GetTime().c_str());
303+ return FAILED;
304+ }
305+ printf("%s - INFO - [XIR]: Finalize ir graph session success\n", GetTime().c_str());
306+ return SUCCESS;
307+}