已合并
【PR】: 修复 Broadcast/Tile + Reduce 时 Reshape 输入输出定义 #4474
JacsonPile创建于 15 天前
【PR】: 修复 Broadcast/Tile + Reduce 时 Reshape 输入输出定义 #4474
已合并
JacsonPile创建于 15 天前
2 个文件变更+85-26
@@ -14,6 +14,7 @@
14#include "graph/utils/graph_utils.h"14#include "graph/utils/graph_utils.h"
15#include "graph/utils/node_utils.h"15#include "graph/utils/node_utils.h"
16#include "graph/utils/op_desc_utils.h"16#include "graph/utils/op_desc_utils.h"
17+#include "graph/attribute_group/attr_group_symbolic_desc.h"
17#include "operator_reg.h"18#include "operator_reg.h"
18#include "common/checker.h"19#include "common/checker.h"
19#include "debug/ge_util.h"20#include "debug/ge_util.h"
@@ -25,6 +26,7 @@ constexpr auto kOpTypeBroadcastTo = "BroadcastTo";
25constexpr auto kOpTypeFill = "Fill";26constexpr auto kOpTypeFill = "Fill";
26constexpr auto kOpTypeTile = "Tile";27constexpr auto kOpTypeTile = "Tile";
27constexpr auto kOpTypeTileD = "TileD";28constexpr auto kOpTypeTileD = "TileD";
29+constexpr auto kOpTypeReshape = "Reshape";
28 30 
29// 归约操作类型(仅支持直接消除的操作,避免数值精度问题)31// 归约操作类型(仅支持直接消除的操作,避免数值精度问题)
30// 注意:ReduceSum 和 ReduceProd 不支持,因为:32// 注意:ReduceSum 和 ReduceProd 不支持,因为:
@@ -34,7 +36,6 @@ const std::unordered_set<std::string> kReduceOpTypes = {"ReduceMax", "ReduceMin
34 "ReduceMaxD", "ReduceMinD", "ReduceMeanD"};36 "ReduceMaxD", "ReduceMinD", "ReduceMeanD"};
35 37 
36constexpr auto kAttrNameAxes = "axes";38constexpr auto kAttrNameAxes = "axes";
37-constexpr auto kAttrNameShape = "shape";
38constexpr auto kAttrNameMultiples = "multiples";39constexpr auto kAttrNameMultiples = "multiples";
39constexpr auto kAttrNameKeepDims = "keep_dims";40constexpr auto kAttrNameKeepDims = "keep_dims";
40 41 
@@ -328,22 +329,47 @@ Status ReplaceAndCleanup(const ComputeGraphPtr &graph, const NodePtr &brc_node,
328// 创建 Reshape 节点329// 创建 Reshape 节点
329NodePtr CreateReshapeNode(const ComputeGraphPtr &graph, const NodePtr &input, const std::vector<int64_t> &target_shape,330NodePtr CreateReshapeNode(const ComputeGraphPtr &graph, const NodePtr &input, const std::vector<int64_t> &target_shape,
330 const std::string &name) {331 const std::string &name) {
331- auto op_desc = std::make_shared<OpDesc>(name, "Reshape");
332- GE_ASSERT_NOTNULL(op_desc);
333- 
334 GeTensorDesc input_desc = input->GetOpDesc()->GetOutputDesc(0);332 GeTensorDesc input_desc = input->GetOpDesc()->GetOutputDesc(0);
335- GE_ASSERT_GRAPH_SUCCESS(op_desc->AddInputDesc(input_desc));
336- 
337- // 设置输出 shape
338 GeTensorDesc output_desc(input_desc);333 GeTensorDesc output_desc(input_desc);
339 output_desc.SetShape(GeShape(target_shape));334 output_desc.SetShape(GeShape(target_shape));
340- GE_ASSERT_GRAPH_SUCCESS(op_desc->AddOutputDesc(output_desc));335+ output_desc.SetOriginShape(GeShape(target_shape));
341 336 
342- // 设置 shape 属性337+ // 输入描述可能携带原始张量的符号化 shape。替换节点是真实的 Reshape,
343- GE_ASSERT_TRUE(AttrUtils::SetListInt(op_desc, kAttrNameShape, target_shape));338+ // 因此符号化 shape 的 rank 必须与目标 shape 以及静态 GeShape 保持一致。
339+ auto symbolic_attr = output_desc.GetOrCreateAttrsGroup<SymbolicDescAttr>();
340+ GE_ASSERT_NOTNULL(symbolic_attr);
341+ std::vector<Expression> symbolic_shape;
342+ symbolic_shape.reserve(target_shape.size());
343+ for (const auto dim : target_shape) {
344+ symbolic_shape.emplace_back(Symbol(dim));
345+ }
346+ symbolic_attr->symbolic_tensor.MutableOriginSymbolShape().MutableDims() = symbolic_shape;
344 347 
345- auto reshape_node = graph->AddNode(op_desc);348+ // Reshape 有两个输入:数据 x 和目标 shape。创建目标 shape 常量并连接到第二个输入。
349+ const auto shape_tensor = ComGraphMakeShared<GeTensor>();
350+ GE_ASSERT_NOTNULL(shape_tensor);
351+ auto &shape_desc = shape_tensor->MutableTensorDesc();
352+ const GeShape shape_tensor_shape({static_cast<int64_t>(target_shape.size())});
353+ shape_desc.Update(shape_tensor_shape, FORMAT_ND, DT_INT64);
354+ shape_desc.SetOriginShape(shape_tensor_shape);
355+ if (!target_shape.empty()) {
356+ GE_ASSERT_GRAPH_SUCCESS(shape_tensor->SetData(reinterpret_cast<const uint8_t *>(target_shape.data()),
357+ target_shape.size() * sizeof(int64_t)));
358+ }
359+ const auto shape_op_desc = OpDescUtils::CreateConstOpZeroCopy(shape_tensor);
360+ GE_ASSERT_NOTNULL(shape_op_desc);
361+ const auto shape_node = graph->AddNode(shape_op_desc);
362+ GE_ASSERT_NOTNULL(shape_node);
363+ 
364+ const auto reshape_op_desc = ComGraphMakeShared<OpDesc>(name, kOpTypeReshape);
365+ GE_ASSERT_NOTNULL(reshape_op_desc);
366+ GE_ASSERT_GRAPH_SUCCESS(reshape_op_desc->AddInputDesc("x", input_desc));
367+ GE_ASSERT_GRAPH_SUCCESS(reshape_op_desc->AddInputDesc("shape", shape_desc));
368+ GE_ASSERT_GRAPH_SUCCESS(reshape_op_desc->AddOutputDesc("y", output_desc));
369+ auto reshape_node = graph->AddNode(reshape_op_desc);
346 GE_ASSERT_NOTNULL(reshape_node);370 GE_ASSERT_NOTNULL(reshape_node);
371+ GE_ASSERT_GRAPH_SUCCESS(GraphUtils::AddEdge(shape_node->GetOutDataAnchor(0), reshape_node->GetInDataAnchor(1)),
372+ "Failed to add shape edge to Reshape node %s", reshape_node->GetNamePtr());
347 GE_ASSERT_GRAPH_SUCCESS(GraphUtils::AddEdge(input->GetOutDataAnchor(0), reshape_node->GetInDataAnchor(0)),373 GE_ASSERT_GRAPH_SUCCESS(GraphUtils::AddEdge(input->GetOutDataAnchor(0), reshape_node->GetInDataAnchor(0)),
348 "Failed to add edge to Reshape node %s", reshape_node->GetNamePtr());374 "Failed to add edge to Reshape node %s", reshape_node->GetNamePtr());
349 375 
@@ -23,6 +23,9 @@
23#include "graph_utils_ex.h"23#include "graph_utils_ex.h"
24#include "op_creator_register.h"24#include "op_creator_register.h"
25#include "pattern_fusion/broadcast_reduce_elimination_pass.h"25#include "pattern_fusion/broadcast_reduce_elimination_pass.h"
26+#include "graph/attribute_group/attr_group_symbolic_desc.h"
27+#include "graph/debug/ge_attr_define.h"
28+#include "graph/utils/node_utils.h"
26#include "graph_metadef/graph/debug/ge_util.h"29#include "graph_metadef/graph/debug/ge_util.h"
27 30 
28namespace ge {31namespace ge {
@@ -79,6 +82,50 @@ class BroadcastReduceEliminationPassTest : public testing::Test {
79 relu.GetEsbTensor()->GetProducer()};82 relu.GetEsbTensor()->GetProducer()};
80 }83 }
81 84 
85+ static void CheckReshapeResult(const ComputeGraphPtr &graph, const std::vector<int64_t> &expected_shape) {
86+ const auto reshape_node = graph->FindNode("data_reduce_max_reshape");
87+ ASSERT_NE(reshape_node, nullptr);
88+ EXPECT_EQ(reshape_node->GetType(), "Reshape");
89+ ASSERT_EQ(reshape_node->GetAllInDataAnchorsSize(), 2U);
90+ 
91+ const auto shape_node = NodeUtils::GetInDataNodeByIndex(*reshape_node, 1);
92+ ASSERT_NE(shape_node, nullptr);
93+ EXPECT_EQ(shape_node->GetType(), CONSTANT);
94+ ConstGeTensorPtr shape_tensor;
95+ ASSERT_TRUE(AttrUtils::GetTensor(shape_node->GetOpDesc(), ATTR_NAME_WEIGHTS, shape_tensor));
96+ ASSERT_NE(shape_tensor, nullptr);
97+ ASSERT_EQ(shape_tensor->GetTensorDesc().GetDataType(), DT_INT64);
98+ ASSERT_EQ(shape_tensor->GetTensorDesc().GetShape().GetDims(),
99+ std::vector<int64_t>({static_cast<int64_t>(expected_shape.size())}));
100+ ASSERT_EQ(shape_tensor->GetData().GetSize(), expected_shape.size() * sizeof(int64_t));
101+ ASSERT_NE(shape_tensor->GetData().GetData(), nullptr);
102+ const auto shape_data = reinterpret_cast<const int64_t *>(shape_tensor->GetData().GetData());
103+ for (size_t i = 0; i < expected_shape.size(); ++i) {
104+ EXPECT_EQ(shape_data[i], expected_shape[i]);
105+ }
106+ 
107+ const auto &output_desc = reshape_node->GetOpDesc()->GetOutputDesc(0);
108+ EXPECT_EQ(output_desc.GetShape().GetDims(), expected_shape);
109+ EXPECT_EQ(output_desc.GetOriginShape().GetDims(), expected_shape);
110+ const auto symbolic_attr = output_desc.GetAttrsGroup<SymbolicDescAttr>();
111+ ASSERT_NE(symbolic_attr, nullptr);
112+ const auto &symbolic_dims = symbolic_attr->symbolic_tensor.GetOriginSymbolShape().GetDims();
113+ ASSERT_EQ(symbolic_dims.size(), expected_shape.size());
114+ for (size_t i = 0; i < expected_shape.size(); ++i) {
115+ EXPECT_EQ(symbolic_dims[i], Symbol(expected_shape[i]));
116+ }
117+ 
118+ const auto data_node = graph->FindNode("data");
119+ const auto relu_node = graph->FindNode("relu");
120+ ASSERT_NE(data_node, nullptr);
121+ ASSERT_NE(relu_node, nullptr);
122+ EXPECT_EQ(NodeUtils::GetInDataNodeByIndex(*reshape_node, 0), data_node);
123+ const auto reshape_out_anchor = reshape_node->GetOutDataAnchor(0);
124+ const auto relu_in_anchor = relu_node->GetInDataAnchor(0);
125+ EXPECT_EQ(reshape_out_anchor->GetPeerInDataAnchors().size(), 1);
126+ EXPECT_EQ(*reshape_out_anchor->GetPeerInDataAnchors().begin(), relu_in_anchor);
127+ }
128+ 
82 std::unique_ptr<es::Graph> es_graph_;129 std::unique_ptr<es::Graph> es_graph_;
83};130};
84 131 
@@ -299,21 +346,7 @@ TEST_F(BroadcastReduceEliminationPassTest, BroadcastReduceMax_EliminateWithSquee
299 EXPECT_EQ(graph->FindNode("broadcast"), nullptr);346 EXPECT_EQ(graph->FindNode("broadcast"), nullptr);
300 EXPECT_EQ(graph->FindNode("reduce_max"), nullptr);347 EXPECT_EQ(graph->FindNode("reduce_max"), nullptr);
301 348 
302- // 验证创建了 Reshape 节点349+ CheckReshapeResult(graph, {10});
303- auto reshape_node = graph->FindNode("data_reduce_max_reshape");
304- ASSERT_NE(reshape_node, nullptr);
305- EXPECT_EQ(reshape_node->GetType(), "Reshape");
306- 
307- // 验证 data -> Reshape -> relu 的连接
308- auto data_node = graph->FindNode("data");
309- auto relu_node = graph->FindNode("relu");
310- ASSERT_NE(data_node, nullptr);
311- ASSERT_NE(relu_node, nullptr);
312- 
313- auto reshape_out_anchor = reshape_node->GetOutDataAnchor(0);
314- auto relu_in_anchor = relu_node->GetInDataAnchor(0);
315- EXPECT_EQ(reshape_out_anchor->GetPeerInDataAnchors().size(), 1);
316- EXPECT_EQ(*reshape_out_anchor->GetPeerInDataAnchors().begin(), relu_in_anchor);
317}350}
318 351 
319// ========== Fill + Reduce 测试用例 ==========352// ========== Fill + Reduce 测试用例 ==========