From d66d57df96db46c7a8d304bd4f8e917ed2bf7a0d Mon Sep 17 00:00:00 2001 From: lakhinderwalia Date: Mon, 13 Jan 2025 15:14:05 -0800 Subject: [PATCH 1/5] Resize onnx op: cleanup for Compute and Space performance of linear option --- src/onnx/parse_resize.cpp | 86 ++++++++++++++++++++++++++------------- 1 file changed, 57 insertions(+), 29 deletions(-) diff --git a/src/onnx/parse_resize.cpp b/src/onnx/parse_resize.cpp index cf015a53414..df6c293f019 100644 --- a/src/onnx/parse_resize.cpp +++ b/src/onnx/parse_resize.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 @@ -35,11 +35,15 @@ namespace onnx { static std::vector calc_neighbor_points(const std::vector>>& vvv_ind, - int i_dim, + size_t i_dim, // input lens index + size_t r_dim, // resized index std::vector> vec_dims, - const shape& in_s) + const shape& in_s, + const shape& out_s) { - if(i_dim == vvv_ind.size()) + auto&& o_lens = out_s.lens(); + + if(i_dim == o_lens.size()) { std::vector vec_ind(vec_dims.size()); std::transform(vec_dims.begin(), vec_dims.end(), vec_ind.begin(), [&](auto idx) { @@ -48,7 +52,19 @@ calc_neighbor_points(const std::vector>>& v return vec_ind; } - const auto& vv_lo = vvv_ind[i_dim][0]; + size_t o_dim_size = o_lens[i_dim]; + + // when a dimension is unchanged in Resize, its indices are identical, and just copied: + if(in_s.lens()[i_dim] == o_dim_size) + { + for(std::size_t v_idx = 0; v_idx < vec_dims.size(); v_idx += o_dim_size) + for(size_t i = 0; i < o_dim_size; i++) + vec_dims[v_idx + i].push_back(i); + return calc_neighbor_points(vvv_ind, i_dim + 1, r_dim, std::move(vec_dims), in_s, out_s); + } + + // when a dimension is unchanged in Resize, its indices are processed below: + const auto& vv_lo = vvv_ind[r_dim][0]; std::vector> vec_dims1; for(std::size_t start = 0; start < vec_dims.size(); start += vv_lo.size()) { @@ -62,7 +78,7 @@ calc_neighbor_points(const std::vector>>& v }); } - const auto& vv_hi = vvv_ind[i_dim][1]; + const auto& vv_hi = vvv_ind[r_dim][1]; for(std::size_t start = 0; start < vec_dims.size(); start += vv_hi.size()) { std::transform(vv_hi.begin(), @@ -75,7 +91,7 @@ calc_neighbor_points(const std::vector>>& v }); } vec_dims.clear(); - return calc_neighbor_points(vvv_ind, i_dim + 1, std::move(vec_dims1), in_s); + return calc_neighbor_points(vvv_ind, i_dim + 1, r_dim + 1, std::move(vec_dims1), in_s, out_s); } static std::string get_coord_trans_mode(const onnx_parser::attribute_map& attr) @@ -350,7 +366,6 @@ struct parse_resize : op_parser ": linear mode not supported for non-constant inputs"); shape out_s{in_s.type(), out_lens}; - std::size_t out_elements = out_s.elements(); // reshape input to one-dimension std::vector rsp_lens = {static_cast(in_s.elements())}; @@ -359,41 +374,55 @@ struct parse_resize : op_parser auto nearest_floor = op::resize::get_nearest_op("floor"); auto nearest_ceil = op::resize::get_nearest_op("ceil"); - // get the number of dimensions - std::size_t n_dim = out_lens.size(); + std::size_t n_dim = out_lens.size(); + std::size_t r_dim = 0; // count: lens dimensions that are resized + std::size_t out_elements = 1; // count: number of elements to fix due to resize. + for(std::size_t dim = 0; dim < n_dim; dim++) + { + if(in_lens[dim] == out_lens[dim]) + continue; + r_dim++; + out_elements *= out_lens[dim]; + } std::vector> vv_ind(2, std::vector(out_elements)); - std::vector>> vvv_ind(n_dim, vv_ind); - std::vector> delta(n_dim, std::vector(out_elements)); + std::vector>> vvv_ind(r_dim, vv_ind); + std::vector> delta(r_dim, std::vector(out_elements)); - shape_for_each(out_s, [&](const auto& out_idx_v, size_t out_idx) { - for(auto ii = 0; ii < in_lens.size(); ++ii) + shape_for_each(out_s, [&](const auto& out_idx_v, std::size_t out_idx) { + std::size_t ii = 0; + for(std::size_t idx = 0; idx < in_lens.size(); ++idx) { - auto idx_val = idx_op(in_lens[ii], out_lens[ii], out_idx_v[ii], vec_scale[ii]); - vvv_ind[ii][0][out_idx] = nearest_floor(in_lens[ii], idx_val); - vvv_ind[ii][1][out_idx] = nearest_ceil(in_lens[ii], idx_val); + if(in_lens[idx] == out_lens[idx]) + continue; + auto idx_val = + idx_op(in_lens[idx], out_lens[idx], out_idx_v[idx], vec_scale[idx]); + vvv_ind[ii][0][out_idx] = nearest_floor(in_lens[idx], idx_val); + vvv_ind[ii][1][out_idx] = nearest_ceil(in_lens[idx], idx_val); delta[ii][out_idx] = idx_val - vvv_ind[ii][0][out_idx]; + ++ii; } }); auto ind = calc_neighbor_points( - vvv_ind, 0, std::vector>(out_elements), in_s); - auto ind_lens = out_lens; - ind_lens[0] *= (std::size_t{1} << n_dim); - shape ind_s{shape::int32_type, ind_lens}; + vvv_ind, 0, 0, std::vector>(out_elements), in_s, out_s); + + auto dim_lens = out_lens; + dim_lens[0] *= (1 << r_dim); + shape ind_s{shape::int32_type, dim_lens}; auto ins_ind = info.add_literal(literal(ind_s, ind)); auto data = info.add_instruction(make_op("gather", {{"axis", 0}}), rsp, ins_ind); - auto dim_lens = out_lens; - dim_lens[0] *= (std::size_t{1} << (n_dim - 1)); - for(std::size_t i = 0; i < n_dim; ++i) + std::size_t lens_idx = out_lens.size(); + for(std::size_t i = 0; i < r_dim; lens_idx--) { + if(in_lens[lens_idx] == out_lens[lens_idx]) + continue; + dim_lens[0] >>= 1; // halved for 2 slices of data shape dim_s{shape::float_type, dim_lens}; - const auto& dim_delta = delta[n_dim - i - 1]; + const auto& dim_delta = delta[r_dim - i - 1]; std::vector delta_data; for(std::size_t j = 0; j < dim_lens[0] / out_lens[0]; ++j) - { delta_data.insert(delta_data.begin(), dim_delta.begin(), dim_delta.end()); - } auto ins_delta = info.add_literal(dim_s, delta_data); // slice the data @@ -408,9 +437,8 @@ struct parse_resize : op_parser auto diff = info.add_instruction(make_op("sub"), hi, low); auto ddf = info.add_instruction(make_op("mul"), diff, ins_delta); data = info.add_instruction(make_op("add"), ddf, low); - dim_lens[0] /= 2; + i++; } - return data; } } From 7b21008fef4a334bb25b088b4f269ec8daf9e163 Mon Sep 17 00:00:00 2001 From: lakhinderwalia Date: Tue, 21 Jan 2025 19:38:41 -0800 Subject: [PATCH 2/5] Update the expected IR for onnx parsing of upsample and resize (linear) tests --- src/onnx/parse_resize.cpp | 4 +- test/onnx/include/onnx_test_utils.hpp | 113 +++++++++--------- .../parse/resize_downsample_linear_test.cpp | 63 +++++----- .../parse/resize_upsample_linear_test.cpp | 93 +------------- test/onnx/parse/upsample_linear_test.cpp | 4 +- 5 files changed, 96 insertions(+), 181 deletions(-) diff --git a/src/onnx/parse_resize.cpp b/src/onnx/parse_resize.cpp index df6c293f019..8c44a8f8d58 100644 --- a/src/onnx/parse_resize.cpp +++ b/src/onnx/parse_resize.cpp @@ -407,7 +407,7 @@ struct parse_resize : op_parser vvv_ind, 0, 0, std::vector>(out_elements), in_s, out_s); auto dim_lens = out_lens; - dim_lens[0] *= (1 << r_dim); + dim_lens[0] *= (1u << r_dim); shape ind_s{shape::int32_type, dim_lens}; auto ins_ind = info.add_literal(literal(ind_s, ind)); auto data = info.add_instruction(make_op("gather", {{"axis", 0}}), rsp, ins_ind); @@ -417,7 +417,7 @@ struct parse_resize : op_parser { if(in_lens[lens_idx] == out_lens[lens_idx]) continue; - dim_lens[0] >>= 1; // halved for 2 slices of data + dim_lens[0] /= 2; // halved for 2 slices of data shape dim_s{shape::float_type, dim_lens}; const auto& dim_delta = delta[r_dim - i - 1]; std::vector delta_data; diff --git a/test/onnx/include/onnx_test_utils.hpp b/test/onnx/include/onnx_test_utils.hpp index cffd6a44519..64dd85e938d 100644 --- a/test/onnx/include/onnx_test_utils.hpp +++ b/test/onnx/include/onnx_test_utils.hpp @@ -233,7 +233,7 @@ make_simplified_layer_norm(const std::vector& input_shape, auto x_sq = add_common_op(*mm, migraphx::make_op("mul"), {float_x, float_x}); auto norm_axis = axis < 0 ? axis + x->get_shape().lens().size() : axis; auto rms = mm->add_instruction(migraphx::make_op("reduce_mean", {{"axes", {norm_axis}}}), x_sq); - rms = mm->add_instruction(migraphx::make_op("convert", {{"target_type", dtype}}), rms); + rms = mm->add_instruction(migraphx::make_op("convert", {{"target_type", dtype}}), rms); rms = add_common_op(*mm, migraphx::make_op("add"), {rms, eps}); auto rrms = mm->add_instruction(migraphx::make_op("rsqrt"), {rms}); auto result = add_common_op(*mm, migraphx::make_op("mul"), {x, rrms}); @@ -325,6 +325,29 @@ inline migraphx::program make_quantizelinear_axis_prog() return p; } +/* Parsed IR equivalent of create_upsample_linear_prog() +module: "main" +@0 = @literal{ ... } -> float_type, {1, 1, 4, 4}, {16, 16, 4, 1} +@1 = @literal{ ... } -> float_type, {2, 1, 4, 4}, {16, 16, 4, 1} +@2 = @literal{ ... } -> int32_type, {4, 1, 4, 4}, {16, 16, 4, 1} +X = @param:X -> float_type, {1, 1, 2, 2}, {4, 4, 2, 1} +@4 = @literal{1, 1, 2, 2} -> float_type, {4}, {1} +@5 = undefined -> float_type, {}, {} +@6 = reshape[dims={4}](X) -> float_type, {4}, {1} +@7 = gather[axis=0](@6,@2) -> float_type, {4, 1, 4, 4}, {16, 16, 4, 1} +@8 = slice[axes={0},starts={0},ends={2}](@7) -> float_type, {2, 1, 4, 4}, {16, 16, 4, 1} +@9 = slice[axes={0},starts={2},ends={4}](@7) -> float_type, {2, 1, 4, 4}, {16, 16, 4, 1} +@10 = sub(@9,@8) -> float_type, {2, 1, 4, 4}, {16, 16, 4, 1} +@11 = mul(@10,@1) -> float_type, {2, 1, 4, 4}, {16, 16, 4, 1} +@12 = add(@11,@8) -> float_type, {2, 1, 4, 4}, {16, 16, 4, 1} +@13 = slice[axes={0},starts={0},ends={1}](@12) -> float_type, {1, 1, 4, 4}, {16, 16, 4, 1} +@14 = slice[axes={0},starts={1},ends={2}](@12) -> float_type, {1, 1, 4, 4}, {16, 16, 4, 1} +@15 = sub(@14,@13) -> float_type, {1, 1, 4, 4}, {16, 16, 4, 1} +@16 = mul(@15,@0) -> float_type, {1, 1, 4, 4}, {16, 16, 4, 1} +@17 = add(@16,@13) -> float_type, {1, 1, 4, 4}, {16, 16, 4, 1} +@18 = @return(@17) +*/ + inline auto create_upsample_linear_prog() { migraphx::program p; @@ -335,75 +358,51 @@ inline auto create_upsample_linear_prog() migraphx::shape sx{migraphx::shape::float_type, {1, 1, 2, 2}}; auto x = mm->add_parameter("X", sx); - migraphx::shape s_ind{migraphx::shape::int32_type, {16, 1, 4, 4}}; - std::vector d_ind = { - 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 2, 2, 2, 3, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 2, - 2, 2, 3, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 2, 2, 2, 3, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, - 0, 1, 2, 2, 2, 3, 0, 0, 0, 1, 2, 2, 2, 3, 2, 2, 2, 3, 2, 2, 2, 3, 0, 0, 0, 1, 2, 2, 2, - 3, 2, 2, 2, 3, 2, 2, 2, 3, 0, 0, 0, 1, 2, 2, 2, 3, 2, 2, 2, 3, 2, 2, 2, 3, 0, 0, 0, 1, - 2, 2, 2, 3, 2, 2, 2, 3, 2, 2, 2, 3, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 2, 3, 3, 3, 0, - 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 2, 3, 3, 3, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 2, 3, - 3, 3, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 2, 3, 3, 3, 0, 1, 1, 1, 2, 3, 3, 3, 2, 3, 3, - 3, 2, 3, 3, 3, 0, 1, 1, 1, 2, 3, 3, 3, 2, 3, 3, 3, 2, 3, 3, 3, 0, 1, 1, 1, 2, 3, 3, 3, - 2, 3, 3, 3, 2, 3, 3, 3, 0, 1, 1, 1, 2, 3, 3, 3, 2, 3, 3, 3, 2, 3, 3, 3}; - auto l_ind = mm->add_literal(migraphx::literal(s_ind, d_ind)); + migraphx::shape s_ind{migraphx::shape::int32_type, {4, 1, 4, 4}}; - migraphx::shape s8{migraphx::shape::float_type, {8, 1, 4, 4}}; - std::vector d8 = { - 0, 1.0f / 3, 2.0f / 3, 0, 0, 1.0f / 3, 2.0f / 3, 0, 0, 1.0f / 3, 2.0f / 3, 0, - 0, 1.0f / 3, 2.0f / 3, 0, 0, 1.0f / 3, 2.0f / 3, 0, 0, 1.0f / 3, 2.0f / 3, 0, - 0, 1.0f / 3, 2.0f / 3, 0, 0, 1.0f / 3, 2.0f / 3, 0, 0, 1.0f / 3, 2.0f / 3, 0, - 0, 1.0f / 3, 2.0f / 3, 0, 0, 1.0f / 3, 2.0f / 3, 0, 0, 1.0f / 3, 2.0f / 3, 0, - 0, 1.0f / 3, 2.0f / 3, 0, 0, 1.0f / 3, 2.0f / 3, 0, 0, 1.0f / 3, 2.0f / 3, 0, - 0, 1.0f / 3, 2.0f / 3, 0, 0, 1.0f / 3, 2.0f / 3, 0, 0, 1.0f / 3, 2.0f / 3, 0, - 0, 1.0f / 3, 2.0f / 3, 0, 0, 1.0f / 3, 2.0f / 3, 0, 0, 1.0f / 3, 2.0f / 3, 0, - 0, 1.0f / 3, 2.0f / 3, 0, 0, 1.0f / 3, 2.0f / 3, 0, 0, 1.0f / 3, 2.0f / 3, 0, - 0, 1.0f / 3, 2.0f / 3, 0, 0, 1.0f / 3, 2.0f / 3, 0, 0, 1.0f / 3, 2.0f / 3, 0, - 0, 1.0f / 3, 2.0f / 3, 0, 0, 1.0f / 3, 2.0f / 3, 0, 0, 1.0f / 3, 2.0f / 3, 0, - 0, 1.0f / 3, 2.0f / 3, 0, 0, 1.0f / 3, 2.0f / 3, 0}; - auto l8 = mm->add_literal(migraphx::literal(s8, d8)); - - migraphx::shape s4{migraphx::shape::float_type, {4, 1, 4, 4}}; - std::vector d4 = { - 0, 0, 0, 0, 1.0f / 3, 1.0f / 3, 1.0f / 3, 1.0f / 3, - 2.0f / 3, 2.0f / 3, 2.0f / 3, 2.0f / 3, 0, 0, 0, 0, - 0, 0, 0, 0, 1.0f / 3, 1.0f / 3, 1.0f / 3, 1.0f / 3, - 2.0f / 3, 2.0f / 3, 2.0f / 3, 2.0f / 3, 0, 0, 0, 0, - 0, 0, 0, 0, 1.0f / 3, 1.0f / 3, 1.0f / 3, 1.0f / 3, - 2.0f / 3, 2.0f / 3, 2.0f / 3, 2.0f / 3, 0, 0, 0, 0, - 0, 0, 0, 0, 1.0f / 3, 1.0f / 3, 1.0f / 3, 1.0f / 3, - 2.0f / 3, 2.0f / 3, 2.0f / 3, 2.0f / 3, 0, 0, 0, 0}; - auto l4 = mm->add_literal(migraphx::literal(s4, d4)); + std::vector d_ind = {0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 2, 2, 2, 3, 0, 0, 0, 1, 2, 2, + 2, 3, 2, 2, 2, 3, 2, 2, 2, 3, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, + 2, 3, 3, 3, 0, 1, 1, 1, 2, 3, 3, 3, 2, 3, 3, 3, 2, 3, 3, 3}; + + auto l_ind = mm->add_literal(migraphx::literal(s_ind, d_ind)); migraphx::shape s2{migraphx::shape::float_type, {2, 1, 4, 4}}; - std::vector d2(32, 0); + + std::vector d2 = {-0.25, 0.25, 0.75, 0.25, -0.25, 0.25, 0.75, 0.25, + -0.25, 0.25, 0.75, 0.25, -0.25, 0.25, 0.75, 0.25, + -0.25, 0.25, 0.75, 0.25, -0.25, 0.25, 0.75, 0.25, + -0.25, 0.25, 0.75, 0.25, -0.25, 0.25, 0.75, 0.25}; + auto l2 = mm->add_literal(migraphx::literal(s2, d2)); migraphx::shape s1{migraphx::shape::float_type, {1, 1, 4, 4}}; - std::vector d1(16, 0.0f); + + std::vector d1 = {-0.25, + -0.25, + -0.25, + -0.25, + 0.25, + 0.25, + 0.25, + 0.25, + 0.75, + 0.75, + 0.75, + 0.75, + 0.25, + 0.25, + 0.25, + 0.25}; + auto l1 = mm->add_literal(migraphx::literal(s1, d1)); mm->add_instruction(migraphx::make_op("undefined")); auto rsp = mm->add_instruction(migraphx::make_op("reshape", {{"dims", {4}}}), x); auto data = mm->add_instruction(migraphx::make_op("gather", {{"axis", 0}}), rsp, l_ind); - auto slc80 = mm->add_instruction( - migraphx::make_op("slice", {{"axes", {0}}, {"starts", {0}}, {"ends", {8}}}), data); - auto slc81 = mm->add_instruction( - migraphx::make_op("slice", {{"axes", {0}}, {"starts", {8}}, {"ends", {16}}}), data); - auto diff8 = mm->add_instruction(migraphx::make_op("sub"), slc81, slc80); - auto mul8 = mm->add_instruction(migraphx::make_op("mul"), diff8, l8); - auto add8 = mm->add_instruction(migraphx::make_op("add"), mul8, slc80); - auto slc40 = mm->add_instruction( - migraphx::make_op("slice", {{"axes", {0}}, {"starts", {0}}, {"ends", {4}}}), add8); - auto slc41 = mm->add_instruction( - migraphx::make_op("slice", {{"axes", {0}}, {"starts", {4}}, {"ends", {8}}}), add8); - auto diff4 = mm->add_instruction(migraphx::make_op("sub"), slc41, slc40); - auto mul4 = mm->add_instruction(migraphx::make_op("mul"), diff4, l4); - auto add4 = mm->add_instruction(migraphx::make_op("add"), mul4, slc40); auto slc20 = mm->add_instruction( - migraphx::make_op("slice", {{"axes", {0}}, {"starts", {0}}, {"ends", {2}}}), add4); + migraphx::make_op("slice", {{"axes", {0}}, {"starts", {0}}, {"ends", {2}}}), data); auto slc21 = mm->add_instruction( - migraphx::make_op("slice", {{"axes", {0}}, {"starts", {2}}, {"ends", {4}}}), add4); + migraphx::make_op("slice", {{"axes", {0}}, {"starts", {2}}, {"ends", {4}}}), data); auto diff2 = mm->add_instruction(migraphx::make_op("sub"), slc21, slc20); auto mul2 = mm->add_instruction(migraphx::make_op("mul"), diff2, l2); auto add2 = mm->add_instruction(migraphx::make_op("add"), mul2, slc20); diff --git a/test/onnx/parse/resize_downsample_linear_test.cpp b/test/onnx/parse/resize_downsample_linear_test.cpp index 8275059d679..210e20310aa 100644 --- a/test/onnx/parse/resize_downsample_linear_test.cpp +++ b/test/onnx/parse/resize_downsample_linear_test.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 @@ -24,6 +24,29 @@ #include +/* IR for the test case below: +module: "main" +@0 = @literal{0.333333, 0.333333} -> float_type, {1, 1, 1, 2}, {2, 2, 2, 1} +@1 = @literal{0.5, 0.5, 0.5, 0.5} -> float_type, {2, 1, 1, 2}, {2, 2, 2, 1} +@2 = @literal{0, 2, 4, 6, 1, 3, 5, 7} -> int32_type, {4, 1, 1, 2}, {2, 2, 2, 1} +X = @param:X -> float_type, {1, 1, 2, 4}, {8, 8, 4, 1} +@4 = @literal{1, 1, 0.6, 0.5} -> float_type, {4}, {1} +@5 = undefined -> float_type, {}, {} +@6 = reshape[dims={8}](X) -> float_type, {8}, {1} +@7 = gather[axis=0](@6,@2) -> float_type, {4, 1, 1, 2}, {2, 2, 2, 1} +@8 = slice[axes={0},starts={0},ends={2}](@7) -> float_type, {2, 1, 1, 2}, {2, 2, 2, 1} +@9 = slice[axes={0},starts={2},ends={4}](@7) -> float_type, {2, 1, 1, 2}, {2, 2, 2, 1} +@10 = sub(@9,@8) -> float_type, {2, 1, 1, 2}, {2, 2, 2, 1} +@11 = mul(@10,@1) -> float_type, {2, 1, 1, 2}, {2, 2, 2, 1} +@12 = add(@11,@8) -> float_type, {2, 1, 1, 2}, {2, 2, 2, 1} +@13 = slice[axes={0},starts={0},ends={1}](@12) -> float_type, {1, 1, 1, 2}, {2, 2, 2, 1} +@14 = slice[axes={0},starts={1},ends={2}](@12) -> float_type, {1, 1, 1, 2}, {2, 2, 2, 1} +@15 = sub(@14,@13) -> float_type, {1, 1, 1, 2}, {2, 2, 2, 1} +@16 = mul(@15,@0) -> float_type, {1, 1, 1, 2}, {2, 2, 2, 1} +@17 = add(@16,@13) -> float_type, {1, 1, 1, 2}, {2, 2, 2, 1} +@18 = @return(@17) +*/ + TEST_CASE(resize_downsample_linear_test) { migraphx::program p; @@ -34,51 +57,31 @@ TEST_CASE(resize_downsample_linear_test) migraphx::shape sx{migraphx::shape::float_type, {1, 1, 2, 4}}; auto x = mm->add_parameter("X", sx); - migraphx::shape s_ind{migraphx::shape::int32_type, {16, 1, 1, 2}}; - std::vector d_ind = {0, 2, 0, 2, 0, 2, 0, 2, 4, 6, 4, 6, 4, 6, 4, 6, - 1, 3, 1, 3, 1, 3, 1, 3, 5, 7, 5, 7, 5, 7, 5, 7}; - auto l_ind = mm->add_literal(migraphx::literal(s_ind, d_ind)); - - migraphx::shape s8{migraphx::shape::float_type, {8, 1, 1, 2}}; - std::vector d8(16, 0.5f); - auto l8 = mm->add_literal(migraphx::literal(s8, d8)); - migraphx::shape s4{migraphx::shape::float_type, {4, 1, 1, 2}}; - std::vector d4(8, 1.0f / 3.0f); - auto l4 = mm->add_literal(migraphx::literal(s4, d4)); + migraphx::shape s_ind{migraphx::shape::int32_type, {4, 1, 1, 2}}; + std::vector d_ind = {0, 2, 4, 6, 1, 3, 5, 7}; + auto l_ind = mm->add_literal(migraphx::literal(s_ind, d_ind)); migraphx::shape s2{migraphx::shape::float_type, {2, 1, 1, 2}}; - std::vector d2(4, 0); + std::vector d2(4, 0.5f); auto l2 = mm->add_literal(migraphx::literal(s2, d2)); migraphx::shape s1{migraphx::shape::float_type, {1, 1, 1, 2}}; - std::vector d1(2, 0.0f); + std::vector d1(2, 1.0f / 3.0f); auto l1 = mm->add_literal(migraphx::literal(s1, d1)); mm->add_instruction(migraphx::make_op("undefined")); + auto rsp = mm->add_instruction(migraphx::make_op("reshape", {{"dims", {8}}}), x); auto data = mm->add_instruction(migraphx::make_op("gather", {{"axis", 0}}), rsp, l_ind); - auto slc80 = mm->add_instruction( - migraphx::make_op("slice", {{"axes", {0}}, {"starts", {0}}, {"ends", {8}}}), data); - auto slc81 = mm->add_instruction( - migraphx::make_op("slice", {{"axes", {0}}, {"starts", {8}}, {"ends", {16}}}), data); - auto diff8 = mm->add_instruction(migraphx::make_op("sub"), slc81, slc80); - auto mul8 = mm->add_instruction(migraphx::make_op("mul"), diff8, l8); - auto add8 = mm->add_instruction(migraphx::make_op("add"), mul8, slc80); - auto slc40 = mm->add_instruction( - migraphx::make_op("slice", {{"axes", {0}}, {"starts", {0}}, {"ends", {4}}}), add8); - auto slc41 = mm->add_instruction( - migraphx::make_op("slice", {{"axes", {0}}, {"starts", {4}}, {"ends", {8}}}), add8); - auto diff4 = mm->add_instruction(migraphx::make_op("sub"), slc41, slc40); - auto mul4 = mm->add_instruction(migraphx::make_op("mul"), diff4, l4); - auto add4 = mm->add_instruction(migraphx::make_op("add"), mul4, slc40); auto slc20 = mm->add_instruction( - migraphx::make_op("slice", {{"axes", {0}}, {"starts", {0}}, {"ends", {2}}}), add4); + migraphx::make_op("slice", {{"axes", {0}}, {"starts", {0}}, {"ends", {2}}}), data); auto slc21 = mm->add_instruction( - migraphx::make_op("slice", {{"axes", {0}}, {"starts", {2}}, {"ends", {4}}}), add4); + migraphx::make_op("slice", {{"axes", {0}}, {"starts", {2}}, {"ends", {4}}}), data); auto diff2 = mm->add_instruction(migraphx::make_op("sub"), slc21, slc20); auto mul2 = mm->add_instruction(migraphx::make_op("mul"), diff2, l2); auto add2 = mm->add_instruction(migraphx::make_op("add"), mul2, slc20); + auto slc10 = mm->add_instruction( migraphx::make_op("slice", {{"axes", {0}}, {"starts", {0}}, {"ends", {1}}}), add2); auto slc11 = mm->add_instruction( diff --git a/test/onnx/parse/resize_upsample_linear_test.cpp b/test/onnx/parse/resize_upsample_linear_test.cpp index b8711bb2136..18a612c9ba4 100644 --- a/test/onnx/parse/resize_upsample_linear_test.cpp +++ b/test/onnx/parse/resize_upsample_linear_test.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 @@ -23,98 +23,11 @@ */ #include +#include TEST_CASE(resize_upsample_linear_test) { - migraphx::program p; - auto* mm = p.get_main_module(); - migraphx::shape ss{migraphx::shape::float_type, {4}}; - std::vector ds = {1, 1, 2, 2}; - mm->add_literal(migraphx::literal(ss, ds)); - - migraphx::shape sx{migraphx::shape::float_type, {1, 1, 2, 2}}; - auto x = mm->add_parameter("X", sx); - migraphx::shape s_ind{migraphx::shape::int32_type, {16, 1, 4, 4}}; - std::vector d_ind = { - 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 2, 2, 2, 3, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 2, - 2, 2, 3, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 2, 2, 2, 3, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, - 0, 1, 2, 2, 2, 3, 0, 0, 0, 1, 2, 2, 2, 3, 2, 2, 2, 3, 2, 2, 2, 3, 0, 0, 0, 1, 2, 2, 2, - 3, 2, 2, 2, 3, 2, 2, 2, 3, 0, 0, 0, 1, 2, 2, 2, 3, 2, 2, 2, 3, 2, 2, 2, 3, 0, 0, 0, 1, - 2, 2, 2, 3, 2, 2, 2, 3, 2, 2, 2, 3, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 2, 3, 3, 3, 0, - 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 2, 3, 3, 3, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 2, 3, - 3, 3, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 2, 3, 3, 3, 0, 1, 1, 1, 2, 3, 3, 3, 2, 3, 3, - 3, 2, 3, 3, 3, 0, 1, 1, 1, 2, 3, 3, 3, 2, 3, 3, 3, 2, 3, 3, 3, 0, 1, 1, 1, 2, 3, 3, 3, - 2, 3, 3, 3, 2, 3, 3, 3, 0, 1, 1, 1, 2, 3, 3, 3, 2, 3, 3, 3, 2, 3, 3, 3}; - auto l_ind = mm->add_literal(migraphx::literal(s_ind, d_ind)); - - migraphx::shape s8{migraphx::shape::float_type, {8, 1, 4, 4}}; - std::vector d8 = { - 0, 1.0f / 3, 2.0f / 3, 0, 0, 1.0f / 3, 2.0f / 3, 0, 0, 1.0f / 3, 2.0f / 3, 0, - 0, 1.0f / 3, 2.0f / 3, 0, 0, 1.0f / 3, 2.0f / 3, 0, 0, 1.0f / 3, 2.0f / 3, 0, - 0, 1.0f / 3, 2.0f / 3, 0, 0, 1.0f / 3, 2.0f / 3, 0, 0, 1.0f / 3, 2.0f / 3, 0, - 0, 1.0f / 3, 2.0f / 3, 0, 0, 1.0f / 3, 2.0f / 3, 0, 0, 1.0f / 3, 2.0f / 3, 0, - 0, 1.0f / 3, 2.0f / 3, 0, 0, 1.0f / 3, 2.0f / 3, 0, 0, 1.0f / 3, 2.0f / 3, 0, - 0, 1.0f / 3, 2.0f / 3, 0, 0, 1.0f / 3, 2.0f / 3, 0, 0, 1.0f / 3, 2.0f / 3, 0, - 0, 1.0f / 3, 2.0f / 3, 0, 0, 1.0f / 3, 2.0f / 3, 0, 0, 1.0f / 3, 2.0f / 3, 0, - 0, 1.0f / 3, 2.0f / 3, 0, 0, 1.0f / 3, 2.0f / 3, 0, 0, 1.0f / 3, 2.0f / 3, 0, - 0, 1.0f / 3, 2.0f / 3, 0, 0, 1.0f / 3, 2.0f / 3, 0, 0, 1.0f / 3, 2.0f / 3, 0, - 0, 1.0f / 3, 2.0f / 3, 0, 0, 1.0f / 3, 2.0f / 3, 0, 0, 1.0f / 3, 2.0f / 3, 0, - 0, 1.0f / 3, 2.0f / 3, 0, 0, 1.0f / 3, 2.0f / 3, 0}; - auto l8 = mm->add_literal(migraphx::literal(s8, d8)); - - migraphx::shape s4{migraphx::shape::float_type, {4, 1, 4, 4}}; - std::vector d4 = { - 0, 0, 0, 0, 1.0f / 3, 1.0f / 3, 1.0f / 3, 1.0f / 3, - 2.0f / 3, 2.0f / 3, 2.0f / 3, 2.0f / 3, 0, 0, 0, 0, - 0, 0, 0, 0, 1.0f / 3, 1.0f / 3, 1.0f / 3, 1.0f / 3, - 2.0f / 3, 2.0f / 3, 2.0f / 3, 2.0f / 3, 0, 0, 0, 0, - 0, 0, 0, 0, 1.0f / 3, 1.0f / 3, 1.0f / 3, 1.0f / 3, - 2.0f / 3, 2.0f / 3, 2.0f / 3, 2.0f / 3, 0, 0, 0, 0, - 0, 0, 0, 0, 1.0f / 3, 1.0f / 3, 1.0f / 3, 1.0f / 3, - 2.0f / 3, 2.0f / 3, 2.0f / 3, 2.0f / 3, 0, 0, 0, 0}; - auto l4 = mm->add_literal(migraphx::literal(s4, d4)); - - migraphx::shape s2{migraphx::shape::float_type, {2, 1, 4, 4}}; - std::vector d2(32, 0); - auto l2 = mm->add_literal(migraphx::literal(s2, d2)); - - migraphx::shape s1{migraphx::shape::float_type, {1, 1, 4, 4}}; - std::vector d1(16, 0.0f); - auto l1 = mm->add_literal(migraphx::literal(s1, d1)); - - mm->add_instruction(migraphx::make_op("undefined")); - auto rsp = mm->add_instruction(migraphx::make_op("reshape", {{"dims", {4}}}), x); - auto data = mm->add_instruction(migraphx::make_op("gather", {{"axis", 0}}), rsp, l_ind); - auto slc80 = mm->add_instruction( - migraphx::make_op("slice", {{"axes", {0}}, {"starts", {0}}, {"ends", {8}}}), data); - auto slc81 = mm->add_instruction( - migraphx::make_op("slice", {{"axes", {0}}, {"starts", {8}}, {"ends", {16}}}), data); - auto diff8 = mm->add_instruction(migraphx::make_op("sub"), slc81, slc80); - auto mul8 = mm->add_instruction(migraphx::make_op("mul"), diff8, l8); - auto add8 = mm->add_instruction(migraphx::make_op("add"), mul8, slc80); - auto slc40 = mm->add_instruction( - migraphx::make_op("slice", {{"axes", {0}}, {"starts", {0}}, {"ends", {4}}}), add8); - auto slc41 = mm->add_instruction( - migraphx::make_op("slice", {{"axes", {0}}, {"starts", {4}}, {"ends", {8}}}), add8); - auto diff4 = mm->add_instruction(migraphx::make_op("sub"), slc41, slc40); - auto mul4 = mm->add_instruction(migraphx::make_op("mul"), diff4, l4); - auto add4 = mm->add_instruction(migraphx::make_op("add"), mul4, slc40); - auto slc20 = mm->add_instruction( - migraphx::make_op("slice", {{"axes", {0}}, {"starts", {0}}, {"ends", {2}}}), add4); - auto slc21 = mm->add_instruction( - migraphx::make_op("slice", {{"axes", {0}}, {"starts", {2}}, {"ends", {4}}}), add4); - auto diff2 = mm->add_instruction(migraphx::make_op("sub"), slc21, slc20); - auto mul2 = mm->add_instruction(migraphx::make_op("mul"), diff2, l2); - auto add2 = mm->add_instruction(migraphx::make_op("add"), mul2, slc20); - auto slc10 = mm->add_instruction( - migraphx::make_op("slice", {{"axes", {0}}, {"starts", {0}}, {"ends", {1}}}), add2); - auto slc11 = mm->add_instruction( - migraphx::make_op("slice", {{"axes", {0}}, {"starts", {1}}, {"ends", {2}}}), add2); - auto diff1 = mm->add_instruction(migraphx::make_op("sub"), slc11, slc10); - auto mul1 = mm->add_instruction(migraphx::make_op("mul"), diff1, l1); - auto add1 = mm->add_instruction(migraphx::make_op("add"), mul1, slc10); - mm->add_return({add1}); - + auto p = create_upsample_linear_prog(); // same net IR as upsample version auto prog = read_onnx("resize_upsample_linear_test.onnx"); EXPECT(p == prog); } diff --git a/test/onnx/parse/upsample_linear_test.cpp b/test/onnx/parse/upsample_linear_test.cpp index cae67a0395e..365009cfb30 100644 --- a/test/onnx/parse/upsample_linear_test.cpp +++ b/test/onnx/parse/upsample_linear_test.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 @@ -27,7 +27,7 @@ TEST_CASE(upsample_linear_test) { - auto p = create_upsample_linear_prog(); + auto p = create_upsample_linear_prog(); // same net IR for resize & upsample auto prog = read_onnx("upsample_linear_test.onnx"); EXPECT(p == prog); } From 59f6eab759cf79fed7502939bba4c38e54b1c6e5 Mon Sep 17 00:00:00 2001 From: lakhinderwalia Date: Wed, 22 Jan 2025 10:10:12 -0800 Subject: [PATCH 3/5] Add a test model for a large linear Resize operation to check performance --- test/onnx/gen_onnx.py | 14 ++++++++++++++ test/onnx/include/onnx_test_utils.hpp | 4 ++-- test/onnx/resize_upsample_linear_large_test.onnx | Bin 0 -> 218 bytes 3 files changed, 16 insertions(+), 2 deletions(-) create mode 100644 test/onnx/resize_upsample_linear_large_test.onnx diff --git a/test/onnx/gen_onnx.py b/test/onnx/gen_onnx.py index 880aac4fed0..cfdd7af7711 100644 --- a/test/onnx/gen_onnx.py +++ b/test/onnx/gen_onnx.py @@ -11457,6 +11457,20 @@ def resize_upsample_linear_test(): return ([node], [X], [Y], [scales_tensor]) +@onnx_test() +def resize_upsample_linear_large_test(): + x = helper.make_tensor_value_info('X', TensorProto.FLOAT, + [1, 1, 1024, 1024]) + s = helper.make_tensor('scales', TensorProto.FLOAT, [4], [1, 1, 2, 2]) + y = helper.make_tensor_value_info('Y', TensorProto.FLOAT, + [1, 1, 2048, 2048]) + node = onnx.helper.make_node('Resize', + inputs=['X', '', 'scales'], + outputs=['Y'], + mode='linear') + return ([node], [x], [y], [s]) + + @onnx_test() def resize_upsample_pf_test(): scales = np.array([1.0, 1.0, 2.0, 3.0], dtype=np.float32) diff --git a/test/onnx/include/onnx_test_utils.hpp b/test/onnx/include/onnx_test_utils.hpp index 64dd85e938d..e997e615cc5 100644 --- a/test/onnx/include/onnx_test_utils.hpp +++ b/test/onnx/include/onnx_test_utils.hpp @@ -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 @@ -233,7 +233,7 @@ make_simplified_layer_norm(const std::vector& input_shape, auto x_sq = add_common_op(*mm, migraphx::make_op("mul"), {float_x, float_x}); auto norm_axis = axis < 0 ? axis + x->get_shape().lens().size() : axis; auto rms = mm->add_instruction(migraphx::make_op("reduce_mean", {{"axes", {norm_axis}}}), x_sq); - rms = mm->add_instruction(migraphx::make_op("convert", {{"target_type", dtype}}), rms); + rms = mm->add_instruction(migraphx::make_op("convert", {{"target_type", dtype}}), rms); rms = add_common_op(*mm, migraphx::make_op("add"), {rms, eps}); auto rrms = mm->add_instruction(migraphx::make_op("rsqrt"), {rms}); auto result = add_common_op(*mm, migraphx::make_op("mul"), {x, rrms}); diff --git a/test/onnx/resize_upsample_linear_large_test.onnx b/test/onnx/resize_upsample_linear_large_test.onnx new file mode 100644 index 0000000000000000000000000000000000000000..d89044e31a59929912000cd00b00d9bb01bda835 GIT binary patch literal 218 zcmdhNmEzYb;jV~=IPRuRHNsZ6R%u7uyiqA7b1Ni8n1TF1zx&BYkO#lXc@ zoSc}GS}epEsl*lp)~6-N#gdz!lB&c8(YJt+nFu4b Date: Wed, 22 Jan 2025 14:07:28 -0800 Subject: [PATCH 4/5] asan fix --- src/onnx/parse_resize.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/onnx/parse_resize.cpp b/src/onnx/parse_resize.cpp index 8c44a8f8d58..b3eda42ccab 100644 --- a/src/onnx/parse_resize.cpp +++ b/src/onnx/parse_resize.cpp @@ -412,7 +412,7 @@ struct parse_resize : op_parser auto ins_ind = info.add_literal(literal(ind_s, ind)); auto data = info.add_instruction(make_op("gather", {{"axis", 0}}), rsp, ins_ind); - std::size_t lens_idx = out_lens.size(); + std::size_t lens_idx = out_lens.size() - 1; for(std::size_t i = 0; i < r_dim; lens_idx--) { if(in_lens[lens_idx] == out_lens[lens_idx]) From 67c5b85f6081f15af27aa2b13c32e7cd2f48262e Mon Sep 17 00:00:00 2001 From: lakhinderwalia Date: Thu, 23 Jan 2025 16:38:24 -0800 Subject: [PATCH 5/5] Handle renaming related comments. Thus re-org loops a bit --- src/onnx/parse_resize.cpp | 42 +++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 22 deletions(-) diff --git a/src/onnx/parse_resize.cpp b/src/onnx/parse_resize.cpp index b3eda42ccab..a0ded6ee8d6 100644 --- a/src/onnx/parse_resize.cpp +++ b/src/onnx/parse_resize.cpp @@ -374,32 +374,33 @@ struct parse_resize : op_parser auto nearest_floor = op::resize::get_nearest_op("floor"); auto nearest_ceil = op::resize::get_nearest_op("ceil"); - std::size_t n_dim = out_lens.size(); - std::size_t r_dim = 0; // count: lens dimensions that are resized - std::size_t out_elements = 1; // count: number of elements to fix due to resize. - for(std::size_t dim = 0; dim < n_dim; dim++) + std::vector resized_axes; // vector of dimensions to be resized + std::size_t out_elements = 1; // total number of elements to be resized + for(std::size_t axis = 0; axis != out_lens.size(); ++axis) { - if(in_lens[dim] == out_lens[dim]) + if(in_lens[axis] == out_lens[axis]) continue; - r_dim++; - out_elements *= out_lens[dim]; + resized_axes.push_back(axis); + out_elements *= out_lens[axis]; } + + // Neighbor indices. For an axis. Two sets of max/min per element: std::vector> vv_ind(2, std::vector(out_elements)); - std::vector>> vvv_ind(r_dim, vv_ind); - std::vector> delta(r_dim, std::vector(out_elements)); + // Neighbor indices. For all resized axes: + std::vector>> vvv_ind(resized_axes.size(), vv_ind); + // Delta list. For each resized axes - per element. + std::vector> delta(resized_axes.size(), + std::vector(out_elements)); shape_for_each(out_s, [&](const auto& out_idx_v, std::size_t out_idx) { - std::size_t ii = 0; - for(std::size_t idx = 0; idx < in_lens.size(); ++idx) + for(size_t ii = 0; ii != resized_axes.size(); ++ii) { - if(in_lens[idx] == out_lens[idx]) - continue; + auto idx = resized_axes[ii]; auto idx_val = idx_op(in_lens[idx], out_lens[idx], out_idx_v[idx], vec_scale[idx]); vvv_ind[ii][0][out_idx] = nearest_floor(in_lens[idx], idx_val); vvv_ind[ii][1][out_idx] = nearest_ceil(in_lens[idx], idx_val); delta[ii][out_idx] = idx_val - vvv_ind[ii][0][out_idx]; - ++ii; } }); @@ -407,19 +408,17 @@ struct parse_resize : op_parser vvv_ind, 0, 0, std::vector>(out_elements), in_s, out_s); auto dim_lens = out_lens; - dim_lens[0] *= (1u << r_dim); + // indices matrix size grows 2x per resized-axis: + dim_lens[0] *= (1u << resized_axes.size()); shape ind_s{shape::int32_type, dim_lens}; auto ins_ind = info.add_literal(literal(ind_s, ind)); auto data = info.add_instruction(make_op("gather", {{"axis", 0}}), rsp, ins_ind); - std::size_t lens_idx = out_lens.size() - 1; - for(std::size_t i = 0; i < r_dim; lens_idx--) + for(auto idx = resized_axes.size(); idx; --idx) { - if(in_lens[lens_idx] == out_lens[lens_idx]) - continue; - dim_lens[0] /= 2; // halved for 2 slices of data + dim_lens[0] /= 2; // halved for 2 slices of data (hi & low below) shape dim_s{shape::float_type, dim_lens}; - const auto& dim_delta = delta[r_dim - i - 1]; + const auto& dim_delta = delta[idx - 1]; std::vector delta_data; for(std::size_t j = 0; j < dim_lens[0] / out_lens[0]; ++j) delta_data.insert(delta_data.begin(), dim_delta.begin(), dim_delta.end()); @@ -437,7 +436,6 @@ struct parse_resize : op_parser auto diff = info.add_instruction(make_op("sub"), hi, low); auto ddf = info.add_instruction(make_op("mul"), diff, ins_delta); data = info.add_instruction(make_op("add"), ddf, low); - i++; } return data; }