Commit 6ad1e633 authored by Brian Pickrell's avatar Brian Pickrell
Browse files

Update multinomial to newer random functions with no attributes; update tests

parent 606ed5e8
/*
* 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.
*/
/**
* Random Uniform distribution operator. Given a shape, populate it with random values.
*
* Inputs: (1) the shape of the set to be populated.
* (2) randomization seed. Optional--if not given, a seed will be generated
* automatically, for nonrepeatable random results.
* Attributes: TBD
*
Output: Same shape.
*
*/
#ifndef MIGRAPHX_GUARD_OPERATORS_MULTINOMIAL_HPP
#define MIGRAPHX_GUARD_OPERATORS_MULTINOMIAL_HPP
#include <migraphx/check_shapes.hpp>
// #include <migraphx/argument.hpp>
#include <migraphx/par_for.hpp>
// #include <migraphx/reflect.hpp>
#include <random>
namespace migraphx {
inline namespace MIGRAPHX_INLINE_NS {
namespace op {
struct rand_uniform
{
// uint32_t sample_size = {20};
uint32_t seed = {0};
bool use_auto_seed = false;
float range_min = 0.0f;
float range_max = 1.0f;
// From Onnx RandomUniform:
// dtype : int (default is 1) The data type for the elements of the output tensor. currently
// float only. high : float (default is 1.0) Upper boundary of the output values. low : float
// (default is 0.0) Lower boundary of the output values. seed : float (Optional) Seed to the
// random generator, if not specified we will auto generate one. shape : list of ints (required)
// The shape of the output tensor.
// In Onnx, the size of array to fill is given by
// TODO: consider removing this and simply using the type of the passed argument.
// The only bar to doing this currently is that we can't create random integers within the
// current bounds of (0, 1).
shape::type_t dtype = shape::type_t::float_type;
std::vector<size_t> output_lens = {};
template <class Self, class F>
static auto reflect(Self& self, F f)
{
return pack(f(self.dtype, "dtype"),
f(self.output_lens, "output_lens"),
f(self.seed, "seed"),
f(self.use_auto_seed, "use_auto_seed"));
}
// value attributes() const { return {{"sample_size", sample_size}, {"seed", seed}}; }
std::string name() const { return "rand_uniform"; }
shape compute_shape(std::vector<shape> inputs) const
{
check_shapes{inputs, *this, true}.has(1, 2);
if(inputs.size() > 1 and inputs.at(1).element_space() > 0 and
inputs.at(1).type() != shape::type_t::uint32_type)
MIGRAPHX_THROW("RAND_UNIFORM: Input 2 (seed) must have type unsigned int");
auto s = inputs.front();
if(s.dynamic())
{
return s.with_type(dtype);
}
else
{
return s.with_lens(s.lens()).with_type(dtype);
}
}
argument compute(const dyn_output& dyn_out, std::vector<argument> args) const
{
(void)args; // suppress compiler warning
argument result{dyn_out.computed_shape};
auto local_seed(seed);
if(use_auto_seed)
local_seed = std::chrono::system_clock::now().time_since_epoch().count();
else
{
if(args.size() > 1)
{
if(args.at(1).get_shape().element_space() > 0)
{
visit_all(args[1])([&](auto data) { local_seed = data[0]; });
}
else // This is a bit of an Easter Egg.
// If a seed argument was given but it has a 0-size shape at
// inference time, also obtain a seed from the system clock:
local_seed = std::chrono::system_clock::now().time_since_epoch().count();
}
}
// If a seed argument was not defined, use the value from the seed attribute,
// or the default.
std::mt19937 gen(local_seed);
std::uniform_real_distribution<> dis(range_min, range_max);
result.visit([&](auto output) {
std::generate(output.begin(), output.end(), [&]() { return dis(gen); });
});
return result;
}
};
} // namespace op
} // namespace MIGRAPHX_INLINE_NS
} // namespace migraphx
#endif
...@@ -66,25 +66,30 @@ struct parse_multinomial : op_parser<parse_multinomial> ...@@ -66,25 +66,30 @@ struct parse_multinomial : op_parser<parse_multinomial>
cdf = info.add_instruction( cdf = info.add_instruction(
migraphx::make_op("prefix_scan_sum", {{"axis", 1}, {"exclusive", false}}), cdf); migraphx::make_op("prefix_scan_sum", {{"axis", 1}, {"exclusive", false}}), cdf);
uint32_t seed(0); instruction_ref seed_input;
if(contains(info.attributes, "seed")) if(contains(info.attributes, "seed"))
seed = info.attributes.at("seed").i(); {
uint32_t seed = info.attributes.at("seed").i();
migraphx::shape s{migraphx::shape::uint32_type, {1}};
std::vector<uint32_t> data = {seed};
seed_input = info.add_literal(migraphx::literal(s, data));
}
else
{
seed_input = info.add_instruction(migraphx::make_op("random_seed"));
}
instruction_ref randoms; instruction_ref randoms;
if(args.size() > 0) if(args.size() > 0)
{ {
shape s0 = args[0]->get_shape(); shape s0 = args[0]->get_shape();
// TODO: Use literal if batch size is fixed
if(s0.dynamic()) if(s0.dynamic())
{ {
// Dynamic batch_size will be taken from args[0]. Other contents of input are // Dynamic batch_size will be taken from args[0]. Other contents of input are
// ignored here. // ignored here.
randoms = info.add_instruction( randoms =
migraphx::make_op("rand_uniform", info.add_instruction(migraphx::make_op("random_uniform"), seed_input, args[0]);
{{"seed", seed},
// {"sample_size", sample_size},
{"use_auto_seed", not contains(info.attributes, "seed")}}),
args[0]);
} }
else else
{ {
...@@ -94,10 +99,7 @@ struct parse_multinomial : op_parser<parse_multinomial> ...@@ -94,10 +99,7 @@ struct parse_multinomial : op_parser<parse_multinomial>
migraphx::literal{migraphx::shape::float_type, {batch_size * sample_size}}); migraphx::literal{migraphx::shape::float_type, {batch_size * sample_size}});
randoms = info.add_instruction( randoms = info.add_instruction(
migraphx::make_op( migraphx::make_op("random_uniform"), seed_input, rand_dummy);
"rand_uniform",
{{"seed", seed}, {"use_auto_seed", not contains(info.attributes, "seed")}}),
rand_dummy);
} }
} }
else else
...@@ -105,8 +107,8 @@ struct parse_multinomial : op_parser<parse_multinomial> ...@@ -105,8 +107,8 @@ struct parse_multinomial : op_parser<parse_multinomial>
// use literal. It may be quite large. // use literal. It may be quite large.
auto rand_dummy = info.add_literal( auto rand_dummy = info.add_literal(
migraphx::literal{migraphx::shape::float_type, {batch_size * sample_size}}); migraphx::literal{migraphx::shape::float_type, {batch_size * sample_size}});
randoms = info.add_instruction(migraphx::make_op("rand_uniform", {{"seed", seed}}), randoms =
rand_dummy); info.add_instruction(migraphx::make_op("random_uniform"), seed_input, rand_dummy);
} }
return info.add_instruction( return info.add_instruction(
......
...@@ -4175,10 +4175,13 @@ TEST_CASE(multinomial_test) ...@@ -4175,10 +4175,13 @@ TEST_CASE(multinomial_test)
cdf = mm->add_instruction( cdf = mm->add_instruction(
migraphx::make_op("prefix_scan_sum", {{"axis", 1}, {"exclusive", false}}), cdf); migraphx::make_op("prefix_scan_sum", {{"axis", 1}, {"exclusive", false}}), cdf);
migraphx::shape s{migraphx::shape::uint32_type, {1}};
std::vector<float> seed_data = {seed};
auto seed_input = mm->add_literal(migraphx::literal(s, seed_data));
auto rand_dummy = auto rand_dummy =
mm->add_literal(migraphx::literal{migraphx::shape::float_type, {batch_size * sample_size}}); mm->add_literal(migraphx::literal{migraphx::shape::float_type, {batch_size * sample_size}});
auto randoms =
mm->add_instruction(migraphx::make_op("rand_uniform", {{"seed", seed}}), rand_dummy); auto randoms = mm->add_instruction(migraphx::make_op("random_uniform"), seed_input, rand_dummy);
mm->add_instruction(migraphx::make_op("multinomial"), cdf, randoms); mm->add_instruction(migraphx::make_op("multinomial"), cdf, randoms);
auto prog = optimize_onnx("multinomial_test.onnx"); auto prog = optimize_onnx("multinomial_test.onnx");
...@@ -4205,10 +4208,11 @@ TEST_CASE(multinomial_dyn_test) ...@@ -4205,10 +4208,11 @@ TEST_CASE(multinomial_dyn_test)
migraphx::shape rs{migraphx::shape::float_type, {1, sample_size}}; migraphx::shape rs{migraphx::shape::float_type, {1, sample_size}};
std::vector<float> data(rs.elements(), 0.3f); std::vector<float> data(rs.elements(), 0.3f);
auto randoms = mm->add_instruction(migraphx::make_op("rand_uniform", migraphx::shape s{migraphx::shape::uint32_type, {1}};
{// {"sample_size", sample_size}, std::vector<float> seed_data = {seed};
{"seed", seed}}), auto seed_input = mm->add_literal(migraphx::literal(s, seed_data));
input);
auto randoms = mm->add_instruction(migraphx::make_op("random_uniform"), seed_input, input);
auto ret = mm->add_instruction(migraphx::make_op("multinomial"), cdf, randoms); auto ret = mm->add_instruction(migraphx::make_op("multinomial"), cdf, randoms);
mm->add_return({ret}); mm->add_return({ret});
...@@ -4238,11 +4242,8 @@ TEST_CASE(multinomial_autoseed_dyn_test) ...@@ -4238,11 +4242,8 @@ TEST_CASE(multinomial_autoseed_dyn_test)
migraphx::shape rs{migraphx::shape::float_type, {1, sample_size}}; migraphx::shape rs{migraphx::shape::float_type, {1, sample_size}};
std::vector<float> data(rs.elements(), 0.3f); std::vector<float> data(rs.elements(), 0.3f);
auto randoms = mm->add_instruction(migraphx::make_op("rand_uniform", auto seed_input = mm->add_instruction(migraphx::make_op("random_seed"));
{// {"sample_size", sample_size}, auto randoms = mm->add_instruction(migraphx::make_op("random_uniform"), seed_input, input);
// {"seed", seed},
{"use_auto_seed", true}}),
input);
auto ret = mm->add_instruction(migraphx::make_op("multinomial"), cdf, randoms); auto ret = mm->add_instruction(migraphx::make_op("multinomial"), cdf, randoms);
mm->add_return({ret}); mm->add_return({ret});
...@@ -4285,13 +4286,16 @@ TEST_CASE(multinomial_int64_test) ...@@ -4285,13 +4286,16 @@ TEST_CASE(multinomial_int64_test)
cdf = mm->add_instruction( cdf = mm->add_instruction(
migraphx::make_op("prefix_scan_sum", {{"axis", 1}, {"exclusive", false}}), cdf); migraphx::make_op("prefix_scan_sum", {{"axis", 1}, {"exclusive", false}}), cdf);
migraphx::shape rs{migraphx::shape::float_type, {1, sample_size}}; // this is random_uniform without output_lens attribute
migraphx::shape s{migraphx::shape::uint32_type, {1}};
std::vector<uint32_t> seed_data = {seed};
auto seed_input = mm->add_literal(migraphx::literal(s, seed_data));
auto rand_dummy = auto rand_dummy =
mm->add_literal(migraphx::literal{migraphx::shape::float_type, {sample_size}}); mm->add_literal(migraphx::literal{migraphx::shape::float_type, {sample_size}});
// this is rand_uniform without output_lens attribute auto randoms = mm->add_instruction(migraphx::make_op("random_uniform"), seed_input, rand_dummy);
auto randoms = mm->add_instruction(
migraphx::make_op("rand_uniform", {{"seed", seed}, {"use_auto_seed", false}}), rand_dummy);
mm->add_instruction(migraphx::make_op("multinomial", {{"dtype", dtype}}), cdf, randoms); mm->add_instruction(migraphx::make_op("multinomial", {{"dtype", dtype}}), cdf, randoms);
......
...@@ -5305,16 +5305,16 @@ TEST_CASE(multinomial_dyn_test) ...@@ -5305,16 +5305,16 @@ TEST_CASE(multinomial_dyn_test)
auto* mm = p.get_main_module(); auto* mm = p.get_main_module();
size_t sample_size = 1000000; size_t sample_size = 1000000;
uint32_t seed = 4;
// Shape of the random data // Shape of the random data
migraphx::shape rs{migraphx::shape::float_type, {{1, 2}, {2, sample_size + 1}}}; migraphx::shape rs{migraphx::shape::float_type, {{1, 2}, {2, sample_size + 1}}};
auto input = mm->add_parameter("Input_1", rs); auto input = mm->add_parameter("Input_1", rs);
// Runtime randomization seed // Runtime randomization seed
// To seed the rand_uniform, we can provide a value by literal or input, // To seed the random_uniform, we can provide a value by literal or input,
// or we can pass it a 0-size shape in which case it will auto-seed. // or ask the system to auto-seed with random_seed op.
migraphx::shape seed_shape{migraphx::shape::uint32_type, {migraphx::shape::dynamic_dimension{0, 1}}}; migraphx::shape seed_shape{migraphx::shape::uint32_type,
{migraphx::shape::dynamic_dimension{0, 1}}};
auto seed_input = mm->add_parameter("Seed", seed_shape); auto seed_input = mm->add_parameter("Seed", seed_shape);
// Shape of the probability distribution, which also defines the number of categories // Shape of the probability distribution, which also defines the number of categories
...@@ -5338,12 +5338,7 @@ TEST_CASE(multinomial_dyn_test) ...@@ -5338,12 +5338,7 @@ TEST_CASE(multinomial_dyn_test)
cdf = mm->add_instruction( cdf = mm->add_instruction(
migraphx::make_op("prefix_scan_sum", {{"axis", 1}, {"exclusive", false}}), cdf); migraphx::make_op("prefix_scan_sum", {{"axis", 1}, {"exclusive", false}}), cdf);
auto randoms = mm->add_instruction(migraphx::make_op("rand_uniform", auto randoms = mm->add_instruction(migraphx::make_op("random_uniform"), seed_input, input);
{
{"seed", seed},
}),
input,
seed_input);
mm->add_instruction(migraphx::make_op("multinomial"), cdf, randoms); mm->add_instruction(migraphx::make_op("multinomial"), cdf, randoms);
p.compile(migraphx::make_target("ref")); p.compile(migraphx::make_target("ref"));
...@@ -5355,8 +5350,8 @@ TEST_CASE(multinomial_dyn_test) ...@@ -5355,8 +5350,8 @@ TEST_CASE(multinomial_dyn_test)
migraphx::parameter_map params0; migraphx::parameter_map params0;
params0["Input_1"] = migraphx::argument(input_fixed_shape1, dummy.data()); params0["Input_1"] = migraphx::argument(input_fixed_shape1, dummy.data());
migraphx::shape seed_fixed_shape{migraphx::shape::uint32_type, {0}}; migraphx::shape seed_fixed_shape{migraphx::shape::uint32_type, {1}};
std::vector<uint32_t> seed_data = {}; std::vector<uint32_t> seed_data = {4};
params0["Seed"] = migraphx::argument(seed_fixed_shape, seed_data.data()); params0["Seed"] = migraphx::argument(seed_fixed_shape, seed_data.data());
params0["Input_2"] = migraphx::argument(input_fixed_shape2, data.data()); params0["Input_2"] = migraphx::argument(input_fixed_shape2, data.data());
......
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