Unverified Commit 23cb7917 authored by Brian Pickrell's avatar Brian Pickrell Committed by GitHub
Browse files

Merge branch 'develop' into blas_tuning

parents b5fcc0bc ea32ca70
......@@ -38,6 +38,15 @@ namespace op {
struct quantizelinear
{
std::string name() const { return "quantizelinear"; }
value attributes() const
{
// Note: point_op attribute is not used in this op. Instead, in
// gpu compilation pipeline, rewrite_quantization will be invoked
// from generate_pointwise() to rewrite this op.
return {{"pointwise", true}};
}
shape compute_shape(std::vector<shape> inputs) const
{
check_shapes{inputs, *this}.same_dims().has(2, 3);
......
......@@ -29,6 +29,7 @@
#include <migraphx/config.hpp>
#include <migraphx/value.hpp>
#include <migraphx/dyn_output.hpp>
#include <migraphx/optional.hpp>
namespace migraphx {
inline namespace MIGRAPHX_INLINE_NS {
......@@ -96,9 +97,115 @@ struct reshape
return {s0.type(), output_dyn_dims};
}
template <class Iterator>
static auto compute_end_dim(Iterator start, Iterator last, std::size_t dim)
{
std::size_t x = 1;
auto it = std::find_if(start, last, [&](auto i) {
x *= i;
return x >= dim;
});
if(x != dim)
return start;
return it;
}
template <class DimIterator, class StrideIterator>
static auto can_strides_merge(DimIterator dim_start,
DimIterator dim_last,
StrideIterator stride_start,
StrideIterator stride_last)
{
assert(std::distance(dim_start, dim_last) == std::distance(stride_start, stride_last));
auto cstride = *std::prev(stride_last);
return std::equal(std::make_reverse_iterator(dim_last),
std::make_reverse_iterator(dim_start + 1),
std::make_reverse_iterator(stride_last - 1),
std::make_reverse_iterator(stride_start),
[&](auto dim, auto stride) {
cstride *= dim;
return stride == cstride;
});
}
// This will reshape the dimesions of the input shape to use the lens of
// `rdims`. If this can't be done without changing memory layout then it
// will return nullopt
static optional<shape> reshape_dims(const shape& input, const std::vector<std::size_t>& rdims)
{
if(input.standard())
return shape{input.type(), rdims};
const auto& idims = input.lens();
const auto& istrides = input.strides();
std::vector<std::size_t> rstrides;
std::size_t i = 0;
std::size_t r = 0;
while(i < idims.size() and r < rdims.size())
{
auto idim = idims[i];
auto rdim = rdims[r];
if(rdim == idim)
{
rstrides.push_back(istrides[i]);
}
// squeeze
else if(rdim > idim)
{
auto start = idims.begin() + i;
auto it = compute_end_dim(start, idims.end(), rdim);
if(it == start)
return nullopt;
auto n = it - start;
assert((i + n) <= istrides.size());
if(not can_strides_merge(
start, it + 1, istrides.begin() + i, istrides.begin() + i + n + 1))
return nullopt;
i += n;
rstrides.push_back(istrides[i]);
}
// unsqueeze
else // if(rdim < idim)
{
auto start = rdims.begin() + i;
auto it = compute_end_dim(start, rdims.end(), idim);
if(it == start)
return nullopt;
auto n = it - start;
assert((r + n) <= rdims.size());
auto stride = istrides[i] * idim;
std::for_each(start, it + 1, [&](auto dim) {
stride /= dim;
rstrides.push_back(stride);
});
r += n;
}
i++;
r++;
}
// Handle trailing 1s
if(rstrides.size() < rdims.size() and not rstrides.empty())
{
auto stride = rstrides.back();
for(auto d : range(rdims.begin() + rstrides.size(), rdims.end()))
{
if(d != 1)
return nullopt;
rstrides.push_back(stride);
}
}
if(rdims.size() != rstrides.size())
return nullopt;
return shape{input.type(), rdims, rstrides};
}
shape static_compute_shape(std::vector<shape> inputs, std::size_t n_neg_dims) const
{
check_shapes{inputs, *this}.standard();
check_shapes{inputs, *this}.has(1);
auto&& idims = inputs.front().lens();
std::vector<std::size_t> rdims(dims.begin(), dims.end());
......@@ -125,12 +232,17 @@ struct reshape
}
}
shape s{inputs.front().type(), rdims};
if(s.elements() != inputs.front().elements())
auto s = reshape_dims(inputs.front(), rdims);
if(not s.has_value())
MIGRAPHX_THROW("Reshape on axis that is not packed.");
if(s->elements() != inputs.front().elements())
MIGRAPHX_THROW("Reshape: Wrong number of elements for reshape: reshape has " +
std::to_string(s.elements()) + " elements whereas the input has " +
std::to_string(s->elements()) + " elements whereas the input has " +
std::to_string(inputs.front().elements()));
return s;
assert(s->bytes() == inputs.front().bytes());
return *s;
}
shape compute_shape(std::vector<shape> inputs) const
......
/*
* The MIT License (MIT)
*
* Copyright (c) 2015-2022 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_RTGLIB_RUN_ON_TARGET_HPP
#define MIGRAPHX_GUARD_RTGLIB_RUN_ON_TARGET_HPP
#include <unordered_map>
#include <vector>
#include <set>
#include <algorithm>
#include <migraphx/config.hpp>
#include <migraphx/errors.hpp>
#include <migraphx/shape.hpp>
#include <migraphx/argument.hpp>
#include <migraphx/module.hpp>
namespace migraphx {
inline namespace MIGRAPHX_INLINE_NS {
namespace op {
struct run_on_target
{
std::size_t target_id = 0;
std::string name() const { return "run_on_target"; }
template <class Self, class F>
static auto reflect(Self& self, F f)
{
return pack(f(self.target_id, "target_id"));
}
migraphx::shape compute_shape(const std::vector<migraphx::shape>& inputs,
std::vector<migraphx::module_ref> mods) const
{
if(mods.size() != 1)
{
MIGRAPHX_THROW("RUN_ON_TARGET: must have exactly 1 module argument");
}
auto* mod_input = mods.front();
if(inputs.size() != mod_input->get_parameter_shapes().size())
{
MIGRAPHX_THROW("RUN_ON_TARGET: Mismatched number of input parameters");
}
auto mod_out_shapes = mod_input->get_output_shapes();
return mod_out_shapes;
}
migraphx::argument
compute(const migraphx::shape&,
const std::vector<migraphx::argument>& args,
const std::vector<migraphx::module_ref>& mods,
const std::function<std::vector<migraphx::argument>(
migraphx::module_ref&, const std::unordered_map<std::string, migraphx::argument>&)>&
run) const
{
std::unordered_map<std::string, migraphx::argument> params;
std::set<std::string> pnames;
const auto* smod = mods.front();
assert(mods.size() == 1);
auto names = smod->get_parameter_names();
pnames.insert(names.begin(), names.end());
assert(pnames.size() == args.size());
std::transform(pnames.begin(),
pnames.end(),
args.begin(),
std::inserter(params, params.end()),
[](auto&& name, auto&& arg) { return std::make_pair(name, arg); });
auto* mod = mods.front();
auto results = run(mod, params);
return migraphx::argument{results};
}
};
} // namespace op
} // namespace MIGRAPHX_INLINE_NS
} // namespace migraphx
#endif
......@@ -125,7 +125,7 @@ struct select_module
auto ps = param_shapes.at(name);
if(a.get_shape() != ps)
{
assert(ps.bytes() == a.get_shape().bytes());
assert(ps.bytes() <= a.get_shape().bytes());
return std::make_pair(name, a.reshape(ps));
}
else
......
......@@ -95,13 +95,10 @@ struct unsqueeze
auto type = input_shape.type();
auto old_lens = input_shape.lens();
auto old_strides = input_shape.strides();
if(input_shape.scalar())
{
if(old_lens.size() == 1 and old_lens.front() == 1)
auto is_scalar = input_shape.scalar();
if(is_scalar and old_lens.size() == 1 and old_lens.front() == 1)
return shape{type, old_lens};
else
MIGRAPHX_THROW("UNSQUEEZE: Input must be a scalar");
}
if(steps.size() > axes.size())
MIGRAPHX_THROW("UNSQUEEZE: Steps provided with no axis");
......@@ -121,13 +118,15 @@ struct unsqueeze
step = steps[axis_idx];
if(step == 0)
MIGRAPHX_THROW("UNSQUEEZE: step must be non-zero");
if(is_scalar and step != 1)
MIGRAPHX_THROW("UNSQUEEZE: step must be 1 when input is scalar");
new_lens[i] = step;
if(p < old_strides.size())
{
if((old_lens[p] % step) != 0)
MIGRAPHX_THROW("UNSQUEEZE: Axis dimenstion is not divisible by step");
old_lens[p] /= step;
new_strides[i] = old_strides[p] * old_lens[p];
new_strides[i] = is_scalar ? 1 : old_strides[p] * old_lens[p];
}
else
{
......
......@@ -143,7 +143,7 @@ auto compute_shape_op(rank<2>, const T& x, const std::vector<shape>& inputs)
if(inputs.empty())
MIGRAPHX_THROW("At least one input is required for " + x.name());
dependent_type<operation, T> y = x;
normalize_attributes(y, inputs[0].max_lens());
normalize_attributes(y, inputs[0]);
return any_cast<T>(y).normalize_compute_shape(inputs);
}
......@@ -251,9 +251,10 @@ auto compute_op(rank<1>,
const shape& output,
const std::vector<argument>& inputs,
const std::vector<module_ref>& module_args,
F f)
-> decltype(
x.compute(make_compute_output_shape(pack(x, output, inputs)), inputs, module_args, f))
F f) -> decltype(x.compute(make_compute_output_shape(pack(x, output, inputs)),
inputs,
module_args,
f))
{
return x.compute(make_compute_output_shape(pack(x, output, inputs)), inputs, module_args, f);
}
......@@ -261,11 +262,13 @@ auto compute_op(rank<1>,
template <class T, class F>
argument compute_op(rank<0>,
const T& x,
const shape&,
const std::vector<argument>&,
const std::vector<module_ref>&,
const shape& output,
const std::vector<argument>& inputs,
const std::vector<module_ref>& module_args,
F)
{
if(module_args.empty())
return compute_op(x, output, inputs);
std::string name = x.name();
MIGRAPHX_THROW("Not computable: " + name);
}
......@@ -307,9 +310,10 @@ auto compute_op(rank<3>,
const shape& output,
const std::vector<argument>& inputs,
const std::vector<module_ref>& module_args,
F f)
-> decltype(
x.compute(make_compute_output_shape(pack(x, output, inputs)), inputs, module_args, f))
F f) -> decltype(x.compute(make_compute_output_shape(pack(x, output, inputs)),
inputs,
module_args,
f))
{
return x.compute(make_compute_output_shape(pack(x, output, inputs)), inputs, module_args, f);
}
......@@ -497,7 +501,7 @@ lifetime get_lifetime_op(const T&)
#ifdef TYPE_ERASED_DECLARATION
// Type-erased interface for:
struct operation
struct MIGRAPHX_EXPORT operation
{
//
std::string name() const;
......@@ -571,7 +575,7 @@ struct operation
{
using std::swap;
auto* derived = this->any_cast<PrivateDetailTypeErasedT>();
if(derived and private_detail_te_handle_mem_var.unique())
if(derived and private_detail_te_handle_mem_var.use_count() == 1)
{
*derived = std::forward<PrivateDetailTypeErasedT>(value);
}
......@@ -1261,7 +1265,7 @@ struct operation
private_detail_te_handle_base_type& private_detail_te_get_handle()
{
assert(private_detail_te_handle_mem_var != nullptr);
if(not private_detail_te_handle_mem_var.unique())
if(private_detail_te_handle_mem_var.use_count() > 1)
private_detail_te_handle_mem_var = private_detail_te_handle_mem_var->clone();
return *private_detail_te_handle_mem_var;
}
......@@ -1388,8 +1392,8 @@ bool has_finalize(const T& x)
return detail::has_finalize_op(x);
}
void migraphx_to_value(value& v, const operation& op);
void migraphx_from_value(const value& v, operation& op);
MIGRAPHX_EXPORT void migraphx_to_value(value& v, const operation& op);
MIGRAPHX_EXPORT void migraphx_from_value(const value& v, operation& op);
#endif
......
......@@ -45,9 +45,10 @@
#include <migraphx/op/contiguous.hpp>
#include <migraphx/op/convert.hpp>
#include <migraphx/op/convolution.hpp>
#include <migraphx/op/convolution_backwards.hpp>
#include <migraphx/op/cosh.hpp>
#include <migraphx/op/cos.hpp>
#include <migraphx/op/deconvolution.hpp>
#include <migraphx/op/dimensions_of.hpp>
#include <migraphx/op/div.hpp>
#include <migraphx/op/dot.hpp>
#include <migraphx/op/elu.hpp>
......
......@@ -36,7 +36,7 @@ struct module_pass_manager;
/**
* Runs several passes in a loop
*/
struct optimize_module
struct MIGRAPHX_EXPORT optimize_module
{
std::string name() const { return "optimize_module"; }
void apply(module_pass_manager& mpm) const;
......
......@@ -32,6 +32,7 @@
namespace migraphx {
inline namespace MIGRAPHX_INLINE_NS {
MIGRAPHX_EXPORT
void calculate_padding(int64_t idx,
std::vector<int64_t>& pads,
int64_t input_dim,
......@@ -45,6 +46,7 @@ void calculate_padding(int64_t idx,
* where the padding calculation must be done at evaluation time.
* \return padding in the form of {x0_begin, x1_begin, ... x0_end , x1_end, ...}
*/
MIGRAPHX_EXPORT
std::vector<std::size_t> calc_dyn_auto_pad(const std::vector<std::size_t>& input_lens,
const std::vector<std::size_t>& wei_lens,
const std::vector<std::size_t>& strides,
......@@ -53,6 +55,7 @@ std::vector<std::size_t> calc_dyn_auto_pad(const std::vector<std::size_t>& input
// Used for dynamic auto padding of convolution operators since padding needs to be computed at
// evaulation time.
MIGRAPHX_EXPORT
shape compute_padded_shape(const shape& input,
const shape& weights,
const std::vector<std::size_t>& padding,
......
......@@ -57,7 +57,7 @@ struct pass
#else
module& get_module(module_pass_manager& mpm);
MIGRAPHX_EXPORT module& get_module(module_pass_manager& mpm);
namespace detail {
......@@ -84,7 +84,7 @@ void module_pass_manager_apply(const T& x, module_pass_manager& mpm)
#ifdef TYPE_ERASED_DECLARATION
// Type-erased interface for:
struct pass
struct MIGRAPHX_EXPORT pass
{
//
std::string name() const;
......@@ -116,7 +116,7 @@ struct pass
{
using std::swap;
auto* derived = this->any_cast<PrivateDetailTypeErasedT>();
if(derived and private_detail_te_handle_mem_var.unique())
if(derived and private_detail_te_handle_mem_var.use_count() == 1)
{
*derived = std::forward<PrivateDetailTypeErasedT>(value);
}
......@@ -292,7 +292,7 @@ struct pass
private_detail_te_handle_base_type& private_detail_te_get_handle()
{
assert(private_detail_te_handle_mem_var != nullptr);
if(not private_detail_te_handle_mem_var.unique())
if(private_detail_te_handle_mem_var.use_count() > 1)
private_detail_te_handle_mem_var = private_detail_te_handle_mem_var->clone();
return *private_detail_te_handle_mem_var;
}
......
......@@ -26,6 +26,7 @@
#include <migraphx/config.hpp>
#include <migraphx/pass.hpp>
#include <migraphx/module_ref.hpp>
#include <migraphx/tracer.hpp>
#include <vector>
......@@ -46,8 +47,14 @@ struct module_pass_manager
virtual ~module_pass_manager() {}
};
void run_passes(module& mod, const std::vector<pass>& passes, tracer trace = tracer{});
void run_passes(program& prog, const std::vector<pass>& passes, tracer trace = tracer{});
MIGRAPHX_EXPORT void run_passes(program& prog,
module_ref root_mod,
const std::vector<pass>& passes,
tracer trace = tracer{});
MIGRAPHX_EXPORT void
run_passes(module& mod, const std::vector<pass>& passes, tracer trace = tracer{});
MIGRAPHX_EXPORT void
run_passes(program& prog, const std::vector<pass>& passes, tracer trace = tracer{});
} // namespace MIGRAPHX_INLINE_NS
} // namespace migraphx
......
......@@ -43,7 +43,7 @@ inline Vector reorder_dims(const Vector& dims, const std::vector<int64_t>& permu
return result;
}
shape reorder_shape(const shape& s, const std::vector<int64_t>& permutation);
MIGRAPHX_EXPORT shape reorder_shape(const shape& s, const std::vector<int64_t>& permutation);
template <class Vector, class Op>
inline std::vector<int64_t> sort_permutation(const Vector& data, Op op)
......@@ -56,15 +56,19 @@ inline std::vector<int64_t> sort_permutation(const Vector& data, Op op)
}
/*!
* Returns the permutation needed to apply to the shape to undo the current permutation
* Returns the inverse permutation that could be applied to undo the inputted permutation
*/
std::vector<int64_t> invert_permutation(const std::vector<int64_t>& permutation);
MIGRAPHX_EXPORT std::vector<int64_t> invert_permutation(const std::vector<int64_t>& permutation);
/*!
* Finds the permutation most likely from a transpose operator that has been applied to the shape.
* Finds the permutation that would make the shape not transposed (refering to shape.transposed())
*/
std::vector<int64_t> find_permutation(const shape& s);
std::vector<int64_t> find_permutation(const std::vector<shape>& shapes);
MIGRAPHX_EXPORT std::vector<int64_t> find_permutation(const shape& s);
MIGRAPHX_EXPORT std::vector<int64_t> find_permutation(const std::vector<shape>& shapes);
/// Normalize the shapes so the order of dimensions will be in the order it is
/// in memory as much as possible.
MIGRAPHX_EXPORT std::vector<shape> normalize_permutation(const std::vector<shape>& shapes);
} // namespace MIGRAPHX_INLINE_NS
} // namespace migraphx
......
......@@ -32,7 +32,7 @@ inline namespace MIGRAPHX_INLINE_NS {
struct module;
struct preallocate_param
struct MIGRAPHX_EXPORT preallocate_param
{
std::string param;
allocation_model model;
......
......@@ -35,7 +35,7 @@ inline namespace MIGRAPHX_INLINE_NS {
struct process_impl;
struct process
struct MIGRAPHX_EXPORT process
{
using writer = std::function<void(const char*, std::size_t)>;
process(const std::string& cmd);
......
......@@ -54,7 +54,7 @@ struct marker;
/**
* @brief Stores the instruction stream
*/
struct program
struct MIGRAPHX_EXPORT program
{
program();
......@@ -79,6 +79,9 @@ struct program
std::vector<argument> eval(parameter_map params,
execution_environment exec_env = execution_environment{}) const;
void finish() const;
std::size_t size() const;
std::vector<shape> get_output_shapes() const;
......@@ -92,6 +95,9 @@ struct program
void compile(const target& t, compile_options options = compile_options{});
void compile(const std::vector<target>& targets,
std::vector<compile_options> compile_opts = {});
bool is_compiled() const;
void finalize();
......@@ -124,8 +130,8 @@ struct program
program& sort();
friend std::ostream& operator<<(std::ostream& os, const program& p);
friend bool operator==(const program& x, const program& y);
MIGRAPHX_EXPORT friend std::ostream& operator<<(std::ostream& os, const program& p);
MIGRAPHX_EXPORT friend bool operator==(const program& x, const program& y);
friend bool operator!=(const program& x, const program& y) { return not(x == y); }
// module related api
......
......@@ -35,7 +35,7 @@ inline namespace MIGRAPHX_INLINE_NS {
* Replace literals in submodules with literals in the root module.
* Intended to allow for reuse of the literals between submodules.
*/
struct promote_literals
struct MIGRAPHX_EXPORT promote_literals
{
std::string name() const { return "promote_literals"; }
void apply(module_pass_manager&) const;
......
......@@ -35,7 +35,7 @@ struct module;
/**
* Replace instructions which take all literals with a literal of the computation.
*/
struct propagate_constant
struct MIGRAPHX_EXPORT propagate_constant
{
std::string name() const { return "propagate_constant"; }
void apply(module& m) const;
......
......@@ -38,12 +38,14 @@ inline namespace MIGRAPHX_INLINE_NS {
struct program;
void quantize_fp16(program& prog, const std::vector<std::string>& ins_names = {"all"});
MIGRAPHX_EXPORT void quantize_fp16(program& prog,
const std::vector<std::string>& ins_names = {"all"});
void quantize_int8(program& prog,
MIGRAPHX_EXPORT void quantize_int8(program& prog,
const target& t,
const std::vector<parameter_map>& calibration,
const std::vector<std::string>& ins_names = {"dot", "convolution"});
const std::vector<std::string>& ins_names = {"dot",
"convolution"});
} // namespace MIGRAPHX_INLINE_NS
} // namespace migraphx
......
......@@ -37,7 +37,7 @@ struct module;
/**
* quantize a program to fp16
*/
struct quantize_fp16_pass
struct MIGRAPHX_EXPORT quantize_fp16_pass
{
std::vector<std::string> ins_names = {"all"};
std::string name() const { return "quantize_fp16"; }
......
......@@ -39,7 +39,7 @@ struct module;
/**
* capture inputs of operators to be quantized to int8
*/
struct capture_arguments_pass
struct MIGRAPHX_EXPORT capture_arguments_pass
{
std::vector<std::string> ins_names = {"dot", "convolution"};
std::function<void(std::size_t, std::vector<argument>)> f{};
......@@ -51,7 +51,7 @@ struct capture_arguments_pass
/**
* quantize a program to int8
*/
struct quantize_int8_pass
struct MIGRAPHX_EXPORT quantize_int8_pass
{
std::vector<std::string> ins_names = {"dot", "convolution"};
std::vector<std::pair<float, float>> quant_params;
......
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