Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions onnxruntime/core/optimizer/graph_transformer_utils.cc
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,11 @@ InlinedVector<std::unique_ptr<GraphTransformer>> GenerateTransformers(
onnxruntime::kAclExecutionProvider,
onnxruntime::kCudaExecutionProvider,
onnxruntime::kDmlExecutionProvider};
const InlinedHashSet<std::string_view> cpu_acl_cuda_dml_webgpu_eps = {onnxruntime::kCpuExecutionProvider,
onnxruntime::kAclExecutionProvider,
onnxruntime::kCudaExecutionProvider,
onnxruntime::kDmlExecutionProvider,
onnxruntime::kWebGpuExecutionProvider};
const InlinedHashSet<std::string_view> cpu_acl_cuda_dml_js_webgpu_eps = {onnxruntime::kCpuExecutionProvider,
onnxruntime::kAclExecutionProvider,
onnxruntime::kCudaExecutionProvider,
Expand Down Expand Up @@ -401,15 +406,15 @@ InlinedVector<std::unique_ptr<GraphTransformer>> GenerateTransformers(

transformers.emplace_back(std::make_unique<ConvActivationFusion>(cpu_acl_js_webgpu_eps));

transformers.emplace_back(std::make_unique<GeluFusion>(cpu_acl_cuda_dml_eps, level));
transformers.emplace_back(std::make_unique<GeluFusion>(cpu_acl_cuda_dml_webgpu_eps, level));
transformers.emplace_back(std::make_unique<LayerNormFusion>(cpu_acl_cuda_dml_eps, level));
transformers.emplace_back(std::make_unique<SimplifiedLayerNormFusion>(cpu_cuda_eps));
transformers.emplace_back(std::make_unique<AttentionFusion>(cpu_acl_cuda_dml_eps));
transformers.emplace_back(std::make_unique<EmbedLayerNormFusion>(cpu_acl_cuda_dml_eps));
transformers.emplace_back(std::make_unique<GatherSliceToSplitFusion>(cpu_cuda_eps));
transformers.emplace_back(std::make_unique<GatherToSliceFusion>(cpu_cuda_eps));
transformers.emplace_back(std::make_unique<MatmulTransposeFusion>(cpu_cuda_dml_eps));
transformers.emplace_back(std::make_unique<BiasGeluFusion>(cpu_acl_cuda_dml_eps));
transformers.emplace_back(std::make_unique<BiasGeluFusion>(cpu_acl_cuda_dml_webgpu_eps));
transformers.emplace_back(std::make_unique<GroupQueryAttentionFusion>(cuda_eps));
// Run MatMulAddFusion again after *AttentionFusion transforms with `preserve_attention_pattern = false`,
// to cleanup the remaining MatMul-Add that were part of the attention pattern but not detected or fused.
Expand Down
16 changes: 16 additions & 0 deletions onnxruntime/test/contrib_ops/activation_op_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,22 @@ TEST_F(ActivationOpTest, Gelu) {
}
#endif

TEST_F(ActivationOpTest, Gelu_half) {
const std::vector<MLFloat16>& X = input_values_fp16[0];
std::vector<MLFloat16> Y;
Y.reserve(X.size());
for (const MLFloat16& x_half : X) {
const float x = x_half.ToFloat();
Y.push_back(MLFloat16(x * 0.5f * (1.0f + std::erf(x * static_cast<float>(M_SQRT1_2)))));
}

OpTester tester("Gelu", 1, onnxruntime::kMSDomain);
const std::vector<int64_t> dims{1, 1, static_cast<int64_t>(X.size())};
tester.AddInput<MLFloat16>("X", dims, X);
tester.AddOutput<MLFloat16>("Y", dims, Y);
tester.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider});
}

#if defined(USE_DNNL)
std::vector<BFloat16> expected_output_bfloat16(const std::vector<float>& input_data) {
std::vector<float> output;
Expand Down
99 changes: 99 additions & 0 deletions onnxruntime/test/optimizer/graph_transform_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -7330,6 +7330,105 @@ TEST_F(GraphTransformationTests, BiasGeluFusionCurrentOpsetTest) {
ModelOptions{kAllowReleasedOpsetsOnly, /*strict_shape_type_inference*/ false}));
}

#if !defined(DISABLE_CONTRIB_OPS)
// Regression test for the WebGPU entry added to the Level-2 GeluFusion allowlist
// (cpu_acl_cuda_dml_webgpu_eps in graph_transformer_utils.cc).
TEST_F(GraphTransformationTests, GeluFusionWebGpu) {
constexpr const ORTCHAR_T* model_uri = MODEL_FOLDER "fusion/gelu.onnx";
std::shared_ptr<Model> p_model;
ASSERT_STATUS_OK(Model::Load(model_uri, p_model, nullptr, *logger_));
Graph& graph = p_model->MainGraph();
#if defined(USE_WEBGPU)
const std::string expected_ep = kWebGpuExecutionProvider;
#else
const std::string expected_ep = kCpuExecutionProvider;
#endif
for (auto& node : graph.Nodes()) {
node.SetExecutionProviderType(expected_ep);
}

SessionOptions session_options;
auto cpu_ep = std::make_unique<CPUExecutionProvider>(CPUExecutionProviderInfo());
const InlinedHashSet<std::string> gelu_transformer_names = {"GeluFusionL1", "GeluFusionL2"};
onnxruntime::GraphTransformerManager graph_transformation_mgr{5};
for (auto level : {TransformerLevel::Level1, TransformerLevel::Level2}) {
for (auto& transformer : optimizer_utils::GenerateTransformers(level, session_options, *cpu_ep, *logger_, {})) {
if (gelu_transformer_names.count(transformer->Name()) != 0) {
ASSERT_STATUS_OK(graph_transformation_mgr.Register(std::move(transformer), level));
}
}
}
ASSERT_STATUS_OK(graph_transformation_mgr.ApplyTransformers(graph, TransformerLevel::Level1, *logger_));
ASSERT_STATUS_OK(graph_transformation_mgr.ApplyTransformers(graph, TransformerLevel::Level2, *logger_));

std::map<std::string, int> op_to_count = CountOpsInGraph(graph);
ASSERT_EQ(op_to_count["com.microsoft.Gelu"], 1);
ASSERT_EQ(op_to_count["Div"], 0);
ASSERT_EQ(op_to_count["Erf"], 0);
ASSERT_EQ(op_to_count["Add"], 0);
ASSERT_EQ(op_to_count["Mul"], 0);

const Node* gelu_node = nullptr;
for (auto& node : graph.Nodes()) {
if (node.OpType() == "Gelu" && node.Domain() == kMSDomain) {
gelu_node = &node;
break;
}
}
ASSERT_NE(gelu_node, nullptr);
EXPECT_EQ(gelu_node->GetExecutionProviderType(), expected_ep);
}

// Regression test for the WebGPU entry added to the BiasGeluFusion allowlist.
TEST_F(GraphTransformationTests, BiasGeluFusionWebGpu) {
constexpr const ORTCHAR_T* model_uri = MODEL_FOLDER "fusion/bias_gelu_fusion.onnx";
std::shared_ptr<Model> p_model;
ASSERT_STATUS_OK(Model::Load(model_uri, p_model, nullptr, *logger_));
Graph& graph = p_model->MainGraph();
#if defined(USE_WEBGPU)
const std::string expected_ep = kWebGpuExecutionProvider;
#else
const std::string expected_ep = kCpuExecutionProvider;
#endif
for (auto& node : graph.Nodes()) {
node.SetExecutionProviderType(expected_ep);
}

SessionOptions session_options;
auto cpu_ep = std::make_unique<CPUExecutionProvider>(CPUExecutionProviderInfo());
const InlinedHashSet<std::string> gelu_transformer_names = {"GeluFusionL1", "BiasGeluFusion"};
Comment thread
fanchenkong1 marked this conversation as resolved.
Resolved
onnxruntime::GraphTransformerManager graph_transformation_mgr{5};
for (auto level : {TransformerLevel::Level1, TransformerLevel::Level2}) {
for (auto& transformer : optimizer_utils::GenerateTransformers(level, session_options, *cpu_ep, *logger_, {})) {
if (gelu_transformer_names.count(transformer->Name()) != 0) {
ASSERT_STATUS_OK(graph_transformation_mgr.Register(std::move(transformer), level));
}
}
}
ASSERT_STATUS_OK(graph_transformation_mgr.ApplyTransformers(graph, TransformerLevel::Level1, *logger_));
ASSERT_STATUS_OK(graph_transformation_mgr.ApplyTransformers(graph, TransformerLevel::Level2, *logger_));

std::map<std::string, int> op_to_count = CountOpsInGraph(graph);
ASSERT_EQ(op_to_count["com.microsoft.BiasGelu"], 1);
ASSERT_EQ(op_to_count["com.microsoft.Gelu"], 0);
ASSERT_EQ(op_to_count["Gelu"], 0);
ASSERT_EQ(op_to_count["Add"], 0);
ASSERT_EQ(op_to_count["Div"], 0);
ASSERT_EQ(op_to_count["Erf"], 0);
ASSERT_EQ(op_to_count["Mul"], 0);

const Node* bias_gelu_node = nullptr;
for (auto& node : graph.Nodes()) {
if (node.OpType() == "BiasGelu" && node.Domain() == kMSDomain) {
bias_gelu_node = &node;
break;
}
}
ASSERT_NE(bias_gelu_node, nullptr);
EXPECT_EQ(bias_gelu_node->GetExecutionProviderType(), expected_ep);
}
#endif // !defined(DISABLE_CONTRIB_OPS)

TEST_F(GraphTransformationTests, MatMulAddFusionCurrentOpsetTest) {
// MatMul + Add -> Gemm fusion
int current_opset = GetCurrentOnnxOpset();
Expand Down