Unverified Commit 0da1037f authored by Charlie Lin's avatar Charlie Lin Committed by GitHub
Browse files

`fill` ref operator (#2087)

Implements a fill operator that sets the values in an output buffer to a given value
Will be used when parsing ONNX ConstantOfShape
Can also be used when a buffer needs to be filled with a value that is determined at runtime
parent fcdb8c2a
...@@ -142,6 +142,7 @@ register_migraphx_ops( ...@@ -142,6 +142,7 @@ register_migraphx_ops(
equal equal
erf erf
exp exp
fill
flatten flatten
floor floor
fmod fmod
......
...@@ -153,7 +153,7 @@ struct check_shapes ...@@ -153,7 +153,7 @@ struct check_shapes
{ {
if(begin != end) if(begin != end)
{ {
if(begin->max_lens().size() != n) if(begin->ndim() != n)
MIGRAPHX_THROW(prefix() + "Only " + std::to_string(n) + "d supported"); MIGRAPHX_THROW(prefix() + "Only " + std::to_string(n) + "d supported");
} }
return *this; return *this;
...@@ -168,7 +168,7 @@ struct check_shapes ...@@ -168,7 +168,7 @@ struct check_shapes
{ {
if(begin != end) if(begin != end)
{ {
if(begin->max_lens().size() > n) if(begin->ndim() > n)
MIGRAPHX_THROW(prefix() + "Shape must have at most " + std::to_string(n) + MIGRAPHX_THROW(prefix() + "Shape must have at most " + std::to_string(n) +
" dimensions"); " dimensions");
} }
...@@ -184,7 +184,7 @@ struct check_shapes ...@@ -184,7 +184,7 @@ struct check_shapes
{ {
if(begin != end) if(begin != end)
{ {
if(begin->max_lens().size() < n) if(begin->ndim() < n)
MIGRAPHX_THROW(prefix() + "Shape must have at least " + std::to_string(n) + MIGRAPHX_THROW(prefix() + "Shape must have at least " + std::to_string(n) +
" dimensions"); " dimensions");
} }
...@@ -254,6 +254,16 @@ struct check_shapes ...@@ -254,6 +254,16 @@ struct check_shapes
return *this; return *this;
} }
/*!
* Check all shapes are scalar.
*/
const check_shapes& scalar() const
{
if(not this->all_of([](const shape& s) { return s.scalar(); }))
MIGRAPHX_THROW(prefix() + "Shapes are not a scalar");
return *this;
}
/*! /*!
* Check all shapes are standard or scalar. * Check all shapes are standard or scalar.
*/ */
......
/*
* The MIT License (MIT)
*
* Copyright (c) 2015-2023 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.
*/
#ifndef MIGRAPHX_GUARD_OPERATORS_FILL_HPP
#define MIGRAPHX_GUARD_OPERATORS_FILL_HPP
#include <migraphx/check_shapes.hpp>
#include <migraphx/dyn_output.hpp>
#include <migraphx/par_for.hpp>
namespace migraphx {
inline namespace MIGRAPHX_INLINE_NS {
namespace op {
/**
* fill(default_value, output_buffer)
* Fill an output buffer with the given default_value.
* Note that if the default_value is a literal and the output_buffer
* has a static shape this operator can be replaced with a literal.
*/
struct fill
{
std::string name() const { return "fill"; }
shape compute_shape(std::vector<shape> inputs) const
{
check_shapes{inputs, *this, true}.has(2).same_type();
if(inputs.at(0).dynamic() or inputs.at(0).elements() != 1)
{
MIGRAPHX_THROW("FILL: default_value is dynamic or more than one element");
}
return inputs.back();
}
argument compute(const dyn_output& dyn_out, std::vector<argument> args) const
{
visit_all(args[0], args[1])([&](auto value, auto output) {
par_for(dyn_out.computed_shape.elements(), [&](auto i) { output[i] = value.front(); });
});
return args[1];
}
std::ptrdiff_t output_alias(const std::vector<shape>&) const { return 1; }
};
} // namespace op
} // namespace MIGRAPHX_INLINE_NS
} // namespace migraphx
#endif
...@@ -55,6 +55,7 @@ ...@@ -55,6 +55,7 @@
#include <migraphx/op/equal.hpp> #include <migraphx/op/equal.hpp>
#include <migraphx/op/erf.hpp> #include <migraphx/op/erf.hpp>
#include <migraphx/op/exp.hpp> #include <migraphx/op/exp.hpp>
#include <migraphx/op/fill.hpp>
#include <migraphx/op/flatten.hpp> #include <migraphx/op/flatten.hpp>
#include <migraphx/op/floor.hpp> #include <migraphx/op/floor.hpp>
#include <migraphx/op/fmod.hpp> #include <migraphx/op/fmod.hpp>
......
...@@ -890,6 +890,50 @@ TEST_CASE(flatten_dyn_axis4) ...@@ -890,6 +890,50 @@ TEST_CASE(flatten_dyn_axis4)
input); input);
} }
TEST_CASE(fill_static_int)
{
migraphx::shape default_value{migraphx::shape::int64_type, {1}, {0}};
migraphx::shape data{migraphx::shape::int64_type, {3, 4, 4}};
expect_shape(migraphx::shape{migraphx::shape::int64_type, {3, 4, 4}},
migraphx::make_op("fill"),
default_value,
data);
}
TEST_CASE(fill_static_float)
{
migraphx::shape default_value{migraphx::shape::float_type, {1}, {0}};
migraphx::shape data{migraphx::shape::float_type, {4, 8}};
expect_shape(migraphx::shape{migraphx::shape::float_type, {4, 8}},
migraphx::make_op("fill"),
default_value,
data);
}
TEST_CASE(fill_dyn_int)
{
migraphx::shape default_value{migraphx::shape::int64_type, {1}, {0}};
migraphx::shape data{migraphx::shape::int64_type,
{{1, 4}, {4, 8, {4, 6, 8}}, {4, 8, {4, 6, 8}}}};
expect_shape(migraphx::shape{migraphx::shape::int64_type,
{{1, 4}, {4, 8, {4, 6, 8}}, {4, 8, {4, 6, 8}}}},
migraphx::make_op("fill"),
default_value,
data);
}
TEST_CASE(fill_dyn_float)
{
migraphx::shape default_value{migraphx::shape::float_type, {1}, {0}};
migraphx::shape data{migraphx::shape::float_type,
{{1, 4}, {4, 8, {4, 6, 8}}, {4, 8, {4, 6, 8}}}};
expect_shape(migraphx::shape{migraphx::shape::float_type,
{{1, 4}, {4, 8, {4, 6, 8}}, {4, 8, {4, 6, 8}}}},
migraphx::make_op("fill"),
default_value,
data);
}
TEST_CASE(gather) TEST_CASE(gather)
{ {
{ {
......
/*
* The MIT License (MIT)
*
* Copyright (c) 2015-2023 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 <migraphx/instruction.hpp>
#include <migraphx/literal.hpp>
#include <migraphx/make_op.hpp>
#include <migraphx/onnx.hpp>
#include <migraphx/register_target.hpp>
#include <migraphx/verify.hpp>
#include <test.hpp>
TEST_CASE(fill_static_int)
{
// Note this case can be simplified to a literal
migraphx::program p;
auto* mm = p.get_main_module();
migraphx::shape lit_shape{migraphx::shape::int64_type, {1}, {0}};
std::vector<int64_t> lit_data = {3};
auto l = mm->add_literal(migraphx::literal{lit_shape, lit_data});
migraphx::shape data_shape{migraphx::shape::int64_type, {3, 4, 4}};
auto input = mm->add_parameter("x", data_shape);
mm->add_instruction(migraphx::make_op("fill"), l, input);
p.compile(migraphx::make_target("ref"));
std::vector<int64_t> input_data(48);
migraphx::parameter_map params;
params["x"] = migraphx::argument(data_shape, input_data.data());
auto result = p.eval(params).back();
std::vector<int64_t> results_vector;
result.visit([&](auto output) { results_vector.assign(output.begin(), output.end()); });
std::vector<int64_t> gold(48, 3);
EXPECT(migraphx::verify::verify_range(results_vector, gold));
}
TEST_CASE(fill_dyn_float)
{
migraphx::program p;
auto* mm = p.get_main_module();
migraphx::shape lit_shape{migraphx::shape::float_type, {1}, {0}};
std::vector<float> lit_data = {7.36};
auto l = mm->add_literal(migraphx::literal{lit_shape, lit_data});
migraphx::shape data_shape{migraphx::shape::float_type,
{{1, 4}, {4, 8, {4, 6, 8}}, {4, 8, {4, 6, 8}}}};
auto input = mm->add_parameter("x", data_shape);
mm->add_instruction(migraphx::make_op("fill"), l, input);
p.compile(migraphx::make_target("ref"));
std::vector<float> input_data(72);
migraphx::parameter_map params;
migraphx::shape static_shape = {migraphx::shape::float_type, {2, 6, 6}};
params["x"] = migraphx::argument(static_shape, input_data.data());
auto result = p.eval(params).back();
std::vector<float> results_vector;
result.visit([&](auto output) { results_vector.assign(output.begin(), output.end()); });
std::vector<float> gold(72, 7.36);
EXPECT(migraphx::verify::verify_range(results_vector, gold));
}
TEST_CASE(fill_var_default_value)
{
migraphx::program p;
auto* mm = p.get_main_module();
migraphx::shape dv_shape{migraphx::shape::int64_type, {1}, {0}};
auto dv = mm->add_parameter("dv", dv_shape);
migraphx::shape data_shape{migraphx::shape::int64_type, {3, 4, 4}};
auto input = mm->add_parameter("x", data_shape);
mm->add_instruction(migraphx::make_op("fill"), dv, input);
p.compile(migraphx::make_target("ref"));
std::vector<int64_t> dv_data = {2};
std::vector<int64_t> input_data(48);
migraphx::parameter_map params;
params["x"] = migraphx::argument(data_shape, input_data.data());
params["dv"] = migraphx::argument(dv_shape, dv_data.data());
auto result = p.eval(params).back();
std::vector<int64_t> results_vector;
result.visit([&](auto output) { results_vector.assign(output.begin(), output.end()); });
std::vector<int64_t> gold(48, 2);
EXPECT(migraphx::verify::verify_range(results_vector, gold));
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment