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
66483df6
Unverified
Commit
66483df6
authored
Sep 27, 2022
by
Chris Austen
Committed by
GitHub
Sep 27, 2022
Browse files
Merge branch 'develop' into simplify_1_mul_div_ops
parents
9310bff0
40118191
Changes
232
Show whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
796 additions
and
109 deletions
+796
-109
test/onnx/onnx_test.cpp
test/onnx/onnx_test.cpp
+148
-22
test/onnx/verify_onnx.cpp
test/onnx/verify_onnx.cpp
+191
-0
test/py/onnx_backend_test.py
test/py/onnx_backend_test.py
+3
-0
test/ref_ops_test.cpp
test/ref_ops_test.cpp
+1
-1
test/simplify_algebra_test.cpp
test/simplify_algebra_test.cpp
+148
-0
test/simplify_reshapes_test.cpp
test/simplify_reshapes_test.cpp
+101
-0
test/verify/test_concat_axis_2.cpp
test/verify/test_concat_axis_2.cpp
+20
-18
test/verify/test_conv_group_add.cpp
test/verify/test_conv_group_add.cpp
+17
-32
test/verify/test_fmod_mod.cpp
test/verify/test_fmod_mod.cpp
+73
-0
test/verify/test_layernorm.cpp
test/verify/test_layernorm.cpp
+18
-3
test/verify/test_unbatched_gemm_1.cpp
test/verify/test_unbatched_gemm_1.cpp
+58
-0
test/verify/test_unbatched_gemm_2.cpp
test/verify/test_unbatched_gemm_2.cpp
+18
-33
No files found.
test/onnx/onnx_test.cpp
View file @
66483df6
...
...
@@ -369,36 +369,134 @@ TEST_CASE(averagepool_same_upper_test)
EXPECT
(
p
==
prog
);
}
TEST_CASE
(
batchnorm_
1d
_test
)
TEST_CASE
(
batch
_
norm_
flat
_test
)
{
migraphx
::
program
p
;
auto
*
mm
=
p
.
get_main_module
();
auto
l0
=
mm
->
add_parameter
(
"0"
,
{
migraphx
::
shape
::
float_type
,
{
1
,
3
,
5
}});
auto
l1
=
mm
->
add_parameter
(
"1"
,
{
migraphx
::
shape
::
float_type
,
{
3
}});
auto
l2
=
mm
->
add_parameter
(
"2"
,
{
migraphx
::
shape
::
float_type
,
{
3
}});
auto
l3
=
mm
->
add_parameter
(
"3"
,
{
migraphx
::
shape
::
float_type
,
{
3
}});
auto
l4
=
mm
->
add_parameter
(
"4"
,
{
migraphx
::
shape
::
float_type
,
{
3
}});
mm
->
add_instruction
(
migraphx
::
make_op
(
"batch_norm_inference"
),
l0
,
l1
,
l2
,
l3
,
l4
);
auto
prog
=
optimize_onnx
(
"batchnorm_1d_test.onnx"
);
auto
x
=
mm
->
add_parameter
(
"x"
,
{
migraphx
::
shape
::
float_type
,
{
10
}});
auto
scale
=
mm
->
add_parameter
(
"scale"
,
{
migraphx
::
shape
::
float_type
,
{
1
}});
auto
bias
=
mm
->
add_parameter
(
"bias"
,
{
migraphx
::
shape
::
float_type
,
{
1
}});
auto
mean
=
mm
->
add_parameter
(
"mean"
,
{
migraphx
::
shape
::
float_type
,
{
1
}});
auto
var
=
mm
->
add_parameter
(
"variance"
,
{
migraphx
::
shape
::
float_type
,
{
1
}});
auto
rt
=
mm
->
add_literal
(
migraphx
::
literal
{
migraphx
::
shape
::
float_type
,
{
0.5
}});
auto
eps
=
mm
->
add_literal
(
migraphx
::
literal
{
migraphx
::
shape
::
float_type
,
{
1e-6
f
}});
auto
numer
=
add_common_op
(
*
mm
,
migraphx
::
make_op
(
"sub"
),
{
x
,
mean
});
auto
var_eps
=
add_common_op
(
*
mm
,
migraphx
::
make_op
(
"add"
),
{
var
,
eps
});
auto
denom
=
add_common_op
(
*
mm
,
migraphx
::
make_op
(
"pow"
),
{
var_eps
,
rt
});
auto
div0
=
add_common_op
(
*
mm
,
migraphx
::
make_op
(
"div"
),
{
numer
,
denom
});
auto
r0
=
add_common_op
(
*
mm
,
migraphx
::
make_op
(
"mul"
),
{
div0
,
scale
});
add_common_op
(
*
mm
,
migraphx
::
make_op
(
"add"
),
{
r0
,
bias
});
auto
prog
=
optimize_onnx
(
"batch_norm_flat_test.onnx"
);
EXPECT
(
p
==
prog
);
}
TEST_CASE
(
batchnorm_
3
d_test
)
TEST_CASE
(
batch
_
norm_
1
d_test
)
{
migraphx
::
program
p
;
auto
*
mm
=
p
.
get_main_module
();
auto
l0
=
mm
->
add_parameter
(
"0"
,
{
migraphx
::
shape
::
float_type
,
{
1
,
3
,
5
,
5
,
5
}});
auto
l1
=
mm
->
add_parameter
(
"1"
,
{
migraphx
::
shape
::
float_type
,
{
3
}});
auto
l2
=
mm
->
add_parameter
(
"2"
,
{
migraphx
::
shape
::
float_type
,
{
3
}});
auto
l3
=
mm
->
add_parameter
(
"3"
,
{
migraphx
::
shape
::
float_type
,
{
3
}});
auto
l4
=
mm
->
add_parameter
(
"4"
,
{
migraphx
::
shape
::
float_type
,
{
3
}});
mm
->
add_instruction
(
migraphx
::
make_op
(
"batch_norm_inference"
),
l0
,
l1
,
l2
,
l3
,
l4
);
auto
prog
=
optimize_onnx
(
"batchnorm_3d_test.onnx"
);
auto
x
=
mm
->
add_parameter
(
"x"
,
{
migraphx
::
shape
::
half_type
,
{
2
,
3
,
4
}});
auto
scale
=
mm
->
add_parameter
(
"scale"
,
{
migraphx
::
shape
::
float_type
,
{
3
}});
auto
bias
=
mm
->
add_parameter
(
"bias"
,
{
migraphx
::
shape
::
float_type
,
{
3
}});
auto
mean
=
mm
->
add_parameter
(
"mean"
,
{
migraphx
::
shape
::
float_type
,
{
3
}});
auto
var
=
mm
->
add_parameter
(
"variance"
,
{
migraphx
::
shape
::
float_type
,
{
3
}});
auto
rt
=
mm
->
add_literal
(
migraphx
::
literal
{
migraphx
::
shape
::
half_type
,
{
0.5
}});
auto
eps
=
mm
->
add_literal
(
migraphx
::
literal
{
migraphx
::
shape
::
half_type
,
{
1e-5
f
}});
auto
usq_scale
=
mm
->
add_instruction
(
migraphx
::
make_op
(
"unsqueeze"
,
{{
"axes"
,
{
1
}}}),
scale
);
auto
usq_bias
=
mm
->
add_instruction
(
migraphx
::
make_op
(
"unsqueeze"
,
{{
"axes"
,
{
1
}}}),
bias
);
auto
usq_mean
=
mm
->
add_instruction
(
migraphx
::
make_op
(
"unsqueeze"
,
{{
"axes"
,
{
1
}}}),
mean
);
auto
usq_var
=
mm
->
add_instruction
(
migraphx
::
make_op
(
"unsqueeze"
,
{{
"axes"
,
{
1
}}}),
var
);
auto
numer
=
add_common_op
(
*
mm
,
migraphx
::
make_op
(
"sub"
),
{
x
,
usq_mean
});
auto
var_eps
=
add_common_op
(
*
mm
,
migraphx
::
make_op
(
"add"
),
{
usq_var
,
eps
});
auto
denom
=
add_common_op
(
*
mm
,
migraphx
::
make_op
(
"pow"
),
{
var_eps
,
rt
});
auto
div0
=
add_common_op
(
*
mm
,
migraphx
::
make_op
(
"div"
),
{
numer
,
denom
});
auto
r0
=
add_common_op
(
*
mm
,
migraphx
::
make_op
(
"mul"
),
{
div0
,
usq_scale
});
add_common_op
(
*
mm
,
migraphx
::
make_op
(
"add"
),
{
r0
,
usq_bias
});
auto
prog
=
optimize_onnx
(
"batch_norm_1d_test.onnx"
);
EXPECT
(
p
==
prog
);
}
TEST_CASE
(
batch_norm_2d_test
)
{
migraphx
::
program
p
;
auto
*
mm
=
p
.
get_main_module
();
auto
x
=
mm
->
add_parameter
(
"x"
,
{
migraphx
::
shape
::
float_type
,
{
2
,
3
,
4
,
4
}});
auto
scale
=
mm
->
add_parameter
(
"scale"
,
{
migraphx
::
shape
::
float_type
,
{
3
}});
auto
bias
=
mm
->
add_parameter
(
"bias"
,
{
migraphx
::
shape
::
float_type
,
{
3
}});
auto
mean
=
mm
->
add_parameter
(
"mean"
,
{
migraphx
::
shape
::
float_type
,
{
3
}});
auto
var
=
mm
->
add_parameter
(
"variance"
,
{
migraphx
::
shape
::
float_type
,
{
3
}});
auto
rt
=
mm
->
add_literal
(
migraphx
::
literal
{
migraphx
::
shape
::
float_type
,
{
0.5
}});
auto
eps
=
mm
->
add_literal
(
migraphx
::
literal
{
migraphx
::
shape
::
float_type
,
{
1e-5
f
}});
auto
usq_scale
=
mm
->
add_instruction
(
migraphx
::
make_op
(
"unsqueeze"
,
{{
"axes"
,
{
1
,
2
}}}),
scale
);
auto
usq_bias
=
mm
->
add_instruction
(
migraphx
::
make_op
(
"unsqueeze"
,
{{
"axes"
,
{
1
,
2
}}}),
bias
);
auto
usq_mean
=
mm
->
add_instruction
(
migraphx
::
make_op
(
"unsqueeze"
,
{{
"axes"
,
{
1
,
2
}}}),
mean
);
auto
usq_var
=
mm
->
add_instruction
(
migraphx
::
make_op
(
"unsqueeze"
,
{{
"axes"
,
{
1
,
2
}}}),
var
);
auto
numer
=
add_common_op
(
*
mm
,
migraphx
::
make_op
(
"sub"
),
{
x
,
usq_mean
});
auto
var_eps
=
add_common_op
(
*
mm
,
migraphx
::
make_op
(
"add"
),
{
usq_var
,
eps
});
auto
denom
=
add_common_op
(
*
mm
,
migraphx
::
make_op
(
"pow"
),
{
var_eps
,
rt
});
auto
div0
=
add_common_op
(
*
mm
,
migraphx
::
make_op
(
"div"
),
{
numer
,
denom
});
auto
r0
=
add_common_op
(
*
mm
,
migraphx
::
make_op
(
"mul"
),
{
div0
,
usq_scale
});
add_common_op
(
*
mm
,
migraphx
::
make_op
(
"add"
),
{
r0
,
usq_bias
});
auto
prog
=
optimize_onnx
(
"batch_norm_2d_test.onnx"
);
EXPECT
(
p
==
prog
);
}
TEST_CASE
(
batch_norm_3d_test
)
{
migraphx
::
program
p
;
auto
*
mm
=
p
.
get_main_module
();
auto
x
=
mm
->
add_parameter
(
"x"
,
{
migraphx
::
shape
::
half_type
,
{
2
,
2
,
2
,
2
,
2
}});
auto
scale
=
mm
->
add_parameter
(
"scale"
,
{
migraphx
::
shape
::
half_type
,
{
2
}});
auto
bias
=
mm
->
add_parameter
(
"bias"
,
{
migraphx
::
shape
::
half_type
,
{
2
}});
auto
mean
=
mm
->
add_parameter
(
"mean"
,
{
migraphx
::
shape
::
half_type
,
{
2
}});
auto
var
=
mm
->
add_parameter
(
"variance"
,
{
migraphx
::
shape
::
half_type
,
{
2
}});
auto
rt
=
mm
->
add_literal
(
migraphx
::
literal
{
migraphx
::
shape
::
half_type
,
{
0.5
}});
auto
eps
=
mm
->
add_literal
(
migraphx
::
literal
{
migraphx
::
shape
::
half_type
,
{
1e-6
f
}});
auto
usq_scale
=
mm
->
add_instruction
(
migraphx
::
make_op
(
"unsqueeze"
,
{{
"axes"
,
{
1
,
2
,
3
}}}),
scale
);
auto
usq_bias
=
mm
->
add_instruction
(
migraphx
::
make_op
(
"unsqueeze"
,
{{
"axes"
,
{
1
,
2
,
3
}}}),
bias
);
auto
usq_mean
=
mm
->
add_instruction
(
migraphx
::
make_op
(
"unsqueeze"
,
{{
"axes"
,
{
1
,
2
,
3
}}}),
mean
);
auto
usq_var
=
mm
->
add_instruction
(
migraphx
::
make_op
(
"unsqueeze"
,
{{
"axes"
,
{
1
,
2
,
3
}}}),
var
);
auto
numer
=
add_common_op
(
*
mm
,
migraphx
::
make_op
(
"sub"
),
{
x
,
usq_mean
});
auto
var_eps
=
add_common_op
(
*
mm
,
migraphx
::
make_op
(
"add"
),
{
usq_var
,
eps
});
auto
denom
=
add_common_op
(
*
mm
,
migraphx
::
make_op
(
"pow"
),
{
var_eps
,
rt
});
auto
div0
=
add_common_op
(
*
mm
,
migraphx
::
make_op
(
"div"
),
{
numer
,
denom
});
auto
r0
=
add_common_op
(
*
mm
,
migraphx
::
make_op
(
"mul"
),
{
div0
,
usq_scale
});
add_common_op
(
*
mm
,
migraphx
::
make_op
(
"add"
),
{
r0
,
usq_bias
});
auto
prog
=
optimize_onnx
(
"batch_norm_3d_test.onnx"
);
EXPECT
(
p
==
prog
);
}
TEST_CASE
(
batch_norm_invalid_rank
)
{
EXPECT
(
test
::
throws
([
&
]
{
migraphx
::
parse_onnx
(
"batch_norm_invalid_rank.onnx"
);
}));
}
TEST_CASE
(
batch_norm_invalid_bias_rank
)
{
EXPECT
(
test
::
throws
([
&
]
{
migraphx
::
parse_onnx
(
"batch_norm_invalid_bias_rank.onnx"
);
}));
}
TEST_CASE
(
cast_test
)
{
migraphx
::
program
p
;
...
...
@@ -795,14 +893,42 @@ TEST_CASE(conv_bn_relu_maxpool_test)
auto
p4
=
mm
->
add_parameter
(
"4"
,
{
migraphx
::
shape
::
float_type
,
{
1
}});
auto
p5
=
mm
->
add_parameter
(
"5"
,
{
migraphx
::
shape
::
float_type
,
{
1
}});
auto
p6
=
mm
->
add_parameter
(
"6"
,
{
migraphx
::
shape
::
float_type
,
{
1
}});
auto
rt
=
mm
->
add_literal
(
migraphx
::
literal
{
migraphx
::
shape
::
float_type
,
{
0.5
}});
auto
eps
=
mm
->
add_literal
(
migraphx
::
literal
{
migraphx
::
shape
::
float_type
,
{
1e-5
f
}});
uint64_t
axis
=
1
;
auto
l3
=
mm
->
add_instruction
(
migraphx
::
make_op
(
"convolution"
,
{{
"padding"
,
{
0
,
0
,
0
,
0
}}}),
l0
,
l1
);
auto
l4
=
mm
->
add_instruction
(
migraphx
::
make_op
(
"broadcast"
,
{{
"axis"
,
axis
},
{
"out_lens"
,
l3
->
get_shape
().
lens
()}}),
l2
);
auto
l5
=
mm
->
add_instruction
(
migraphx
::
make_op
(
"add"
),
l3
,
l4
);
auto
l6
=
mm
->
add_instruction
(
migraphx
::
make_op
(
"batch_norm_inference"
,
{{
"epsilon"
,
1.0e-5
f
}}),
l5
,
p3
,
p4
,
p5
,
p6
);
auto
usq_scale
=
mm
->
add_instruction
(
migraphx
::
make_op
(
"unsqueeze"
,
{{
"axes"
,
{
1
,
2
}}}),
p3
);
auto
usq_bias
=
mm
->
add_instruction
(
migraphx
::
make_op
(
"unsqueeze"
,
{{
"axes"
,
{
1
,
2
}}}),
p4
);
auto
usq_mean
=
mm
->
add_instruction
(
migraphx
::
make_op
(
"unsqueeze"
,
{{
"axes"
,
{
1
,
2
}}}),
p5
);
auto
usq_var
=
mm
->
add_instruction
(
migraphx
::
make_op
(
"unsqueeze"
,
{{
"axes"
,
{
1
,
2
}}}),
p6
);
auto
mb_mean
=
mm
->
add_instruction
(
migraphx
::
make_op
(
"multibroadcast"
,
{{
"out_lens"
,
{
1
,
1
,
28
,
28
}}}),
usq_mean
);
auto
numer
=
mm
->
add_instruction
(
migraphx
::
make_op
(
"sub"
),
l5
,
mb_mean
);
auto
mb_eps
=
mm
->
add_instruction
(
migraphx
::
make_op
(
"multibroadcast"
,
{{
"out_lens"
,
{
1
,
1
,
1
}}}),
eps
);
auto
var_eps
=
mm
->
add_instruction
(
migraphx
::
make_op
(
"add"
),
usq_var
,
mb_eps
);
auto
mb_rt
=
mm
->
add_instruction
(
migraphx
::
make_op
(
"multibroadcast"
,
{{
"out_lens"
,
{
1
,
1
,
1
}}}),
rt
);
auto
denom
=
mm
->
add_instruction
(
migraphx
::
make_op
(
"pow"
),
var_eps
,
mb_rt
);
auto
mb_denom
=
mm
->
add_instruction
(
migraphx
::
make_op
(
"multibroadcast"
,
{{
"out_lens"
,
{
1
,
1
,
28
,
28
}}}),
denom
);
auto
div0
=
mm
->
add_instruction
(
migraphx
::
make_op
(
"div"
),
numer
,
mb_denom
);
auto
mb_scale
=
mm
->
add_instruction
(
migraphx
::
make_op
(
"multibroadcast"
,
{{
"out_lens"
,
{
1
,
1
,
28
,
28
}}}),
usq_scale
);
auto
r0
=
mm
->
add_instruction
(
migraphx
::
make_op
(
"mul"
),
div0
,
mb_scale
);
auto
mb_bias
=
mm
->
add_instruction
(
migraphx
::
make_op
(
"multibroadcast"
,
{{
"out_lens"
,
{
1
,
1
,
28
,
28
}}}),
usq_bias
);
auto
l6
=
mm
->
add_instruction
(
migraphx
::
make_op
(
"add"
),
r0
,
mb_bias
);
auto
l7
=
mm
->
add_instruction
(
migraphx
::
make_op
(
"relu"
),
l6
);
mm
->
add_instruction
(
migraphx
::
make_op
(
"pooling"
,
{{
"mode"
,
migraphx
::
op
::
pooling_mode
::
max
},
...
...
test/onnx/verify_onnx.cpp
View file @
66483df6
...
...
@@ -30,6 +30,7 @@
#include <migraphx/pass_manager.hpp>
#include <migraphx/verify.hpp>
#include <migraphx/onnx.hpp>
#include <migraphx/half.hpp>
#include "test.hpp"
TEST_CASE
(
averagepool_notset_test
)
...
...
@@ -68,6 +69,196 @@ TEST_CASE(averagepool_nt_cip_test)
EXPECT
(
migraphx
::
verify_range
(
result_vector
,
gold
));
}
TEST_CASE
(
batch_norm_flat_test
)
{
migraphx
::
program
p
=
migraphx
::
parse_onnx
(
"batch_norm_flat_test.onnx"
);
p
.
compile
(
migraphx
::
ref
::
target
{});
migraphx
::
shape
x_shape
{
migraphx
::
shape
::
float_type
,
{
10
}};
migraphx
::
shape
c_shape
(
migraphx
::
shape
::
float_type
,
{
1
});
std
::
vector
<
float
>
x_data
=
{
1.6524342
,
-
0.51048076
,
0.32543048
,
2.4410043
,
2.0833702
,
0.44981122
,
1.0044622
,
-
0.24006313
,
-
0.43065986
,
0.07626268
};
std
::
vector
<
float
>
scale_data
=
{
-
0.02927135
};
std
::
vector
<
float
>
bias_data
=
{
0.42347777
};
std
::
vector
<
float
>
mean_data
=
{
-
0.00449735
};
std
::
vector
<
float
>
variance_data
=
{
0.5184545
};
migraphx
::
parameter_map
params
;
params
[
"x"
]
=
migraphx
::
argument
(
x_shape
,
x_data
.
data
());
params
[
"scale"
]
=
migraphx
::
argument
(
c_shape
,
scale_data
.
data
());
params
[
"bias"
]
=
migraphx
::
argument
(
c_shape
,
bias_data
.
data
());
params
[
"mean"
]
=
migraphx
::
argument
(
c_shape
,
mean_data
.
data
());
params
[
"variance"
]
=
migraphx
::
argument
(
c_shape
,
variance_data
.
data
());
auto
result
=
p
.
eval
(
params
).
back
();
std
::
vector
<
float
>
result_vector
;
result
.
visit
([
&
](
auto
output
)
{
result_vector
.
assign
(
output
.
begin
(),
output
.
end
());
});
std
::
vector
<
float
>
gold
=
{
0.35612
,
0.44404706
,
0.4100655
,
0.32406294
,
0.33860153
,
0.40500915
,
0.38246143
,
0.43305403
,
0.4408022
,
0.42019472
};
EXPECT
(
migraphx
::
verify_range
(
result_vector
,
gold
));
}
TEST_CASE
(
batch_norm_1d_test
)
{
migraphx
::
program
p
=
migraphx
::
parse_onnx
(
"batch_norm_1d_test.onnx"
);
p
.
compile
(
migraphx
::
ref
::
target
{});
migraphx
::
shape
x_shape
{
migraphx
::
shape
::
half_type
,
{
2
,
3
,
4
}};
migraphx
::
shape
c_shape
(
migraphx
::
shape
::
float_type
,
{
3
});
std
::
vector
<
float
>
tmp
=
{
1.652
,
-
0.5103
,
0.3254
,
2.441
,
2.084
,
0.4497
,
1.005
,
-
0.2401
,
-
0.4307
,
0.07623
,
-
0.02927
,
0.4236
,
-
0.004498
,
-
0.4282
,
-
0.5527
,
0.02205
,
-
1.472
,
-
1.7295
,
0.796
,
0.9507
,
0.2312
,
0.664
,
-
0.06964
,
1.035
};
std
::
vector
<
migraphx
::
half
>
x_data
{
tmp
.
cbegin
(),
tmp
.
cend
()};
std
::
vector
<
float
>
scale_data
=
{
-
1.336926
,
-
1.0679098
,
0.10368501
};
std
::
vector
<
float
>
bias_data
=
{
0.20240043
,
-
0.70175606
,
-
0.8859727
};
std
::
vector
<
float
>
mean_data
=
{
0.30854642
,
-
0.36574763
,
-
0.9463552
};
std
::
vector
<
float
>
variance_data
=
{
0.43428132
,
0.97773486
,
0.30332062
};
migraphx
::
parameter_map
params
;
params
[
"x"
]
=
migraphx
::
argument
(
x_shape
,
x_data
.
data
());
params
[
"scale"
]
=
migraphx
::
argument
(
c_shape
,
scale_data
.
data
());
params
[
"bias"
]
=
migraphx
::
argument
(
c_shape
,
bias_data
.
data
());
params
[
"mean"
]
=
migraphx
::
argument
(
c_shape
,
mean_data
.
data
());
params
[
"variance"
]
=
migraphx
::
argument
(
c_shape
,
variance_data
.
data
());
auto
result
=
p
.
eval
(
params
).
back
();
std
::
vector
<
migraphx
::
half
>
result_vector
;
result
.
visit
([
&
](
auto
output
)
{
result_vector
.
assign
(
output
.
begin
(),
output
.
end
());
});
tmp
=
{
-
2.523
,
1.863
,
0.1681
,
-
4.125
,
-
3.348
,
-
1.582
,
-
2.182
,
-
0.8374
,
-
0.789
,
-
0.6934
,
-
0.7134
,
-
0.628
,
0.8374
,
1.697
,
1.949
,
0.7837
,
0.4927
,
0.771
,
-
1.956
,
-
2.123
,
-
0.664
,
-
0.583
,
-
0.7207
,
-
0.5127
};
std
::
vector
<
migraphx
::
half
>
gold
{
tmp
.
cbegin
(),
tmp
.
cend
()};
EXPECT
(
migraphx
::
verify_range
(
result_vector
,
gold
));
}
TEST_CASE
(
batch_norm_2d_test
)
{
migraphx
::
program
p
=
migraphx
::
parse_onnx
(
"batch_norm_2d_test.onnx"
);
p
.
compile
(
migraphx
::
ref
::
target
{});
migraphx
::
shape
x_shape
{
migraphx
::
shape
::
float_type
,
{
2
,
3
,
4
,
4
}};
migraphx
::
shape
c_shape
(
migraphx
::
shape
::
float_type
,
{
3
});
std
::
vector
<
float
>
x_data
=
{
1.6524342
,
-
0.51048076
,
0.32543048
,
2.4410043
,
2.0833702
,
0.44981122
,
1.0044622
,
-
0.24006313
,
-
0.43065986
,
0.07626268
,
-
0.02927135
,
0.42347777
,
-
0.00449735
,
-
0.4281568
,
-
0.5527635
,
0.02204161
,
-
1.4719028
,
-
1.7298799
,
0.79596406
,
0.9505461
,
0.23115851
,
0.6639593
,
-
0.06963254
,
1.0348768
,
-
1.336926
,
-
1.0679098
,
0.10368501
,
0.20240043
,
-
0.70175606
,
-
0.8859727
,
0.30854642
,
-
0.36574763
,
-
0.9463552
,
0.9476916
,
0.37686515
,
-
0.05184272
,
-
0.7151244
,
-
0.37341377
,
0.59440356
,
0.10051094
,
-
0.20755945
,
0.9098465
,
1.1664004
,
1.4075205
,
-
1.1522529
,
-
0.34607422
,
0.32027543
,
-
0.6885485
,
0.5404544
,
0.10012514
,
0.8767704
,
1.0032021
,
-
1.2755303
,
0.23577735
,
0.74239916
,
1.0146079
,
0.60875916
,
-
0.29163074
,
1.4872868
,
0.20466477
,
-
0.26367408
,
-
0.56394804
,
-
0.56043875
,
0.7763664
,
-
0.9626441
,
0.29653943
,
-
3.2231965
,
0.03322164
,
0.03402911
,
0.77308357
,
-
0.0654009
,
-
0.30463725
,
0.22182712
,
-
0.22594836
,
-
0.5807543
,
-
0.22390617
,
-
0.24484141
,
-
2.0761833
,
1.8459716
,
0.2455878
,
0.99913245
,
-
0.9266217
,
-
0.1938893
,
0.6417983
,
-
1.0880078
,
0.49565446
,
2.1584804
,
1.2276239
,
3.3091128
,
0.14217089
,
0.9425477
,
0.07578196
,
0.4067431
,
0.71984154
,
-
0.20796849
,
0.90003085
};
std
::
vector
<
float
>
scale_data
=
{
0.658487
,
0.03700604
,
2.463201
};
std
::
vector
<
float
>
bias_data
=
{
0.03497279
,
0.17080553
,
0.5636415
};
std
::
vector
<
float
>
mean_data
=
{
0.1954783
,
0.6203974
,
0.8116831
};
std
::
vector
<
float
>
variance_data
=
{
0.30558077
,
0.04536599
,
0.05461315
};
migraphx
::
parameter_map
params
;
params
[
"x"
]
=
migraphx
::
argument
(
x_shape
,
x_data
.
data
());
params
[
"scale"
]
=
migraphx
::
argument
(
c_shape
,
scale_data
.
data
());
params
[
"bias"
]
=
migraphx
::
argument
(
c_shape
,
bias_data
.
data
());
params
[
"mean"
]
=
migraphx
::
argument
(
c_shape
,
mean_data
.
data
());
params
[
"variance"
]
=
migraphx
::
argument
(
c_shape
,
variance_data
.
data
());
auto
result
=
p
.
eval
(
params
).
back
();
std
::
vector
<
float
>
result_vector
;
result
.
visit
([
&
](
auto
output
)
{
result_vector
.
assign
(
output
.
begin
(),
output
.
end
());
});
std
::
vector
<
float
>
gold
=
{
1.77046824e+00
,
-
8.05950999e-01
,
1.89769119e-01
,
2.70979643e+00
,
2.28379035e+00
,
3.37928861e-01
,
9.98617530e-01
,
-
4.83835101e-01
,
-
7.10869908e-01
,
-
1.07034385e-01
,
-
2.32744321e-01
,
3.06560963e-01
,
-
2.03234047e-01
,
-
7.07888365e-01
,
-
8.56317282e-01
,
-
1.71621382e-01
,
-
1.92677066e-01
,
-
2.37493858e-01
,
2.01305658e-01
,
2.28160262e-01
,
1.03185430e-01
,
1.78373277e-01
,
5.09308279e-02
,
2.42810518e-01
,
-
1.69228360e-01
,
-
1.22493818e-01
,
8.10402334e-02
,
9.81894583e-02
,
-
5.88841513e-02
,
-
9.08869803e-02
,
1.16629556e-01
,
-
5.11445105e-04
,
-
1.79648399e+01
,
1.99707508e+00
,
-
4.01903248e+00
,
-
8.53731060e+00
,
-
1.55278311e+01
,
-
1.19264421e+01
,
-
1.72633123e+00
,
-
6.93161058e+00
,
-
1.01784554e+01
,
1.59821415e+00
,
4.30211163e+00
,
6.84334660e+00
,
-
2.01348572e+01
,
-
1.16383028e+01
,
-
4.61544800e+00
,
-
1.52477398e+01
,
4.45901126e-01
,
-
7.86099210e-02
,
8.46513629e-01
,
9.97116446e-01
,
-
1.71726203e+00
,
8.29761624e-02
,
6.86453462e-01
,
1.01070285e+00
,
5.27264357e-01
,
-
5.45261383e-01
,
1.57374811e+00
,
4.59154993e-02
,
-
5.11959970e-01
,
-
8.69639993e-01
,
-
8.65459919e-01
,
7.26914644e-01
,
-
1.04206637e-01
,
1.14543661e-01
,
-
4.96918678e-01
,
6.87990561e-02
,
6.89393356e-02
,
1.97330773e-01
,
5.16659655e-02
,
1.01048872e-02
,
1.01564340e-01
,
2.37750299e-02
,
-
3.78632471e-02
,
2.41298079e-02
,
2.04928555e-02
,
-
2.97655046e-01
,
3.83717060e-01
,
1.05692141e-01
,
2.53922558e+00
,
-
1.77568626e+01
,
-
1.00343809e+01
,
-
1.22682428e+00
,
-
1.94577579e+01
,
-
2.76707697e+00
,
1.47579327e+01
,
4.94736385e+00
,
2.68847847e+01
,
-
6.49254417e+00
,
1.94286156e+00
,
-
7.19223642e+00
,
-
3.70413971e+00
,
-
4.04303551e-01
,
-
1.01827660e+01
,
1.49476433e+00
};
EXPECT
(
migraphx
::
verify_range
(
result_vector
,
gold
));
}
TEST_CASE
(
batch_norm_3d_test
)
{
migraphx
::
program
p
=
migraphx
::
parse_onnx
(
"batch_norm_3d_test.onnx"
);
p
.
compile
(
migraphx
::
ref
::
target
{});
migraphx
::
shape
x_shape
{
migraphx
::
shape
::
half_type
,
{
2
,
2
,
2
,
2
,
2
}};
migraphx
::
shape
c_shape
(
migraphx
::
shape
::
half_type
,
{
2
});
// using migraphx::half copy conversion since it doesn't have initializer_list constructor
std
::
vector
<
float
>
tmp
=
{
5.
,
5.
,
8.
,
7.
,
3.
,
4.
,
1.
,
7.
,
5.
,
5.
,
9.
,
4.
,
7.
,
2.
,
2.
,
2.
,
6.
,
1.
,
4.
,
9.
,
2.
,
8.
,
0.
,
2.
,
1.
,
4.
,
8.
,
8.
,
3.
,
3.
,
0.
,
8.
};
std
::
vector
<
migraphx
::
half
>
x_data
{
tmp
.
cbegin
(),
tmp
.
cend
()};
tmp
=
{
1.
,
1.
};
std
::
vector
<
migraphx
::
half
>
scale_data
{
tmp
.
cbegin
(),
tmp
.
cend
()};
tmp
=
{
0.
,
0.
,
};
std
::
vector
<
migraphx
::
half
>
bias_data
{
tmp
.
cbegin
(),
tmp
.
cend
()};
tmp
=
{
-
0.75
,
0.29
};
std
::
vector
<
migraphx
::
half
>
mean_data
{
tmp
.
cbegin
(),
tmp
.
cend
()};
tmp
=
{
0.31
,
0.37
};
std
::
vector
<
migraphx
::
half
>
variance_data
{
tmp
.
cbegin
(),
tmp
.
cend
()};
migraphx
::
parameter_map
params
;
params
[
"x"
]
=
migraphx
::
argument
(
x_shape
,
x_data
.
data
());
params
[
"scale"
]
=
migraphx
::
argument
(
c_shape
,
scale_data
.
data
());
params
[
"bias"
]
=
migraphx
::
argument
(
c_shape
,
bias_data
.
data
());
params
[
"mean"
]
=
migraphx
::
argument
(
c_shape
,
mean_data
.
data
());
params
[
"variance"
]
=
migraphx
::
argument
(
c_shape
,
variance_data
.
data
());
auto
result
=
p
.
eval
(
params
).
back
();
std
::
vector
<
migraphx
::
half
>
result_vector
;
result
.
visit
([
&
](
auto
output
)
{
result_vector
.
assign
(
output
.
begin
(),
output
.
end
());
});
tmp
=
{
10.33
,
10.33
,
15.71
,
13.914
,
6.734
,
8.53
,
3.143
,
13.914
,
7.742
,
7.742
,
14.32
,
6.098
,
11.03
,
2.81
,
2.81
,
2.81
,
12.125
,
3.143
,
8.53
,
17.52
,
4.938
,
15.71
,
1.347
,
4.938
,
1.167
,
6.098
,
12.67
,
12.67
,
4.453
,
4.453
,
-
0.4768
,
12.67
};
std
::
vector
<
migraphx
::
half
>
gold
{
tmp
.
cbegin
(),
tmp
.
cend
()};
EXPECT
(
migraphx
::
verify_range
(
result_vector
,
gold
));
}
TEST_CASE
(
celu_verify_test
)
{
migraphx
::
program
p
=
migraphx
::
parse_onnx
(
"celu_verify_test.onnx"
);
...
...
test/py/onnx_backend_test.py
View file @
66483df6
...
...
@@ -138,6 +138,7 @@ def create_backend_test(testname=None, target_device=None):
backend_test
.
include
(
r
'.*test_eyelike.*'
)
backend_test
.
include
(
r
'.*test_flatten.*'
)
backend_test
.
include
(
r
'.*test_floor.*'
)
backend_test
.
include
(
r
'.*test_fmod.*'
)
backend_test
.
include
(
r
'.*test_gather.*'
)
backend_test
.
include
(
r
'.*test_gemm.*'
)
backend_test
.
include
(
r
'.*test_globalaveragepool.*'
)
...
...
@@ -162,6 +163,7 @@ def create_backend_test(testname=None, target_device=None):
backend_test
.
include
(
r
'.*test_MaxPool[1-9]d.*'
)
backend_test
.
include
(
r
'.*test_mean.*'
)
backend_test
.
include
(
r
'.*test_min.*'
)
backend_test
.
include
(
r
' .*test_mod.*'
)
backend_test
.
include
(
r
'.*test_mul.*'
)
backend_test
.
include
(
r
'.*test_multinomial.*'
)
backend_test
.
include
(
r
'.*test_Multinomial.*'
)
...
...
@@ -179,6 +181,7 @@ def create_backend_test(testname=None, target_device=None):
backend_test
.
include
(
r
'.*test_operator_max_.*'
)
backend_test
.
include
(
r
'.*test_operator_maxpool.*'
)
backend_test
.
include
(
r
'.*test_operator_min.*'
)
backend_test
.
include
(
r
'.*test_operator_mod.*'
)
backend_test
.
include
(
r
'.*test_operator_mm.*'
)
backend_test
.
include
(
r
'.*test_operator_non_float_params.*'
)
backend_test
.
include
(
r
'.*test_operator_params.*'
)
...
...
test/ref_ops_test.cpp
View file @
66483df6
...
...
@@ -3591,7 +3591,7 @@ TEST_CASE(multinomial_test)
result
.
visit
([
&
](
auto
output
)
{
result_vec
.
assign
(
output
.
begin
(),
output
.
end
());
});
std
::
vector
<
int
>
res_dist
(
5
,
0
);
for
(
auto
&
r
:
result_vec
)
for
(
const
auto
&
r
:
result_vec
)
res_dist
[
r
]
++
;
auto
dist_sum
=
std
::
accumulate
(
dist
.
begin
(),
dist
.
end
(),
0
);
auto
res_dist_sum
=
std
::
accumulate
(
res_dist
.
begin
(),
res_dist
.
end
(),
0
);
...
...
test/simplify_algebra_test.cpp
View file @
66483df6
...
...
@@ -263,6 +263,105 @@ TEST_CASE(simplify_mul_conv1)
EXPECT
(
new_conv
->
outputs
().
front
()
->
name
()
!=
"mul"
);
}
TEST_CASE
(
simplify_mul_conv2
)
{
migraphx
::
module
m
;
auto
x
=
m
.
add_parameter
(
"x"
,
{
migraphx
::
shape
::
int32_type
,
{
1
,
128
,
28
,
28
}});
auto
w
=
m
.
add_literal
(
migraphx
::
generate_literal
({
migraphx
::
shape
::
int32_type
,
{
256
,
128
,
3
,
3
}}));
auto
conv
=
m
.
add_instruction
(
migraphx
::
make_op
(
"convolution"
,
{{
"padding"
,
{
1
,
1
}},
{
"stride"
,
{
2
,
2
}},
{
"dilation"
,
{
1
,
1
}}}),
x
,
w
);
auto
a
=
m
.
add_literal
(
migraphx
::
generate_literal
({
migraphx
::
shape
::
int32_type
,
{
256
}}));
auto
unsq_a
=
m
.
add_instruction
(
migraphx
::
make_op
(
"unsqueeze"
,
{{
"axes"
,
{
1
,
2
}}}),
a
);
auto
b
=
m
.
add_instruction
(
migraphx
::
make_op
(
"multibroadcast"
,
{{
"out_lens"
,
{
1
,
256
,
14
,
14
}}}),
unsq_a
);
auto
mul
=
m
.
add_instruction
(
migraphx
::
make_op
(
"mul"
),
conv
,
b
);
m
.
add_instruction
(
pass_op
{},
mul
);
EXPECT
(
conv
->
outputs
().
front
()
->
name
()
==
"mul"
);
run_pass
(
m
);
auto
new_conv
=
std
::
find_if
(
m
.
begin
(),
m
.
end
(),
[](
auto
&&
ins
)
{
return
ins
.
name
()
==
"convolution"
;
});
EXPECT
(
new_conv
->
outputs
().
front
()
->
name
()
!=
"mul"
);
}
// len = 1 case
TEST_CASE
(
simplify_mul_conv3
)
{
migraphx
::
module
m
;
auto
x
=
m
.
add_parameter
(
"x"
,
{
migraphx
::
shape
::
int32_type
,
{
1
,
128
,
28
,
28
}});
auto
w
=
m
.
add_literal
(
migraphx
::
generate_literal
({
migraphx
::
shape
::
int32_type
,
{
256
,
128
,
3
,
3
}}));
auto
conv
=
m
.
add_instruction
(
migraphx
::
make_op
(
"convolution"
,
{{
"padding"
,
{
1
,
1
}},
{
"stride"
,
{
2
,
2
}},
{
"dilation"
,
{
1
,
1
}}}),
x
,
w
);
auto
a
=
m
.
add_literal
(
migraphx
::
generate_literal
({
migraphx
::
shape
::
int32_type
,
{
256
,
1
,
1
},
{
1
,
18
,
1
}}));
auto
b
=
m
.
add_instruction
(
migraphx
::
make_op
(
"multibroadcast"
,
{{
"out_lens"
,
{
1
,
256
,
14
,
14
}}}),
a
);
auto
mul
=
m
.
add_instruction
(
migraphx
::
make_op
(
"mul"
),
conv
,
b
);
m
.
add_instruction
(
pass_op
{},
mul
);
EXPECT
(
conv
->
outputs
().
front
()
->
name
()
==
"mul"
);
run_pass
(
m
);
auto
new_conv
=
std
::
find_if
(
m
.
begin
(),
m
.
end
(),
[](
auto
&&
ins
)
{
return
ins
.
name
()
==
"convolution"
;
});
EXPECT
(
new_conv
->
outputs
().
front
()
->
name
()
!=
"mul"
);
}
// Previously broadcasted literal case, should skip
TEST_CASE
(
simplify_mul_conv_skip1
)
{
migraphx
::
module
m
;
auto
x
=
m
.
add_parameter
(
"x"
,
{
migraphx
::
shape
::
int32_type
,
{
1
,
128
,
28
,
28
}});
auto
w
=
m
.
add_literal
(
migraphx
::
generate_literal
({
migraphx
::
shape
::
int32_type
,
{
256
,
128
,
3
,
3
}}));
auto
conv
=
m
.
add_instruction
(
migraphx
::
make_op
(
"convolution"
,
{{
"padding"
,
{
1
,
1
}},
{
"stride"
,
{
2
,
2
}},
{
"dilation"
,
{
1
,
1
}}}),
x
,
w
);
auto
a
=
m
.
add_literal
(
migraphx
::
generate_literal
({
migraphx
::
shape
::
int32_type
,
{
256
,
14
,
14
},
{
1
,
0
,
0
}}));
auto
b
=
m
.
add_instruction
(
migraphx
::
make_op
(
"broadcast"
,
{{
"axis"
,
1
},
{
"out_lens"
,
{
1
,
256
,
14
,
14
}}}),
a
);
auto
mul
=
m
.
add_instruction
(
migraphx
::
make_op
(
"mul"
),
conv
,
b
);
m
.
add_instruction
(
pass_op
{},
mul
);
EXPECT
(
conv
->
outputs
().
front
()
->
name
()
==
"mul"
);
run_pass
(
m
);
auto
new_conv
=
std
::
find_if
(
m
.
begin
(),
m
.
end
(),
[](
auto
&&
ins
)
{
return
ins
.
name
()
==
"convolution"
;
});
EXPECT
(
new_conv
->
outputs
().
front
()
->
name
()
==
"mul"
);
}
// Another previously broadcasted literal case, should skip
TEST_CASE
(
simplify_mul_conv_skip2
)
{
migraphx
::
module
m
;
auto
x
=
m
.
add_parameter
(
"x"
,
{
migraphx
::
shape
::
int32_type
,
{
1
,
128
,
28
,
28
}});
auto
w
=
m
.
add_literal
(
migraphx
::
generate_literal
({
migraphx
::
shape
::
int32_type
,
{
256
,
128
,
3
,
3
}}));
auto
conv
=
m
.
add_instruction
(
migraphx
::
make_op
(
"convolution"
,
{{
"padding"
,
{
1
,
1
}},
{
"stride"
,
{
2
,
2
}},
{
"dilation"
,
{
1
,
1
}}}),
x
,
w
);
auto
a
=
m
.
add_literal
(
migraphx
::
generate_literal
({
migraphx
::
shape
::
int32_type
,
{
256
,
14
,
14
},
{
1
,
0
,
0
}}));
auto
b
=
m
.
add_instruction
(
migraphx
::
make_op
(
"multibroadcast"
,
{{
"out_lens"
,
{
1
,
256
,
14
,
14
}}}),
a
);
auto
mul
=
m
.
add_instruction
(
migraphx
::
make_op
(
"mul"
),
conv
,
b
);
m
.
add_instruction
(
pass_op
{},
mul
);
EXPECT
(
conv
->
outputs
().
front
()
->
name
()
==
"mul"
);
run_pass
(
m
);
auto
new_conv
=
std
::
find_if
(
m
.
begin
(),
m
.
end
(),
[](
auto
&&
ins
)
{
return
ins
.
name
()
==
"convolution"
;
});
EXPECT
(
new_conv
->
outputs
().
front
()
->
name
()
==
"mul"
);
}
TEST_CASE
(
simplify_mul_slice_conv1
)
{
migraphx
::
module
m1
;
...
...
@@ -2583,6 +2682,55 @@ TEST_CASE(reorder_reshape_slice_move_axis2)
EXPECT
(
m1
.
sort
()
==
m2
.
sort
());
}
TEST_CASE
(
reorder_reshape_slice_len_1
)
{
migraphx
::
module
m1
;
{
migraphx
::
shape
s
{
migraphx
::
shape
::
float_type
,
{
1
,
128
,
3
}};
auto
input
=
m1
.
add_parameter
(
"input"
,
s
);
auto
slc0
=
m1
.
add_instruction
(
migraphx
::
make_op
(
"slice"
,
{{
"axes"
,
{
2
}},
{
"starts"
,
{
0
}},
{
"ends"
,
{
1
}}}),
input
);
auto
slc1
=
m1
.
add_instruction
(
migraphx
::
make_op
(
"slice"
,
{{
"axes"
,
{
2
}},
{
"starts"
,
{
1
}},
{
"ends"
,
{
2
}}}),
input
);
auto
slc2
=
m1
.
add_instruction
(
migraphx
::
make_op
(
"slice"
,
{{
"axes"
,
{
2
}},
{
"starts"
,
{
2
}},
{
"ends"
,
{
3
}}}),
input
);
auto
c0
=
m1
.
add_instruction
(
migraphx
::
make_op
(
"contiguous"
),
slc0
);
auto
c1
=
m1
.
add_instruction
(
migraphx
::
make_op
(
"contiguous"
),
slc1
);
auto
c2
=
m1
.
add_instruction
(
migraphx
::
make_op
(
"contiguous"
),
slc2
);
std
::
vector
<
int64_t
>
lens
=
{
1
,
128
};
auto
r0
=
m1
.
add_instruction
(
migraphx
::
make_op
(
"reshape"
,
{{
"dims"
,
lens
}}),
c0
);
auto
r1
=
m1
.
add_instruction
(
migraphx
::
make_op
(
"reshape"
,
{{
"dims"
,
lens
}}),
c1
);
auto
r2
=
m1
.
add_instruction
(
migraphx
::
make_op
(
"reshape"
,
{{
"dims"
,
lens
}}),
c2
);
auto
sum
=
m1
.
add_instruction
(
migraphx
::
make_op
(
"add"
),
r0
,
r1
);
auto
ret
=
m1
.
add_instruction
(
migraphx
::
make_op
(
"mul"
),
sum
,
r2
);
m1
.
add_return
({
ret
});
};
migraphx
::
module
m2
;
{
auto
s
=
migraphx
::
shape
{
migraphx
::
shape
::
float_type
,
{
1
,
128
,
3
}};
auto
input
=
m2
.
add_parameter
(
"input"
,
s
);
std
::
vector
<
int64_t
>
lens
=
{
1
,
384
};
auto
rsp
=
m2
.
add_instruction
(
migraphx
::
make_op
(
"reshape"
,
{{
"dims"
,
lens
}}),
input
);
auto
slc0
=
m2
.
add_instruction
(
migraphx
::
make_op
(
"slice"
,
{{
"axes"
,
{
1
}},
{
"starts"
,
{
0
}},
{
"ends"
,
{
128
}}}),
rsp
);
auto
slc1
=
m2
.
add_instruction
(
migraphx
::
make_op
(
"slice"
,
{{
"axes"
,
{
1
}},
{
"starts"
,
{
128
}},
{
"ends"
,
{
256
}}}),
rsp
);
auto
slc2
=
m2
.
add_instruction
(
migraphx
::
make_op
(
"slice"
,
{{
"axes"
,
{
1
}},
{
"starts"
,
{
256
}},
{
"ends"
,
{
384
}}}),
rsp
);
auto
sum
=
m2
.
add_instruction
(
migraphx
::
make_op
(
"add"
),
slc0
,
slc1
);
auto
ret
=
m2
.
add_instruction
(
migraphx
::
make_op
(
"mul"
),
sum
,
slc2
);
m2
.
add_return
({
ret
});
};
run_pass
(
m1
);
EXPECT
(
m1
.
sort
()
==
m2
.
sort
());
}
TEST_CASE
(
reorder_reshape_slice_not_apply
)
{
auto
create_p
=
[]
{
...
...
test/simplify_reshapes_test.cpp
View file @
66483df6
...
...
@@ -48,6 +48,26 @@ inline std::vector<std::vector<std::size_t>> to_lens(const std::vector<migraphx:
return
result
;
}
migraphx
::
module
make_concat_multibroadcast
(
const
std
::
vector
<
size_t
>&
in_lens
,
const
std
::
vector
<
size_t
>&
mbcast_lens
,
const
int
axis
)
{
migraphx
::
module
m
;
auto
s
=
migraphx
::
shape
{
migraphx
::
shape
::
float_type
,
in_lens
};
auto
x
=
m
.
add_parameter
(
"x"
,
s
);
auto
y
=
m
.
add_parameter
(
"y"
,
s
);
auto
z
=
m
.
add_parameter
(
"z"
,
s
);
auto
xm
=
m
.
add_instruction
(
migraphx
::
make_op
(
"multibroadcast"
,
{{
"out_lens"
,
mbcast_lens
}}),
x
);
auto
ym
=
m
.
add_instruction
(
migraphx
::
make_op
(
"multibroadcast"
,
{{
"out_lens"
,
mbcast_lens
}}),
y
);
auto
zm
=
m
.
add_instruction
(
migraphx
::
make_op
(
"multibroadcast"
,
{{
"out_lens"
,
mbcast_lens
}}),
z
);
auto
concat
=
m
.
add_instruction
(
migraphx
::
make_op
(
"concat"
,
{{
"axis"
,
axis
}}),
xm
,
ym
,
zm
);
m
.
add_return
({
concat
});
return
m
;
}
TEST_CASE
(
double_contig
)
{
migraphx
::
program
p
;
...
...
@@ -337,6 +357,87 @@ TEST_CASE(nop_convert)
EXPECT
(
std
::
distance
(
m
.
begin
(),
m
.
end
())
==
n
-
1
);
}
TEST_CASE
(
concat_multibroadcasts1
)
{
// Broadcasted batch dim, new axis < old axis
std
::
vector
<
std
::
size_t
>
in_lens
=
{
3
,
4
};
std
::
vector
<
std
::
size_t
>
mbcast_lens
=
{
2
,
3
,
4
};
const
int
axis
=
2
;
auto
m
=
make_concat_multibroadcast
(
in_lens
,
mbcast_lens
,
axis
);
auto
out_shape
=
m
.
get_output_shapes
().
back
();
auto
n
=
std
::
distance
(
m
.
begin
(),
m
.
end
());
run_pass
(
m
);
EXPECT
(
m
.
get_output_shapes
().
back
().
lens
()
==
out_shape
.
lens
());
EXPECT
(
std
::
distance
(
m
.
begin
(),
m
.
end
())
==
n
-
2
);
auto
new_concat
=
std
::
find_if
(
m
.
begin
(),
m
.
end
(),
[](
auto
ins
)
{
return
ins
.
name
()
==
"concat"
;
});
EXPECT
(
bool
{
new_concat
!=
m
.
end
()});
auto
cd
=
std
::
distance
(
m
.
begin
(),
new_concat
);
auto
new_mb
=
std
::
find_if
(
m
.
begin
(),
m
.
end
(),
[](
auto
ins
)
{
return
ins
.
name
()
==
"multibroadcast"
;
});
auto
md
=
std
::
distance
(
m
.
begin
(),
new_mb
);
EXPECT
(
cd
==
md
-
1
);
EXPECT
(
migraphx
::
any_cast
<
migraphx
::
op
::
concat
>
(
new_concat
->
get_operator
()).
axis
==
1
);
}
TEST_CASE
(
concat_multibroadcasts2
)
{
// Broadcasted middle dim, new axis == old axis
std
::
vector
<
std
::
size_t
>
in_lens
=
{
3
,
1
,
4
};
std
::
vector
<
std
::
size_t
>
mbcast_lens
=
{
3
,
2
,
4
};
const
int
axis
=
0
;
auto
m
=
make_concat_multibroadcast
(
in_lens
,
mbcast_lens
,
axis
);
auto
out_shape
=
m
.
get_output_shapes
().
back
();
auto
n
=
std
::
distance
(
m
.
begin
(),
m
.
end
());
run_pass
(
m
);
EXPECT
(
m
.
get_output_shapes
().
back
().
lens
()
==
out_shape
.
lens
());
EXPECT
(
std
::
distance
(
m
.
begin
(),
m
.
end
())
==
n
-
2
);
auto
new_concat
=
std
::
find_if
(
m
.
begin
(),
m
.
end
(),
[](
auto
ins
)
{
return
ins
.
name
()
==
"concat"
;
});
EXPECT
(
bool
{
new_concat
!=
m
.
end
()});
auto
cd
=
std
::
distance
(
m
.
begin
(),
new_concat
);
auto
new_mb
=
std
::
find_if
(
m
.
begin
(),
m
.
end
(),
[](
auto
ins
)
{
return
ins
.
name
()
==
"multibroadcast"
;
});
auto
md
=
std
::
distance
(
m
.
begin
(),
new_mb
);
EXPECT
(
cd
==
md
-
1
);
EXPECT
(
migraphx
::
any_cast
<
migraphx
::
op
::
concat
>
(
new_concat
->
get_operator
()).
axis
==
0
);
}
TEST_CASE
(
concat_multibroadcasts3
)
{
// Broadcasted middle dim, new axis == old axis
std
::
vector
<
std
::
size_t
>
in_lens
=
{
3
,
1
,
4
};
std
::
vector
<
std
::
size_t
>
mbcast_lens
=
{
3
,
2
,
4
};
const
int
axis
=
2
;
auto
m
=
make_concat_multibroadcast
(
in_lens
,
mbcast_lens
,
axis
);
auto
out_shape
=
m
.
get_output_shapes
().
back
();
auto
n
=
std
::
distance
(
m
.
begin
(),
m
.
end
());
run_pass
(
m
);
EXPECT
(
m
.
get_output_shapes
().
back
().
lens
()
==
out_shape
.
lens
());
EXPECT
(
std
::
distance
(
m
.
begin
(),
m
.
end
())
==
n
-
2
);
auto
new_concat
=
std
::
find_if
(
m
.
begin
(),
m
.
end
(),
[](
auto
ins
)
{
return
ins
.
name
()
==
"concat"
;
});
EXPECT
(
bool
{
new_concat
!=
m
.
end
()});
auto
cd
=
std
::
distance
(
m
.
begin
(),
new_concat
);
auto
new_mb
=
std
::
find_if
(
m
.
begin
(),
m
.
end
(),
[](
auto
ins
)
{
return
ins
.
name
()
==
"multibroadcast"
;
});
auto
md
=
std
::
distance
(
m
.
begin
(),
new_mb
);
EXPECT
(
cd
==
md
-
1
);
EXPECT
(
migraphx
::
any_cast
<
migraphx
::
op
::
concat
>
(
new_concat
->
get_operator
()).
axis
==
2
);
}
TEST_CASE
(
concat_multibroadcasts4
)
{
// Broadcasted batch dim, axis is broadcasted dim
std
::
vector
<
std
::
size_t
>
in_lens
=
{
3
,
4
};
std
::
vector
<
std
::
size_t
>
mbcast_lens
=
{
2
,
3
,
4
};
const
int
axis
=
0
;
auto
m
=
make_concat_multibroadcast
(
in_lens
,
mbcast_lens
,
axis
);
auto
m1
=
m
;
run_pass
(
m
);
EXPECT
(
m1
==
m
);
}
TEST_CASE
(
concat_transpose1
)
{
migraphx
::
module
m
;
...
...
src/targets/gpu/include/migraphx/gpu/device/softmax.h
pp
→
test/verify/test_concat_axis_2.c
pp
View file @
66483df6
...
...
@@ -21,23 +21,25 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef MIGRAPHX_GUARD_RTGLIB_DEVICE_SOFTMAX_HPP
#define MIGRAPHX_GUARD_RTGLIB_DEVICE_SOFTMAX_HPP
#include <migraphx/argument.hpp>
#include <migraphx/config.hpp>
#include <hip/hip_runtime_api.h>
#include "verify_program.hpp"
#include <migraphx/program.hpp>
#include <migraphx/generate.hpp>
#include <migraphx/make_op.hpp>
namespace
migraphx
{
inline
namespace
MIGRAPHX_INLINE_NS
{
namespace
gpu
{
namespace
device
{
void
softmax
(
hipStream_t
stream
,
const
argument
&
result
,
const
argument
&
arg
,
int64_t
axis
);
}
// namespace device
}
// namespace gpu
}
// namespace MIGRAPHX_INLINE_NS
}
// namespace migraphx
#endif
struct
test_concat_axis_2
:
verify_program
<
test_concat_axis_2
>
{
migraphx
::
program
create_program
()
const
{
migraphx
::
program
p
;
auto
*
mm
=
p
.
get_main_module
();
migraphx
::
shape
s0
{
migraphx
::
shape
::
int32_type
,
{
3
,
2
,
1
}};
migraphx
::
shape
s1
{
migraphx
::
shape
::
int32_type
,
{
3
,
2
,
1
}};
migraphx
::
shape
s2
{
migraphx
::
shape
::
int32_type
,
{
3
,
2
,
1
}};
auto
l0
=
mm
->
add_parameter
(
"x"
,
s0
);
auto
l1
=
mm
->
add_parameter
(
"y"
,
s1
);
auto
l2
=
mm
->
add_parameter
(
"z"
,
s2
);
mm
->
add_instruction
(
migraphx
::
make_op
(
"concat"
,
{{
"axis"
,
2
}}),
l0
,
l1
,
l2
);
return
p
;
}
};
src/targets/gpu/include/migraphx/gpu/concat.h
pp
→
test/verify/test_conv_group_add.c
pp
View file @
66483df6
...
...
@@ -21,41 +21,26 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef MIGRAPHX_GUARD_RTGLIB_CONCAT_HPP
#define MIGRAPHX_GUARD_RTGLIB_CONCAT_HPP
#include <migraphx/argument.hpp>
#include <migraphx/reflect.hpp>
#include <migraphx/op/concat.hpp>
#include "verify_program.hpp"
#include <migraphx/program.hpp>
#include <migraphx/generate.hpp>
#include <migraphx/make_op.hpp>
namespace
migraphx
{
inline
namespace
MIGRAPHX_INLINE_NS
{
namespace
gpu
{
struct
context
;
struct
hip_concat
struct
test_conv_group_add
:
verify_program
<
test_conv_group_add
>
{
op
::
concat
op
;
template
<
class
Self
,
class
F
>
static
auto
reflect
(
Self
&
self
,
F
f
)
{
return
migraphx
::
reflect
(
self
.
op
,
f
);
}
std
::
string
name
()
const
{
return
"gpu::concat"
;
}
shape
compute_shape
(
std
::
vector
<
shape
>
inputs
)
const
;
argument
compute
(
context
&
ctx
,
const
shape
&
output_shape
,
const
std
::
vector
<
argument
>&
args
)
const
;
std
::
ptrdiff_t
output_alias
(
const
std
::
vector
<
shape
>&
shapes
)
const
migraphx
::
program
create_program
()
const
{
return
shapes
.
size
()
-
1
;
migraphx
::
program
p
;
auto
*
mm
=
p
.
get_main_module
();
migraphx
::
shape
s
{
migraphx
::
shape
::
float_type
,
{
1
,
68
,
28
,
28
}};
auto
x
=
mm
->
add_parameter
(
"x"
,
s
);
auto
w
=
mm
->
add_parameter
(
"w"
,
{
migraphx
::
shape
::
float_type
,
{
68
,
17
,
1
,
1
}});
auto
b
=
mm
->
add_parameter
(
"b"
,
{
migraphx
::
shape
::
float_type
,
{
68
}});
auto
conv
=
mm
->
add_instruction
(
migraphx
::
make_op
(
"convolution"
,
{{
"group"
,
4
}}),
x
,
w
);
auto
bb
=
mm
->
add_instruction
(
migraphx
::
make_op
(
"broadcast"
,
{{
"axis"
,
1
},
{
"out_lens"
,
{
1
,
68
,
28
,
28
}}}),
b
);
mm
->
add_instruction
(
migraphx
::
make_op
(
"add"
),
conv
,
bb
);
return
p
;
}
};
}
// namespace gpu
}
// namespace MIGRAPHX_INLINE_NS
}
// namespace migraphx
#endif
src/targets/gpu/include/migraphx/gpu/convert.h
pp
→
test/verify/test_fmod_mod.c
pp
View file @
66483df6
...
...
@@ -21,43 +21,53 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef MIGRAPHX_GUARD_RTGLIB_CONVERT_HPP
#define MIGRAPHX_GUARD_RTGLIB_CONVERT_HPP
#include <migraphx/argument.hpp>
#include <migraphx/reflect.hpp>
#include <migraphx/op/convert.hpp>
#include "verify_program.hpp"
#include <migraphx/program.hpp>
#include <migraphx/generate.hpp>
#include <migraphx/make_op.hpp>
#include <migraphx/common.hpp>
namespace
migraphx
{
inline
namespace
MIGRAPHX_INLINE_NS
{
namespace
gpu
{
struct
context
;
/*
Checking for y == 0 ? eps : y
struct
hip_convert
Adding this because HIP fmod sign changes when y = 0 resulting in nan and -nan not beign
consistent between ref and gpu implementations.
*/
migraphx
::
instruction_ref
add_epsilon
(
migraphx
::
module
&
m
,
migraphx
::
instruction_ref
y
)
{
op
::
convert
op
;
auto
zero
=
m
.
add_literal
(
0.0
f
);
auto
eps
=
m
.
add_literal
(
1e-3
f
);
auto
op_y
=
add_common_op
(
m
,
migraphx
::
make_op
(
"equal"
),
{
y
,
zero
});
return
add_common_op
(
m
,
migraphx
::
make_op
(
"where"
),
{
op_y
,
eps
,
y
});
}
template
<
class
Self
,
class
F
>
static
auto
reflect
(
Self
&
self
,
F
f
)
struct
test_fmod
:
verify_program
<
test_fmod
>
{
migraphx
::
program
create_program
()
const
{
return
migraphx
::
reflect
(
self
.
op
,
f
);
migraphx
::
program
p
;
auto
*
mm
=
p
.
get_main_module
();
migraphx
::
shape
s
{
migraphx
::
shape
::
float_type
,
{
64
}};
auto
x
=
mm
->
add_parameter
(
"x"
,
s
);
auto
y
=
mm
->
add_parameter
(
"y"
,
s
);
auto
op_where
=
add_epsilon
(
*
mm
,
y
);
mm
->
add_instruction
(
migraphx
::
make_op
(
"fmod"
),
x
,
op_where
);
return
p
;
}
};
std
::
string
name
()
const
{
return
"gpu::convert"
;
}
shape
compute_shape
(
std
::
vector
<
shape
>
inputs
)
const
;
argument
compute
(
context
&
ctx
,
const
shape
&
,
const
std
::
vector
<
argument
>&
args
)
const
;
std
::
ptrdiff_t
output_alias
(
const
std
::
vector
<
shape
>&
shapes
)
const
struct
test_mod
:
verify_program
<
test_mod
>
{
migraphx
::
program
create_program
()
const
{
return
shapes
.
size
()
-
1
;
migraphx
::
program
p
;
auto
*
mm
=
p
.
get_main_module
();
migraphx
::
shape
s
{
migraphx
::
shape
::
float_type
,
{
64
}};
auto
x
=
mm
->
add_parameter
(
"x"
,
s
);
auto
y
=
mm
->
add_parameter
(
"y"
,
s
);
auto
op_where
=
add_epsilon
(
*
mm
,
y
);
mm
->
add_instruction
(
migraphx
::
make_op
(
"mod"
),
x
,
op_where
);
return
p
;
}
};
}
// namespace gpu
}
// namespace MIGRAPHX_INLINE_NS
}
// namespace migraphx
#endif
test/verify/test_layernorm.cpp
View file @
66483df6
...
...
@@ -29,14 +29,16 @@
#include <migraphx/op/reduce_mean.hpp>
migraphx
::
instruction_ref
add_layernorm
(
migraphx
::
module
&
m
,
migraphx
::
instruction_ref
x
,
std
::
vector
<
size_t
>
dims
)
migraphx
::
instruction_ref
add_layernorm
(
migraphx
::
module
&
m
,
migraphx
::
instruction_ref
x
,
std
::
vector
<
size_t
>
dims
,
float
eps
=
1e-12
f
)
{
auto
scale
=
m
.
add_parameter
(
"scale"
,
migraphx
::
shape
{
migraphx
::
shape
::
float_type
,
{
dims
.
back
()}});
auto
bias
=
m
.
add_parameter
(
"bias"
,
migraphx
::
shape
{
migraphx
::
shape
::
float_type
,
{
dims
.
back
()}});
auto
epsilon
=
m
.
add_literal
(
1e-12
f
);
auto
epsilon
=
m
.
add_literal
(
eps
);
auto
exponent
=
m
.
add_literal
(
2.0
f
);
auto
mean
=
m
.
add_instruction
(
migraphx
::
op
::
reduce_mean
({
2
}),
x
);
...
...
@@ -88,6 +90,19 @@ struct test_layernorm2 : verify_program<test_layernorm2>
}
};
struct
test_layernorm_eps
:
verify_program
<
test_layernorm_eps
>
{
migraphx
::
program
create_program
()
const
{
migraphx
::
program
p
;
auto
*
mm
=
p
.
get_main_module
();
std
::
vector
<
size_t
>
dims
=
{
1
,
2
,
5
};
auto
x
=
mm
->
add_parameter
(
"x"
,
migraphx
::
shape
{
migraphx
::
shape
::
float_type
,
dims
});
add_layernorm
(
*
mm
,
x
,
dims
,
1e-5
f
);
return
p
;
}
};
struct
test_layernorm_triadd
:
verify_program
<
test_layernorm_triadd
>
{
migraphx
::
program
create_program
()
const
...
...
test/verify/test_unbatched_gemm_1.cpp
0 → 100644
View file @
66483df6
/*
* 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.
*/
#include "verify_program.hpp"
#include <migraphx/program.hpp>
#include <migraphx/generate.hpp>
#include <migraphx/make_op.hpp>
#include <migraphx/apply_alpha_beta.hpp>
struct
test_unbatched_gemm_1
:
verify_program
<
test_unbatched_gemm_1
>
{
migraphx
::
program
create_program
()
const
{
migraphx
::
program
p
;
auto
*
mm
=
p
.
get_main_module
();
migraphx
::
shape
m1_shape
{
migraphx
::
shape
::
float_type
,
{
2
,
32
,
64
}};
migraphx
::
shape
m2_shape
{
migraphx
::
shape
::
float_type
,
{
64
,
64
}};
migraphx
::
shape
m3_shape
{
migraphx
::
shape
::
float_type
,
{
2
,
32
,
192
}};
auto
l1
=
mm
->
add_parameter
(
"1"
,
m1_shape
);
auto
l2
=
mm
->
add_literal
(
migraphx
::
generate_literal
(
m2_shape
));
l2
=
mm
->
add_instruction
(
migraphx
::
make_op
(
"multibroadcast"
,
{{
"out_lens"
,
{
2
,
64
,
64
}}}),
l2
);
auto
l3
=
mm
->
add_literal
(
migraphx
::
generate_literal
(
m2_shape
));
l3
=
mm
->
add_instruction
(
migraphx
::
make_op
(
"multibroadcast"
,
{{
"out_lens"
,
{
2
,
64
,
64
}}}),
l3
);
auto
l4
=
mm
->
add_literal
(
migraphx
::
generate_literal
(
m2_shape
));
l4
=
mm
->
add_instruction
(
migraphx
::
make_op
(
"multibroadcast"
,
{{
"out_lens"
,
{
2
,
64
,
64
}}}),
l4
);
auto
concat
=
mm
->
add_instruction
(
migraphx
::
make_op
(
"concat"
,
{{
"axis"
,
2
}}),
l2
,
l3
,
l4
);
auto
l5
=
mm
->
add_parameter
(
"3"
,
m3_shape
);
float
alpha
=
1.0
f
;
float
beta
=
1.0
f
;
migraphx
::
add_apply_alpha_beta
(
*
mm
,
{
l1
,
concat
,
l5
},
migraphx
::
make_op
(
"dot"
),
alpha
,
beta
);
return
p
;
}
};
src/targets/gpu/include/migraphx/gpu/clip.h
pp
→
test/verify/test_unbatched_gemm_2.c
pp
View file @
66483df6
...
...
@@ -21,41 +21,26 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef MIGRAPHX_GUARD_RTGLIB_CLIP_HPP
#define MIGRAPHX_GUARD_RTGLIB_CLIP_HPP
#include <migraphx/argument.hpp>
#include <migraphx/reflect.hpp>
#include <migraphx/op/clip.hpp>
namespace
migraphx
{
inline
namespace
MIGRAPHX_INLINE_NS
{
namespace
gpu
{
struct
context
;
struct
hip_clip
#include "verify_program.hpp"
#include <migraphx/program.hpp>
#include <migraphx/generate.hpp>
#include <migraphx/make_op.hpp>
#include <migraphx/apply_alpha_beta.hpp>
struct
test_unbatched_gemm_2
:
verify_program
<
test_unbatched_gemm_2
>
{
op
::
clip
op
;
template
<
class
Self
,
class
F
>
static
auto
reflect
(
Self
&
self
,
F
f
)
migraphx
::
program
create_program
()
const
{
return
migraphx
::
reflect
(
self
.
op
,
f
);
}
std
::
string
name
()
const
{
return
"gpu::clip"
;
}
shape
compute_shape
(
std
::
vector
<
shape
>
inputs
)
const
;
argument
compute
(
context
&
ctx
,
const
shape
&
output_shape
,
const
std
::
vector
<
argument
>&
args
)
const
;
std
::
ptrdiff_t
output_alias
(
const
std
::
vector
<
shape
>&
shapes
)
const
{
return
shapes
.
size
()
-
1
;
migraphx
::
program
p
;
auto
*
mm
=
p
.
get_main_module
();
migraphx
::
shape
m1_shape
{
migraphx
::
shape
::
float_type
,
{
4
,
32
,
64
}};
migraphx
::
shape
m2_shape
{
migraphx
::
shape
::
float_type
,
{
64
,
64
}};
auto
l1
=
mm
->
add_parameter
(
"1"
,
m1_shape
);
auto
l2
=
mm
->
add_literal
(
migraphx
::
generate_literal
(
m2_shape
));
l2
=
mm
->
add_instruction
(
migraphx
::
make_op
(
"multibroadcast"
,
{{
"out_lens"
,
{
4
,
64
,
64
}}}),
l2
);
mm
->
add_instruction
(
migraphx
::
make_op
(
"dot"
),
l1
,
l2
);
return
p
;
}
};
}
// namespace gpu
}
// namespace MIGRAPHX_INLINE_NS
}
// namespace migraphx
#endif
Prev
1
…
8
9
10
11
12
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