Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
gaoqiong
MIGraphX
Commits
538dbd75
Commit
538dbd75
authored
Dec 05, 2023
by
Brian Pickrell
Browse files
Merge branch 'develop' into resize_op
parents
c7161d99
e3e00547
Changes
182
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
1335 additions
and
465 deletions
+1335
-465
src/onnx/parse_multinomial.cpp
src/onnx/parse_multinomial.cpp
+3
-3
src/onnx/parse_pooling.cpp
src/onnx/parse_pooling.cpp
+11
-207
src/onnx/parse_qlinearpooling.cpp
src/onnx/parse_qlinearpooling.cpp
+115
-0
src/onnx/parse_qlinearunary.cpp
src/onnx/parse_qlinearunary.cpp
+151
-0
src/onnx/parse_scatternd.cpp
src/onnx/parse_scatternd.cpp
+7
-5
src/onnx/parse_unique.cpp
src/onnx/parse_unique.cpp
+92
-0
src/onnx/pooling.cpp
src/onnx/pooling.cpp
+247
-0
src/rewrite_pooling.cpp
src/rewrite_pooling.cpp
+131
-17
src/schedule.cpp
src/schedule.cpp
+2
-2
src/simplify_dyn_ops.cpp
src/simplify_dyn_ops.cpp
+134
-21
src/targets/cpu/dnnl.cpp
src/targets/cpu/dnnl.cpp
+1
-0
src/targets/cpu/lowering.cpp
src/targets/cpu/lowering.cpp
+12
-1
src/targets/cpu/pooling.cpp
src/targets/cpu/pooling.cpp
+13
-4
src/targets/gpu/CMakeLists.txt
src/targets/gpu/CMakeLists.txt
+0
-4
src/targets/gpu/compile_gen.cpp
src/targets/gpu/compile_gen.cpp
+10
-0
src/targets/gpu/compile_hip.cpp
src/targets/gpu/compile_hip.cpp
+27
-23
src/targets/gpu/compile_hip_code_object.cpp
src/targets/gpu/compile_hip_code_object.cpp
+1
-1
src/targets/gpu/device/include/migraphx/gpu/device/scan.hpp
src/targets/gpu/device/include/migraphx/gpu/device/scan.hpp
+15
-7
src/targets/gpu/driver/precompile_op.cpp
src/targets/gpu/driver/precompile_op.cpp
+84
-0
src/targets/gpu/fuse_mlir.cpp
src/targets/gpu/fuse_mlir.cpp
+279
-170
No files found.
src/onnx/parse_multinomial.cpp
View file @
538dbd75
...
@@ -127,9 +127,9 @@ struct parse_multinomial : op_parser<parse_multinomial>
...
@@ -127,9 +127,9 @@ struct parse_multinomial : op_parser<parse_multinomial>
// use literal. The array populated by random_uniform may have any shape, as long its
// use literal. The array populated by random_uniform may have any shape, as long its
// number of elements is batch_size * sample_size .
// number of elements is batch_size * sample_size .
size_t
batch_size
=
s0
.
lens
().
front
();
size_t
batch_size
=
s0
.
lens
().
front
();
auto
rand_dummy
=
info
.
add_literal
(
auto
rand_dummy
=
info
.
add_literal
(
migraphx
::
literal
{
migraphx
::
literal
{
migraphx
::
shape
::
float_type
,
{
batch_size
*
sample_size
}}
);
migraphx
::
shape
{
migraphx
::
shape
::
float_type
,
{
batch_size
,
sample_size
}}
,
std
::
vector
<
float
>
(
batch_size
*
sample_size
)});
randoms
=
randoms
=
info
.
add_instruction
(
migraphx
::
make_op
(
"random_uniform"
),
seed_input
,
rand_dummy
);
info
.
add_instruction
(
migraphx
::
make_op
(
"random_uniform"
),
seed_input
,
rand_dummy
);
}
}
...
...
src/onnx/parse_pooling.cpp
View file @
538dbd75
...
@@ -22,14 +22,8 @@
...
@@ -22,14 +22,8 @@
* THE SOFTWARE.
* THE SOFTWARE.
*/
*/
#include <migraphx/onnx/op_parser.hpp>
#include <migraphx/onnx/op_parser.hpp>
#include <migraphx/onnx/checks.hpp>
#include <migraphx/onnx/pooling.hpp>
#include <migraphx/onnx/padding.hpp>
#include <migraphx/op/pad.hpp>
#include <migraphx/op/pooling.hpp>
#include <migraphx/instruction.hpp>
#include <migraphx/instruction.hpp>
#include <migraphx/ranges.hpp>
#include <migraphx/stringutils.hpp>
#include <migraphx/make_op.hpp>
namespace
migraphx
{
namespace
migraphx
{
inline
namespace
MIGRAPHX_INLINE_NS
{
inline
namespace
MIGRAPHX_INLINE_NS
{
...
@@ -39,68 +33,14 @@ struct parse_pooling : op_parser<parse_pooling>
...
@@ -39,68 +33,14 @@ struct parse_pooling : op_parser<parse_pooling>
{
{
std
::
vector
<
op_desc
>
operators
()
const
std
::
vector
<
op_desc
>
operators
()
const
{
{
return
{{
"AveragePool"
,
"average"
},
return
{
{
"AveragePool"
,
"average"
},
{
"GlobalAveragePool"
,
"average"
},
{
"GlobalAveragePool"
,
"average"
},
{
"GlobalMaxPool"
,
"max"
},
{
"GlobalMaxPool"
,
"max"
},
{
"MaxPool"
,
"max"
},
{
"MaxPool"
,
"max"
},
{
"LpPool"
,
"lpnorm"
},
{
"LpPool"
,
"lpnorm"
},
{
"GlobalLpPool"
,
"lpnorm"
}};
{
"GlobalLpPool"
,
"lpnorm"
},
}
};
value
handle_values
(
const
op_desc
&
opd
,
onnx_parser
::
node_info
info
,
const
shape
&
in_shape
,
value
values
)
const
{
auto
kdims
=
in_shape
.
ndim
()
-
2
;
if
(
starts_with
(
opd
.
onnx_name
,
"Global"
))
{
// if spatial dimensions are dynamic use dyn_global flag
if
(
in_shape
.
dynamic
()
and
std
::
any_of
(
in_shape
.
dyn_dims
().
cbegin
()
+
2
,
in_shape
.
dyn_dims
().
cend
(),
[](
auto
dd
)
{
return
not
dd
.
is_fixed
();
}))
{
values
[
"dyn_global"
]
=
true
;
values
[
"lengths"
]
=
std
::
vector
<
size_t
>
();
}
else
{
// works with static and fixed dynamic shape
auto
m_lens
=
in_shape
.
max_lens
();
values
[
"lengths"
]
=
std
::
vector
<
size_t
>
(
m_lens
.
begin
()
+
2
,
m_lens
.
end
());
}
}
if
(
contains
(
info
.
attributes
,
"ceil_mode"
))
{
values
[
"ceil_mode"
]
=
static_cast
<
bool
>
(
info
.
attributes
.
at
(
"ceil_mode"
).
i
());
}
if
(
contains
(
info
.
attributes
,
"strides"
))
{
values
[
"stride"
].
clear
();
copy
(
info
.
attributes
[
"strides"
].
ints
(),
std
::
back_inserter
(
values
[
"stride"
]));
check_attr_sizes
(
kdims
,
values
[
"stride"
].
size
(),
"PARSE_POOLING: inconsistent strides"
);
}
if
(
contains
(
info
.
attributes
,
"kernel_shape"
))
{
values
[
"lengths"
].
clear
();
copy
(
info
.
attributes
[
"kernel_shape"
].
ints
(),
std
::
back_inserter
(
values
[
"lengths"
]));
check_attr_sizes
(
kdims
,
values
[
"lengths"
].
size
(),
"PARSE_POOLING: inconsistent lengths"
);
}
// lp_order attribute
if
(
contains
(
info
.
attributes
,
"p"
))
{
values
[
"lp_order"
]
=
info
.
attributes
.
at
(
"p"
).
i
();
}
// ensure pads available only when auto_pad is "NOT_SET"
check_padding_mode
(
info
,
"POOLING"
);
return
values
;
}
}
instruction_ref
parse
(
const
op_desc
&
opd
,
instruction_ref
parse
(
const
op_desc
&
opd
,
...
@@ -108,144 +48,8 @@ struct parse_pooling : op_parser<parse_pooling>
...
@@ -108,144 +48,8 @@ struct parse_pooling : op_parser<parse_pooling>
onnx_parser
::
node_info
info
,
onnx_parser
::
node_info
info
,
std
::
vector
<
instruction_ref
>
args
)
const
std
::
vector
<
instruction_ref
>
args
)
const
{
{
std
::
string
mode
=
opd
.
op_name
;
return
add_pooling_op
(
opd
,
std
::
move
(
info
),
args
[
0
]);
const
std
::
unordered_map
<
std
::
string
,
op
::
pooling_mode
>
mode_map
=
{
};
{
"max"
,
op
::
pooling_mode
::
max
},
{
"average"
,
op
::
pooling_mode
::
average
},
{
"lpnorm"
,
op
::
pooling_mode
::
lpnorm
}};
if
(
not
contains
(
mode_map
,
mode
))
{
MIGRAPHX_THROW
(
"PARSE_POOLING: onnx pooling mode must be [
\"
max
\"
,
\"
average
\"
,
\"
lpnorm
\"
]"
);
}
operation
op
=
make_op
(
"pooling"
,
{{
"mode"
,
mode_map
.
at
(
mode
)}});
value
values
=
op
.
to_value
();
auto
l0
=
args
[
0
];
auto
in_shape
=
l0
->
get_shape
();
assert
(
in_shape
.
ndim
()
>
2
);
auto
kdims
=
in_shape
.
ndim
()
-
2
;
values
=
handle_values
(
opd
,
info
,
in_shape
,
values
);
// count include padding, if count include pad is 1, we always use
// explicit pad
int
count_include_pad
=
0
;
if
(
contains
(
info
.
attributes
,
"count_include_pad"
))
{
if
(
in_shape
.
dynamic
())
{
MIGRAPHX_THROW
(
"PARSE_POOLING: count_include_pad attribute is not supported for "
"dynamic input shape"
);
}
count_include_pad
=
info
.
attributes
.
at
(
"count_include_pad"
).
i
();
}
std
::
vector
<
int64_t
>
paddings
;
float
pad_val
=
((
mode
==
"max"
)
?
std
::
numeric_limits
<
float
>::
lowest
()
:
0.0
f
);
if
(
contains
(
info
.
attributes
,
"pads"
))
{
values
[
"padding"
].
clear
();
copy
(
info
.
attributes
[
"pads"
].
ints
(),
std
::
back_inserter
(
paddings
));
check_attr_sizes
(
kdims
,
paddings
.
size
()
/
2
,
"PARSE_POOLING: inconsistent explicit paddings"
);
}
if
(
paddings
.
size
()
!=
2
*
kdims
)
{
paddings
.
resize
(
kdims
*
2
);
std
::
fill_n
(
paddings
.
begin
(),
2
*
kdims
,
0
);
}
if
(
values
[
"padding"
].
size
()
!=
kdims
)
{
values
[
"padding"
].
resize
(
kdims
);
std
::
fill_n
(
values
[
"padding"
].
begin
(),
kdims
,
0
);
}
if
(
values
[
"stride"
].
size
()
!=
kdims
)
{
values
[
"stride"
].
resize
(
kdims
);
std
::
fill_n
(
values
[
"stride"
].
begin
(),
kdims
,
1
);
}
// used to calculate the supposed output shape
std
::
vector
<
int64_t
>
orig_padding
=
paddings
;
// TODO: add parsing for dilations
if
(
contains
(
info
.
attributes
,
"auto_pad"
)
and
to_upper
(
info
.
attributes
[
"auto_pad"
].
s
())
!=
"NOTSET"
)
{
auto
auto_pad
=
to_upper
(
info
.
attributes
[
"auto_pad"
].
s
());
// don't use the given padding sizes, if any
// values["padding"].clear();
if
(
in_shape
.
dynamic
())
{
// set padding_mode to trigger auto padding at runtime
bool
is_same_upper
=
(
auto_pad
.
find
(
"SAME_UPPER"
)
!=
std
::
string
::
npos
);
values
[
"padding_mode"
]
=
is_same_upper
?
to_value
(
op
::
padding_mode_t
::
same_upper
)
:
to_value
(
op
::
padding_mode_t
::
same_lower
);
}
else
{
// Calculate auto padding
// dilations (argument 4) not supported; default to all 1's
cal_auto_padding_size
(
info
,
values
,
values
[
"lengths"
].
to_vector
<
std
::
size_t
>
(),
std
::
vector
<
size_t
>
(
in_shape
.
ndim
()
-
2
,
1
),
in_shape
.
lens
(),
paddings
);
values
[
"padding"
]
=
paddings
;
// default padding_mode indicates that padding sizes are not calculated dynamically
values
[
"padding_mode"
]
=
migraphx
::
op
::
padding_mode_t
::
default_
;
}
}
std
::
vector
<
int64_t
>
slice_start
;
std
::
vector
<
int64_t
>
slice_end
;
tune_padding_size
(
values
,
paddings
,
count_include_pad
,
slice_start
);
if
(
not
slice_start
.
empty
())
{
if
(
in_shape
.
dynamic
())
{
MIGRAPHX_THROW
(
"PARSE_POOLING: asymmetric padding not supported for dynamic input shape"
);
}
// calculate expected output shape
orig_padding
.
insert
(
orig_padding
.
begin
()
+
kdims
,
2
,
0
);
orig_padding
.
insert
(
orig_padding
.
begin
(),
2
,
0
);
op
::
pad
pad
{
orig_padding
,
0.0
f
};
shape
padded_shape
=
pad
.
compute_shape
({
l0
->
get_shape
()});
// make an op just to get its output shape
auto
out_lens
=
make_op
(
"pooling"
,
values
).
compute_shape
({
padded_shape
}).
lens
();
// compute slice_end information
slice_end
.
resize
(
slice_start
.
size
());
std
::
transform
(
out_lens
.
begin
()
+
2
,
out_lens
.
end
(),
slice_start
.
begin
(),
slice_end
.
begin
(),
[](
auto
i
,
auto
j
)
{
return
i
+
j
;
});
}
values
[
"padding"
]
=
std
::
vector
<
size_t
>
(
paddings
.
begin
(),
paddings
.
end
());
check_asym_padding
(
info
,
l0
,
paddings
,
values
,
count_include_pad
,
pad_val
);
op
.
from_value
(
values
);
auto
l1
=
info
.
add_instruction
(
op
,
l0
);
if
(
not
slice_start
.
empty
())
{
std
::
vector
<
int64_t
>
axes
(
kdims
);
std
::
iota
(
axes
.
begin
(),
axes
.
end
(),
2
);
l1
=
info
.
add_instruction
(
make_op
(
"slice"
,
{{
"axes"
,
axes
},
{
"starts"
,
slice_start
},
{
"ends"
,
slice_end
}}),
l1
);
}
return
l1
;
}
};
};
}
// namespace onnx
}
// namespace onnx
...
...
src/onnx/parse_qlinear
glavg
pool.cpp
→
src/onnx/parse_qlinearpool
ing
.cpp
View file @
538dbd75
...
@@ -23,6 +23,7 @@
...
@@ -23,6 +23,7 @@
*/
*/
#include <migraphx/onnx/op_parser.hpp>
#include <migraphx/onnx/op_parser.hpp>
#include <migraphx/onnx/pooling.hpp>
#include <migraphx/ranges.hpp>
#include <migraphx/ranges.hpp>
#include <migraphx/op/pooling.hpp>
#include <migraphx/op/pooling.hpp>
#include <migraphx/make_op.hpp>
#include <migraphx/make_op.hpp>
...
@@ -36,90 +37,56 @@ namespace onnx {
...
@@ -36,90 +37,56 @@ namespace onnx {
/*
/*
*********************************************************************************
*********************************************************************************
* Reference: see QLinear
GlobalAveragePool in
*
* Reference: see QLinear
AveragePool and QLinearGlobalAveragePool in
*
* github.com/microsoft/onnxruntime/blob/main/docs/ContribOperators.md *
* github.com/microsoft/onnxruntime/blob/main/docs/ContribOperators.md *
*********************************************************************************
*********************************************************************************
*/
QLinearGlobalAveragePool consumes an input tensor X and applies
struct
parse_qlinearpooling
:
op_parser
<
parse_qlinearpooling
>
Average pooling across the values in the same channel. This is
equivalent to AveragePool with kernel size equal to the spatial
dimension of input tensor. Input is of type uint8_t or int8_t.
Version
This version of the operator has been available since version 1 of the 'com.microsoft' operator set.
Attributes
channels_last : int
Inputs
X : T
Input data tensor from the previous operator; According to channels_last, dimensions for image case
are (N x C x H x W), or (N x H x W x C) where N is the batch size, C is the number of channels, and
H and W are the height and the width of the data. For non image case, the dimensions are in the form
of (N x C x D1 x D2 ... Dn), or (N x D1 X D2 ... Dn x C) where N is the batch size.
x_scale : tensor(float)
Scale of quantized input 'X'. It must be a scalar.
x_zero_point : T
Zero point tensor for input 'X'. It must be a scalar.
y_scale : tensor(float)
Scale of quantized output 'Y'. It must be a scalar.
y_zero_point : T
Zero point tensor for output 'Y'. It must be a scalar.
Outputs
Y : T
Output data tensor from pooling across the input tensor. The output tensor has the same rank as the
input. with the N and C value keep it value, while the other dimensions are all 1. Type Constraints
T : tensor(uint8), tensor(int8)
Constrain input and output types to signed/unsigned int8 tensors.
*/
struct
parse_qlinearglobalaveragepool
:
op_parser
<
parse_qlinearglobalaveragepool
>
{
{
std
::
vector
<
op_desc
>
operators
()
const
{
return
{{
"QLinearGlobalAveragePool"
}};
}
std
::
vector
<
op_desc
>
operators
()
const
// basic type checking for QLinearGlobalAveragePool Operator
void
check_inputs
(
const
std
::
vector
<
instruction_ref
>&
args
)
const
{
{
if
(
args
.
size
()
<
5
)
return
{{
"QLinearGlobalAveragePool"
,
"average"
},
{
"QLinearAveragePool"
,
"average"
}};
MIGRAPHX_THROW
(
"QLINEARGLOBALAVERAGEPOOL: missing inputs"
);
}
void
check_inputs
(
const
op_desc
&
opd
,
const
std
::
vector
<
instruction_ref
>&
args
)
const
{
const
auto
&
in_x
=
args
[
0
];
const
auto
&
in_x
=
args
[
0
];
const
auto
&
zero_pt_x
=
args
[
2
];
const
auto
onnx_name
=
opd
.
onnx_name
;
const
auto
&
zero_pt_y
=
args
[
4
];
if
(
in_x
->
get_shape
().
ndim
()
<=
2
)
if
(
in_x
->
get_shape
().
ndim
()
<=
2
)
MIGRAPHX_THROW
(
"QLINEARGLOBALAVERAGEPOOL
: input dimensions too small"
);
MIGRAPHX_THROW
(
onnx_name
+
"
: input dimensions too small"
);
auto
type_x
=
in_x
->
get_shape
().
type
();
auto
type_x
=
in_x
->
get_shape
().
type
();
if
(
type_x
!=
migraphx
::
shape
::
int8_type
and
type_x
!=
migraphx
::
shape
::
uint8_type
)
if
(
type_x
!=
migraphx
::
shape
::
int8_type
and
type_x
!=
migraphx
::
shape
::
uint8_type
)
MIGRAPHX_THROW
(
"QLINEARGLOBALAVERAGEPOOL
: unsupported input type"
);
MIGRAPHX_THROW
(
onnx_name
+
"
: unsupported input type"
);
const
auto
&
zero_pt_x
=
args
[
2
];
if
(
type_x
!=
zero_pt_x
->
get_shape
().
type
())
if
(
type_x
!=
zero_pt_x
->
get_shape
().
type
())
MIGRAPHX_THROW
(
"QLINEARGLOBALAVERAGEPOOL
: mismatched type: input zero point"
);
MIGRAPHX_THROW
(
onnx_name
+
"
: mismatched type: input zero point"
);
if
(
args
.
size
()
==
5
)
{
const
auto
&
zero_pt_y
=
args
[
4
];
if
(
type_x
!=
zero_pt_y
->
get_shape
().
type
())
if
(
type_x
!=
zero_pt_y
->
get_shape
().
type
())
MIGRAPHX_THROW
(
"QLINEARGLOBALAVERAGEPOOL: mismatched type: output zero point"
);
MIGRAPHX_THROW
(
onnx_name
+
": mismatched type: output zero point"
);
}
}
}
instruction_ref
parse
(
const
op_desc
&
/* opd */
,
instruction_ref
parse
(
const
op_desc
&
opd
,
const
onnx_parser
&
parser
,
const
onnx_parser
&
parser
,
const
onnx_parser
::
node_info
&
info
,
const
onnx_parser
::
node_info
&
info
,
const
std
::
vector
<
instruction_ref
>&
args
)
const
const
std
::
vector
<
instruction_ref
>&
args
)
const
{
if
(
contains
(
info
.
attributes
,
"channel_last"
))
{
{
int
channels_last
=
int
channels_last
=
parser
.
parse_value
(
info
.
attributes
.
at
(
"channels_last"
)).
template
at
<
int
>();
parser
.
parse_value
(
info
.
attributes
.
at
(
"channels_last"
)).
template
at
<
int
>();
if
(
channels_last
!=
0
)
if
(
channels_last
!=
0
)
MIGRAPHX_THROW
(
MIGRAPHX_THROW
(
opd
.
onnx_name
+
": channels_last (N x D1..Dn x C) is not supported"
);
"QLINEARGLOBALAVERAGEPOOL: channels_last (N x D1..Dn x C) is not supported"
);
}
check_inputs
(
args
);
check_inputs
(
opd
,
args
);
// Input: X
// Input: X
...
@@ -128,21 +95,18 @@ struct parse_qlinearglobalaveragepool : op_parser<parse_qlinearglobalaveragepool
...
@@ -128,21 +95,18 @@ struct parse_qlinearglobalaveragepool : op_parser<parse_qlinearglobalaveragepool
const
auto
&
zero_pt_x
=
args
[
2
];
const
auto
&
zero_pt_x
=
args
[
2
];
auto
dquant_x
=
bcast_qdq_instr
(
"dequantizelinear"
,
in_x
,
scale_x
,
zero_pt_x
,
info
);
auto
dquant_x
=
bcast_qdq_instr
(
"dequantizelinear"
,
in_x
,
scale_x
,
zero_pt_x
,
info
);
// Output Y = globalaveragepool(X)
// Output Y = pooling_op(X)
auto
op
=
migraphx
::
op
::
pooling
{
migraphx
::
op
::
pooling_mode
::
average
};
auto
lens
=
in_x
->
get_shape
().
lens
();
std
::
vector
<
size_t
>
lengths
(
lens
.
begin
()
+
2
,
lens
.
end
());
op
.
lengths
=
lengths
;
op
.
padding
=
std
::
vector
<
size_t
>
(
lens
.
size
());
auto
out_y
=
info
.
add_instruction
(
op
,
dquant_x
);
const
auto
&
scale_y
=
args
[
3
];
auto
out_y
=
add_pooling_op
(
opd
,
info
,
dquant_x
);
const
auto
&
zero_pt_y
=
args
[
4
];
auto
out_quant_y
=
bcast_qdq_instr
(
"quantizelinear"
,
out_y
,
scale_y
,
zero_pt_y
,
info
);
const
auto
&
in_scale_y
=
args
[
3
];
// zero_pt for Y is supplied as the last optional argument..
if
(
args
.
size
()
==
5
)
return
(
bcast_qdq_instr
(
"quantizelinear"
,
out_y
,
in_scale_y
,
args
[
4
],
info
));
return
out_quant_y
;
// if no zero_pt: just broadcast the scale..
auto
bcast_scale_y
=
bcast_scalar_instr
(
out_y
->
get_shape
(),
in_scale_y
,
info
);
return
(
info
.
add_instruction
(
migraphx
::
make_op
(
"quantizelinear"
),
out_y
,
bcast_scale_y
));
}
}
};
};
...
...
src/onnx/parse_qlinearunary.cpp
0 → 100644
View file @
538dbd75
/*
* 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/onnx/op_parser.hpp>
#include <migraphx/ranges.hpp>
#include <migraphx/common.hpp>
#include <migraphx/make_op.hpp>
#include <migraphx/onnx/checks.hpp>
#include <migraphx/onnx/broadcast_qdq.hpp>
#include <migraphx/op/pooling.hpp>
#include <migraphx/instruction.hpp>
namespace
migraphx
{
inline
namespace
MIGRAPHX_INLINE_NS
{
namespace
onnx
{
/*
*********************************************************************************
* Reference: see QLinearSigmoid, QLinearLeakyRelu in *
* https://github.com/microsoft/onnxruntime/blob/main/docs/ContribOperators.md *
*********************************************************************************
com.microsoft.QLinearSigmoid
QLinearSigmoid takes quantized input data (Tensor), and quantize parameter for output, and produces
one output data (Tensor) where the function f(x) = quantize(Sigmoid(dequantize(x))), is applied to
the data tensor elementwise. Where the function Sigmoid(x) = 1 / (1 + exp(-x))
Version
This version of the operator has been available since version 1 of the 'com.microsoft' operator
set.
*****************************************************************************************************
com.microsoft.QLinearLeakyRelu
QLinearLeakyRelu takes quantized input data (Tensor), an argument alpha, and quantize parameter for
output, and produces one output data (Tensor) where the function f(x) = quantize(alpha *
dequantize(x)) for dequantize(x) < 0, f(x) = quantize(dequantize(x)) for dequantize(x) >= 0, is
applied to the data tensor elementwise.
Version
This version of the operator has been available since version 1 of the 'com.microsoft' operator set.
Attributes
alpha : float
Coefficient of leakage.
******************************************************************************************************
Generic input layout of QLinear unary operators:
Inputs (4 - 5)
X : T
Input tensor
X_scale : tensor(float)
Input X's scale. It's a scalar, which means a per-tensor/layer quantization.
X_zero_point (optional) : T
Input X's zero point. Default value is 0 if it's not specified. It's a scalar, which means a
per-tensor/layer quantization.
Y_scale : tensor(float) Output Y's scale. It's a scalar, which means
a per-tensor/layer quantization.
Y_zero_point (optional) : T Output Y's zero point. Default value is
0 if it's not specified. It's a scalar, which means a per-tensor/layer quantization.
Outputs
Y : T
Output tensor
Type Constraints
T : tensor(uint8), tensor(int8)
Constrain input and output types to 8 bit tensors.
*/
struct
parse_qlinearunary
:
op_parser
<
parse_qlinearunary
>
{
std
::
vector
<
op_desc
>
operators
()
const
{
return
{{
"QLinearSigmoid"
,
"sigmoid"
},
{
"QLinearLeakyRelu"
,
"leaky_relu"
}};
}
void
check_inputs
(
const
op_desc
&
opd
,
const
std
::
vector
<
instruction_ref
>&
args
)
const
{
if
(
args
.
size
()
<
4
)
MIGRAPHX_THROW
(
opd
.
op_name
+
": missing inputs"
);
const
auto
&
in_x
=
args
[
0
];
auto
sh_x
=
in_x
->
get_shape
();
auto
type_x
=
sh_x
.
type
();
if
(
type_x
!=
migraphx
::
shape
::
int8_type
and
type_x
!=
migraphx
::
shape
::
uint8_type
)
MIGRAPHX_THROW
(
opd
.
op_name
+
": unsupported input type"
);
}
instruction_ref
parse
(
const
op_desc
&
opd
,
const
onnx_parser
&
parser
,
const
onnx_parser
::
node_info
&
info
,
const
std
::
vector
<
instruction_ref
>&
args
)
const
{
check_inputs
(
opd
,
args
);
// X
const
auto
&
in_x
=
args
[
0
];
const
auto
&
in_scale_x
=
args
[
1
];
const
auto
&
in_zero_pt_x
=
args
[
2
];
auto
dquant_x
=
bcast_qdq_instr
(
"dequantizelinear"
,
in_x
,
in_scale_x
,
in_zero_pt_x
,
info
);
// Y = (op(dequantizelinear(x))
auto
op
=
parser
.
load
(
opd
.
op_name
,
info
);
auto
y
=
info
.
add_instruction
(
op
,
dquant_x
);
const
auto
&
in_scale_y
=
args
[
3
];
// zero_pt for Y is supplied as the last optional argument..
if
(
args
.
size
()
==
5
)
return
(
bcast_qdq_instr
(
"quantizelinear"
,
y
,
in_scale_y
,
args
[
4
],
info
));
// if no zero_pt: just broadcast the scale..
auto
bcast_scale_sigm
=
bcast_scalar_instr
(
y
->
get_shape
(),
in_scale_y
,
info
);
return
(
info
.
add_instruction
(
migraphx
::
make_op
(
"quantizelinear"
),
y
,
bcast_scale_sigm
));
}
};
}
// namespace onnx
}
// namespace MIGRAPHX_INLINE_NS
}
// namespace migraphx
src/onnx/parse_scatternd.cpp
View file @
538dbd75
...
@@ -39,15 +39,17 @@ struct parse_scatternd : op_parser<parse_scatternd>
...
@@ -39,15 +39,17 @@ struct parse_scatternd : op_parser<parse_scatternd>
const
onnx_parser
::
node_info
&
info
,
const
onnx_parser
::
node_info
&
info
,
std
::
vector
<
instruction_ref
>&
args
)
const
std
::
vector
<
instruction_ref
>&
args
)
const
{
{
std
::
string
reduction
=
"none"
;
if
(
contains
(
info
.
attributes
,
"reduction"
))
if
(
contains
(
info
.
attributes
,
"reduction"
))
{
{
if
(
info
.
attributes
.
at
(
"reduction"
).
s
()
==
"add"
)
reduction
=
info
.
attributes
.
at
(
"reduction"
).
s
();
return
info
.
add_instruction
(
migraphx
::
make_op
(
"scatternd_add"
),
args
);
if
(
not
contains
({
"none"
,
"add"
,
"mul"
,
"min"
,
"max"
},
reduction
))
if
(
info
.
attributes
.
at
(
"reduction"
).
s
()
==
"mul"
)
{
return
info
.
add_instruction
(
migraphx
::
make_op
(
"scatternd_mul"
),
args
);
MIGRAPHX_THROW
(
"PARSE_SCATTERND: unsupported reduction mode "
+
reduction
);
}
}
}
return
info
.
add_instruction
(
migraphx
::
make_op
(
"scatternd_
none"
),
args
);
return
info
.
add_instruction
(
migraphx
::
make_op
(
"scatternd_
"
+
reduction
),
args
);
}
}
};
};
...
...
src/onnx/parse_unique.cpp
0 → 100644
View file @
538dbd75
/*
* 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/onnx/op_parser.hpp>
#include <migraphx/ranges.hpp>
#include <migraphx/instruction.hpp>
#include <migraphx/make_op.hpp>
#include <migraphx/tune_axis.hpp>
#include <optional>
namespace
migraphx
{
inline
namespace
MIGRAPHX_INLINE_NS
{
namespace
onnx
{
// generate unique output stream y, given input stream x;
//
// case unsorted:
// input x: [2, 1, 1, 3, 4, 3], attr_sorted = 0;
// output(s):
// y: [2, 1, 3, 4] --- the unique output
// y_indices: [0, 1, 3, 4] --- first incidence, in terms of indices of x
// x_rev_indices: [0, 1, 1, 2, 3, 2] --- x seen in terms of indices of y
// y_count: [1, 2, 2, 1] -- count at each y_index. sum = len(x)
//
// case sorted:
// input x: [2, 1, 1, 3, 4, 3], attr_sorted = 1;
// output(s):
// y: [1, 2, 3, 4] --- the unique output
// y_indices: [1, 0, 3, 4] --- first incidence, in terms of indices of x
// x_rev_indices: [1, 0, 0, 2, 3, 2] --- x seen in terms of indices of y
// y_count: [2, 1, 2, 1] -- count at each y_index. sum = len(x)
struct
parse_unique
:
op_parser
<
parse_unique
>
{
std
::
vector
<
op_desc
>
operators
()
const
{
return
{{
"Unique"
}};
}
std
::
vector
<
instruction_ref
>
parse
(
const
op_desc
&
opd
,
const
onnx_parser
&
parser
,
const
onnx_parser
::
node_info
&
info
,
std
::
vector
<
instruction_ref
>
args
)
const
{
int64_t
sorted
=
1
;
// default = sorted.
if
(
contains
(
info
.
attributes
,
"sorted"
))
sorted
=
parser
.
parse_value
(
info
.
attributes
.
at
(
"sorted"
)).
at
<
int
>
();
std
::
optional
<
int64_t
>
axis
;
if
(
contains
(
info
.
attributes
,
"axis"
))
{
auto
n_dim
=
args
[
0
]
->
get_shape
().
ndim
();
axis
=
parser
.
parse_value
(
info
.
attributes
.
at
(
"axis"
)).
at
<
int
>
();
axis
=
tune_axis
(
n_dim
,
*
axis
,
opd
.
op_name
);
}
migraphx
::
argument
data_arg
=
args
.
back
()
->
eval
();
auto
opr
=
axis
?
migraphx
::
make_op
(
"unique"
,
{{
"axis"
,
*
axis
},
{
"sorted"
,
sorted
}})
:
migraphx
::
make_op
(
"unique"
,
{{
"sorted"
,
sorted
}});
auto
u_opr
=
info
.
add_instruction
(
opr
,
args
.
at
(
0
));
auto
i_y
=
info
.
add_instruction
(
make_op
(
"get_tuple_elem"
,
{{
"index"
,
0
}}),
u_opr
);
auto
i_y_idx
=
info
.
add_instruction
(
make_op
(
"get_tuple_elem"
,
{{
"index"
,
1
}}),
u_opr
);
auto
i_x_idx
=
info
.
add_instruction
(
make_op
(
"get_tuple_elem"
,
{{
"index"
,
2
}}),
u_opr
);
auto
i_count
=
info
.
add_instruction
(
make_op
(
"get_tuple_elem"
,
{{
"index"
,
3
}}),
u_opr
);
return
{
i_y
,
i_y_idx
,
i_x_idx
,
i_count
};
}
};
}
// namespace onnx
}
// namespace MIGRAPHX_INLINE_NS
}
// namespace migraphx
src/onnx/pooling.cpp
0 → 100644
View file @
538dbd75
/*
* 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/onnx/pooling.hpp>
#include <migraphx/onnx/checks.hpp>
#include <migraphx/onnx/padding.hpp>
#include <migraphx/stringutils.hpp>
#include <migraphx/make_op.hpp>
#include <migraphx/op/pooling.hpp>
#include <migraphx/op/pad.hpp>
#include <migraphx/ranges.hpp>
namespace
migraphx
{
inline
namespace
MIGRAPHX_INLINE_NS
{
namespace
onnx
{
value
handle_pooling_values
(
const
op_desc
&
opd
,
onnx_parser
::
node_info
info
,
const
shape
&
in_shape
,
value
values
)
{
auto
kdims
=
in_shape
.
ndim
()
-
2
;
if
(
starts_with
(
opd
.
onnx_name
,
"Global"
)
or
starts_with
(
opd
.
onnx_name
,
"QLinearGlobal"
))
{
// if spatial dimensions are dynamic use dyn_global flag
if
(
in_shape
.
dynamic
()
and
std
::
any_of
(
in_shape
.
dyn_dims
().
cbegin
()
+
2
,
in_shape
.
dyn_dims
().
cend
(),
[](
auto
dd
)
{
return
not
dd
.
is_fixed
();
}))
{
values
[
"dyn_global"
]
=
true
;
values
[
"lengths"
]
=
std
::
vector
<
size_t
>
();
}
else
{
// works with static and fixed dynamic shape
auto
m_lens
=
in_shape
.
max_lens
();
values
[
"lengths"
]
=
std
::
vector
<
size_t
>
(
m_lens
.
begin
()
+
2
,
m_lens
.
end
());
}
}
if
(
contains
(
info
.
attributes
,
"ceil_mode"
))
{
values
[
"ceil_mode"
]
=
static_cast
<
bool
>
(
info
.
attributes
.
at
(
"ceil_mode"
).
i
());
}
if
(
contains
(
info
.
attributes
,
"strides"
))
{
values
[
"stride"
].
clear
();
copy
(
info
.
attributes
[
"strides"
].
ints
(),
std
::
back_inserter
(
values
[
"stride"
]));
check_attr_sizes
(
kdims
,
values
[
"stride"
].
size
(),
"PARSE_POOLING: inconsistent strides"
);
}
if
(
contains
(
info
.
attributes
,
"kernel_shape"
))
{
values
[
"lengths"
].
clear
();
copy
(
info
.
attributes
[
"kernel_shape"
].
ints
(),
std
::
back_inserter
(
values
[
"lengths"
]));
check_attr_sizes
(
kdims
,
values
[
"lengths"
].
size
(),
"PARSE_POOLING: inconsistent lengths"
);
}
if
(
contains
(
info
.
attributes
,
"dilations"
))
{
values
[
"dilations"
].
clear
();
copy
(
info
.
attributes
[
"dilations"
].
ints
(),
std
::
back_inserter
(
values
[
"dilations"
]));
check_attr_sizes
(
kdims
,
values
[
"dilations"
].
size
(),
"PARSE_POOLING: inconsistent dilations"
);
}
// lp_order attribute
if
(
contains
(
info
.
attributes
,
"p"
))
{
values
[
"lp_order"
]
=
info
.
attributes
.
at
(
"p"
).
i
();
}
// ensure pads available only when auto_pad is "NOT_SET"
check_padding_mode
(
info
,
"POOLING"
);
return
values
;
}
instruction_ref
add_pooling_op
(
const
op_desc
&
opd
,
onnx_parser
::
node_info
info
,
instruction_ref
l0
)
{
std
::
string
mode
=
opd
.
op_name
;
const
std
::
unordered_map
<
std
::
string
,
op
::
pooling_mode
>
mode_map
=
{
{
"max"
,
op
::
pooling_mode
::
max
},
{
"average"
,
op
::
pooling_mode
::
average
},
{
"lpnorm"
,
op
::
pooling_mode
::
lpnorm
}};
if
(
not
contains
(
mode_map
,
mode
))
{
MIGRAPHX_THROW
(
"PARSE_POOLING: onnx pooling mode must be [
\"
max
\"
,
\"
average
\"
,
\"
lpnorm
\"
]"
);
}
operation
op
=
make_op
(
"pooling"
,
{{
"mode"
,
mode_map
.
at
(
mode
)}});
value
values
=
op
.
to_value
();
auto
in_shape
=
l0
->
get_shape
();
assert
(
in_shape
.
ndim
()
>
2
);
auto
kdims
=
in_shape
.
ndim
()
-
2
;
values
=
handle_pooling_values
(
opd
,
info
,
in_shape
,
values
);
// count include padding, if count include pad is 1, we always use
// explicit pad
int
count_include_pad
=
0
;
if
(
contains
(
info
.
attributes
,
"count_include_pad"
))
{
if
(
in_shape
.
dynamic
())
{
MIGRAPHX_THROW
(
"PARSE_POOLING: count_include_pad attribute is not supported for "
"dynamic input shape"
);
}
count_include_pad
=
info
.
attributes
.
at
(
"count_include_pad"
).
i
();
}
std
::
vector
<
int64_t
>
paddings
;
float
pad_val
=
((
mode
==
"max"
)
?
std
::
numeric_limits
<
float
>::
lowest
()
:
0.0
f
);
if
(
contains
(
info
.
attributes
,
"pads"
))
{
values
[
"padding"
].
clear
();
copy
(
info
.
attributes
[
"pads"
].
ints
(),
std
::
back_inserter
(
paddings
));
check_attr_sizes
(
kdims
,
paddings
.
size
()
/
2
,
"PARSE_POOLING: inconsistent explicit paddings"
);
}
if
(
paddings
.
size
()
!=
2
*
kdims
)
{
paddings
.
resize
(
kdims
*
2
);
std
::
fill_n
(
paddings
.
begin
(),
2
*
kdims
,
0
);
}
if
(
values
[
"padding"
].
size
()
!=
kdims
)
{
values
[
"padding"
].
resize
(
kdims
);
std
::
fill_n
(
values
[
"padding"
].
begin
(),
kdims
,
0
);
}
if
(
values
[
"stride"
].
size
()
!=
kdims
)
{
values
[
"stride"
].
resize
(
kdims
);
std
::
fill_n
(
values
[
"stride"
].
begin
(),
kdims
,
1
);
}
if
(
values
[
"dilations"
].
size
()
!=
kdims
)
{
values
[
"dilations"
].
resize
(
kdims
);
std
::
fill_n
(
values
[
"dilations"
].
begin
(),
kdims
,
1
);
}
// used to calculate the supposed output shape
std
::
vector
<
int64_t
>
orig_padding
=
paddings
;
// TODO: add parsing for dilations
if
(
contains
(
info
.
attributes
,
"auto_pad"
)
and
to_upper
(
info
.
attributes
[
"auto_pad"
].
s
())
!=
"NOTSET"
)
{
auto
auto_pad
=
to_upper
(
info
.
attributes
[
"auto_pad"
].
s
());
// don't use the given padding sizes, if any
// values["padding"].clear();
if
(
in_shape
.
dynamic
())
{
// set padding_mode to trigger auto padding at runtime
bool
is_same_upper
=
(
auto_pad
.
find
(
"SAME_UPPER"
)
!=
std
::
string
::
npos
);
values
[
"padding_mode"
]
=
is_same_upper
?
to_value
(
op
::
padding_mode_t
::
same_upper
)
:
to_value
(
op
::
padding_mode_t
::
same_lower
);
}
else
{
// Calculate auto padding
// dilations (argument 4) not supported; default to all 1's
cal_auto_padding_size
(
info
,
values
,
values
[
"lengths"
].
to_vector
<
std
::
size_t
>
(),
values
[
"dilations"
].
to_vector
<
std
::
size_t
>
(),
in_shape
.
lens
(),
paddings
);
values
[
"padding"
]
=
paddings
;
// default padding_mode indicates that padding sizes are not calculated dynamically
values
[
"padding_mode"
]
=
migraphx
::
op
::
padding_mode_t
::
default_
;
}
}
std
::
vector
<
int64_t
>
slice_start
;
std
::
vector
<
int64_t
>
slice_end
;
tune_padding_size
(
values
,
paddings
,
count_include_pad
,
slice_start
);
if
(
not
slice_start
.
empty
())
{
if
(
in_shape
.
dynamic
())
{
MIGRAPHX_THROW
(
"PARSE_POOLING: asymmetric padding not supported for dynamic input shape"
);
}
// calculate expected output shape
orig_padding
.
insert
(
orig_padding
.
begin
()
+
kdims
,
2
,
0
);
orig_padding
.
insert
(
orig_padding
.
begin
(),
2
,
0
);
op
::
pad
pad
{
orig_padding
,
0.0
f
};
shape
padded_shape
=
pad
.
compute_shape
({
l0
->
get_shape
()});
// make an op just to get its output shape
auto
out_lens
=
make_op
(
"pooling"
,
values
).
compute_shape
({
padded_shape
}).
lens
();
// compute slice_end information
slice_end
.
resize
(
slice_start
.
size
());
std
::
transform
(
out_lens
.
begin
()
+
2
,
out_lens
.
end
(),
slice_start
.
begin
(),
slice_end
.
begin
(),
[](
auto
i
,
auto
j
)
{
return
i
+
j
;
});
}
values
[
"padding"
]
=
std
::
vector
<
size_t
>
(
paddings
.
begin
(),
paddings
.
end
());
check_asym_padding
(
info
,
l0
,
paddings
,
values
,
count_include_pad
,
pad_val
);
op
.
from_value
(
values
);
auto
l1
=
info
.
add_instruction
(
op
,
l0
);
if
(
not
slice_start
.
empty
())
{
std
::
vector
<
int64_t
>
axes
(
kdims
);
std
::
iota
(
axes
.
begin
(),
axes
.
end
(),
2
);
l1
=
info
.
add_instruction
(
make_op
(
"slice"
,
{{
"axes"
,
axes
},
{
"starts"
,
slice_start
},
{
"ends"
,
slice_end
}}),
l1
);
}
return
l1
;
}
}
// namespace onnx
}
// namespace MIGRAPHX_INLINE_NS
}
// namespace migraphx
src/rewrite_pooling.cpp
View file @
538dbd75
...
@@ -35,25 +35,14 @@
...
@@ -35,25 +35,14 @@
namespace
migraphx
{
namespace
migraphx
{
inline
namespace
MIGRAPHX_INLINE_NS
{
inline
namespace
MIGRAPHX_INLINE_NS
{
void
rewrite_pooling
::
apply
(
module
&
m
)
const
static
void
replace_with_reduce
(
module
&
m
,
instruction_ref
ins
)
{
{
for
(
auto
ins
:
iterator_for
(
m
))
{
if
(
ins
->
name
()
!=
"pooling"
)
continue
;
if
(
ins
->
inputs
().
empty
())
continue
;
auto
&&
s
=
ins
->
inputs
().
front
()
->
get_shape
();
auto
&&
s
=
ins
->
inputs
().
front
()
->
get_shape
();
auto
&&
op
=
any_cast
<
op
::
pooling
>
(
ins
->
get_operator
());
auto
&&
op
=
any_cast
<
op
::
pooling
>
(
ins
->
get_operator
());
if
(
not
std
::
all_of
(
op
.
padding
.
begin
(),
op
.
padding
.
end
(),
[](
auto
i
)
{
return
i
==
0
;
}))
continue
;
if
(
not
std
::
all_of
(
op
.
stride
.
begin
(),
op
.
stride
.
end
(),
[](
auto
i
)
{
return
i
==
1
;
}))
continue
;
auto
lens
=
s
.
lens
();
auto
lens
=
s
.
lens
();
if
(
not
std
::
equal
(
lens
.
begin
()
+
2
,
lens
.
end
(),
op
.
lengths
.
begin
(),
op
.
lengths
.
end
()))
continue
;
std
::
vector
<
std
::
int64_t
>
axes
(
lens
.
size
()
-
2
);
std
::
vector
<
std
::
int64_t
>
axes
(
lens
.
size
()
-
2
);
std
::
iota
(
axes
.
begin
(),
axes
.
end
(),
2
);
std
::
iota
(
axes
.
begin
(),
axes
.
end
(),
2
);
// average pooling
// average pooling
if
(
op
.
mode
==
op
::
pooling_mode
::
average
)
if
(
op
.
mode
==
op
::
pooling_mode
::
average
)
{
{
...
@@ -64,6 +53,131 @@ void rewrite_pooling::apply(module& m) const
...
@@ -64,6 +53,131 @@ void rewrite_pooling::apply(module& m) const
{
{
m
.
replace_instruction
(
ins
,
make_op
(
"reduce_max"
,
{{
"axes"
,
axes
}}),
ins
->
inputs
());
m
.
replace_instruction
(
ins
,
make_op
(
"reduce_max"
,
{{
"axes"
,
axes
}}),
ins
->
inputs
());
}
}
}
static
void
replace_dilations_with_gather_pooling
(
module
&
m
,
instruction_ref
ins
)
{
// TODO remove this when MIOpen supports dilated pooling
auto
&&
s
=
ins
->
inputs
().
front
()
->
get_shape
();
auto
&&
op
=
any_cast
<
op
::
pooling
>
(
ins
->
get_operator
());
// Ignore N, C axes
std
::
vector
<
size_t
>
dims
=
{
s
.
lens
().
cbegin
()
+
2
,
s
.
lens
().
cend
()};
bool
default_padding
=
std
::
all_of
(
op
.
padding
.
cbegin
(),
op
.
padding
.
cend
(),
[](
auto
i
)
{
return
i
==
0
;
});
if
(
not
default_padding
)
{
for
(
size_t
idx
{
0
};
idx
<
op
.
padding
.
size
();
++
idx
)
{
// We need to pad both ends
dims
[
idx
]
+=
op
.
padding
.
at
(
idx
)
*
2
;
}
}
std
::
vector
<
size_t
>
kernels
=
op
.
lengths
;
std
::
vector
<
size_t
>
strides
=
op
.
stride
;
std
::
vector
<
size_t
>
dilations
=
op
.
dilations
;
std
::
vector
<
std
::
vector
<
int
>>
axis_indices
;
axis_indices
.
resize
(
dims
.
size
());
for
(
auto
idx
{
0
};
idx
<
dims
.
size
();
++
idx
)
{
// Only consider if iw fits into the window
for
(
size_t
stride
{
0
};
stride
<
dims
.
at
(
idx
)
-
dilations
.
at
(
idx
)
*
(
kernels
.
at
(
idx
)
-
1
);
stride
+=
strides
.
at
(
idx
))
{
for
(
size_t
step
{
0
};
step
<
kernels
.
at
(
idx
);
++
step
)
{
axis_indices
.
at
(
idx
).
push_back
(
stride
+
dilations
.
at
(
idx
)
*
step
);
}
}
}
auto
elements
=
ins
->
inputs
().
front
();
if
(
not
default_padding
)
{
// Pad supports asym, we need to provide both ends
std
::
vector
<
size_t
>
padding
(
2
*
s
.
lens
().
size
(),
0
);
// Format will be e.g {N, C, P1, P2, N, C, P1, P2}
for
(
size_t
idx
{
0
};
idx
<
op
.
padding
.
size
();
++
idx
)
{
// Ignore N, C axes
padding
.
at
(
2
+
idx
)
=
op
.
padding
.
at
(
idx
);
padding
.
at
(
2
+
idx
+
s
.
lens
().
size
())
=
op
.
padding
.
at
(
idx
);
}
// Default value needed for Max pooling
elements
=
m
.
insert_instruction
(
ins
,
make_op
(
"pad"
,
{{
"pads"
,
padding
},
{
"value"
,
std
::
numeric_limits
<
float
>::
lowest
()}}),
elements
);
}
for
(
auto
idx
{
0
};
idx
<
axis_indices
.
size
();
++
idx
)
{
migraphx
::
shape
s_indices
{
migraphx
::
shape
::
int32_type
,
{
axis_indices
.
at
(
idx
).
size
()}};
auto
indices
=
m
.
add_literal
(
migraphx
::
literal
{
s_indices
,
axis_indices
.
at
(
idx
)});
elements
=
m
.
insert_instruction
(
ins
,
make_op
(
"gather"
,
{{
"axis"
,
idx
+
2
/*ignore N,C*/
}}),
elements
,
indices
);
}
// Ignore padding
std
::
vector
<
size_t
>
new_padding
(
kernels
.
size
(),
0
);
// The kernel window elements are places next to each other. E.g. {x1, y1, x2, y2, ...}
// We need to skip them to not overlap
std
::
vector
<
size_t
>
new_strides
(
kernels
);
// Ignore dilations
std
::
vector
<
size_t
>
new_dilations
(
kernels
.
size
(),
1
);
m
.
replace_instruction
(
ins
,
make_op
(
"pooling"
,
{{
"mode"
,
op
.
mode
},
{
"padding"
,
new_padding
},
{
"stride"
,
new_strides
},
{
"lengths"
,
kernels
},
{
"dilations"
,
new_dilations
}}),
elements
);
}
void
rewrite_pooling
::
apply
(
module
&
m
)
const
{
for
(
auto
ins
:
iterator_for
(
m
))
{
if
(
ins
->
name
()
!=
"pooling"
)
continue
;
if
(
ins
->
inputs
().
empty
())
continue
;
auto
&&
s
=
ins
->
inputs
().
front
()
->
get_shape
();
auto
&&
op
=
any_cast
<
op
::
pooling
>
(
ins
->
get_operator
());
bool
same_kernel_as_shape
=
std
::
equal
(
s
.
lens
().
cbegin
()
+
2
,
s
.
lens
().
cend
(),
op
.
lengths
.
cbegin
(),
op
.
lengths
.
cend
());
bool
default_strides
=
std
::
all_of
(
op
.
stride
.
cbegin
(),
op
.
stride
.
cend
(),
[](
auto
i
)
{
return
i
==
1
;
});
bool
default_padding
=
std
::
all_of
(
op
.
padding
.
cbegin
(),
op
.
padding
.
cend
(),
[](
auto
i
)
{
return
i
==
0
;
});
bool
default_dilations
=
std
::
all_of
(
op
.
dilations
.
cbegin
(),
op
.
dilations
.
cend
(),
[](
auto
i
)
{
return
i
==
1
;
});
if
(
same_kernel_as_shape
and
default_strides
and
default_padding
and
default_dilations
)
{
replace_with_reduce
(
m
,
ins
);
}
else
if
(
not
default_dilations
)
{
// Dilated AvgPool with padding is not supported
if
(
not
default_padding
and
op
.
mode
==
op
::
pooling_mode
::
average
)
{
continue
;
}
auto
size
=
std
::
accumulate
(
s
.
lens
().
cbegin
(),
s
.
lens
().
cend
(),
1
,
std
::
multiplies
<
size_t
>
());
// Can't handle too much size because of literal size
if
(
size
>
100000
)
{
continue
;
}
replace_dilations_with_gather_pooling
(
m
,
ins
);
}
}
}
}
}
...
...
src/schedule.cpp
View file @
538dbd75
...
@@ -27,7 +27,7 @@
...
@@ -27,7 +27,7 @@
#include <migraphx/iterator_for.hpp>
#include <migraphx/iterator_for.hpp>
#include <migraphx/iterator.hpp>
#include <migraphx/iterator.hpp>
#include <migraphx/dfor.hpp>
#include <migraphx/dfor.hpp>
#include <migraphx/par_for.hpp>
#include <migraphx/
simple_
par_for.hpp>
#include <migraphx/functional.hpp>
#include <migraphx/functional.hpp>
#include <migraphx/ranges.hpp>
#include <migraphx/ranges.hpp>
#include <migraphx/dom_info.hpp>
#include <migraphx/dom_info.hpp>
...
@@ -461,7 +461,7 @@ struct stream_info
...
@@ -461,7 +461,7 @@ struct stream_info
std
::
back_inserter
(
index_to_ins
),
std
::
back_inserter
(
index_to_ins
),
[](
auto
&&
it
)
{
return
it
.
first
;
});
[](
auto
&&
it
)
{
return
it
.
first
;
});
par_for
(
concur_ins
.
size
(),
[
&
](
auto
ins_index
,
auto
tid
)
{
simple_
par_for
(
concur_ins
.
size
(),
[
&
](
auto
ins_index
,
auto
tid
)
{
auto
merge_first
=
index_to_ins
[
ins_index
];
auto
merge_first
=
index_to_ins
[
ins_index
];
assert
(
concur_ins
.
count
(
merge_first
)
>
0
);
assert
(
concur_ins
.
count
(
merge_first
)
>
0
);
auto
&
merge_second
=
concur_ins
.
at
(
merge_first
);
auto
&
merge_second
=
concur_ins
.
at
(
merge_first
);
...
...
src/simplify_dyn_ops.cpp
View file @
538dbd75
...
@@ -22,6 +22,7 @@
...
@@ -22,6 +22,7 @@
* THE SOFTWARE.
* THE SOFTWARE.
*/
*/
#include <migraphx/simplify_dyn_ops.hpp>
#include <migraphx/simplify_dyn_ops.hpp>
#include <migraphx/op/slice.hpp>
#include <migraphx/matcher.hpp>
#include <migraphx/matcher.hpp>
#include <migraphx/make_op.hpp>
#include <migraphx/make_op.hpp>
#include <migraphx/literal.hpp>
#include <migraphx/literal.hpp>
...
@@ -65,8 +66,65 @@ struct find_static_2in_broadcasts
...
@@ -65,8 +66,65 @@ struct find_static_2in_broadcasts
};
};
/**
/**
* Simplify slice with variable `starts` and `ends` to the constant version if
* Simplify slice with 2 inputs to the 1 input version if inputs[1] is constant.
* the `input_starts` and `input_ends` inputs are constant.
* From:
* slice(data, constant_input); two attributes set
* To:
* slice(data); slice.starts, slice.ends. slice.axes set
*/
struct
find_const_2in_slice
{
auto
matcher
()
const
{
return
match
::
name
(
"slice"
)(
match
::
nargs
(
2
),
match
::
arg
(
1
)(
match
::
is_constant
()));
}
void
apply
(
module
&
m
,
const
match
::
matcher_result
&
mr
)
const
{
auto
ins
=
mr
.
result
;
auto
inputs
=
ins
->
inputs
();
auto
slice_op
=
any_cast
<
op
::
slice
>
(
ins
->
get_operator
());
auto
set_attrs
=
slice_op
.
get_set_attributes
();
std
::
vector
<
int64_t
>
starts_vec
;
std
::
vector
<
int64_t
>
ends_vec
;
std
::
vector
<
int64_t
>
axes_vec
;
if
(
set_attrs
==
op
::
slice
::
ends_axes
)
{
// slice(data, starts)
inputs
.
at
(
1
)
->
eval
().
visit
(
[
&
](
auto
output
)
{
starts_vec
.
assign
(
output
.
begin
(),
output
.
end
());
});
ends_vec
=
slice_op
.
ends
;
axes_vec
=
slice_op
.
axes
;
}
else
if
(
set_attrs
==
op
::
slice
::
starts_axes
)
{
// slice(data, ends)
inputs
.
at
(
1
)
->
eval
().
visit
(
[
&
](
auto
output
)
{
ends_vec
.
assign
(
output
.
begin
(),
output
.
end
());
});
starts_vec
=
slice_op
.
starts
;
axes_vec
=
slice_op
.
axes
;
}
else
{
// slice(data, axes)
inputs
.
at
(
1
)
->
eval
().
visit
(
[
&
](
auto
output
)
{
axes_vec
.
assign
(
output
.
begin
(),
output
.
end
());
});
starts_vec
=
slice_op
.
starts
;
ends_vec
=
slice_op
.
ends
;
}
m
.
replace_instruction
(
ins
,
make_op
(
"slice"
,
{{
"starts"
,
starts_vec
},
{
"ends"
,
ends_vec
},
{
"axes"
,
axes_vec
}}),
inputs
.
at
(
0
));
}
};
/**
* Simplify slice with 3 inputs to the 1 input version if inputs[1:2] are constant.
* From:
* slice(data, constant_input1, constant_input2); one attribute set
* To:
* slice(data); slice.starts, slice.ends. slice.axes set
*/
*/
struct
find_const_3in_slice
struct
find_const_3in_slice
{
{
...
@@ -81,27 +139,51 @@ struct find_const_3in_slice
...
@@ -81,27 +139,51 @@ struct find_const_3in_slice
{
{
auto
ins
=
mr
.
result
;
auto
ins
=
mr
.
result
;
auto
inputs
=
ins
->
inputs
();
auto
inputs
=
ins
->
inputs
();
argument
starts_arg
=
inputs
.
at
(
1
)
->
eval
();
auto
slice_op
=
any_cast
<
op
::
slice
>
(
ins
->
get_operator
());
argument
ends_arg
=
inputs
.
at
(
2
)
->
eval
();
auto
set_attrs
=
slice_op
.
get_set_attributes
();
if
(
not
starts_arg
.
empty
()
and
not
ends_arg
.
empty
())
{
std
::
vector
<
int64_t
>
starts_vec
;
std
::
vector
<
int64_t
>
starts_vec
;
std
::
vector
<
int64_t
>
ends_vec
;
std
::
vector
<
int64_t
>
ends_vec
;
starts_arg
.
visit
([
&
](
auto
output
)
{
starts_vec
.
assign
(
output
.
begin
(),
output
.
end
());
});
std
::
vector
<
int64_t
>
axes_vec
;
ends_arg
.
visit
([
&
](
auto
output
)
{
ends_vec
.
assign
(
output
.
begin
(),
output
.
end
());
});
if
(
set_attrs
==
op
::
slice
::
axes_only
)
auto
slice_val
=
ins
->
get_operator
().
to_value
();
{
auto
axes_vec
=
slice_val
.
at
(
"axes"
).
to_vector
<
int64_t
>
();
// slice(data, starts, ends)
inputs
.
at
(
1
)
->
eval
().
visit
(
[
&
](
auto
output
)
{
starts_vec
.
assign
(
output
.
begin
(),
output
.
end
());
});
inputs
.
at
(
2
)
->
eval
().
visit
(
[
&
](
auto
output
)
{
ends_vec
.
assign
(
output
.
begin
(),
output
.
end
());
});
axes_vec
=
slice_op
.
axes
;
}
else
if
(
set_attrs
==
op
::
slice
::
ends_only
)
{
// slice(data, starts, axes)
inputs
.
at
(
1
)
->
eval
().
visit
(
[
&
](
auto
output
)
{
starts_vec
.
assign
(
output
.
begin
(),
output
.
end
());
});
inputs
.
at
(
2
)
->
eval
().
visit
(
[
&
](
auto
output
)
{
axes_vec
.
assign
(
output
.
begin
(),
output
.
end
());
});
ends_vec
=
slice_op
.
ends
;
}
else
{
// slice(data, ends, axes)
inputs
.
at
(
1
)
->
eval
().
visit
(
[
&
](
auto
output
)
{
ends_vec
.
assign
(
output
.
begin
(),
output
.
end
());
});
inputs
.
at
(
2
)
->
eval
().
visit
(
[
&
](
auto
output
)
{
axes_vec
.
assign
(
output
.
begin
(),
output
.
end
());
});
starts_vec
=
slice_op
.
starts
;
}
m
.
replace_instruction
(
m
.
replace_instruction
(
ins
,
ins
,
make_op
(
"slice"
,
{{
"starts"
,
starts_vec
},
{
"ends"
,
ends_vec
},
{
"axes"
,
axes_vec
}}),
make_op
(
"slice"
,
{{
"starts"
,
starts_vec
},
{
"ends"
,
ends_vec
},
{
"axes"
,
axes_vec
}}),
inputs
.
at
(
0
));
inputs
.
at
(
0
));
}
}
}
};
};
/**
/**
* Simplify slice with variable `starts`, `ends`, and `input_axes` to the constant version if
* Simplify slice with 4 inputs to the 1 input version if inputs[1:3] are constant.
* the `input_starts`, `input_ends`, and `input_axes` inputs are constant.
* From:
* slice(data, constant_starts, constant_ends, constant_axes)
* To:
* slice(data); slice.starts, slice.ends. slice.axes set
*/
*/
struct
find_const_4in_slice
struct
find_const_4in_slice
{
{
...
@@ -117,9 +199,9 @@ struct find_const_4in_slice
...
@@ -117,9 +199,9 @@ struct find_const_4in_slice
{
{
auto
ins
=
mr
.
result
;
auto
ins
=
mr
.
result
;
auto
inputs
=
ins
->
inputs
();
auto
inputs
=
ins
->
inputs
();
argument
starts_arg
=
inputs
.
at
(
1
)
->
eval
();
argument
starts_arg
=
inputs
.
at
(
1
)
->
eval
(
false
);
argument
ends_arg
=
inputs
.
at
(
2
)
->
eval
();
argument
ends_arg
=
inputs
.
at
(
2
)
->
eval
(
false
);
argument
axes_arg
=
inputs
.
at
(
3
)
->
eval
();
argument
axes_arg
=
inputs
.
at
(
3
)
->
eval
(
false
);
if
(
not
starts_arg
.
empty
()
and
not
ends_arg
.
empty
()
and
not
axes_arg
.
empty
())
if
(
not
starts_arg
.
empty
()
and
not
ends_arg
.
empty
()
and
not
axes_arg
.
empty
())
{
{
std
::
vector
<
int64_t
>
starts_vec
;
std
::
vector
<
int64_t
>
starts_vec
;
...
@@ -179,6 +261,7 @@ struct find_static_dimensions_of
...
@@ -179,6 +261,7 @@ struct find_static_dimensions_of
/**
/**
* Simplify allocate into 2 argument reshape that has constant output dimensions into a static 1
* Simplify allocate into 2 argument reshape that has constant output dimensions into a static 1
* argument reshape. Intended to simplify what ONNX parse_reshape creates for dynamic reshapes.
* argument reshape. Intended to simplify what ONNX parse_reshape creates for dynamic reshapes.
* This matcher can be generalized to matching reshape(data, static_shape_output_tensor).
* From:
* From:
* x = allocate(constant_output_dims) -> reshape(data, x)
* x = allocate(constant_output_dims) -> reshape(data, x)
* To:
* To:
...
@@ -207,14 +290,44 @@ struct find_const_alloc_reshapes
...
@@ -207,14 +290,44 @@ struct find_const_alloc_reshapes
}
}
};
};
/**
* Simplify allocate into fill operator that has constant output dimensions and constant value.
* The allocate into fill instructions is what is produced when parsing the ONNX
* ConstantOfShape operator. This replacement could be handled with propagate_constant, but
* would rather have the simplification happen earlier during compiling.
* This matcher can be generalized to matching fill(constant_value, static_shape_output_tensor).
* From:
* x = allocate(constant_ouptut_dims) -> fill(constant_value, x)
* To:
* literal
*/
struct
find_const_alloc_fill
{
auto
matcher
()
const
{
return
match
::
name
(
"fill"
)(
match
::
arg
(
0
)(
match
::
is_constant
()),
match
::
arg
(
1
)(
match
::
name
(
"allocate"
)(
match
::
is_constant
())));
}
void
apply
(
module
&
m
,
const
match
::
matcher_result
&
mr
)
const
{
auto
fill_ins
=
mr
.
result
;
auto
fill_arg
=
fill_ins
->
eval
(
false
);
auto
l
=
m
.
add_literal
(
fill_arg
.
get_shape
(),
fill_arg
.
data
());
m
.
replace_instruction
(
fill_ins
,
l
);
}
};
void
simplify_dyn_ops
::
apply
(
module
&
m
)
const
void
simplify_dyn_ops
::
apply
(
module
&
m
)
const
{
{
match
::
find_matches
(
m
,
match
::
find_matches
(
m
,
find_static_dimensions_of
{},
find_static_dimensions_of
{},
find_const_alloc_reshapes
{},
find_const_alloc_reshapes
{},
find_static_2in_broadcasts
{},
find_static_2in_broadcasts
{},
find_const_2in_slice
{},
find_const_3in_slice
{},
find_const_3in_slice
{},
find_const_4in_slice
{});
find_const_4in_slice
{},
find_const_alloc_fill
{});
}
}
}
// namespace MIGRAPHX_INLINE_NS
}
// namespace MIGRAPHX_INLINE_NS
...
...
src/targets/cpu/dnnl.cpp
View file @
538dbd75
...
@@ -68,6 +68,7 @@ dnnl::memory::data_type to_dnnl_memory_data_type(shape::type_t t)
...
@@ -68,6 +68,7 @@ dnnl::memory::data_type to_dnnl_memory_data_type(shape::type_t t)
case
st
::
int32_type
:
return
dt
::
s32
;
case
st
::
int32_type
:
return
dt
::
s32
;
case
st
::
int8_type
:
return
dt
::
s8
;
case
st
::
int8_type
:
return
dt
::
s8
;
case
st
::
uint8_type
:
return
dt
::
u8
;
case
st
::
uint8_type
:
return
dt
::
u8
;
case
st
::
fp8e4m3fnuz_type
:
MIGRAPHX_THROW
(
"fp8e4m3fnuz unsupported in DNNL"
);
default:
MIGRAPHX_THROW
(
"Unsupported data type"
);
default:
MIGRAPHX_THROW
(
"Unsupported data type"
);
}
}
}
}
...
...
src/targets/cpu/lowering.cpp
View file @
538dbd75
...
@@ -340,7 +340,6 @@ struct cpu_apply
...
@@ -340,7 +340,6 @@ struct cpu_apply
{
"reduce_min"
,
"reduction_min"
},
{
"reduce_min"
,
"reduction_min"
},
{
"reduce_sum"
,
"reduction_sum"
},
{
"reduce_sum"
,
"reduction_sum"
},
});
});
extend_op
(
"concat"
,
"dnnl::concat"
);
extend_op
(
"concat"
,
"dnnl::concat"
);
extend_op
(
"contiguous"
,
"dnnl::reorder"
);
extend_op
(
"contiguous"
,
"dnnl::reorder"
);
extend_op
(
"convolution"
,
"dnnl::convolution"
);
extend_op
(
"convolution"
,
"dnnl::convolution"
);
...
@@ -376,6 +375,12 @@ struct cpu_apply
...
@@ -376,6 +375,12 @@ struct cpu_apply
// Apply these operators first so the inputs can be const folded
// Apply these operators first so the inputs can be const folded
for
(
auto
it
:
iterator_for
(
*
modl
))
for
(
auto
it
:
iterator_for
(
*
modl
))
{
{
// skip lowering if input has fp8 as one of the inputs since oneDNN doesn't have fp8
// supported yet.
if
(
std
::
any_of
(
it
->
inputs
().
begin
(),
it
->
inputs
().
end
(),
[](
const
auto
&
i
)
{
return
i
->
get_shape
().
type
()
==
migraphx
::
shape
::
fp8e4m3fnuz_type
;
}))
continue
;
if
(
it
->
name
()
==
"pow"
)
if
(
it
->
name
()
==
"pow"
)
{
{
apply_pow
(
it
);
apply_pow
(
it
);
...
@@ -383,6 +388,12 @@ struct cpu_apply
...
@@ -383,6 +388,12 @@ struct cpu_apply
}
}
for
(
auto
it
:
iterator_for
(
*
modl
))
for
(
auto
it
:
iterator_for
(
*
modl
))
{
{
// skip lowering if input has fp8 as one of the inputs since oneDNN doesn't have fp8
// supported yet.
if
(
std
::
any_of
(
it
->
inputs
().
begin
(),
it
->
inputs
().
end
(),
[](
const
auto
&
i
)
{
return
i
->
get_shape
().
type
()
==
migraphx
::
shape
::
fp8e4m3fnuz_type
;
}))
continue
;
if
(
it
->
name
()
==
"pooling"
)
if
(
it
->
name
()
==
"pooling"
)
{
{
apply_pooling
(
it
);
apply_pooling
(
it
);
...
...
src/targets/cpu/pooling.cpp
View file @
538dbd75
...
@@ -34,23 +34,32 @@ namespace migraphx {
...
@@ -34,23 +34,32 @@ namespace migraphx {
inline
namespace
MIGRAPHX_INLINE_NS
{
inline
namespace
MIGRAPHX_INLINE_NS
{
namespace
cpu
{
namespace
cpu
{
struct
dnnl_pooling
:
dnnl_extend_op
<
dnnl_pooling
,
dnnl
::
pooling_forward
,
op
::
pooling
>
struct
dnnl_pooling
:
dnnl_extend_op
<
dnnl_pooling
,
dnnl
::
pooling_
v2_
forward
,
op
::
pooling
>
{
{
std
::
vector
<
int
>
arg_map
(
int
)
const
{
return
{
MIGRAPHX_DNNL_PREFIX
(
ARG_SRC
)};
}
std
::
vector
<
int
>
arg_map
(
int
)
const
{
return
{
MIGRAPHX_DNNL_PREFIX
(
ARG_SRC
)};
}
dnnl
::
pooling_forward
::
desc
get_desc
(
const
std
::
unordered_map
<
int
,
dnnl
::
memory
::
desc
>&
m
)
const
dnnl
::
pooling_v2_forward
::
desc
get_desc
(
const
std
::
unordered_map
<
int
,
dnnl
::
memory
::
desc
>&
m
)
const
{
{
auto
algo
=
op
.
mode
==
op
::
pooling_mode
::
max
?
dnnl
::
algorithm
::
pooling_max
auto
algo
=
op
.
mode
==
op
::
pooling_mode
::
max
?
dnnl
::
algorithm
::
pooling_max
:
dnnl
::
algorithm
::
pooling_avg
;
:
dnnl
::
algorithm
::
pooling_avg
;
auto
kdims
=
op
.
kdims
();
auto
kdims
=
op
.
kdims
();
std
::
vector
<
size_t
>
padding_l
(
op
.
padding
.
begin
(),
op
.
padding
.
begin
()
+
kdims
);
std
::
vector
<
size_t
>
padding_l
(
op
.
padding
.
begin
(),
op
.
padding
.
begin
()
+
kdims
);
std
::
vector
<
size_t
>
padding_r
(
op
.
padding
.
begin
()
+
kdims
,
op
.
padding
.
end
());
std
::
vector
<
size_t
>
padding_r
(
op
.
padding
.
begin
()
+
kdims
,
op
.
padding
.
end
());
// Note: It is not documented, but the default dilation seems to be 0 instead of 1.
// We need to offset dilations with -1.
std
::
vector
<
size_t
>
dilations
;
std
::
transform
(
op
.
dilations
.
cbegin
(),
op
.
dilations
.
cend
(),
std
::
back_inserter
(
dilations
),
[](
size_t
d
)
{
return
d
-
1
;
});
return
{
dnnl
::
prop_kind
::
forward_inference
,
return
{
dnnl
::
prop_kind
::
forward_inference
,
algo
,
algo
,
m
.
at
(
MIGRAPHX_DNNL_PREFIX
(
ARG_SRC
)),
m
.
at
(
MIGRAPHX_DNNL_PREFIX
(
ARG_SRC
)),
m
.
at
(
MIGRAPHX_DNNL_PREFIX
(
ARG_DST
)),
m
.
at
(
MIGRAPHX_DNNL_PREFIX
(
ARG_DST
)),
to_dnnl_dims
(
op
.
stride
),
to_dnnl_dims
(
op
.
stride
),
to_dnnl_dims
(
op
.
lengths
),
to_dnnl_dims
(
op
.
lengths
),
to_dnnl_dims
(
dilations
),
to_dnnl_dims
(
padding_l
),
to_dnnl_dims
(
padding_l
),
to_dnnl_dims
(
padding_r
)};
to_dnnl_dims
(
padding_r
)};
}
}
...
...
src/targets/gpu/CMakeLists.txt
View file @
538dbd75
...
@@ -126,7 +126,6 @@ add_library(migraphx_gpu
...
@@ -126,7 +126,6 @@ add_library(migraphx_gpu
fuse_ck.cpp
fuse_ck.cpp
fuse_mlir.cpp
fuse_mlir.cpp
fuse_ops.cpp
fuse_ops.cpp
gather.cpp
gemm_impl.cpp
gemm_impl.cpp
hip.cpp
hip.cpp
kernel.cpp
kernel.cpp
...
@@ -140,7 +139,6 @@ add_library(migraphx_gpu
...
@@ -140,7 +139,6 @@ add_library(migraphx_gpu
nonzero.cpp
nonzero.cpp
pack_args.cpp
pack_args.cpp
prefuse_ops.cpp
prefuse_ops.cpp
pad.cpp
perfdb.cpp
perfdb.cpp
pooling.cpp
pooling.cpp
reverse.cpp
reverse.cpp
...
@@ -168,12 +166,10 @@ endfunction()
...
@@ -168,12 +166,10 @@ endfunction()
register_migraphx_gpu_ops
(
hip_
register_migraphx_gpu_ops
(
hip_
argmax
argmax
argmin
argmin
gather
logsoftmax
logsoftmax
loop
loop
multinomial
multinomial
nonzero
nonzero
pad
prefix_scan_sum
prefix_scan_sum
reverse
reverse
scatter
scatter
...
...
src/targets/gpu/compile_gen.cpp
View file @
538dbd75
...
@@ -54,6 +54,11 @@ vectorize vectorize::elements(std::size_t axis,
...
@@ -54,6 +54,11 @@ vectorize vectorize::elements(std::size_t axis,
const
std
::
vector
<
shape
>&
inputs
,
const
std
::
vector
<
shape
>&
inputs
,
const
std
::
vector
<
std
::
size_t
>&
sizes
)
const
std
::
vector
<
std
::
size_t
>&
sizes
)
{
{
// disable vectorization for fp8 types
if
(
std
::
any_of
(
inputs
.
begin
(),
inputs
.
end
(),
[
&
](
auto
ishape
)
{
return
ishape
.
type
()
==
migraphx
::
shape
::
fp8e4m3fnuz_type
;
}))
return
{
1
,
axis
};
if
(
std
::
all_of
(
if
(
std
::
all_of
(
inputs
.
begin
(),
inputs
.
end
(),
[
&
](
const
auto
&
s
)
{
return
s
.
lens
()[
axis
]
==
1
;
}))
inputs
.
begin
(),
inputs
.
end
(),
[
&
](
const
auto
&
s
)
{
return
s
.
lens
()[
axis
]
==
1
;
}))
return
{
1
,
axis
};
return
{
1
,
axis
};
...
@@ -86,6 +91,11 @@ vectorize vectorize::elements(std::size_t axis,
...
@@ -86,6 +91,11 @@ vectorize vectorize::elements(std::size_t axis,
vectorize
vectorize
::
elements
(
context
&
ctx
,
std
::
size_t
axis
,
const
std
::
vector
<
shape
>&
inputs
)
vectorize
vectorize
::
elements
(
context
&
ctx
,
std
::
size_t
axis
,
const
std
::
vector
<
shape
>&
inputs
)
{
{
// disable vectorization for fp8 types
if
(
std
::
any_of
(
inputs
.
begin
(),
inputs
.
end
(),
[
&
](
auto
ishape
)
{
return
ishape
.
type
()
==
migraphx
::
shape
::
fp8e4m3fnuz_type
;
}))
return
{
1
,
axis
};
if
(
inputs
.
empty
())
if
(
inputs
.
empty
())
return
{
1
,
axis
};
return
{
1
,
axis
};
std
::
size_t
n
=
std
::
max_element
(
inputs
.
begin
(),
std
::
size_t
n
=
std
::
max_element
(
inputs
.
begin
(),
...
...
src/targets/gpu/compile_hip.cpp
View file @
538dbd75
...
@@ -194,7 +194,7 @@ struct hiprtc_program
...
@@ -194,7 +194,7 @@ struct hiprtc_program
};
};
std
::
vector
<
std
::
vector
<
char
>>
compile_hip_src_with_hiprtc
(
std
::
vector
<
hiprtc_src_file
>
srcs
,
std
::
vector
<
std
::
vector
<
char
>>
compile_hip_src_with_hiprtc
(
std
::
vector
<
hiprtc_src_file
>
srcs
,
std
::
string
params
,
const
std
::
string
&
params
,
const
std
::
string
&
arch
)
const
std
::
string
&
arch
)
{
{
hiprtc_program
prog
(
std
::
move
(
srcs
));
hiprtc_program
prog
(
std
::
move
(
srcs
));
...
@@ -238,8 +238,9 @@ bool hip_has_flags(const std::vector<std::string>& flags)
...
@@ -238,8 +238,9 @@ bool hip_has_flags(const std::vector<std::string>& flags)
}
}
}
}
std
::
vector
<
std
::
vector
<
char
>>
std
::
vector
<
std
::
vector
<
char
>>
compile_hip_src
(
const
std
::
vector
<
src_file
>&
srcs
,
compile_hip_src
(
const
std
::
vector
<
src_file
>&
srcs
,
std
::
string
params
,
const
std
::
string
&
arch
)
const
std
::
string
&
params
,
const
std
::
string
&
arch
)
{
{
std
::
vector
<
hiprtc_src_file
>
hsrcs
{
srcs
.
begin
(),
srcs
.
end
()};
std
::
vector
<
hiprtc_src_file
>
hsrcs
{
srcs
.
begin
(),
srcs
.
end
()};
if
(
enabled
(
MIGRAPHX_GPU_DUMP_SRC
{}))
if
(
enabled
(
MIGRAPHX_GPU_DUMP_SRC
{}))
...
@@ -281,13 +282,13 @@ compile_hip_src(const std::vector<src_file>& srcs, std::string params, const std
...
@@ -281,13 +282,13 @@ compile_hip_src(const std::vector<src_file>& srcs, std::string params, const std
if
(
fs
::
exists
(
out
))
if
(
fs
::
exists
(
out
))
return
{
read_buffer
(
out
.
string
())};
return
{
read_buffer
(
out
.
string
())};
}
}
return
compile_hip_src_with_hiprtc
(
std
::
move
(
hsrcs
),
std
::
move
(
params
)
,
arch
);
return
compile_hip_src_with_hiprtc
(
std
::
move
(
hsrcs
),
params
,
arch
);
}
}
#else // MIGRAPHX_USE_HIPRTC
#else // MIGRAPHX_USE_HIPRTC
std
::
vector
<
std
::
vector
<
char
>>
compile_hip_src_with_hiprtc
(
std
::
vector
<
hiprtc_src_file
>
,
// NOLINT
std
::
vector
<
std
::
vector
<
char
>>
compile_hip_src_with_hiprtc
(
std
::
vector
<
hiprtc_src_file
>
,
// NOLINT
std
::
string
,
// NOLINT
const
std
::
string
&
,
// NOLINT
const
std
::
string
&
)
const
std
::
string
&
)
{
{
MIGRAPHX_THROW
(
"Not using hiprtc"
);
MIGRAPHX_THROW
(
"Not using hiprtc"
);
...
@@ -316,29 +317,15 @@ src_compiler assemble(src_compiler compiler)
...
@@ -316,29 +317,15 @@ src_compiler assemble(src_compiler compiler)
return
compiler
;
return
compiler
;
}
}
std
::
vector
<
std
::
vector
<
char
>>
std
::
vector
<
std
::
vector
<
char
>>
compile_hip_src
(
const
std
::
vector
<
src_file
>&
srcs
,
compile_hip_src
(
const
std
::
vector
<
src_file
>&
srcs
,
std
::
string
params
,
const
std
::
string
&
arch
)
const
std
::
string
&
params
,
const
std
::
string
&
arch
)
{
{
assert
(
not
srcs
.
empty
());
assert
(
not
srcs
.
empty
());
if
(
not
is_hip_clang_compiler
())
if
(
not
is_hip_clang_compiler
())
MIGRAPHX_THROW
(
"Unknown hip compiler: "
MIGRAPHX_HIP_COMPILER
);
MIGRAPHX_THROW
(
"Unknown hip compiler: "
MIGRAPHX_HIP_COMPILER
);
if
(
params
.
find
(
"-std="
)
==
std
::
string
::
npos
)
params
+=
" --std=c++17"
;
params
+=
" -fno-gpu-rdc"
;
if
(
enabled
(
MIGRAPHX_GPU_DEBUG_SYM
{}))
params
+=
" -g"
;
params
+=
" -c"
;
params
+=
" --offload-arch="
+
arch
;
params
+=
" --cuda-device-only"
;
params
+=
" -O"
+
string_value_of
(
MIGRAPHX_GPU_OPTIMIZE
{},
"3"
)
+
" "
;
if
(
enabled
(
MIGRAPHX_GPU_DEBUG
{}))
params
+=
" -DMIGRAPHX_DEBUG"
;
params
+=
" -Wno-unused-command-line-argument -Wno-cuda-compat "
;
params
+=
MIGRAPHX_HIP_COMPILER_FLAGS
;
src_compiler
compiler
;
src_compiler
compiler
;
compiler
.
flags
=
params
;
compiler
.
flags
=
params
;
compiler
.
compiler
=
MIGRAPHX_HIP_COMPILER
;
compiler
.
compiler
=
MIGRAPHX_HIP_COMPILER
;
...
@@ -346,6 +333,23 @@ compile_hip_src(const std::vector<src_file>& srcs, std::string params, const std
...
@@ -346,6 +333,23 @@ compile_hip_src(const std::vector<src_file>& srcs, std::string params, const std
if
(
has_compiler_launcher
())
if
(
has_compiler_launcher
())
compiler
.
launcher
=
MIGRAPHX_HIP_COMPILER_LAUNCHER
;
compiler
.
launcher
=
MIGRAPHX_HIP_COMPILER_LAUNCHER
;
#endif
#endif
if
(
params
.
find
(
"-std="
)
==
std
::
string
::
npos
)
compiler
.
flags
+=
" --std=c++17"
;
compiler
.
flags
+=
" -fno-gpu-rdc"
;
if
(
enabled
(
MIGRAPHX_GPU_DEBUG_SYM
{}))
compiler
.
flags
+=
" -g"
;
compiler
.
flags
+=
" -c"
;
compiler
.
flags
+=
" --offload-arch="
+
arch
;
compiler
.
flags
+=
" --cuda-device-only"
;
compiler
.
flags
+=
" -O"
+
string_value_of
(
MIGRAPHX_GPU_OPTIMIZE
{},
"3"
)
+
" "
;
if
(
enabled
(
MIGRAPHX_GPU_DEBUG
{}))
compiler
.
flags
+=
" -DMIGRAPHX_DEBUG"
;
compiler
.
flags
+=
" -Wno-unused-command-line-argument -Wno-cuda-compat "
;
compiler
.
flags
+=
MIGRAPHX_HIP_COMPILER_FLAGS
;
if
(
enabled
(
MIGRAPHX_GPU_DUMP_SRC
{}))
if
(
enabled
(
MIGRAPHX_GPU_DUMP_SRC
{}))
{
{
for
(
const
auto
&
src
:
srcs
)
for
(
const
auto
&
src
:
srcs
)
...
...
src/targets/gpu/compile_hip_code_object.cpp
View file @
538dbd75
...
@@ -200,7 +200,7 @@ operation compile_hip_code_object(const std::string& content, hip_compile_option
...
@@ -200,7 +200,7 @@ operation compile_hip_code_object(const std::string& content, hip_compile_option
options
.
params
+=
" "
+
join_strings
(
compiler_warnings
(),
" "
);
options
.
params
+=
" "
+
join_strings
(
compiler_warnings
(),
" "
);
options
.
params
+=
" -ftemplate-backtrace-limit=0"
;
options
.
params
+=
" -ftemplate-backtrace-limit=0"
;
options
.
params
+=
" -Werror"
;
options
.
params
+=
" -Werror"
;
auto
cos
=
compile_hip_src
(
srcs
,
std
::
move
(
options
.
params
)
,
get_device_name
());
auto
cos
=
compile_hip_src
(
srcs
,
options
.
params
,
get_device_name
());
if
(
cos
.
size
()
!=
1
)
if
(
cos
.
size
()
!=
1
)
MIGRAPHX_THROW
(
"No code object"
);
MIGRAPHX_THROW
(
"No code object"
);
return
code_object_op
{
value
::
binary
{
cos
.
front
()},
return
code_object_op
{
value
::
binary
{
cos
.
front
()},
...
...
src/targets/gpu/device/include/migraphx/gpu/device/scan.hpp
View file @
538dbd75
...
@@ -43,24 +43,32 @@ template <index_int N,
...
@@ -43,24 +43,32 @@ template <index_int N,
__device__
void
block_scan
(
index
idx
,
Op
op
,
T
init
,
ForStride
fs
,
Input
input
,
Output
output
)
__device__
void
block_scan
(
index
idx
,
Op
op
,
T
init
,
ForStride
fs
,
Input
input
,
Output
output
)
{
{
using
type
=
decltype
(
input
(
deduce_for_stride
(
fs
)));
using
type
=
decltype
(
input
(
deduce_for_stride
(
fs
)));
MIGRAPHX_DEVICE_SHARED
type
buffer
[
N
];
MIGRAPHX_DEVICE_SHARED
type
buffer
[
2
][
N
];
type
x
=
init
;
type
x
=
init
;
fs
([
&
](
auto
i
)
{
fs
([
&
](
auto
i
)
{
index_int
iout
=
0
;
index_int
iin
=
1
;
if
(
idx
.
local
==
0
)
if
(
idx
.
local
==
0
)
buffer
[
idx
.
local
]
=
op
(
input
(
i
),
x
);
buffer
[
iout
][
idx
.
local
]
=
op
(
input
(
i
),
x
);
else
else
buffer
[
idx
.
local
]
=
input
(
i
);
buffer
[
iout
][
idx
.
local
]
=
input
(
i
);
__syncthreads
();
__syncthreads
();
for
(
index_int
s
=
1
;
s
<
idx
.
nlocal
();
s
*=
2
)
for
(
index_int
s
=
1
;
s
<
idx
.
nlocal
();
s
*=
2
)
{
{
if
(
idx
.
local
+
s
<
idx
.
nlocal
())
iout
=
1
-
iout
;
iin
=
1
-
iin
;
if
(
idx
.
local
>=
s
)
{
{
buffer
[
idx
.
local
+
s
]
=
op
(
buffer
[
idx
.
local
],
buffer
[
idx
.
local
+
s
]);
buffer
[
iout
][
idx
.
local
]
=
op
(
buffer
[
iin
][
idx
.
local
],
buffer
[
iin
][
idx
.
local
-
s
]);
}
else
{
buffer
[
iout
][
idx
.
local
]
=
buffer
[
iin
][
idx
.
local
];
}
}
__syncthreads
();
__syncthreads
();
}
}
x
=
buffer
[
idx
.
nlocal
()
-
1
];
x
=
buffer
[
iout
][
idx
.
nlocal
()
-
1
];
output
(
i
,
buffer
[
idx
.
local
]);
output
(
i
,
buffer
[
iout
][
idx
.
local
]);
});
});
}
}
...
...
src/targets/gpu/driver/precompile_op.cpp
0 → 100644
View file @
538dbd75
/*
* 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/gpu/driver/action.hpp>
#include <migraphx/gpu/time_op.hpp>
#include <migraphx/gpu/context.hpp>
#include <migraphx/gpu/lowering.hpp>
#include <migraphx/gpu/compile_ops.hpp>
#include <migraphx/make_op.hpp>
#include <migraphx/pass_manager.hpp>
#include <migraphx/program.hpp>
#include <migraphx/instruction.hpp>
namespace
migraphx
{
inline
namespace
MIGRAPHX_INLINE_NS
{
namespace
gpu
{
namespace
driver
{
struct
precompile_op
:
action
<
precompile_op
>
{
static
program
create_preop_program
(
const
operation
&
preop
,
std
::
vector
<
shape
>
inputs
)
{
program
p
;
auto
*
mm
=
p
.
get_main_module
();
std
::
vector
<
instruction_ref
>
args
;
inputs
.
pop_back
();
transform
(
inputs
,
range
(
inputs
.
size
()),
std
::
back_inserter
(
args
),
[
&
](
auto
input
,
auto
i
)
{
return
mm
->
add_parameter
(
"x"
+
std
::
to_string
(
i
),
input
);
});
mm
->
add_instruction
(
preop
,
args
);
return
p
;
}
static
operation
get_code_object
(
const
program
&
p
)
{
MIGRAPHX_TIDY_CONST
auto
*
mm
=
p
.
get_main_module
();
auto
it
=
std
::
find_if
(
mm
->
begin
(),
mm
->
end
(),
[](
const
auto
&
ins
)
{
return
(
ins
.
name
()
==
"gpu::code_object"
);
});
if
(
it
==
mm
->
end
())
MIGRAPHX_THROW
(
"Failed to create code object"
);
return
it
->
get_operator
();
}
static
void
apply
(
const
parser
&
p
,
const
value
&
v
)
{
context
ctx
;
auto
inputs
=
p
.
parse_shapes
(
v
.
at
(
"inputs"
));
auto
name
=
v
.
at
(
"name"
).
to
<
std
::
string
>
();
auto
preop
=
make_op
(
name
);
if
(
v
.
contains
(
"fields"
))
preop
.
from_value
(
v
.
at
(
"fields"
));
bool
exhaustive
=
v
.
get
(
"exhaustive"
,
false
);
auto
prog
=
create_preop_program
(
preop
,
inputs
);
run_passes
(
prog
,
{
lowering
{},
compile_ops
{
&
ctx
,
exhaustive
}});
auto
op
=
get_code_object
(
prog
);
auto
t
=
time_op
(
ctx
,
op
,
inputs
,
p
.
get
(
v
,
"iterations"
,
100
));
std
::
cout
<<
preop
<<
": "
<<
t
<<
"ms"
<<
std
::
endl
;
}
};
}
// namespace driver
}
// namespace gpu
}
// namespace MIGRAPHX_INLINE_NS
}
// namespace migraphx
src/targets/gpu/fuse_mlir.cpp
View file @
538dbd75
This diff is collapsed.
Click to expand it.
Prev
1
2
3
4
5
6
7
…
10
Next
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment