From f22eaac760c33b8f398d29c7106702ff96d46b8a Mon Sep 17 00:00:00 2001 From: charlie Date: Fri, 12 Sep 2025 11:11:51 -0500 Subject: [PATCH 1/6] Initial --- src/onnx/onnx_parser.cpp | 1 + src/onnx/parse_dynamicscale.cpp | 52 +++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+) create mode 100644 src/onnx/parse_dynamicscale.cpp diff --git a/src/onnx/onnx_parser.cpp b/src/onnx/onnx_parser.cpp index b81abe4839c..11c5b0bb307 100644 --- a/src/onnx/onnx_parser.cpp +++ b/src/onnx/onnx_parser.cpp @@ -831,6 +831,7 @@ shape::type_t get_type(int dtype) case 18: return shape::fp8e4m3fnuz_type; case 21: return shape::uint8_type; case 22: return shape::int8_type; + case 23: return shape::fp4x2_type; case 14: case 15: case 16: return shape::bf16_type; diff --git a/src/onnx/parse_dynamicscale.cpp b/src/onnx/parse_dynamicscale.cpp new file mode 100644 index 00000000000..2e38d066fe4 --- /dev/null +++ b/src/onnx/parse_dynamicscale.cpp @@ -0,0 +1,52 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2015-2025 Advanced Micro Devices, Inc. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include + +namespace migraphx { +inline namespace MIGRAPHX_INLINE_NS { +namespace onnx { + +/** + * Operator from Brevitas to calculate dynamic quantization scales. + */ +struct parse_dynamicscale : op_parser +{ + + std::vector operators() const { return {{"DynamicScale"}}; }; + + instruction_ref parse(const op_desc& /*opd*/, + const onnx_parser& parser, + onnx_parser::node_info info, + const std::vector& args) const + { + value options = {}; + +}; + +} // namespace onnx +} // namespace MIGRAPHX_INLINE_NS +} // namespace migraphx From 8d1e86cb248d752b53a008142a14308204350d01 Mon Sep 17 00:00:00 2001 From: charlie Date: Mon, 15 Sep 2025 15:58:16 -0500 Subject: [PATCH 2/6] Progress? --- src/onnx/parse_dynamicscale.cpp | 105 ++++++++++++++++++++++++++++++-- 1 file changed, 101 insertions(+), 4 deletions(-) diff --git a/src/onnx/parse_dynamicscale.cpp b/src/onnx/parse_dynamicscale.cpp index 2e38d066fe4..92360337bd4 100644 --- a/src/onnx/parse_dynamicscale.cpp +++ b/src/onnx/parse_dynamicscale.cpp @@ -22,9 +22,11 @@ * THE SOFTWARE. */ -#include -#include #include +#include +#include +#include +#include namespace migraphx { inline namespace MIGRAPHX_INLINE_NS { @@ -39,12 +41,107 @@ struct parse_dynamicscale : op_parser std::vector operators() const { return {{"DynamicScale"}}; }; instruction_ref parse(const op_desc& /*opd*/, - const onnx_parser& parser, + const onnx_parser& /*parser*/, onnx_parser::node_info info, const std::vector& args) const { - value options = {}; + const instruction_ref input = args.front(); + instruction_ref tmp_in = input; + const auto input_lens = input->get_shape().lens(); + if(args.size() != 1) + { + MIGRAPHX_THROW("DynamicScale: must have only 1 input"); + } + int block_axis = info.attributes.at("group_dim").i(); + block_axis = tune_axis(input->get_shape().ndim(), block_axis, "DynamicScale"); + int block_size = info.attributes.at("group_size").i(); + if(block_size != 32) + { + MIGRAPHX_THROW("DynamicScale: only group_size of 32 is supported"); + } + migraphx::shape::type_t output_type = get_type(info.attributes.at("output_dtype").i()); + + // TODO expand this to handle other MX types + if(output_type != migraphx::shape::fp4x2_type) + { + MIGRAPHX_THROW("DynamicScale: only support MXFP4 type"); + } + + std::string scale_selection_method = info.attributes.at("scale_selection_method").s(); + if(scale_selection_method != "floor") + { + MIGRAPHX_THROW("DynamicScale: only support floor scale selection"); + } + + std::string zero_point_selection_method = "None"; + if(contains(info.attributes, "zero_point_selection_method")) + zero_point_selection_method = info.attributes.at("zero_point_selection_method").i(); + + if(zero_point_selection_method != "None") + { + MIGRAPHX_THROW("DynamicScale: zero_point not supported"); + } + + // make reduction axes for calculating block scales + // tmp_lens != input_lens if runt block is padded + auto tmp_lens = input_lens; + auto block_dim = tmp_lens.at(block_axis); + std::size_t block_padding = + std::ceil(double(block_dim) / double(block_size)) * block_size - block_dim; + // handle runt block by padding + if(block_padding != 0) + { + std::vector pads_vec(2 * tmp_lens.size(), 0); + pads_vec.at(block_axis + tmp_lens.size()) = block_padding; + tmp_in = info.add_instruction(make_op("pad", {{"pads", pads_vec}}), tmp_in); + tmp_lens = tmp_in->get_shape().lens(); + } + // reshape block dimension to {num_blocks, block_size} + std::size_t num_blocks = tmp_lens.at(block_axis) / std::size_t(block_size); + std::vector reduct_dims = tmp_lens; + reduct_dims.at(block_axis) = block_size; + reduct_dims.insert(reduct_dims.begin() + block_axis, num_blocks); + instruction_ref reshape_ins = + info.add_instruction(make_op("reshape", {{"dims", reduct_dims}}), tmp_in); + + // dynamic quantization for MX types: + // V_k = fp32 vector input of block size k + // B_k = pow(2, floor(log2(reduce_max(abs(V_k))))) # largest power of 2 less than V + // X_k = block scale k = B_k / (largest power of 2 in fp4e2m1) = B_k / 4 + auto abs_ins = info.add_instruction(make_op("abs"), reshape_ins); + auto reduce_max_ins = + info.add_instruction(make_op("reduce_max", {{"axes", {block_axis + 1}}}), abs_ins); + auto log2_ins = info.add_instruction(make_op("log2"), reduce_max_ins); + auto floor_ins = info.add_instruction(make_op("floor"), log2_ins); + auto lit_2_ins = info.add_literal( + migraphx::literal{migraphx::shape{migraphx::shape::float_type}, {2.f}}); + auto broadcast_lit_2_ins = info.add_instruction( + make_op("multibroadcast", {{"out_lens", reduce_max_ins->get_shape().lens()}}), + lit_2_ins); + auto pow_ins = info.add_instruction(make_op("pow"), broadcast_lit_2_ins, floor_ins); + auto lit_4_ins = info.add_literal( + migraphx::literal{migraphx::shape{migraphx::shape::float_type}, {4.f}}); + auto broadcast_lit_4_ins = info.add_instruction( + make_op("multibroadcast", {{"out_lens", reduce_max_ins->get_shape().lens()}}), + lit_4_ins); + auto block_scales_ins = info.add_instruction(make_op("div"), pow_ins, broadcast_lit_4_ins); + + // broadcast scales for use in quantizelinear + block_scales_ins = info.add_instruction( + make_op("multibroadcast", {{"out_lens", reduct_dims}}), block_scales_ins); + block_scales_ins = + info.add_instruction(make_op("reshape", {{"dims", tmp_lens}}), block_scales_ins); + // if padded runt block do slicing + if(tmp_lens != input_lens) + { + std::size_t slice_size = input_lens.at(block_axis); + block_scales_ins = info.add_instruction( + make_op("slice", {{"axes", {block_axis}}, {"starts", {0}}, {"ends", {slice_size}}}), + block_scales_ins); + } + return block_scales_ins; + } }; } // namespace onnx From 0f8f9dc2e94b02e980ccf5ac1cc48bce1c58f9bd Mon Sep 17 00:00:00 2001 From: charlie Date: Tue, 16 Sep 2025 18:15:55 -0500 Subject: [PATCH 3/6] Initial idea --- src/onnx/parse_dynamicscale.cpp | 16 +++---------- src/onnx/parse_quantizelinear.cpp | 40 +++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 13 deletions(-) diff --git a/src/onnx/parse_dynamicscale.cpp b/src/onnx/parse_dynamicscale.cpp index 92360337bd4..afa48d4681d 100644 --- a/src/onnx/parse_dynamicscale.cpp +++ b/src/onnx/parse_dynamicscale.cpp @@ -126,20 +126,10 @@ struct parse_dynamicscale : op_parser lit_4_ins); auto block_scales_ins = info.add_instruction(make_op("div"), pow_ins, broadcast_lit_4_ins); - // broadcast scales for use in quantizelinear - block_scales_ins = info.add_instruction( - make_op("multibroadcast", {{"out_lens", reduct_dims}}), block_scales_ins); - block_scales_ins = - info.add_instruction(make_op("reshape", {{"dims", tmp_lens}}), block_scales_ins); + // squeeze reduction axis for use in block quantized quantizelinear + block_scales_ins = info.add_instruction(make_op("squeeze", {{"axes", {block_axis + 1}}}), + block_scales_ins); - // if padded runt block do slicing - if(tmp_lens != input_lens) - { - std::size_t slice_size = input_lens.at(block_axis); - block_scales_ins = info.add_instruction( - make_op("slice", {{"axes", {block_axis}}, {"starts", {0}}, {"ends", {slice_size}}}), - block_scales_ins); - } return block_scales_ins; } }; diff --git a/src/onnx/parse_quantizelinear.cpp b/src/onnx/parse_quantizelinear.cpp index 92a773ae63d..d0c041996f2 100644 --- a/src/onnx/parse_quantizelinear.cpp +++ b/src/onnx/parse_quantizelinear.cpp @@ -91,6 +91,46 @@ struct parse_quantizelinear : op_parser args = transform_quantize_dequantize_linear_inputs( info, opd.onnx_name, block_size, axis, args); + if(output_type == migraphx::shape::fp4x2_type) + { + // Parsing in pack_fp4 and unpack_fp4 for the FP4 case + auto q_ins = info.add_instruction( + make_op("quantizelinear", {{"out_type", migraphx::shape::float_type}}), args); + + // packing axis set to fastest dimension + auto quantized_shape = q_ins->get_shape(); + const auto& qs_strides = quantized_shape.strides(); + if(qs_strides.empty()) + { + MIGRAPHX_THROW("QuantizeLinear: MX type quantized_shape has no strides"); + } + int fast_axis = + std::min_element(qs_strides.cbegin(), qs_strides.cend()) - qs_strides.cbegin(); + bool odd_fast_axis = (quantized_shape.lens().at(fast_axis) % 2 == 1); + if(odd_fast_axis) + { + // pad fastest dimension by 1 if it is odd + std::vector padding(2 * quantized_shape.ndim(), 0); + padding.at(fast_axis * 2 + 1) = 1; + q_ins = info.add_instruction(make_op("pad", {{"pads", padding}}), q_ins); + } + auto pack_ins = info.add_instruction(make_op("pack_fp4", {{"axis", fast_axis}}), + q_ins); // output is fp4x2_type + auto unpack_ins = info.add_instruction(make_op("unpack_fp4", {{"axis", fast_axis}}), + pack_ins); // output is fp8e4m3fn_type + if(odd_fast_axis) + { + // slice off padded values + unpack_ins = info.add_instruction( + make_op("slice", + {{"axes", {fast_axis}}, + {"starts", {0}}, + {"ends", {quantized_shape.lens().at(fast_axis)}}}), + unpack_ins); + } + return unpack_ins; + } + if(parser.opset_version < 19) { auto common_type = common_shape({args[0]->get_shape(), args[1]->get_shape()}).type(); From a3f4e584bc4951daab271666632eb126aede54f1 Mon Sep 17 00:00:00 2001 From: charlie Date: Thu, 18 Sep 2025 17:23:09 -0500 Subject: [PATCH 4/6] Add tests --- src/onnx/parse_dynamicscale.cpp | 2 +- test/onnx/dynamicscale_even_test.onnx | 21 +++++ test/onnx/dynamicscale_odd_test.onnx | Bin 0 -> 280 bytes test/onnx/dynamicscale_small_test.onnx | 17 ++++ test/onnx/gen_onnx.py | 81 +++++++++++++++++ test/onnx/parse/dynamicscale_test.cpp | 85 ++++++++++++++++++ .../parse/quantizelinear_mx_type_test.cpp | 66 ++++++++++++++ test/onnx/quantizelinear_mxfp4_even_test.onnx | 26 ++++++ test/onnx/quantizelinear_mxfp4_odd_test.onnx | 26 ++++++ test/onnx/verify/dynamicscale_small_test.cpp | 62 +++++++++++++ 10 files changed, 385 insertions(+), 1 deletion(-) create mode 100644 test/onnx/dynamicscale_even_test.onnx create mode 100644 test/onnx/dynamicscale_odd_test.onnx create mode 100644 test/onnx/dynamicscale_small_test.onnx create mode 100644 test/onnx/parse/dynamicscale_test.cpp create mode 100644 test/onnx/parse/quantizelinear_mx_type_test.cpp create mode 100644 test/onnx/quantizelinear_mxfp4_even_test.onnx create mode 100644 test/onnx/quantizelinear_mxfp4_odd_test.onnx create mode 100644 test/onnx/verify/dynamicscale_small_test.cpp diff --git a/src/onnx/parse_dynamicscale.cpp b/src/onnx/parse_dynamicscale.cpp index afa48d4681d..a68b27b173f 100644 --- a/src/onnx/parse_dynamicscale.cpp +++ b/src/onnx/parse_dynamicscale.cpp @@ -75,7 +75,7 @@ struct parse_dynamicscale : op_parser std::string zero_point_selection_method = "None"; if(contains(info.attributes, "zero_point_selection_method")) - zero_point_selection_method = info.attributes.at("zero_point_selection_method").i(); + zero_point_selection_method = info.attributes.at("zero_point_selection_method").s(); if(zero_point_selection_method != "None") { diff --git a/test/onnx/dynamicscale_even_test.onnx b/test/onnx/dynamicscale_even_test.onnx new file mode 100644 index 00000000000..37ade59662c --- /dev/null +++ b/test/onnx/dynamicscale_even_test.onnx @@ -0,0 +1,21 @@ + dynamicscale_even_test: + +inputoutput" DynamicScale* + group_dim* + +group_size * + output_dtype*" +scale_selection_method"floor*& +zero_point_selection_method"Nonedynamicscale_even_testZ +input + + +@ + +b +output + + +@ + +B \ No newline at end of file diff --git a/test/onnx/dynamicscale_odd_test.onnx b/test/onnx/dynamicscale_odd_test.onnx new file mode 100644 index 0000000000000000000000000000000000000000..5a4bfcc7a0d3e8bb2c50138716e5e1caead2b988 GIT binary patch literal 280 zcmZ{fu?~Vj5JWu`gBuDwqmpQ0C@lB{OJibZV`pT|mO{`)2z + +TEST_CASE(dynamicscale_even_test) +{ + migraphx::program p; + auto* mm = p.get_main_module(); + auto input = + mm->add_parameter("input", migraphx::shape{migraphx::shape::float_type, {3, 64, 4, 4}}); + auto reduce_reshape = + mm->add_instruction(migraphx::make_op("reshape", {{"dims", {3, 2, 32, 4, 4}}}), input); + auto abs_ins = mm->add_instruction(migraphx::make_op("abs"), reduce_reshape); + auto reduce_max_ins = + mm->add_instruction(migraphx::make_op("reduce_max", {{"axes", {2}}}), abs_ins); + auto log2_ins = mm->add_instruction(migraphx::make_op("log2"), reduce_max_ins); + auto floor_ins = mm->add_instruction(migraphx::make_op("floor"), log2_ins); + auto lit_2_ins = mm->add_literal({migraphx::shape{migraphx::shape::float_type}, {2.f}}); + auto broadcast_lit_2 = mm->add_instruction( + migraphx::make_op("multibroadcast", {{"out_lens", reduce_max_ins->get_shape().lens()}}), + lit_2_ins); + auto pow_ins = mm->add_instruction(migraphx::make_op("pow"), broadcast_lit_2, floor_ins); + auto lit_4_ins = mm->add_literal({migraphx::shape{migraphx::shape::float_type}, {4.f}}); + auto broadcast_lit_4 = mm->add_instruction( + migraphx::make_op("multibroadcast", {{"out_lens", reduce_max_ins->get_shape().lens()}}), + lit_4_ins); + auto block_scales_ins = mm->add_instruction(migraphx::make_op("div"), pow_ins, broadcast_lit_4); + mm->add_instruction(migraphx::make_op("squeeze", {{"axes", {2}}}), block_scales_ins); + + auto prog = optimize_onnx("dynamicscale_even_test.onnx"); + EXPECT(p == prog); +} + +TEST_CASE(dynamicscale_odd_test) +{ + migraphx::program p; + auto* mm = p.get_main_module(); + auto input = + mm->add_parameter("input", migraphx::shape{migraphx::shape::float_type, {71, 5, 5}}); + auto padded_input = + mm->add_instruction(migraphx::make_op("pad", {{"pads", {0, 0, 0, 25, 0, 0}}}), input); + auto reduce_reshape = + mm->add_instruction(migraphx::make_op("reshape", {{"dims", {3, 32, 5, 5}}}), padded_input); + auto abs_ins = mm->add_instruction(migraphx::make_op("abs"), reduce_reshape); + auto reduce_max_ins = + mm->add_instruction(migraphx::make_op("reduce_max", {{"axes", {1}}}), abs_ins); + auto log2_ins = mm->add_instruction(migraphx::make_op("log2"), reduce_max_ins); + auto floor_ins = mm->add_instruction(migraphx::make_op("floor"), log2_ins); + auto lit_2_ins = mm->add_literal({migraphx::shape{migraphx::shape::float_type}, {2.f}}); + auto broadcast_lit_2 = mm->add_instruction( + migraphx::make_op("multibroadcast", {{"out_lens", reduce_max_ins->get_shape().lens()}}), + lit_2_ins); + auto pow_ins = mm->add_instruction(migraphx::make_op("pow"), broadcast_lit_2, floor_ins); + auto lit_4_ins = mm->add_literal({migraphx::shape{migraphx::shape::float_type}, {4.f}}); + auto broadcast_lit_4 = mm->add_instruction( + migraphx::make_op("multibroadcast", {{"out_lens", reduce_max_ins->get_shape().lens()}}), + lit_4_ins); + auto block_scales_ins = mm->add_instruction(migraphx::make_op("div"), pow_ins, broadcast_lit_4); + mm->add_instruction(migraphx::make_op("squeeze", {{"axes", {1}}}), block_scales_ins); + + auto prog = optimize_onnx("dynamicscale_odd_test.onnx"); + EXPECT(p == prog); +} diff --git a/test/onnx/parse/quantizelinear_mx_type_test.cpp b/test/onnx/parse/quantizelinear_mx_type_test.cpp new file mode 100644 index 00000000000..16a63f19c6e --- /dev/null +++ b/test/onnx/parse/quantizelinear_mx_type_test.cpp @@ -0,0 +1,66 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2015-2025 Advanced Micro Devices, Inc. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +// even fastest dimension +TEST_CASE(quantizelinear_mxfp4_even_test) +{ + migraphx::program p; + auto* mm = p.get_main_module(); + auto l0 = mm->add_parameter("0", {migraphx::shape::float_type, {3, 64, 4, 4}}); + auto l1 = mm->add_parameter("1", {migraphx::shape::float_type, {3, 2, 4, 4}}); + auto l1_reshape = mm->add_instruction(migraphx::make_op("unsqueeze", {{"axes", {2}}}), l1); + l1_reshape = mm->add_instruction(migraphx::make_op("multibroadcast", {{"out_lens", {3, 2, 32, 4, 4}}}), l1_reshape); + l1_reshape = mm->add_instruction(migraphx::make_op("reshape", {{"dims", {3, 64, 4, 4}}}), l1_reshape); + auto q_ins = mm->add_instruction(migraphx::make_op("quantizelinear", {{"out_type", migraphx::shape::float_type}}), l0, l1_reshape); + auto pack_ins = mm->add_instruction(migraphx::make_op("pack_fp4", {{"axis", 3}}), q_ins); + auto unpack_ins = mm->add_instruction(migraphx::make_op("unpack_fp4", {{"axis", 3}}), pack_ins); + mm->add_return({unpack_ins}); + + auto prog = read_onnx("quantizelinear_mxfp4_even_test.onnx"); + EXPECT(p.sort() == prog.sort()); +} + +// odd fastest dimension +TEST_CASE(quantizelinear_mxfp4_odd_test) +{ + migraphx::program p; + auto* mm = p.get_main_module(); + auto l0 = mm->add_parameter("0", {migraphx::shape::float_type, {3, 64, 4, 7}}); + auto l1 = mm->add_parameter("1", {migraphx::shape::float_type, {3, 2, 4, 7}}); + auto l1_reshape = mm->add_instruction(migraphx::make_op("unsqueeze", {{"axes", {2}}}), l1); + l1_reshape = mm->add_instruction(migraphx::make_op("multibroadcast", {{"out_lens", {3, 2, 32, 4, 7}}}), l1_reshape); + l1_reshape = mm->add_instruction(migraphx::make_op("reshape", {{"dims", {3, 64, 4, 7}}}), l1_reshape); + auto q_ins = mm->add_instruction(migraphx::make_op("quantizelinear", {{"out_type", migraphx::shape::float_type}}), l0, l1_reshape); + auto pad_ins = mm->add_instruction(migraphx::make_op("pad", {{"pads", {0, 0, 0, 0, 0, 0, 0, 1}}}), q_ins); + auto pack_ins = mm->add_instruction(migraphx::make_op("pack_fp4", {{"axis", 3}}), pad_ins); + auto unpack_ins = mm->add_instruction(migraphx::make_op("unpack_fp4", {{"axis", 3}}), pack_ins); + auto slice_ins = mm->add_instruction(migraphx::make_op("slice", {{"axes", {3}}, {"starts", {0}}, {"ends", {7}}}), unpack_ins); + mm->add_return({slice_ins}); + + auto prog = read_onnx("quantizelinear_mxfp4_odd_test.onnx"); + EXPECT(p.sort() == prog.sort()); +} diff --git a/test/onnx/quantizelinear_mxfp4_even_test.onnx b/test/onnx/quantizelinear_mxfp4_even_test.onnx new file mode 100644 index 00000000000..f2c2fb01b34 --- /dev/null +++ b/test/onnx/quantizelinear_mxfp4_even_test.onnx @@ -0,0 +1,26 @@ + quantizelinear_mxfp4_even_test: +P +0 +1out"QuantizeLinear* +axis* + +block_size * + output_dtypequantizelinear_mxfp4_even_testZ +0 + + +@ + +Z +1 + + + + +b +out + + +@ + +B \ No newline at end of file diff --git a/test/onnx/quantizelinear_mxfp4_odd_test.onnx b/test/onnx/quantizelinear_mxfp4_odd_test.onnx new file mode 100644 index 00000000000..52baba83ed8 --- /dev/null +++ b/test/onnx/quantizelinear_mxfp4_odd_test.onnx @@ -0,0 +1,26 @@ + quantizelinear_mxfp4_odd_test: +P +0 +1out"QuantizeLinear* +axis* + +block_size * + output_dtypequantizelinear_mxfp4_odd_testZ +0 + + +@ + +Z +1 + + + + +b +out + + +@ + +B \ No newline at end of file diff --git a/test/onnx/verify/dynamicscale_small_test.cpp b/test/onnx/verify/dynamicscale_small_test.cpp new file mode 100644 index 00000000000..70b5cc26e7e --- /dev/null +++ b/test/onnx/verify/dynamicscale_small_test.cpp @@ -0,0 +1,62 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2015-2025 Advanced Micro Devices, Inc. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include + +TEST_CASE(dynamicscale_small_test) +{ + migraphx::program p = read_onnx("dynamicscale_small_test.onnx"); + p.compile(migraphx::make_target("ref")); + std::vector input_lens{4, 4}; + auto input_type = migraphx::shape::float_type; + migraphx::shape data_shape{input_type, input_lens}; + std::vector data = {-100.f, + -12.f, + 32.f, + 819.f, + -6.f, + -5.75f, + -5.50f, + -5.25f, + -5.f, + -0.30f, + -1.40f, + -1.20f, + 2.0f, + 0.25f, + 0.33f, + 2.20f}; + migraphx::parameter_map pp; + pp["input"] = migraphx::argument(data_shape, data.data()); + auto result = p.eval(pp).back(); + std::vector result_vector; + result.visit([&](auto output) { result_vector.assign(output.begin(), output.end()); }); + + // hand calculated values + std::vector gold = {128.f, 1.f, 1.f, 0.5f}; + + EXPECT(migraphx::verify::verify_rms_range(result_vector, gold)); +} From 528ef13bca4ecbe790b74a2caa0c751b63778247 Mon Sep 17 00:00:00 2001 From: charlie Date: Thu, 18 Sep 2025 17:23:27 -0500 Subject: [PATCH 5/6] Formatting --- .../parse/quantizelinear_mx_type_test.cpp | 44 ++++++++++++------- 1 file changed, 28 insertions(+), 16 deletions(-) diff --git a/test/onnx/parse/quantizelinear_mx_type_test.cpp b/test/onnx/parse/quantizelinear_mx_type_test.cpp index 16a63f19c6e..4beb1395533 100644 --- a/test/onnx/parse/quantizelinear_mx_type_test.cpp +++ b/test/onnx/parse/quantizelinear_mx_type_test.cpp @@ -29,14 +29,19 @@ TEST_CASE(quantizelinear_mxfp4_even_test) { migraphx::program p; - auto* mm = p.get_main_module(); - auto l0 = mm->add_parameter("0", {migraphx::shape::float_type, {3, 64, 4, 4}}); - auto l1 = mm->add_parameter("1", {migraphx::shape::float_type, {3, 2, 4, 4}}); + auto* mm = p.get_main_module(); + auto l0 = mm->add_parameter("0", {migraphx::shape::float_type, {3, 64, 4, 4}}); + auto l1 = mm->add_parameter("1", {migraphx::shape::float_type, {3, 2, 4, 4}}); auto l1_reshape = mm->add_instruction(migraphx::make_op("unsqueeze", {{"axes", {2}}}), l1); - l1_reshape = mm->add_instruction(migraphx::make_op("multibroadcast", {{"out_lens", {3, 2, 32, 4, 4}}}), l1_reshape); - l1_reshape = mm->add_instruction(migraphx::make_op("reshape", {{"dims", {3, 64, 4, 4}}}), l1_reshape); - auto q_ins = mm->add_instruction(migraphx::make_op("quantizelinear", {{"out_type", migraphx::shape::float_type}}), l0, l1_reshape); - auto pack_ins = mm->add_instruction(migraphx::make_op("pack_fp4", {{"axis", 3}}), q_ins); + l1_reshape = mm->add_instruction( + migraphx::make_op("multibroadcast", {{"out_lens", {3, 2, 32, 4, 4}}}), l1_reshape); + l1_reshape = + mm->add_instruction(migraphx::make_op("reshape", {{"dims", {3, 64, 4, 4}}}), l1_reshape); + auto q_ins = mm->add_instruction( + migraphx::make_op("quantizelinear", {{"out_type", migraphx::shape::float_type}}), + l0, + l1_reshape); + auto pack_ins = mm->add_instruction(migraphx::make_op("pack_fp4", {{"axis", 3}}), q_ins); auto unpack_ins = mm->add_instruction(migraphx::make_op("unpack_fp4", {{"axis", 3}}), pack_ins); mm->add_return({unpack_ins}); @@ -48,17 +53,24 @@ TEST_CASE(quantizelinear_mxfp4_even_test) TEST_CASE(quantizelinear_mxfp4_odd_test) { migraphx::program p; - auto* mm = p.get_main_module(); - auto l0 = mm->add_parameter("0", {migraphx::shape::float_type, {3, 64, 4, 7}}); - auto l1 = mm->add_parameter("1", {migraphx::shape::float_type, {3, 2, 4, 7}}); + auto* mm = p.get_main_module(); + auto l0 = mm->add_parameter("0", {migraphx::shape::float_type, {3, 64, 4, 7}}); + auto l1 = mm->add_parameter("1", {migraphx::shape::float_type, {3, 2, 4, 7}}); auto l1_reshape = mm->add_instruction(migraphx::make_op("unsqueeze", {{"axes", {2}}}), l1); - l1_reshape = mm->add_instruction(migraphx::make_op("multibroadcast", {{"out_lens", {3, 2, 32, 4, 7}}}), l1_reshape); - l1_reshape = mm->add_instruction(migraphx::make_op("reshape", {{"dims", {3, 64, 4, 7}}}), l1_reshape); - auto q_ins = mm->add_instruction(migraphx::make_op("quantizelinear", {{"out_type", migraphx::shape::float_type}}), l0, l1_reshape); - auto pad_ins = mm->add_instruction(migraphx::make_op("pad", {{"pads", {0, 0, 0, 0, 0, 0, 0, 1}}}), q_ins); - auto pack_ins = mm->add_instruction(migraphx::make_op("pack_fp4", {{"axis", 3}}), pad_ins); + l1_reshape = mm->add_instruction( + migraphx::make_op("multibroadcast", {{"out_lens", {3, 2, 32, 4, 7}}}), l1_reshape); + l1_reshape = + mm->add_instruction(migraphx::make_op("reshape", {{"dims", {3, 64, 4, 7}}}), l1_reshape); + auto q_ins = mm->add_instruction( + migraphx::make_op("quantizelinear", {{"out_type", migraphx::shape::float_type}}), + l0, + l1_reshape); + auto pad_ins = + mm->add_instruction(migraphx::make_op("pad", {{"pads", {0, 0, 0, 0, 0, 0, 0, 1}}}), q_ins); + auto pack_ins = mm->add_instruction(migraphx::make_op("pack_fp4", {{"axis", 3}}), pad_ins); auto unpack_ins = mm->add_instruction(migraphx::make_op("unpack_fp4", {{"axis", 3}}), pack_ins); - auto slice_ins = mm->add_instruction(migraphx::make_op("slice", {{"axes", {3}}, {"starts", {0}}, {"ends", {7}}}), unpack_ins); + auto slice_ins = mm->add_instruction( + migraphx::make_op("slice", {{"axes", {3}}, {"starts", {0}}, {"ends", {7}}}), unpack_ins); mm->add_return({slice_ins}); auto prog = read_onnx("quantizelinear_mxfp4_odd_test.onnx"); From 86c7e00d4458840b1743c0a11442c65ee3f7939e Mon Sep 17 00:00:00 2001 From: charlie Date: Fri, 26 Sep 2025 11:47:59 -0500 Subject: [PATCH 6/6] Licensing --- src/onnx/parse_quantizelinear.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/onnx/parse_quantizelinear.cpp b/src/onnx/parse_quantizelinear.cpp index d0c041996f2..03a6395308f 100644 --- a/src/onnx/parse_quantizelinear.cpp +++ b/src/onnx/parse_quantizelinear.cpp @@ -1,7 +1,7 @@ /* * The MIT License (MIT) * - * Copyright (c) 2015-2024 Advanced Micro Devices, Inc. All rights reserved. + * Copyright (c) 2015-2025 Advanced Micro Devices, Inc. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal