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
f12064ee
Commit
f12064ee
authored
Aug 25, 2023
by
umangyadav
Browse files
Merge branch 'develop' into resnet50_partition
parents
2c4f70be
6f1c947f
Changes
126
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
712 additions
and
386 deletions
+712
-386
src/api/CMakeLists.txt
src/api/CMakeLists.txt
+1
-0
src/api/api.cpp
src/api/api.cpp
+3
-3
src/api/include/migraphx/migraphx.h
src/api/include/migraphx/migraphx.h
+298
-266
src/api/migraphx.py
src/api/migraphx.py
+3
-2
src/driver/CMakeLists.txt
src/driver/CMakeLists.txt
+1
-1
src/driver/argument_parser.hpp
src/driver/argument_parser.hpp
+14
-4
src/driver/main.cpp
src/driver/main.cpp
+22
-9
src/dynamic_loader.cpp
src/dynamic_loader.cpp
+13
-1
src/eliminate_contiguous.cpp
src/eliminate_contiguous.cpp
+20
-1
src/fuse_pointwise.cpp
src/fuse_pointwise.cpp
+1
-1
src/fuse_reduce.cpp
src/fuse_reduce.cpp
+2
-2
src/include/migraphx/algorithm.hpp
src/include/migraphx/algorithm.hpp
+38
-0
src/include/migraphx/builtin.hpp
src/include/migraphx/builtin.hpp
+11
-1
src/include/migraphx/check_shapes.hpp
src/include/migraphx/check_shapes.hpp
+28
-23
src/include/migraphx/dynamic_loader.hpp
src/include/migraphx/dynamic_loader.hpp
+4
-0
src/include/migraphx/normalize_attributes.hpp
src/include/migraphx/normalize_attributes.hpp
+32
-1
src/include/migraphx/op/convolution.hpp
src/include/migraphx/op/convolution.hpp
+1
-1
src/include/migraphx/op/if_op.hpp
src/include/migraphx/op/if_op.hpp
+1
-1
src/include/migraphx/op/loop.hpp
src/include/migraphx/op/loop.hpp
+3
-3
src/include/migraphx/op/slice.hpp
src/include/migraphx/op/slice.hpp
+216
-66
No files found.
src/api/CMakeLists.txt
View file @
f12064ee
...
...
@@ -26,6 +26,7 @@ add_library(migraphx_c
api.cpp
)
set_target_properties
(
migraphx_c PROPERTIES EXPORT_NAME c
)
migraphx_generate_export_header
(
migraphx_c DIRECTORY migraphx/api
)
# migraphx_c is stable API interface library. SO version of this should be
# bumped when binary compatibility is broken.
...
...
src/api/api.cpp
View file @
f12064ee
...
...
@@ -44,7 +44,7 @@ namespace migraphx {
static
thread_local
bool
disable_exception_catch
=
false
;
// NOLINT
extern
"C"
void
migraphx_test_private_disable_exception_catch
(
bool
b
)
extern
"C"
MIGRAPHX_C_EXPORT
void
migraphx_test_private_disable_exception_catch
(
bool
b
)
{
disable_exception_catch
=
b
;
}
...
...
@@ -899,7 +899,7 @@ migraphx_dynamic_dimensions_assign_to(migraphx_dynamic_dimensions_t output,
extern
"C"
migraphx_status
migraphx_dynamic_dimensions_create
(
migraphx_dynamic_dimensions_t
*
dynamic_dimensions
,
const_migraphx_dynamic_dimension_t
*
ptr
,
const
const_migraphx_dynamic_dimension_t
*
ptr
,
size_t
size
)
{
auto
api_error_result
=
migraphx
::
try_
([
&
]
{
...
...
@@ -1432,7 +1432,7 @@ extern "C" migraphx_status migraphx_instructions_assign_to(migraphx_instructions
}
extern
"C"
migraphx_status
migraphx_instructions_create
(
migraphx_instructions_t
*
instructions
,
const_migraphx_instruction_t
*
ptr
,
const
const_migraphx_instruction_t
*
ptr
,
size_t
size
)
{
auto
api_error_result
=
migraphx
::
try_
([
&
]
{
...
...
src/api/include/migraphx/migraphx.h
View file @
f12064ee
This diff is collapsed.
Click to expand it.
src/api/migraphx.py
View file @
f12064ee
...
...
@@ -79,7 +79,8 @@ def dynamic_dimension(h):
def
dynamic_dimensions
(
h
):
h
.
constructor
(
'create'
,
api
.
params
(
ptr
=
'const_migraphx_dynamic_dimension_t*'
,
size
=
'size_t'
),
api
.
params
(
ptr
=
'const const_migraphx_dynamic_dimension_t*'
,
size
=
'size_t'
),
fname
=
'migraphx::to_obj_vector<const_migraphx_dynamic_dimension_t>'
)
h
.
method
(
'size'
,
returns
=
'size_t'
)
h
.
method
(
'get'
,
...
...
@@ -215,7 +216,7 @@ def instruction(h):
def
instructions
(
h
):
h
.
constructor
(
'create'
,
api
.
params
(
ptr
=
'const_migraphx_instruction_t*'
,
size
=
'size_t'
),
api
.
params
(
ptr
=
'const
const
_migraphx_instruction_t*'
,
size
=
'size_t'
),
fname
=
'migraphx::to_obj_vector<const_migraphx_instruction_t>'
)
...
...
src/driver/CMakeLists.txt
View file @
f12064ee
...
...
@@ -45,7 +45,7 @@ if(NOT WIN32)
endif
()
rocm_clang_tidy_check
(
driver
)
target_link_libraries
(
driver migraphx_all_targets migraphx_onnx migraphx_tf
)
target_link_libraries
(
driver migraphx_all_targets migraphx_onnx migraphx_tf
migraphx_py
)
rocm_install_targets
(
TARGETS driver
...
...
src/driver/argument_parser.hpp
View file @
f12064ee
...
...
@@ -338,11 +338,22 @@ struct argument_parser
MIGRAPHX_DRIVER_STATIC
auto
file_exist
()
{
return
validate
([](
auto
&
,
auto
&
,
auto
&
params
)
{
return
validate
([](
auto
&
,
auto
&
,
const
auto
&
params
)
{
if
(
params
.
empty
())
throw
std
::
runtime_error
(
"No argument passed."
);
if
(
not
fs
::
exists
(
params
.
back
()))
throw
std
::
runtime_error
(
"Path does not exists: "
+
params
.
back
());
throw
std
::
runtime_error
(
"Path does not exist: "
+
params
.
back
());
});
}
MIGRAPHX_DRIVER_STATIC
auto
matches
(
const
std
::
unordered_set
<
std
::
string
>&
names
)
{
return
validate
([
=
](
auto
&
,
auto
&
,
const
auto
&
params
)
{
auto
invalid_param
=
std
::
find_if
(
params
.
begin
(),
params
.
end
(),
[
&
](
const
auto
&
p
)
{
return
names
.
count
(
p
)
==
0
;
});
if
(
invalid_param
!=
params
.
end
())
throw
std
::
runtime_error
(
"Invalid argument: "
+
*
invalid_param
+
". Valid arguments are {"
+
to_string_range
(
names
)
+
"}"
);
});
}
...
...
@@ -570,8 +581,7 @@ struct argument_parser
continue
;
if
(
flag
[
0
]
!=
'-'
)
continue
;
auto
d
=
levenshtein_distance
(
flag
.
begin
(),
flag
.
end
(),
input
.
begin
(),
input
.
end
());
std
::
ptrdiff_t
d
=
levenshtein_distance
(
flag
,
input
);
if
(
d
<
result
.
distance
)
result
=
result_t
{
&
arg
,
flag
,
input
,
d
};
}
...
...
src/driver/main.cpp
View file @
f12064ee
...
...
@@ -32,6 +32,7 @@
#include <migraphx/tf.hpp>
#include <migraphx/onnx.hpp>
#include <migraphx/py.hpp>
#include <migraphx/stringutils.hpp>
#include <migraphx/convert_to_json.hpp>
#include <migraphx/load_save.hpp>
...
...
@@ -81,6 +82,7 @@ struct loader
{
"--model"
},
ap
.
help
(
"Load model"
),
ap
.
type
(
"resnet50|inceptionv3|alexnet"
),
ap
.
matches
({
"resnet50"
,
"inceptionv3"
,
"alexnet"
}),
ap
.
group
(
"input"
));
ap
(
file_type
,
{
"--onnx"
},
ap
.
help
(
"Load as onnx"
),
ap
.
set_value
(
"onnx"
));
ap
(
file_type
,
{
"--tf"
},
ap
.
help
(
"Load as tensorflow"
),
ap
.
set_value
(
"tf"
));
...
...
@@ -241,6 +243,20 @@ struct loader
return
options
;
}
static
std
::
string
get_file_type
(
const
std
::
string
&
file
)
{
if
(
ends_with
(
file
,
".onnx"
))
return
"onnx"
;
else
if
(
ends_with
(
file
,
".pb"
))
return
"tf"
;
else
if
(
ends_with
(
file
,
".json"
))
return
"json"
;
else
if
(
ends_with
(
file
,
".py"
))
return
"py"
;
else
return
"migraphx"
;
}
program
load
()
{
program
p
;
...
...
@@ -248,14 +264,7 @@ struct loader
{
if
(
file_type
.
empty
())
{
if
(
ends_with
(
file
,
".onnx"
))
file_type
=
"onnx"
;
else
if
(
ends_with
(
file
,
".pb"
))
file_type
=
"tf"
;
else
if
(
ends_with
(
file
,
".json"
))
file_type
=
"json"
;
else
file_type
=
"migraphx"
;
file_type
=
get_file_type
(
file
);
}
std
::
cout
<<
"Reading: "
<<
file
<<
std
::
endl
;
if
(
file_type
==
"onnx"
)
...
...
@@ -272,6 +281,10 @@ struct loader
options
.
format
=
"json"
;
p
=
migraphx
::
load
(
file
,
options
);
}
else
if
(
file_type
==
"py"
)
{
p
=
migraphx
::
load_py
(
file
);
}
else
if
(
file_type
==
"migraphx"
)
{
p
=
migraphx
::
load
(
file
);
...
...
@@ -757,7 +770,7 @@ struct main_command
{
std
::
cout
<<
"'"
<<
color
::
fg_yellow
<<
wrong_commands
.
front
()
<<
color
::
reset
<<
"' is not a valid command."
<<
std
::
endl
;
std
::
cout
<<
get_command_help
(
"Available commands:"
)
<<
std
::
endl
;
std
::
cout
<<
get_command_help
(
"Available commands:"
);
}
else
{
...
...
src/dynamic_loader.cpp
View file @
f12064ee
...
...
@@ -48,7 +48,7 @@ struct dynamic_loader_impl
#pragma GCC diagnostic ignored "-Wignored-attributes"
#endif
dynamic_loader_impl
(
const
fs
::
path
&
p
,
std
::
shared_ptr
<
tmp_dir
>
t
=
nullptr
)
:
handle
(
dlopen
(
p
.
string
().
c_str
(),
RTLD_
LAZY
),
:
handle
(
dlopen
(
p
.
string
().
c_str
(),
RTLD_
GLOBAL
|
RTLD_NOW
),
manage_deleter
<
decltype
(
&
dlclose
),
&
dlclose
>
{}),
temp
(
std
::
move
(
t
))
{
...
...
@@ -81,6 +81,18 @@ fs::path dynamic_loader::path(void* address)
return
p
;
}
optional
<
dynamic_loader
>
dynamic_loader
::
try_load
(
const
fs
::
path
&
p
)
{
try
{
return
dynamic_loader
{
p
};
}
catch
(
const
std
::
exception
&
)
{
return
nullopt
;
}
}
dynamic_loader
::
dynamic_loader
(
const
fs
::
path
&
p
)
:
impl
(
std
::
make_shared
<
dynamic_loader_impl
>
(
p
))
{
}
...
...
src/eliminate_contiguous.cpp
View file @
f12064ee
...
...
@@ -35,6 +35,8 @@
namespace
migraphx
{
inline
namespace
MIGRAPHX_INLINE_NS
{
MIGRAPHX_DECLARE_ENV_VAR
(
MIGRAPHX_TRACE_ELIMINATE_CONTIGUOUS
)
static
bool
try_compute_shape
(
instruction_ref
ins
,
const
std
::
vector
<
shape
>&
inputs
,
const
std
::
vector
<
module_ref
>&
mods
)
...
...
@@ -78,14 +80,26 @@ static bool try_compute_shape(instruction_ref ins,
return
(
arg
==
ins
)
?
new_shape
:
arg
->
get_shape
();
});
if
(
not
try_compute_shape
(
output
,
input_shapes
,
mods
))
if
(
not
try_compute_shape
(
output
,
input_shapes
,
output
->
module_inputs
()
))
{
return
false
;
}
}
}
catch
(
const
std
::
exception
&
e
)
{
if
(
enabled
(
MIGRAPHX_TRACE_ELIMINATE_CONTIGUOUS
{}))
{
std
::
cout
<<
"Exception: "
<<
e
.
what
()
<<
std
::
endl
;
}
return
false
;
}
catch
(...)
{
if
(
enabled
(
MIGRAPHX_TRACE_ELIMINATE_CONTIGUOUS
{}))
{
std
::
cout
<<
"Unknown exception"
<<
std
::
endl
;
}
return
false
;
}
...
...
@@ -127,6 +141,11 @@ static void remove_contiguous(const std::string& op_name, module& m, F f)
{
if
(
arg
->
name
()
!=
op_name
)
continue
;
if
(
enabled
(
MIGRAPHX_TRACE_ELIMINATE_CONTIGUOUS
{}))
{
std
::
cout
<<
"eliminate_contiguous: "
;
m
.
debug_print
(
ins
);
}
auto
prev
=
arg
->
inputs
().
front
();
replace
(
new_args
,
arg
,
prev
);
if
(
try_compute_shape
(
ins
,
new_args
,
mod_args
))
...
...
src/fuse_pointwise.cpp
View file @
f12064ee
...
...
@@ -41,7 +41,7 @@ static literal get_scalar(instruction_ref ins)
if
(
ins
->
name
()
==
"contiguous"
)
return
get_scalar
(
ins
->
inputs
().
front
());
const
auto
&
s
=
ins
->
get_shape
();
if
(
s
.
elements
()
!=
1
&&
not
(
s
.
scalar
()))
if
(
s
.
elements
()
!=
1
and
not
(
s
.
scalar
()))
return
{};
if
(
not
ins
->
can_eval
())
return
{};
...
...
src/fuse_reduce.cpp
View file @
f12064ee
...
...
@@ -52,7 +52,7 @@ struct fused_reduce
{
if
(
mods
.
size
()
!=
1
)
MIGRAPHX_THROW
(
"should have one submodule."
);
auto
*
sm
=
mods
.
front
();
const
auto
*
sm
=
mods
.
front
();
if
(
sm
->
get_output_shapes
().
size
()
!=
1
)
MIGRAPHX_THROW
(
"Only one output supported"
);
auto
names
=
sm
->
get_parameter_names
();
...
...
@@ -143,7 +143,7 @@ insert_module_in_submodule(module_ref sm,
}
static
std
::
vector
<
instruction_ref
>
find_inputs
(
module_ref
sm
,
find_inputs
(
const_
module_ref
sm
,
const
module
&
parent
,
const
std
::
unordered_map
<
instruction_ref
,
instruction_ref
>&
map_ins
)
{
...
...
src/include/migraphx/algorithm.hpp
View file @
f12064ee
...
...
@@ -26,6 +26,8 @@
#include <algorithm>
#include <numeric>
#include <string>
#include <vector>
#include <migraphx/config.hpp>
namespace
migraphx
{
...
...
@@ -90,6 +92,42 @@ levenshtein_distance(Iterator1 first1, Iterator1 last1, Iterator2 first2, Iterat
return
std
::
ptrdiff_t
{
1
}
+
std
::
min
({
x1
,
x2
,
x3
});
}
inline
size_t
levenshtein_distance
(
const
std
::
string
&
s1
,
const
std
::
string
&
s2
)
{
const
size_t
l1
=
s1
.
length
();
const
size_t
l2
=
s2
.
length
();
if
(
l1
<
l2
)
levenshtein_distance
(
s2
,
s1
);
std
::
vector
<
size_t
>
d
(
l2
+
1
);
std
::
iota
(
d
.
begin
(),
d
.
end
(),
0
);
for
(
size_t
i
=
1
;
i
<=
l1
;
i
++
)
{
size_t
prev_cost
=
d
[
0
];
d
[
0
]
=
i
;
for
(
size_t
j
=
1
;
j
<=
l2
;
j
++
)
{
if
(
s1
[
i
-
1
]
==
s2
[
j
-
1
])
{
d
[
j
]
=
prev_cost
;
}
else
{
size_t
cost_insert_or_delete
=
std
::
min
(
d
[
j
-
1
],
d
[
j
]);
size_t
cost_substitute
=
prev_cost
;
prev_cost
=
d
[
j
];
d
[
j
]
=
std
::
min
(
cost_substitute
,
cost_insert_or_delete
)
+
1
;
}
}
}
return
d
[
l2
];
}
}
// namespace MIGRAPHX_INLINE_NS
}
// namespace migraphx
...
...
src/include/migraphx/builtin.hpp
View file @
f12064ee
...
...
@@ -90,7 +90,17 @@ struct param
struct
returns
{
std
::
string
name
()
const
{
return
"@return"
;
}
shape
compute_shape
(
const
std
::
vector
<
shape
>&
)
const
{
return
{};
}
shape
compute_shape
(
const
std
::
vector
<
shape
>&
arg
)
const
{
if
(
arg
.
empty
())
return
{};
else
if
(
arg
.
size
()
==
1
)
return
arg
[
0
];
else
return
arg
;
}
argument
compute
(
context
&
,
const
shape
&
,
const
std
::
vector
<
argument
>&
)
const
{
MIGRAPHX_THROW
(
"builtin"
);
...
...
src/include/migraphx/check_shapes.hpp
View file @
f12064ee
/*
* The MIT License (MIT)
*
* Copyright (c) 2015-202
2
Advanced Micro Devices, Inc. All rights reserved.
* Copyright (c) 2015-202
3
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
...
...
@@ -34,21 +34,37 @@
namespace
migraphx
{
inline
namespace
MIGRAPHX_INLINE_NS
{
// Check that deduced type is incrementable, dereferencable, and comparable
template
<
class
,
class
=
void
>
struct
is_iterator
{
};
template
<
class
T
>
struct
is_iterator
<
T
,
std
::
void_t
<
decltype
(
++
std
::
declval
<
T
&>
()),
decltype
(
*
std
::
declval
<
T
&>
()),
decltype
(
std
::
declval
<
T
&>
()
==
std
::
declval
<
T
&>
())
>>
:
std
::
true_type
{
};
template
<
class
Iterator
>
struct
check_shapes
{
const
shape
*
begin
;
const
shape
*
end
;
static_assert
(
is_iterator
<
Iterator
>
{},
"CHECK_SHAPES: Deduced type must be an iterator"
);
Iterator
begin
;
Iterator
end
;
std
::
string
name
;
bool
dynamic_allowed
;
check_shapes
(
const
shape
*
b
,
const
shape
*
e
,
const
std
::
string
&
n
,
const
bool
d
=
false
)
check_shapes
(
Iterator
b
,
Iterator
e
,
const
std
::
string
&
n
,
const
bool
d
=
false
)
:
begin
(
b
),
end
(
e
),
name
(
n
),
dynamic_allowed
(
d
)
{
check_dynamic
();
}
template
<
class
Op
>
check_shapes
(
const
shape
*
b
,
const
shape
*
e
,
const
Op
&
op
,
const
bool
d
=
false
)
check_shapes
(
Iterator
b
,
Iterator
e
,
const
Op
&
op
,
const
bool
d
=
false
)
:
begin
(
b
),
end
(
e
),
name
(
op
.
name
()),
dynamic_allowed
(
d
)
{
check_dynamic
();
...
...
@@ -56,7 +72,7 @@ struct check_shapes
template
<
class
Op
>
check_shapes
(
const
std
::
vector
<
shape
>&
s
,
const
Op
&
op
,
const
bool
d
=
false
)
:
begin
(
s
.
data
()),
end
(
s
.
data
()
+
s
.
size
()),
name
(
op
.
name
()),
dynamic_allowed
(
d
)
:
begin
(
s
.
begin
()),
end
(
s
.
end
()),
name
(
op
.
name
()),
dynamic_allowed
(
d
)
{
check_dynamic
();
}
...
...
@@ -81,8 +97,6 @@ struct check_shapes
{
if
(
begin
==
end
)
return
0
;
assert
(
begin
!=
nullptr
);
assert
(
end
!=
nullptr
);
return
end
-
begin
;
}
...
...
@@ -131,8 +145,6 @@ struct check_shapes
*/
const
check_shapes
&
only_dims
(
std
::
size_t
n
)
const
{
assert
(
begin
!=
nullptr
);
assert
(
end
!=
nullptr
);
if
(
begin
!=
end
)
{
if
(
begin
->
max_lens
().
size
()
!=
n
)
...
...
@@ -148,8 +160,6 @@ struct check_shapes
*/
const
check_shapes
&
max_ndims
(
std
::
size_t
n
)
const
{
assert
(
begin
!=
nullptr
);
assert
(
end
!=
nullptr
);
if
(
begin
!=
end
)
{
if
(
begin
->
max_lens
().
size
()
>
n
)
...
...
@@ -166,8 +176,6 @@ struct check_shapes
*/
const
check_shapes
&
min_ndims
(
std
::
size_t
n
)
const
{
assert
(
begin
!=
nullptr
);
assert
(
end
!=
nullptr
);
if
(
begin
!=
end
)
{
if
(
begin
->
max_lens
().
size
()
<
n
)
...
...
@@ -330,8 +338,6 @@ struct check_shapes
{
if
(
begin
==
end
)
return
true
;
assert
(
begin
!=
nullptr
);
assert
(
end
!=
nullptr
);
auto
&&
key
=
f
(
*
begin
);
return
this
->
all_of
([
&
](
const
shape
&
s
)
{
return
f
(
s
)
==
key
;
});
}
...
...
@@ -341,8 +347,6 @@ struct check_shapes
{
if
(
begin
==
end
)
return
true
;
assert
(
begin
!=
nullptr
);
assert
(
end
!=
nullptr
);
return
std
::
all_of
(
begin
,
end
,
p
);
}
...
...
@@ -351,17 +355,13 @@ struct check_shapes
{
if
(
begin
==
end
)
return
false
;
assert
(
begin
!=
nullptr
);
assert
(
end
!=
nullptr
);
return
std
::
any_of
(
begin
,
end
,
p
);
}
const
shape
*
get
(
long
i
)
const
Iterator
get
(
long
i
)
const
{
if
(
i
>=
size
())
MIGRAPHX_THROW
(
prefix
()
+
"Accessing shape out of bounds"
);
assert
(
begin
!=
nullptr
);
assert
(
end
!=
nullptr
);
if
(
i
<
0
)
return
end
-
i
;
return
begin
+
i
;
...
...
@@ -394,6 +394,11 @@ struct check_shapes
}
};
// Deduction guide for std::vector constructor
template
<
class
Op
>
check_shapes
(
const
std
::
vector
<
shape
>&
,
const
Op
&
,
bool
d
=
false
)
->
check_shapes
<
std
::
vector
<
shape
>::
const_iterator
>
;
}
// namespace MIGRAPHX_INLINE_NS
}
// namespace migraphx
...
...
src/include/migraphx/dynamic_loader.hpp
View file @
f12064ee
...
...
@@ -26,6 +26,7 @@
#include <migraphx/config.hpp>
#include <migraphx/filesystem.hpp>
#include <migraphx/optional.hpp>
#include <functional>
#include <memory>
#include <vector>
...
...
@@ -43,6 +44,9 @@ struct MIGRAPHX_EXPORT dynamic_loader
return
path
(
reinterpret_cast
<
void
*>
(
address
));
}
static
fs
::
path
path
(
void
*
address
);
static
optional
<
dynamic_loader
>
try_load
(
const
fs
::
path
&
p
);
dynamic_loader
()
=
default
;
dynamic_loader
(
const
fs
::
path
&
p
);
...
...
src/include/migraphx/normalize_attributes.hpp
View file @
f12064ee
/*
* The MIT License (MIT)
*
* Copyright (c) 2015-202
2
Advanced Micro Devices, Inc. All rights reserved.
* Copyright (c) 2015-202
3
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
...
...
@@ -28,6 +28,7 @@
#include <migraphx/shape.hpp>
#include <cstring>
#include <vector>
#include <migraphx/op/normalize_attribute.hpp>
namespace
migraphx
{
inline
namespace
MIGRAPHX_INLINE_NS
{
...
...
@@ -42,6 +43,36 @@ struct select_dependent_type
template
<
class
T
,
class
...
Ts
>
using
dependent_type
=
typename
select_dependent_type
<
T
,
Ts
...
>::
type
;
/**
* Used to normalize variable input axes at model runtime.
* Example: the axes inputs of the slice operator.
*
* \param axes the axes to normalize
* \param input_shape shape of the input tensor
* \param attr_val the normalize_axes attributes from the operator
* \param prefix error message prefix
*/
std
::
vector
<
int64_t
>
normalize_axes
(
const
std
::
vector
<
int64_t
>&
axes
,
const
shape
&
input_shape
,
const
value
&
attr_val
,
const
std
::
string
&
prefix
=
""
);
/**
* Used to normalize variable input axes at model runtime.
* Example: the starts and ends inputs of the slice operator.
*
* \param indices the indices to normalize
* \param axes which axes the indices apply over
* \param input_shape shape of the input tensor
* \param attr_val the normalize_axes attributes from the operator
* \param prefix error message prefix
*/
std
::
vector
<
int64_t
>
normalize_indices
(
const
std
::
vector
<
int64_t
>&
indices
,
const
std
::
vector
<
int64_t
>&
axes
,
const
shape
&
input_shape
,
const
value
&
attr_val
,
const
std
::
string
&
prefix
=
""
);
MIGRAPHX_EXPORT
bool
normalize_attributes
(
operation
&
op
,
const
shape
&
input_shape
);
...
...
src/include/migraphx/op/convolution.hpp
View file @
f12064ee
...
...
@@ -82,7 +82,7 @@ struct convolution
const
auto
input_ndim
=
inputs
[
0
].
ndim
();
const
auto
padding_size
=
padding
.
size
();
if
(
input_ndim
!=
padding_size
/
2
+
2
&&
input_ndim
!=
padding_size
+
2
)
if
(
input_ndim
!=
padding_size
/
2
+
2
and
input_ndim
!=
padding_size
+
2
)
{
MIGRAPHX_THROW
(
"CONVOLUTION: input and attribute size mismatch!"
);
}
...
...
src/include/migraphx/op/if_op.hpp
View file @
f12064ee
...
...
@@ -71,7 +71,7 @@ struct if_op
std
::
unordered_map
<
std
::
string
,
argument
>
params
;
std
::
set
<
std
::
string
>
pnames
;
for
(
const
auto
&
smod
:
mods
)
for
(
const
_module_ref
smod
:
mods
)
{
auto
names
=
smod
->
get_parameter_names
();
pnames
.
insert
(
names
.
begin
(),
names
.
end
());
...
...
src/include/migraphx/op/loop.hpp
View file @
f12064ee
...
...
@@ -59,9 +59,9 @@ struct loop
MIGRAPHX_THROW
(
"LOOP: operator should have one submodule."
);
}
const
auto
&
mod
=
mods
.
front
();
auto
mod_out_shapes
=
mod
->
get_output_shapes
();
auto
dep_param_num
=
inputs
.
size
()
-
2
;
const
_module_ref
mod
=
mods
.
front
();
auto
mod_out_shapes
=
mod
->
get_output_shapes
();
auto
dep_param_num
=
inputs
.
size
()
-
2
;
// first item of the mod output shapes is condition used in loop,
// which is not needed to compute output shape
...
...
src/include/migraphx/op/slice.hpp
View file @
f12064ee
...
...
@@ -27,19 +27,34 @@
#include <migraphx/check_shapes.hpp>
#include <migraphx/argument.hpp>
#include <migraphx/config.hpp>
#include <migraphx/dyn_output.hpp>
#include <migraphx/value.hpp>
#include <migraphx/dyn_output.hpp>
#include <migraphx/op/normalize_attribute.hpp>
#include <migraphx/normalize_attributes.hpp>
namespace
migraphx
{
inline
namespace
MIGRAPHX_INLINE_NS
{
namespace
op
{
/**
* Slice operator that accepts variable axes, starts and ends.
*
* Attributes:
* axes: constant axes to slice over (optional)
* starts: constant slice starting indices (optional)
* ends: constant slice ending indices (optional)
*
* Parameters:
* data: the input tensor to slice (dynamic or static shape)
* input_starts: starting indicies of slice (optional, static shape)
* input_ends: ending indicies of slice (optional, static shape)
* input_axes: axes to slice over (optional, static shape)
*/
struct
slice
{
std
::
vector
<
int64_t
>
axes
;
std
::
vector
<
int64_t
>
starts
;
std
::
vector
<
int64_t
>
ends
;
std
::
vector
<
int64_t
>
axes
{}
;
std
::
vector
<
int64_t
>
starts
{}
;
std
::
vector
<
int64_t
>
ends
{}
;
template
<
class
Self
,
class
F
>
static
auto
reflect
(
Self
&
self
,
F
f
)
...
...
@@ -48,8 +63,8 @@ struct slice
}
/**
* Ensure that attribute vectors axes, starts, and ends are all the same size and values are
in
* limits.
* Ensure that attribute vectors axes, starts, and ends are all the same size and values are
*
within
limits.
*/
value
attributes
()
const
{
...
...
@@ -70,6 +85,90 @@ struct slice
std
::
string
name
()
const
{
return
"slice"
;
}
/**
* Computes the slice output shape dimensions for given starts, ends,and axes.
* Templated to also handle tensor views.
* Possibily different type between [in_starts, in_ends] and [in_axes] if in_axes is this
* object's axes attribute. Assumes in_starts and in_ends are normalized; in_axes are valid.
*/
template
<
class
A
,
class
B
>
std
::
vector
<
std
::
size_t
>
lens_calc
(
const
std
::
vector
<
std
::
size_t
>&
lengths
,
A
in_starts
,
A
in_ends
,
B
in_axes
)
const
{
auto
new_lens
=
lengths
;
for
(
std
::
size_t
i
=
0
;
i
<
in_axes
.
size
();
++
i
)
{
auto
axis
=
in_axes
[
i
];
new_lens
[
axis
]
=
in_ends
[
i
]
-
in_starts
[
i
];
}
return
new_lens
;
}
shape
normalize_compute_shape
(
std
::
vector
<
shape
>
inputs
)
const
{
check_shapes
{
inputs
,
*
this
,
true
}.
has
(
1
,
3
,
4
);
auto
input_shape
=
inputs
[
0
];
if
(
inputs
.
size
()
==
1
)
{
auto
t
=
input_shape
.
type
();
if
(
input_shape
.
dynamic
()
and
std
::
any_of
(
axes
.
begin
(),
axes
.
end
(),
[
&
](
auto
axis
)
{
return
not
input_shape
.
dyn_dims
()[
axis
].
is_fixed
();
}))
{
MIGRAPHX_THROW
(
"SLICE: slicing is not allowed on non-fixed dynamic input axis "
);
}
if
(
input_shape
.
dynamic
())
{
return
shape
{
t
,
lens_calc
(
input_shape
.
min_lens
(),
starts
,
ends
,
axes
),
lens_calc
(
input_shape
.
max_lens
(),
starts
,
ends
,
axes
),
{}};
}
else
{
return
shape
{
t
,
lens_calc
(
input_shape
.
lens
(),
starts
,
ends
,
axes
),
input_shape
.
strides
()};
}
}
else
{
// check that starts, ends, and optionally input_axes are all 1D, have the same
// dimension, and are static
check_shapes
{
inputs
.
begin
()
+
1
,
inputs
.
end
(),
std
::
string
(
"SLICE: inputs (starts, ends, and input_axes)"
),
false
}
.
only_dims
(
1
)
.
same_dims
();
auto
dds
=
input_shape
.
to_dynamic
().
dyn_dims
();
if
(
inputs
.
size
()
==
3
)
{
if
(
inputs
[
1
].
lens
().
at
(
0
)
!=
axes
.
size
())
{
MIGRAPHX_THROW
(
"SLICE: inputs starts and ends do not have the same dimension "
"as the axes attribute"
);
}
std
::
for_each
(
axes
.
cbegin
(),
axes
.
cend
(),
[
&
](
const
auto
&
axis
)
{
dds
.
at
(
axis
)
=
{
0
,
dds
.
at
(
axis
).
max
};
});
}
else
{
// if axes is an input, then all the output dimensions could be 0 to the max value
std
::
transform
(
dds
.
begin
(),
dds
.
end
(),
dds
.
begin
(),
[](
auto
dd
)
{
return
shape
::
dynamic_dimension
{
0
,
dd
.
max
};
});
}
return
shape
{
input_shape
.
type
(),
dds
};
}
}
/**
* Calculates the starting offset for the sliced tensor.
* Used in compute when only data input and all other information are in the attributes.
*
* \param s static input shape
*/
auto
compute_offset
(
const
shape
&
s
)
const
{
const
std
::
vector
<
std
::
size_t
>&
lens
=
s
.
lens
();
...
...
@@ -90,80 +189,131 @@ struct slice
offset
+=
starts
[
axis
]
*
strides
[
axis
];
}
}
return
offset
;
return
offset
*
s
.
type_size
()
;
}
shape
normalize_compute_shape
(
std
::
vector
<
shape
>
inputs
)
const
/**
* Calculates the starting offset for the sliced tensor (for aliasing).
* Used when the starts and/or the axes are inputs.
*
* \param s static input shape
* \param input_starts starting indices of slice
* \param ax_vec axes to slice on
*/
template
<
class
IndView
,
class
Axes
>
auto
compute_offset
(
const
shape
&
s
,
const
IndView
&
input_starts
,
const
Axes
&
ax_vec
)
const
{
check_shapes
{
inputs
,
*
this
,
true
}.
has
(
1
);
auto
input_shape
=
inputs
[
0
];
auto
t
=
input_shape
.
type
();
// TODO: When support for dynamic shapes is added to normalize_attributes,
// remove this restriction.
if
(
input_shape
.
dynamic
()
and
std
::
any_of
(
axes
.
begin
(),
axes
.
end
(),
[
&
](
auto
axis
)
{
return
not
input_shape
.
dyn_dims
()[
axis
].
is_fixed
();
}))
auto
ret
=
0
;
for
(
std
::
size_t
i
=
0
;
i
<
ax_vec
.
size
();
++
i
)
{
MIGRAPHX_THROW
(
"SLICE: slicing is not allowed on non-fixed dynamic input axis "
);
auto
axis
=
ax_vec
[
i
];
ret
+=
input_starts
[
i
]
*
s
.
strides
().
at
(
axis
);
}
return
ret
*
s
.
type_size
();
}
std
::
unordered_map
<
std
::
string
,
std
::
vector
<
int64_t
>>
normalize_inputs
(
const
shape
&
input_shape
,
const
std
::
vector
<
int64_t
>&
input_starts
,
const
std
::
vector
<
int64_t
>&
input_ends
)
const
{
auto
attrs
=
this
->
attributes
().
at
(
"normalize_axes"
);
return
{{
"input_starts"
,
normalize_indices
(
input_starts
,
this
->
axes
,
input_shape
,
attrs
.
at
(
"starts"
),
"Slice variable input_starts"
)},
{
"input_ends"
,
normalize_indices
(
input_ends
,
this
->
axes
,
input_shape
,
attrs
.
at
(
"ends"
),
"Slice variable input_ends"
)}};
}
/**
* Three input version of the normalize_inputs.
* This one also checks that the input_axes are valid.
*/
std
::
unordered_map
<
std
::
string
,
std
::
vector
<
int64_t
>>
normalize_inputs
(
shape
input_shape
,
const
std
::
vector
<
int64_t
>&
input_starts
,
const
std
::
vector
<
int64_t
>&
input_ends
,
const
std
::
vector
<
int64_t
>&
input_axes
)
const
{
auto
attrs
=
this
->
attributes
().
at
(
"normalize_axes"
);
auto
norm_axes
=
normalize_axes
(
input_axes
,
input_shape
,
attrs
.
at
(
"axes"
),
"Slice variable input_axes"
);
return
{{
"input_starts"
,
normalize_indices
(
input_starts
,
norm_axes
,
input_shape
,
attrs
.
at
(
"starts"
),
"Slice variable input_starts"
)},
{
"input_ends"
,
normalize_indices
(
input_ends
,
norm_axes
,
input_shape
,
attrs
.
at
(
"ends"
),
"Slice variable input ends"
)},
{
"input_axes"
,
norm_axes
}};
}
// For a static shape, old_lens will be adjusted to a new size
// for those axes that are sliced.
// For dynamic shape, the adjusted old_lens become the new max values,
// while updating the old mins and optimals if possible.
std
::
vector
<
std
::
size_t
>
new_mins
;
std
::
vector
<
std
::
size_t
>
old_lens
;
std
::
vector
<
std
::
size_t
>
old_strides
;
// Doesn't handle optimals
if
(
input_shape
.
dynamic
())
argument
compute
(
const
dyn_output
&
dyn_out
,
std
::
vector
<
argument
>
args
)
const
{
auto
input
=
args
[
0
];
auto
input_shape
=
input
.
get_shape
();
switch
(
args
.
size
())
{
old_lens
=
input_shape
.
max_lens
();
new_mins
=
input_shape
.
min_lens
();
case
1
:
{
std
::
size_t
offset
=
compute_offset
(
input_shape
);
return
{
dyn_out
.
computed_shape
,
[
=
]
{
return
input
.
data
()
+
offset
;
}};
}
else
{
old_lens
=
input_shape
.
lens
();
// For static shape (including during eval step after a dynamic input) the strides are
// indexed into the pre-slice array, so they are larger than the apparent size of the
// resulting shape.
old_strides
=
input_shape
.
strides
();
case
3
:
{
shape
calc_shape
;
std
::
size_t
offset
=
0
;
visit_all
(
args
[
1
],
args
[
2
])([
&
](
auto
input_starts
,
auto
input_ends
)
{
auto
norm_inputs
=
normalize_inputs
(
input_shape
,
input_starts
.
template
to_vector
<
int64_t
>(),
input_ends
.
template
to_vector
<
int64_t
>());
offset
=
compute_offset
(
input_shape
,
norm_inputs
.
at
(
"input_starts"
),
this
->
axes
);
calc_shape
=
{
input_shape
.
type
(),
lens_calc
(
input_shape
.
lens
(),
norm_inputs
.
at
(
"input_starts"
),
norm_inputs
.
at
(
"input_ends"
),
this
->
axes
),
input_shape
.
strides
()};
});
return
{
calc_shape
,
[
=
]
{
return
input
.
data
()
+
offset
;
}};
}
std
::
vector
<
std
::
size_t
>
new_lens
=
old_lens
;
for
(
std
::
size_t
i
=
0
;
i
<
axes
.
size
();
i
++
)
{
auto
axis
=
axes
[
i
];
size_t
sliced_length
=
ends
[
i
]
-
starts
[
i
];
// A Numpy indexing convention: a slice size larger than the actual dimension
// is legal and the "ends" value is clipped to the axis size
new_lens
[
axis
]
=
std
::
min
(
new_lens
[
axis
],
sliced_length
);
if
(
input_shape
.
dynamic
())
{
// TODO: when non-fixed shape slicing is allowed, this will be different than
// sliced_length, making use of TBD start/end values.
std
::
size_t
sliced_min_length
=
ends
[
i
]
-
starts
[
i
];
// if the slice size is smaller than maxes but larger than mins
new_mins
[
axis
]
=
std
::
min
(
sliced_min_length
,
new_mins
[
axis
]);
}
case
4
:
{
shape
calc_shape
;
std
::
size_t
offset
=
0
;
visit_all
(
args
[
1
],
args
[
2
],
args
[
3
])(
[
&
](
auto
input_starts
,
auto
input_ends
,
auto
input_axes
)
{
auto
norm_inputs
=
normalize_inputs
(
input_shape
,
input_starts
.
template
to_vector
<
int64_t
>(),
input_ends
.
template
to_vector
<
int64_t
>(),
input_axes
.
template
to_vector
<
int64_t
>());
offset
=
compute_offset
(
input_shape
,
norm_inputs
.
at
(
"input_starts"
),
norm_inputs
.
at
(
"input_axes"
));
calc_shape
=
shape
{
input_shape
.
type
(),
lens_calc
(
input_shape
.
lens
(),
norm_inputs
.
at
(
"input_starts"
),
norm_inputs
.
at
(
"input_ends"
),
norm_inputs
.
at
(
"input_axes"
)),
input_shape
.
strides
()};
});
return
{
calc_shape
,
[
=
]
{
return
input
.
data
()
+
offset
;
}};
}
if
(
input_shape
.
dynamic
())
{
return
shape
{
t
,
new_mins
,
new_lens
,
{}}
;
default:
{
// Should never get here; covering in case some code change occurs
MIGRAPHX_THROW
(
"SLICE: invalid number of inputs"
)
;
}
else
{
return
shape
{
t
,
new_lens
,
old_strides
};
}
}
argument
compute
(
const
dyn_output
&
dyn_out
,
std
::
vector
<
argument
>
args
)
const
{
auto
input
=
args
[
0
];
auto
offset
=
compute_offset
(
input
.
get_shape
())
*
dyn_out
.
computed_shape
.
type_size
();
return
{
dyn_out
.
computed_shape
,
[
=
]
{
return
input
.
data
()
+
offset
;
}};
}
std
::
ptrdiff_t
output_alias
(
const
std
::
vector
<
shape
>&
)
const
{
return
0
;
}
};
...
...
Prev
1
2
3
4
5
6
7
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