diff --git a/docs/sphinx/requirements.txt b/docs/sphinx/requirements.txt index 88f52fff4bc..4a6de8f6fe5 100644 --- a/docs/sphinx/requirements.txt +++ b/docs/sphinx/requirements.txt @@ -46,7 +46,7 @@ idna==3.7 # via requests imagesize==1.4.1 # via sphinx -jinja2==3.1.3 +jinja2==3.1.4 # via # myst-parser # sphinx diff --git a/src/fuse_pointwise.cpp b/src/fuse_pointwise.cpp index 36610645ab0..a13bee3c7f1 100644 --- a/src/fuse_pointwise.cpp +++ b/src/fuse_pointwise.cpp @@ -41,7 +41,7 @@ inline namespace MIGRAPHX_INLINE_NS { static literal get_scalar(instruction_ref ins) { - if(ins->name() == "contiguous") + if(contains({"contiguous", "broadcast", "multibroadcast"}, ins->name())) return get_scalar(ins->inputs().front()); const auto& s = ins->get_shape(); if(s.elements() != 1 and not(s.scalar())) diff --git a/src/onnx/parse_convolution.cpp b/src/onnx/parse_convolution.cpp index 155faf10b93..f0791222bd4 100644 --- a/src/onnx/parse_convolution.cpp +++ b/src/onnx/parse_convolution.cpp @@ -1,7 +1,7 @@ /* * The MIT License (MIT) * - * Copyright (c) 2015-2022 Advanced Micro Devices, Inc. All rights reserved. + * Copyright (c) 2015-2024 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 @@ -30,6 +30,7 @@ #include #include #include +#include namespace migraphx { inline namespace MIGRAPHX_INLINE_NS { @@ -42,18 +43,199 @@ struct parse_convolution : op_parser return {{"Conv", "convolution"}, {"ConvInteger", "quant_convolution"}}; } + // Convert to half prior to a shift to ensure we preserve accuracy here then + // convert back to int8 + static instruction_ref add_int8_shift(const onnx_parser::node_info& info, + const instruction_ref& offset_op, + instruction_ref& unshifted_input) + { + auto unshifted_input_half = info.add_instruction( + migraphx::make_op("convert", {{"target_type", migraphx::shape::half_type}}), + unshifted_input); + + auto input_shifted_half = info.add_common_op("add", unshifted_input_half, offset_op); + + return info.add_instruction( + migraphx::make_op("convert", {{"target_type", migraphx::shape::int8_type}}), + input_shifted_half); + } + + static void shift_input_and_bias(const onnx_parser::node_info& info, + const instruction_ref& offset_op, + const bool has_bias, + instruction_ref& input, + instruction_ref& input_bias) + { + input = add_int8_shift(info, offset_op, input); + if(has_bias) + { + input_bias = add_int8_shift(info, offset_op, input_bias); + } + } + + static float get_symmetric_value(const instruction_ref& input) + { + float symmetric_value = 0; + // adjust symmetric zero point value for uint8 types + if(input->get_shape().type() == migraphx::shape::uint8_type) + { + symmetric_value = 128; + } + return symmetric_value; + } + + static instruction_ref gen_symmetric_literal(const instruction_ref& input, + const bool is_quant_conv, + onnx_parser::node_info& info) + { + instruction_ref ret = input; + if(is_quant_conv) + { + float symmetric_value = get_symmetric_value(input); + ret = info.add_literal(migraphx::literal{ + migraphx::shape{input->get_shape().type(), {1}, {0}}, {symmetric_value}}); + } + + return ret; + } + + static instruction_ref get_zero_point(const instruction_ref& input, + int index, + const bool is_quant_conv, + onnx_parser::node_info& info, + const std::vector& args) + { + instruction_ref ret = input; + if(args.size() > index) + { + // Check for type mismatch on parse + if(input->get_shape().type() != args[index]->get_shape().type()) + MIGRAPHX_THROW("PARSE:Conv Data and Data Zero Point must have same type"); + + ret = args[index]; + if(is_symmetric_zero_point(ret)) + { + ret = gen_symmetric_literal(ret, is_quant_conv, info); + } + } + else + { + ret = gen_symmetric_literal(ret, is_quant_conv, info); + } + + return ret; + } + + static bool is_symmetric_zero_point(instruction_ref zp) + { + if(not zp->can_eval()) + return false; + + float symmetric_value = get_symmetric_value(zp); + + bool all_zeros = false; + zp->eval().visit([&](auto z) { + all_zeros = std::all_of( + z.begin(), z.end(), [&](auto val) { return float_equal(val, symmetric_value); }); + }); + return all_zeros; + } + + static auto + qparam_broadcast_op(instruction_ref qparam, std::vector lens, std::size_t axis) + { + if(qparam->get_shape().scalar()) + { + return migraphx::make_op("multibroadcast", {{"out_lens", lens}}); + } + else + { + return migraphx::make_op("broadcast", {{"out_lens", lens}, {"axis", axis}}); + } + } + + static instruction_ref handle_quant_bias(const operation& op, + const instruction_ref& input, + const instruction_ref& x, + const instruction_ref& weights, + const instruction_ref& x_zp, + const instruction_ref& w_zp, + onnx_parser::node_info& info) + { + instruction_ref ret = input; + if(not is_symmetric_zero_point(x_zp)) + { + auto out_zp_1 = info.add_common_op(op.name(), x_zp, weights); + ret = info.add_common_op("sub", ret, out_zp_1); + } + + if(not is_symmetric_zero_point(w_zp)) + { + auto out_zp_2 = info.add_common_op(op.name(), x, w_zp); + ret = info.add_common_op("sub", ret, out_zp_2); + } + + if(not(is_symmetric_zero_point(x_zp)) and not(is_symmetric_zero_point(w_zp))) + { + auto x_zp_bc = + info.add_instruction(qparam_broadcast_op(x_zp, x->get_shape().lens(), 0), x_zp); + auto w_zp_bc = info.add_instruction( + qparam_broadcast_op(w_zp, weights->get_shape().lens(), 0), w_zp); + + auto out_zp_3 = info.add_instruction(op, x_zp_bc, w_zp_bc); + + ret = info.add_common_op("add", ret, out_zp_3); + } + return ret; + } + + static void handle_quant_inputs(const bool is_quant_conv, + instruction_ref& input, + instruction_ref& weights, + instruction_ref& input_zp, + instruction_ref& weight_zp, + onnx_parser::node_info& info) + { + if(not is_quant_conv) + return; + + auto input_type = input->get_shape().type(); + auto weight_type = weights->get_shape().type(); + + // Handle uint8 bias and input shifts + instruction_ref offset_op; + if(((input_type == migraphx::shape::uint8_type) or + (weight_type == migraphx::shape::uint8_type))) + { + offset_op = info.add_literal( + migraphx::literal{migraphx::shape{migraphx::shape::half_type}, {-128}}); + } + + if(input_type == migraphx::shape::uint8_type) + { + shift_input_and_bias( + info, offset_op, (not is_symmetric_zero_point(input_zp)), input, input_zp); + } + + if(weight_type == migraphx::shape::uint8_type) + { + shift_input_and_bias( + info, offset_op, (not is_symmetric_zero_point(weight_zp)), weights, weight_zp); + } + } + instruction_ref parse(const op_desc& opd, const onnx_parser& parser, onnx_parser::node_info info, std::vector args) const { - auto op = make_op(opd.op_name); - auto values = op.to_value(); - auto l0 = args[0]; - auto weights = args[1]; - auto l0_shape = l0->get_shape(); - auto w_shape = weights->get_shape(); - auto in_lens = l0_shape.max_lens(); + auto op = make_op(opd.op_name); + auto values = op.to_value(); + auto x = args[0]; + auto weights = args[1]; + auto x_shape = x->get_shape(); + auto w_shape = weights->get_shape(); + auto in_lens = x_shape.max_lens(); assert(in_lens.size() > 2); auto kdims = in_lens.size() - 2; @@ -92,9 +274,9 @@ struct parse_convolution : op_parser // check if image shape is dynamic bool image_shape_dynamic = false; - if(l0_shape.dynamic()) + if(x_shape.dynamic()) { - auto dyn_dims = l0_shape.dyn_dims(); + auto dyn_dims = x_shape.dyn_dims(); std::for_each(dyn_dims.begin() + 2, dyn_dims.end(), [&](auto dyn_dim) { if(not dyn_dim.is_fixed()) { @@ -149,9 +331,31 @@ struct parse_convolution : op_parser recalc_conv_attributes(values, kdims); + instruction_ref ret; + // parse a_zero_point and b_zero_point values + auto is_quant_conv = opd.op_name == "quant_convolution"; + + auto x_zp = get_zero_point(x, 2, is_quant_conv, info, args); + auto w_zp = get_zero_point(weights, 3, is_quant_conv, info, args); + op.from_value(values); - auto l1 = info.add_instruction(op, l0, args[1]); - return info.add_bias(args, l1, 1); + + handle_quant_inputs(is_quant_conv, x, weights, x_zp, w_zp, info); + + ret = info.add_instruction(op, x, weights); + + // Handle quant_conv residuals between input/weights to avoid overflow + if(is_quant_conv) + { + ret = handle_quant_bias(op, ret, x, weights, x_zp, w_zp, info); + } + else + { + // Handle Convolution case with bias to output + ret = info.add_bias(args, ret, 1); + } + + return ret; } }; diff --git a/src/targets/gpu/compile_gen.cpp b/src/targets/gpu/compile_gen.cpp index 7597d31a437..f4c0d66e326 100644 --- a/src/targets/gpu/compile_gen.cpp +++ b/src/targets/gpu/compile_gen.cpp @@ -288,6 +288,15 @@ static bool use_lazy_inner(instruction_ref ins) { if(ins->outputs().size() != 1) return false; + // When the inputs are broadcasted, it means the lambda will capture SGPRs + // when doing block/wave reduction. This can cause register spilling in + // the compiler when the lambda is evaluated at a later time although it + // shouldn't. Instead, use `inner` to workaround this issue in the + // compiler. + if(std::any_of(ins->inputs().begin(), ins->inputs().end(), [](instruction_ref input) { + return input->get_shape().broadcasted(); + })) + return false; auto output = ins->outputs().front(); return contains(output->name(), "reduce") or output->name() == "@return"; } diff --git a/test/fuse_pointwise.cpp b/test/fuse_pointwise.cpp index 5edb9e2916b..1dcec23a61d 100644 --- a/test/fuse_pointwise.cpp +++ b/test/fuse_pointwise.cpp @@ -243,6 +243,34 @@ TEST_CASE(scalar_input) EXPECT(p1 == p2); } +TEST_CASE(scalar_like_input) +{ + migraphx::shape s{migraphx::shape::float_type, {2, 1}}; + migraphx::program p1; + { + auto* mm = p1.get_main_module(); + auto x = mm->add_parameter("x", s); + auto one = mm->add_literal( + migraphx::literal{migraphx::shape{migraphx::shape::float_type, {1}}, {1.0f}}); + auto y = + mm->add_instruction(migraphx::make_op("multibroadcast", {{"out_lens", s.lens()}}), one); + auto add1 = mm->add_instruction(migraphx::make_op("add"), x, y); + mm->add_return({add1}); + } + run_pass(p1); + migraphx::program p2; + { + auto* mm = p2.get_main_module(); + auto x = mm->add_parameter("x", s); + auto add1 = add_pointwise(p2, "main:pointwise0", {x}, [=](auto* pm, const auto& inputs) { + auto y = pm->add_literal(1.0f); + return pm->add_instruction(migraphx::make_op("add"), inputs[0], y); + }); + mm->add_return({add1}); + } + EXPECT(p1 == p2); +} + TEST_CASE(contiguous_input) { migraphx::shape s{migraphx::shape::float_type, {2, 3}}; diff --git a/test/onnx/conv_bad_bias_test.onnx b/test/onnx/conv_bad_bias_test.onnx new file mode 100644 index 00000000000..e5a1e3016de --- /dev/null +++ b/test/onnx/conv_bad_bias_test.onnx @@ -0,0 +1,29 @@ + conv_bad_bias_test:¶ +8 +0 +1 +23"Conv* + dilations@@ * +strides@@ conv_bad_bias_testZ +0 + + + + + Z +1 + + + + +Z +2 + + +b +3 + + + + +B \ No newline at end of file diff --git a/test/onnx/convinteger_bias_test.onnx b/test/onnx/convinteger_bias_test.onnx index 518c98b9dc4..e7d66aef429 100644 --- a/test/onnx/convinteger_bias_test.onnx +++ b/test/onnx/convinteger_bias_test.onnx @@ -1,4 +1,4 @@ -convinteger_bias_test:À + convinteger_bias_test:À ? 0 1 @@ -19,11 +19,11 @@ Z 2 - + b 3     -B \ No newline at end of file +B \ No newline at end of file diff --git a/test/onnx/convinteger_dual_bias_test.onnx b/test/onnx/convinteger_dual_bias_test.onnx new file mode 100644 index 00000000000..4b166872b7f --- /dev/null +++ b/test/onnx/convinteger_dual_bias_test.onnx @@ -0,0 +1,34 @@ + convinteger_dual_bias_test:Ù +B +0 +1 +2 +34" ConvInteger* + dilations@@ * +strides@@ convinteger_dual_bias_testZ +0 + + + + +Z +1 + + + + +Z +2 + + +Z +3 + + +b +4 + + + + +B \ No newline at end of file diff --git a/test/onnx/convinteger_mismatched_data_bias_test.onnx b/test/onnx/convinteger_mismatched_data_bias_test.onnx new file mode 100644 index 00000000000..5cfeda8eacc --- /dev/null +++ b/test/onnx/convinteger_mismatched_data_bias_test.onnx @@ -0,0 +1,34 @@ + %convinteger_mismatched_data_bias_test:ä +B +0 +1 +2 +34" ConvInteger* + dilations@@ * +strides@@ %convinteger_mismatched_data_bias_testZ +0 + + + + + Z +1 + + + + +Z +2 + + +Z +3 + + +b +4 + + + + +B \ No newline at end of file diff --git a/test/onnx/convinteger_mismatched_input_types_test.onnx b/test/onnx/convinteger_mismatched_input_types_test.onnx new file mode 100644 index 00000000000..1a624850b5f --- /dev/null +++ b/test/onnx/convinteger_mismatched_input_types_test.onnx @@ -0,0 +1,24 @@ + 'convinteger_mismatched_input_types_test:¾ +< +0 +14" ConvInteger* + dilations@@ * +strides@@ 'convinteger_mismatched_input_types_testZ +0 + + + + + Z +1 + + + + +b +4 + + + + +B \ No newline at end of file diff --git a/test/onnx/convinteger_mismatched_inputs_dual_bias_test.onnx b/test/onnx/convinteger_mismatched_inputs_dual_bias_test.onnx new file mode 100644 index 00000000000..5a03cfe9ac1 --- /dev/null +++ b/test/onnx/convinteger_mismatched_inputs_dual_bias_test.onnx @@ -0,0 +1,34 @@ + ,convinteger_mismatched_inputs_dual_bias_test:ë +B +0 +1 +2 +34" ConvInteger* + dilations@@ * +strides@@ ,convinteger_mismatched_inputs_dual_bias_testZ +0 + + + + +Z +1 + + + + +Z +2 + + +Z +3 + + +b +4 + + + + +B \ No newline at end of file diff --git a/test/onnx/convinteger_mismatched_inputs_dual_symmetric_bias_test.onnx b/test/onnx/convinteger_mismatched_inputs_dual_symmetric_bias_test.onnx new file mode 100644 index 00000000000..ab276573022 Binary files /dev/null and b/test/onnx/convinteger_mismatched_inputs_dual_symmetric_bias_test.onnx differ diff --git a/test/onnx/convinteger_mismatched_weight_bias_test.onnx b/test/onnx/convinteger_mismatched_weight_bias_test.onnx new file mode 100644 index 00000000000..b2e7ff3f10b --- /dev/null +++ b/test/onnx/convinteger_mismatched_weight_bias_test.onnx @@ -0,0 +1,34 @@ + 'convinteger_mismatched_weight_bias_test:æ +B +0 +1 +2 +34" ConvInteger* + dilations@@ * +strides@@ 'convinteger_mismatched_weight_bias_testZ +0 + + + + + Z +1 + + + + +Z +2 + + +Z +3 + + +b +4 + + + + +B \ No newline at end of file diff --git a/test/onnx/convinteger_no_bias_test.onnx b/test/onnx/convinteger_no_bias_test.onnx new file mode 100644 index 00000000000..057c95f6ae7 --- /dev/null +++ b/test/onnx/convinteger_no_bias_test.onnx @@ -0,0 +1,24 @@ + convinteger_no_bias_test:¯ +< +0 +13" ConvInteger* + dilations@@ * +strides@@ convinteger_no_bias_testZ +0 + + + + +Z +1 + + + + +b +3 + + + + +B \ No newline at end of file diff --git a/test/onnx/convinteger_no_bias_uint8_test.onnx b/test/onnx/convinteger_no_bias_uint8_test.onnx new file mode 100644 index 00000000000..13c4acd3d6b --- /dev/null +++ b/test/onnx/convinteger_no_bias_uint8_test.onnx @@ -0,0 +1,24 @@ + convinteger_no_bias_uint8_test:µ +< +0 +13" ConvInteger* + dilations@@ * +strides@@ convinteger_no_bias_uint8_testZ +0 + + + + + Z +1 + + + + +b +3 + + + + +B \ No newline at end of file diff --git a/test/onnx/gen_onnx.py b/test/onnx/gen_onnx.py index edc364c68e7..e5afa0068fc 100644 --- a/test/onnx/gen_onnx.py +++ b/test/onnx/gen_onnx.py @@ -1315,6 +1315,22 @@ def conv_bias_test(): return ([node], [x, y, z], [out]) +@onnx_test() +def conv_bad_bias_test(): + x = helper.make_tensor_value_info('0', TensorProto.FLOAT, [1, 3, 32, 32]) + y = helper.make_tensor_value_info('1', TensorProto.FLOAT, [1, 3, 5, 5]) + z = helper.make_tensor_value_info('2', TensorProto.INT32, [1]) + out = helper.make_tensor_value_info('3', TensorProto.FLOAT, [1, 2, 28, 28]) + + node = onnx.helper.make_node('Conv', + inputs=['0', '1', '2'], + outputs=['3'], + dilations=[1, 1], + strides=[1, 1]) + + return ([node], [x, y, z], [out]) + + @onnx_test() def conv_bn_relu_maxpool_test(): x = helper.make_tensor_value_info('0', TensorProto.FLOAT, [1, 3, 32, 32]) @@ -1529,11 +1545,41 @@ def conv_relu_maxpool_x2_test(): return ([node1, node2, node3, node4, node5, node6], [x, y, z, m, n], [out]) +@onnx_test() +def convinteger_no_bias_test(): + x = helper.make_tensor_value_info('0', TensorProto.INT8, [1, 3, 5, 5]) + y = helper.make_tensor_value_info('1', TensorProto.INT8, [1, 3, 2, 2]) + out = helper.make_tensor_value_info('3', TensorProto.INT32, [1, 1, 4, 4]) + + node = onnx.helper.make_node('ConvInteger', + inputs=['0', '1'], + outputs=['3'], + dilations=[1, 1], + strides=[1, 1]) + + return ([node], [x, y], [out]) + + +@onnx_test() +def convinteger_no_bias_uint8_test(): + x = helper.make_tensor_value_info('0', TensorProto.UINT8, [1, 3, 32, 32]) + y = helper.make_tensor_value_info('1', TensorProto.UINT8, [1, 3, 5, 5]) + out = helper.make_tensor_value_info('3', TensorProto.INT32, [1, 2, 28, 28]) + + node = onnx.helper.make_node('ConvInteger', + inputs=['0', '1'], + outputs=['3'], + dilations=[1, 1], + strides=[1, 1]) + + return ([node], [x, y], [out]) + + @onnx_test() def convinteger_bias_test(): x = helper.make_tensor_value_info('0', TensorProto.INT8, [1, 3, 32, 32]) y = helper.make_tensor_value_info('1', TensorProto.INT8, [1, 3, 5, 5]) - z = helper.make_tensor_value_info('2', TensorProto.INT32, [1]) + z = helper.make_tensor_value_info('2', TensorProto.INT8, [1]) out = helper.make_tensor_value_info('3', TensorProto.INT32, [1, 2, 28, 28]) node = onnx.helper.make_node('ConvInteger', @@ -1545,6 +1591,89 @@ def convinteger_bias_test(): return ([node], [x, y, z], [out]) +@onnx_test() +def convinteger_dual_bias_test(): + x = helper.make_tensor_value_info('0', TensorProto.INT8, [1, 3, 5, 5]) + y = helper.make_tensor_value_info('1', TensorProto.INT8, [1, 3, 2, 2]) + z = helper.make_tensor_value_info('2', TensorProto.INT8, [1]) + w = helper.make_tensor_value_info('3', TensorProto.INT8, [1]) + out = helper.make_tensor_value_info('4', TensorProto.INT32, [1, 1, 4, 4]) + + node = onnx.helper.make_node('ConvInteger', + inputs=['0', '1', '2', '3'], + outputs=['4'], + dilations=[1, 1], + strides=[1, 1]) + + return ([node], [x, y, z, w], [out]) + + +@onnx_test() +def convinteger_mismatched_input_types_test(): + x = helper.make_tensor_value_info('0', TensorProto.INT8, [1, 3, 32, 32]) + y = helper.make_tensor_value_info('1', TensorProto.UINT8, [1, 3, 5, 5]) + out = helper.make_tensor_value_info('4', TensorProto.INT32, [1, 2, 28, 28]) + + node = onnx.helper.make_node('ConvInteger', + inputs=['0', '1'], + outputs=['4'], + dilations=[1, 1], + strides=[1, 1]) + + return ([node], [x, y], [out]) + + +@onnx_test() +def convinteger_mismatched_inputs_dual_bias_test(): + x = helper.make_tensor_value_info('0', TensorProto.UINT8, [1, 3, 5, 5]) + y = helper.make_tensor_value_info('1', TensorProto.INT8, [1, 3, 2, 2]) + z = helper.make_tensor_value_info('2', TensorProto.UINT8, [1]) + w = helper.make_tensor_value_info('3', TensorProto.INT8, [1]) + out = helper.make_tensor_value_info('4', TensorProto.INT32, [1, 1, 4, 4]) + + node = onnx.helper.make_node('ConvInteger', + inputs=['0', '1', '2', '3'], + outputs=['4'], + dilations=[1, 1], + strides=[1, 1]) + + return ([node], [x, y, z, w], [out]) + + +@onnx_test() +def convinteger_mismatched_data_bias_test(): + x = helper.make_tensor_value_info('0', TensorProto.INT8, [1, 3, 32, 32]) + y = helper.make_tensor_value_info('1', TensorProto.INT8, [1, 3, 5, 5]) + z = helper.make_tensor_value_info('2', TensorProto.UINT8, [1]) + w = helper.make_tensor_value_info('3', TensorProto.INT8, [1]) + out = helper.make_tensor_value_info('4', TensorProto.INT32, [1, 2, 28, 28]) + + node = onnx.helper.make_node('ConvInteger', + inputs=['0', '1', '2', '3'], + outputs=['4'], + dilations=[1, 1], + strides=[1, 1]) + + return ([node], [x, y, z, w], [out]) + + +@onnx_test() +def convinteger_mismatched_weight_bias_test(): + x = helper.make_tensor_value_info('0', TensorProto.INT8, [1, 3, 32, 32]) + y = helper.make_tensor_value_info('1', TensorProto.INT8, [1, 3, 5, 5]) + z = helper.make_tensor_value_info('2', TensorProto.INT8, [1]) + w = helper.make_tensor_value_info('3', TensorProto.UINT8, [1]) + out = helper.make_tensor_value_info('4', TensorProto.INT32, [1, 2, 28, 28]) + + node = onnx.helper.make_node('ConvInteger', + inputs=['0', '1', '2', '3'], + outputs=['4'], + dilations=[1, 1], + strides=[1, 1]) + + return ([node], [x, y, z, w], [out]) + + @onnx_test() def cos_test(): x = helper.make_tensor_value_info('x', TensorProto.FLOAT, [10]) diff --git a/test/onnx/parse/conv_bad_bias_test.cpp b/test/onnx/parse/conv_bad_bias_test.cpp new file mode 100644 index 00000000000..c0ffac73dc6 --- /dev/null +++ b/test/onnx/parse/conv_bad_bias_test.cpp @@ -0,0 +1,30 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2015-2024 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 + +TEST_CASE(conv_bad_bias_test) +{ + EXPECT(test::throws([&] { migraphx::parse_onnx("conv_bad_bias_test.onnx"); })); +} diff --git a/test/onnx/parse/conv_bias_test.cpp b/test/onnx/parse/conv_bias_test.cpp index d96ef970ba8..0ce1983e6c3 100644 --- a/test/onnx/parse/conv_bias_test.cpp +++ b/test/onnx/parse/conv_bias_test.cpp @@ -1,7 +1,7 @@ /* * The MIT License (MIT) * - * Copyright (c) 2015-2023 Advanced Micro Devices, Inc. All rights reserved. + * Copyright (c) 2015-2024 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 diff --git a/test/onnx/parse/convinteger_bad_data_bias_type.cpp b/test/onnx/parse/convinteger_bad_data_bias_type.cpp new file mode 100644 index 00000000000..fb13c2c603a --- /dev/null +++ b/test/onnx/parse/convinteger_bad_data_bias_type.cpp @@ -0,0 +1,30 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2015-2024 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 + +TEST_CASE(convinteger_bad_data_bias_type_test) +{ + EXPECT(test::throws([&] { migraphx::parse_onnx("convinteger_mismatched_data_bias.onnx"); })); +} diff --git a/test/onnx/parse/convinteger_bad_weight_bias_type.cpp b/test/onnx/parse/convinteger_bad_weight_bias_type.cpp new file mode 100644 index 00000000000..4392d78c3ac --- /dev/null +++ b/test/onnx/parse/convinteger_bad_weight_bias_type.cpp @@ -0,0 +1,30 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2015-2024 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 + +TEST_CASE(convinteger_bad_weight_bias_type_test) +{ + EXPECT(test::throws([&] { migraphx::parse_onnx("convinteger_mismatched_weight_bias.onnx"); })); +} diff --git a/test/onnx/parse/convinteger_bias_test.cpp b/test/onnx/parse/convinteger_bias_test.cpp index e7392d264bd..38d9c42412f 100644 --- a/test/onnx/parse/convinteger_bias_test.cpp +++ b/test/onnx/parse/convinteger_bias_test.cpp @@ -1,7 +1,7 @@ /* * The MIT License (MIT) * - * Copyright (c) 2015-2023 Advanced Micro Devices, Inc. All rights reserved. + * Copyright (c) 2015-2024 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 @@ -27,15 +27,25 @@ TEST_CASE(convinteger_bias_test) { migraphx::program p; - auto* mm = p.get_main_module(); - auto l0 = mm->add_parameter("0", {migraphx::shape::int8_type, {1, 3, 32, 32}}); - auto l1 = mm->add_parameter("1", {migraphx::shape::int8_type, {1, 3, 5, 5}}); - auto l2 = mm->add_parameter("2", {migraphx::shape::int32_type, {1}}); - uint64_t axis = 1; - auto l3 = mm->add_instruction(migraphx::make_op("quant_convolution"), l0, l1); - auto l4 = mm->add_instruction( - migraphx::make_op("broadcast", {{"axis", axis}, {"out_lens", l3->get_shape().lens()}}), l2); - mm->add_instruction(migraphx::make_op("add"), l3, l4); + auto* mm = p.get_main_module(); + auto data = mm->add_parameter("0", {migraphx::shape::int8_type, {1, 3, 32, 32}}); + auto weights = mm->add_parameter("1", {migraphx::shape::int8_type, {1, 3, 5, 5}}); + auto data_bias = mm->add_parameter("2", {migraphx::shape::int8_type, {1}, {1}}); + + mm->add_literal(migraphx::literal{migraphx::shape{data->get_shape().type(), {1}, {0}}, {0}}); + auto quant = mm->add_instruction(migraphx::make_op("quant_convolution"), data, weights); + + auto bcast_data_bias = mm->add_instruction( + migraphx::make_op("multibroadcast", {{"out_lens", weights->get_shape().lens()}}), + data_bias); + + auto quant2 = + mm->add_instruction(migraphx::make_op("quant_convolution"), bcast_data_bias, weights); + + auto bcast_quant2 = mm->add_instruction( + migraphx::make_op("multibroadcast", {{"out_lens", quant->get_shape().lens()}}), quant2); + + mm->add_instruction(migraphx::make_op("sub"), quant, bcast_quant2); auto prog = optimize_onnx("convinteger_bias_test.onnx"); EXPECT(p == prog); diff --git a/test/onnx/parse/convinteger_dual_bias_test.cpp b/test/onnx/parse/convinteger_dual_bias_test.cpp new file mode 100644 index 00000000000..97445ff6ab9 --- /dev/null +++ b/test/onnx/parse/convinteger_dual_bias_test.cpp @@ -0,0 +1,71 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2015-2024 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 + +TEST_CASE(convinteger_dual_bias_test) +{ + migraphx::program p; + auto* mm = p.get_main_module(); + auto data = mm->add_parameter("0", {migraphx::shape::int8_type, {1, 3, 5, 5}}); + auto weight = mm->add_parameter("1", {migraphx::shape::int8_type, {1, 3, 2, 2}}); + auto data_bias = mm->add_parameter("2", {migraphx::shape::int8_type, {1}, {1}}); + auto weight_bias = mm->add_parameter("3", {migraphx::shape::int8_type, {1}, {1}}); + + auto quant = mm->add_instruction(migraphx::make_op("quant_convolution"), data, weight); + + auto mbcast_data_bias = mm->add_instruction( + migraphx::make_op("multibroadcast", {{"out_lens", weight->get_shape().lens()}}), data_bias); + + auto quant_db_w = + mm->add_instruction(migraphx::make_op("quant_convolution"), mbcast_data_bias, weight); + + auto quant_mb_w = mm->add_instruction( + migraphx::make_op("multibroadcast", {{"out_lens", quant->get_shape().lens()}}), quant_db_w); + + quant = mm->add_instruction(migraphx::make_op("sub"), quant, quant_mb_w); + + auto mbcast_weight_bias = mm->add_instruction( + migraphx::make_op("multibroadcast", {{"out_lens", data->get_shape().lens()}}), weight_bias); + + auto quant_d_wb = + mm->add_instruction(migraphx::make_op("quant_convolution"), data, mbcast_weight_bias); + + auto quant_md_wb = mm->add_instruction( + migraphx::make_op("multibroadcast", {{"out_lens", quant->get_shape().lens()}}), quant_d_wb); + + quant = mm->add_instruction(migraphx::make_op("sub"), quant, quant_md_wb); + + auto bcast_data_bias = mm->add_instruction( + migraphx::make_op("broadcast", {{"out_lens", data->get_shape().lens()}}), data_bias); + auto bcast_weight_bias = mm->add_instruction( + migraphx::make_op("broadcast", {{"out_lens", weight->get_shape().lens()}}), weight_bias); + auto bias_quant = mm->add_instruction( + migraphx::make_op("quant_convolution"), bcast_data_bias, bcast_weight_bias); + + mm->add_instruction(migraphx::make_op("add"), quant, bias_quant); + + auto prog = optimize_onnx("convinteger_dual_bias_test.onnx"); + EXPECT(p == prog); +} diff --git a/test/onnx/parse/convinteger_no_bias.cpp b/test/onnx/parse/convinteger_no_bias.cpp new file mode 100644 index 00000000000..2242c43ed94 --- /dev/null +++ b/test/onnx/parse/convinteger_no_bias.cpp @@ -0,0 +1,40 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2015-2024 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 + +TEST_CASE(convinteger_no_bias) +{ + migraphx::program p; + auto* mm = p.get_main_module(); + auto data = mm->add_parameter("0", {migraphx::shape::int8_type, {1, 3, 5, 5}}); + auto weight = mm->add_parameter("1", {migraphx::shape::int8_type, {1, 3, 2, 2}}); + mm->add_literal(migraphx::literal{migraphx::shape{data->get_shape().type(), {1}, {0}}, {0}}); + mm->add_literal(migraphx::literal{migraphx::shape{data->get_shape().type(), {1}, {0}}, {0}}); + + mm->add_instruction(migraphx::make_op("quant_convolution"), data, weight); + + auto prog = optimize_onnx("convinteger_no_bias_test.onnx"); + EXPECT(p == prog); +} diff --git a/test/onnx/parse/convinteger_no_bias_mismatched_inputs.cpp b/test/onnx/parse/convinteger_no_bias_mismatched_inputs.cpp new file mode 100644 index 00000000000..3796f3e3127 --- /dev/null +++ b/test/onnx/parse/convinteger_no_bias_mismatched_inputs.cpp @@ -0,0 +1,61 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2015-2024 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 + +TEST_CASE(convinteger_no_bias_mismatched_data_inputs_test) +{ + migraphx::program p; + auto* mm = p.get_main_module(); + auto data = mm->add_parameter("0", {migraphx::shape::int8_type, {1, 3, 32, 32}}); + auto weight = mm->add_parameter("1", {migraphx::shape::uint8_type, {1, 3, 5, 5}}); + + mm->add_literal(migraphx::literal{migraphx::shape{data->get_shape().type(), {1}, {0}}, {0}}); + mm->add_literal( + migraphx::literal{migraphx::shape{weight->get_shape().type(), {1}, {0}}, {128}}); + + // shift uint8 input + auto int8_shift2 = + mm->add_literal(migraphx::literal{migraphx::shape{migraphx::shape::half_type}, {-128}}); + + // shift uint8 input + auto unshifted_input_half = mm->add_instruction( + migraphx::make_op("convert", {{"target_type", migraphx::shape::half_type}}), weight); + + auto mbr2 = mm->add_instruction( + migraphx::make_op("multibroadcast", {{"out_lens", weight->get_shape().lens()}}), + int8_shift2); + + auto input_shifted_half = + mm->add_instruction(migraphx::make_op("add"), unshifted_input_half, mbr2); + + weight = mm->add_instruction( + migraphx::make_op("convert", {{"target_type", migraphx::shape::int8_type}}), + input_shifted_half); + + mm->add_instruction(migraphx::make_op("quant_convolution"), data, weight); + + auto prog = optimize_onnx("convinteger_mismatched_input_types_test.onnx"); + EXPECT(p == prog); +} diff --git a/test/onnx/parse/convinteger_no_bias_uint8.cpp b/test/onnx/parse/convinteger_no_bias_uint8.cpp new file mode 100644 index 00000000000..596029ed024 --- /dev/null +++ b/test/onnx/parse/convinteger_no_bias_uint8.cpp @@ -0,0 +1,73 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2015-2024 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 + +TEST_CASE(convinteger_no_bias_uint8) +{ + migraphx::program p; + auto* mm = p.get_main_module(); + auto data = mm->add_parameter("0", {migraphx::shape::uint8_type, {1, 3, 32, 32}}); + auto weights = mm->add_parameter("1", {migraphx::shape::uint8_type, {1, 3, 5, 5}}); + + mm->add_literal(migraphx::literal{migraphx::shape{data->get_shape().type(), {1}, {0}}, {128}}); + mm->add_literal(migraphx::literal{migraphx::shape{data->get_shape().type(), {1}, {0}}, {128}}); + + // Shift uint8 input + auto int8_shift2 = + mm->add_literal(migraphx::literal{migraphx::shape{migraphx::shape::half_type}, {-128}}); + + // Shift uint8 input + auto unshifted_input_half = mm->add_instruction( + migraphx::make_op("convert", {{"target_type", migraphx::shape::half_type}}), data); + + auto mbr2 = mm->add_instruction( + migraphx::make_op("multibroadcast", {{"out_lens", {1, 3, 32, 32}}}), int8_shift2); + + auto input_shifted_half = + mm->add_instruction(migraphx::make_op("add"), unshifted_input_half, mbr2); + + data = mm->add_instruction( + migraphx::make_op("convert", {{"target_type", migraphx::shape::int8_type}}), + input_shifted_half); + + // Shift uint8 weights + auto unshifted_weights_half = mm->add_instruction( + migraphx::make_op("convert", {{"target_type", migraphx::shape::half_type}}), weights); + + auto mbr3 = mm->add_instruction( + migraphx::make_op("multibroadcast", {{"out_lens", {1, 3, 5, 5}}}), int8_shift2); + + auto weights_shifted_half = + mm->add_instruction(migraphx::make_op("add"), unshifted_weights_half, mbr3); + + weights = mm->add_instruction( + migraphx::make_op("convert", {{"target_type", migraphx::shape::int8_type}}), + weights_shifted_half); + + mm->add_instruction(migraphx::make_op("quant_convolution"), data, weights); + + auto prog = optimize_onnx("convinteger_no_bias_uint8_test.onnx"); + EXPECT(p == prog); +} diff --git a/test/onnx/verify/quant_convolution_dual_bias_test.cpp b/test/onnx/verify/quant_convolution_dual_bias_test.cpp new file mode 100644 index 00000000000..a4a8f6fab9c --- /dev/null +++ b/test/onnx/verify/quant_convolution_dual_bias_test.cpp @@ -0,0 +1,134 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2015-2024 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(quant_convolution_dual_zero_bias_test) +{ + migraphx::program p = migraphx::parse_onnx("convinteger_dual_bias_test.onnx"); + p.compile(migraphx::make_target("ref")); + + migraphx::shape a{migraphx::shape::int8_type, {1, 3, 5, 5}}; + std::vector data_a = { + 0, -2, 4, -6, 8, -10, 12, -14, 16, -18, 20, 22, -24, 26, -28, + 30, -32, 34, -36, 38, -40, 42, -44, 46, -48, 50, -52, 54, -56, 58, + -60, 62, -64, 66, -68, 70, -72, 74, -76, 78, -80, 82, -84, 86, -88, + 90, -92, 94, -96, 98, -100, 102, -104, 106, -108, 110, -112, 114, -116, 118, + -120, 122, -124, 126, -127, 127, -64, 32, -16, 8, -4, 2, -1, 0, 1}; + + migraphx::shape b{migraphx::shape::int8_type, {1, 3, 2, 2}}; + std::vector data_b = {-127, -64, -32, -8, -4, 0, 2, 4, 8, 16, 64, 127}; + + migraphx::shape a_bias{migraphx::shape::int8_type, {1}, {1}}; + std::vector data_a_bias = {0}; + + migraphx::shape b_bias{migraphx::shape::int8_type, {1}, {1}}; + std::vector data_b_bias = {0}; + + migraphx::parameter_map pp; + pp["0"] = migraphx::argument(a, data_a.data()); + pp["1"] = migraphx::argument(b, data_b.data()); + pp["2"] = migraphx::argument(a_bias, data_a_bias.data()); + pp["3"] = migraphx::argument(b_bias, data_b_bias.data()); + + auto result = p.eval(pp).back(); + + std::vector result_vector; + result.visit([&](auto output) { result_vector.assign(output.begin(), output.end()); }); + + std::vector gold = {-6072, + 6264, + -6456, + 6648, + 6680, + -8248, + 8536, + -8697, + -3772, + -1430, + 1504, + -1570, + -696, + 761, + -898, + 1035}; + + EXPECT(migraphx::verify::verify_rms_range(result_vector, gold)); +} + +TEST_CASE(quant_convolution_dual_non_zero_bias_test) +{ + // github.com/microsoft/onnxruntime/blob/main/docs/ContribOperators.md#com.microsoft.QLinearMul + migraphx::program p = migraphx::parse_onnx("convinteger_dual_bias_test.onnx"); + p.compile(migraphx::make_target("ref")); + + migraphx::shape a{migraphx::shape::int8_type, {1, 3, 5, 5}}; + std::vector data_a = { + 0, -2, 4, -6, 8, -10, 12, -14, 16, -18, 20, 22, -24, 26, -28, + 30, -32, 34, -36, 38, -40, 42, -44, 46, -48, 50, -52, 54, -56, 58, + -60, 62, -64, 66, -68, 70, -72, 74, -76, 78, -80, 82, -84, 86, -88, + 90, -92, 94, -96, 98, -100, 102, -104, 106, -108, 110, -112, 114, -116, 118, + -120, 122, -124, 126, -127, 127, -64, 32, -16, 8, -4, 2, -1, 0, 1}; + + migraphx::shape b{migraphx::shape::int8_type, {1, 3, 2, 2}}; + std::vector data_b = {-127, -64, -32, -8, -4, 0, 2, 4, 8, 16, 64, 127}; + + migraphx::shape a_bias{migraphx::shape::int8_type, {1}, {1}}; + std::vector data_a_bias = {10}; + + migraphx::shape b_bias{migraphx::shape::int8_type, {1}, {1}}; + std::vector data_b_bias = {-2}; + + migraphx::parameter_map pp; + pp["0"] = migraphx::argument(a, data_a.data()); + pp["1"] = migraphx::argument(b, data_b.data()); + pp["2"] = migraphx::argument(a_bias, data_a_bias.data()); + pp["3"] = migraphx::argument(b_bias, data_b_bias.data()); + + auto result = p.eval(pp).back(); + + std::vector result_vector; + result.visit([&](auto output) { result_vector.assign(output.begin(), output.end()); }); + + std::vector gold = {-6088, + 6248, + -6472, + 6632, + 6664, + -8264, + 8520, + -8713, + -3788, + -1446, + 1488, + -1586, + -712, + 745, + -914, + 1019}; + + EXPECT(migraphx::verify::verify_rms_range(result_vector, gold)); +} diff --git a/test/onnx/verify/quant_convolution_mismatched_input_dual_bias_test.cpp b/test/onnx/verify/quant_convolution_mismatched_input_dual_bias_test.cpp new file mode 100644 index 00000000000..caf587d38fa --- /dev/null +++ b/test/onnx/verify/quant_convolution_mismatched_input_dual_bias_test.cpp @@ -0,0 +1,133 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2015-2024 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(quant_convolution_mismatched_inputs_dual_zero_bias_test) +{ + migraphx::program p = migraphx::parse_onnx("convinteger_mismatched_inputs_dual_bias_test.onnx"); + p.compile(migraphx::make_target("ref")); + + migraphx::shape a{migraphx::shape::uint8_type, {1, 3, 5, 5}}; + std::vector data_a = {128, 126, 132, 122, 136, 118, 140, 114, 144, 110, 148, 150, 104, + 154, 100, 158, 96, 162, 92, 166, 88, 170, 84, 174, 80, 178, + 76, 182, 72, 186, 68, 190, 64, 194, 60, 198, 56, 202, 52, + 206, 48, 210, 44, 214, 40, 218, 36, 222, 32, 226, 28, 230, + 24, 234, 20, 238, 16, 242, 12, 246, 8, 250, 4, 254, 1, + 255, 64, 160, 112, 136, 124, 130, 127, 128, 129}; + + migraphx::shape b{migraphx::shape::int8_type, {1, 3, 2, 2}}; + std::vector data_b = {-127, -64, -32, -8, -4, 0, 2, 4, 8, 16, 64, 127}; + + migraphx::shape a_bias{migraphx::shape::uint8_type, {1}, {1}}; + std::vector data_a_bias = {128}; + + migraphx::shape b_bias{migraphx::shape::int8_type, {1}, {1}}; + std::vector data_b_bias = {0}; + + migraphx::parameter_map pp; + pp["0"] = migraphx::argument(a, data_a.data()); + pp["1"] = migraphx::argument(b, data_b.data()); + pp["2"] = migraphx::argument(a_bias, data_a_bias.data()); + pp["3"] = migraphx::argument(b_bias, data_b_bias.data()); + + auto result = p.eval(pp).back(); + + std::vector result_vector; + result.visit([&](auto output) { result_vector.assign(output.begin(), output.end()); }); + + std::vector gold = {-6072, + 6264, + -6456, + 6648, + 6680, + -8248, + 8536, + -8697, + -3772, + -1430, + 1504, + -1570, + -696, + 761, + -898, + 1035}; + + EXPECT(migraphx::verify::verify_rms_range(result_vector, gold)); +} + +TEST_CASE(quant_convolution_mismatched_inputs_dual_non_zero_bias_test) +{ + migraphx::program p = migraphx::parse_onnx("convinteger_mismatched_inputs_dual_bias_test.onnx"); + p.compile(migraphx::make_target("ref")); + + migraphx::shape a{migraphx::shape::uint8_type, {1, 3, 5, 5}}; + std::vector data_a = {128, 126, 132, 122, 136, 118, 140, 114, 144, 110, 148, 150, 104, + 154, 100, 158, 96, 162, 92, 166, 88, 170, 84, 174, 80, 178, + 76, 182, 72, 186, 68, 190, 64, 194, 60, 198, 56, 202, 52, + 206, 48, 210, 44, 214, 40, 218, 36, 222, 32, 226, 28, 230, + 24, 234, 20, 238, 16, 242, 12, 246, 8, 250, 4, 254, 1, + 255, 64, 160, 112, 136, 124, 130, 127, 128, 129}; + + migraphx::shape b{migraphx::shape::int8_type, {1, 3, 2, 2}}; + std::vector data_b = {-127, -64, -32, -8, -4, 0, 2, 4, 8, 16, 64, 127}; + + migraphx::shape a_bias{migraphx::shape::uint8_type, {1}, {1}}; + std::vector data_a_bias = {138}; + + migraphx::shape b_bias{migraphx::shape::int8_type, {1}, {1}}; + std::vector data_b_bias = {-2}; + + migraphx::parameter_map pp; + pp["0"] = migraphx::argument(a, data_a.data()); + pp["1"] = migraphx::argument(b, data_b.data()); + pp["2"] = migraphx::argument(a_bias, data_a_bias.data()); + pp["3"] = migraphx::argument(b_bias, data_b_bias.data()); + + auto result = p.eval(pp).back(); + + std::vector result_vector; + result.visit([&](auto output) { result_vector.assign(output.begin(), output.end()); }); + + std::vector gold = {-6088, + 6248, + -6472, + 6632, + 6664, + -8264, + 8520, + -8713, + -3788, + -1446, + 1488, + -1586, + -712, + 745, + -914, + 1019}; + + EXPECT(migraphx::verify::verify_rms_range(result_vector, gold)); +} diff --git a/test/onnx/verify/quant_convolution_test.cpp b/test/onnx/verify/quant_convolution_test.cpp new file mode 100644 index 00000000000..73986631952 --- /dev/null +++ b/test/onnx/verify/quant_convolution_test.cpp @@ -0,0 +1,72 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2015-2024 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(quant_convolution_test) +{ + // github.com/microsoft/onnxruntime/blob/main/docs/ContribOperators.md#com.microsoft.QLinearMul + migraphx::program p = migraphx::parse_onnx("convinteger_no_bias_test.onnx"); + p.compile(migraphx::make_target("ref")); + + migraphx::shape a{migraphx::shape::int8_type, {1, 3, 5, 5}}; + std::vector data_a = { + 0, -2, 4, -6, 8, -10, 12, -14, 16, -18, 20, 22, -24, 26, -28, + 30, -32, 34, -36, 38, -40, 42, -44, 46, -48, 50, -52, 54, -56, 58, + -60, 62, -64, 66, -68, 70, -72, 74, -76, 78, -80, 82, -84, 86, -88, + 90, -92, 94, -96, 98, -100, 102, -104, 106, -108, 110, -112, 114, -116, 118, + -120, 122, -124, 126, -127, 127, -64, 32, -16, 8, -4, 2, -1, 0, 1}; + + migraphx::shape b{migraphx::shape::int8_type, {1, 3, 2, 2}}; + std::vector data_b = {-127, -64, -32, -8, -4, 0, 2, 4, 8, 16, 64, 127}; + + migraphx::parameter_map pp; + pp["0"] = migraphx::argument(a, data_a.data()); + pp["1"] = migraphx::argument(b, data_b.data()); + auto result = p.eval(pp).back(); + + std::vector result_vector; + result.visit([&](auto output) { result_vector.assign(output.begin(), output.end()); }); + + std::vector gold = {-6072, + 6264, + -6456, + 6648, + 6680, + -8248, + 8536, + -8697, + -3772, + -1430, + 1504, + -1570, + -696, + 761, + -898, + 1035}; + + EXPECT(migraphx::verify::verify_rms_range(result_vector, gold)); +}