Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
MegEngine 天元
MegEngine
提交
fc74d5f2
MegEngine
项目概览
MegEngine 天元
/
MegEngine
1 年多 前同步成功
通知
403
Star
4705
Fork
582
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
MegEngine
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
提交
fc74d5f2
编写于
9月 11, 2020
作者:
M
Megvii Engine Team
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
feat(mge/dump): add more options for megbrain_graph.dump_graph
GitOrigin-RevId: 848e3c87c183e716c750a2744f0dc27a50e5186a
上级
fade97d4
变更
4
隐藏空白更改
内联
并排
Showing
4 changed file
with
279 addition
and
124 deletion
+279
-124
imperative/python/megengine/core/tensor/megbrain_graph.py
imperative/python/megengine/core/tensor/megbrain_graph.py
+186
-93
imperative/python/megengine/jit/tracing.py
imperative/python/megengine/jit/tracing.py
+3
-1
imperative/python/src/graph_rt.cpp
imperative/python/src/graph_rt.cpp
+85
-26
imperative/python/test/unit/test_tracing.py
imperative/python/test/unit/test_tracing.py
+5
-4
未找到文件。
imperative/python/megengine/core/tensor/megbrain_graph.py
浏览文件 @
fc74d5f2
...
...
@@ -11,6 +11,7 @@ import json
import
threading
import
weakref
from
concurrent.futures
import
Future
,
ThreadPoolExecutor
from
typing
import
Dict
,
List
,
Union
import
numpy
as
np
...
...
@@ -85,6 +86,97 @@ class Graph(_imperative_rt.ComputingGraph):
return
self
.
_wrap
(
_imperative_rt
.
make_h2d
(
self
,
device
,
dtype
,
shape
,
name
))
class
VarNode
(
TensorBase
):
def
__init__
(
self
,
node
:
_imperative_rt
.
VarNode
):
self
.
_node
=
node
if
hasattr
(
self
.
graph
,
"_var_cache"
):
self
.
graph
.
_var_cache
[
node
]
=
self
@
property
def
graph
(
self
)
->
Graph
:
return
self
.
_node
.
graph
@
property
def
op
(
self
):
if
hasattr
(
self
.
graph
,
"_wrap"
):
return
self
.
graph
.
_wrap
(
self
.
_node
.
owner
)
else
:
return
self
.
_node
.
owner
@
property
def
name
(
self
):
return
self
.
_node
.
name
@
property
def
id
(
self
):
return
self
.
_node
.
id
@
name
.
setter
def
name
(
self
,
name
):
self
.
_node
.
name
=
name
@
property
def
dtype
(
self
):
return
self
.
_node
.
dtype
@
property
def
device
(
self
):
return
as_device
(
self
.
_node
.
comp_node
)
@
property
def
shape
(
self
):
return
self
.
_node
.
shape
@
property
def
value
(
self
):
return
self
.
_node
.
value
class
OpNode
:
def
__init__
(
self
,
node
:
_imperative_rt
.
OperatorNode
):
self
.
_node
=
node
if
hasattr
(
self
.
graph
,
"_op_cache"
):
self
.
graph
.
_op_cache
[
node
]
=
self
@
property
def
graph
(
self
)
->
Graph
:
return
self
.
_node
.
graph
@
property
def
name
(
self
):
return
self
.
_node
.
name
@
property
def
id
(
self
):
return
self
.
_node
.
id
@
name
.
setter
def
name
(
self
,
name
):
self
.
_node
.
name
=
name
@
property
def
inputs
(
self
):
if
hasattr
(
self
.
graph
,
"_wrap"
):
return
tuple
(
map
(
self
.
graph
.
_wrap
,
self
.
_node
.
inputs
))
else
:
return
self
.
_node
.
inputs
@
property
def
outputs
(
self
):
if
hasattr
(
self
.
graph
,
"_wrap"
):
return
tuple
(
map
(
self
.
graph
.
_wrap
,
self
.
_node
.
outputs
))
else
:
return
self
.
_node
.
outputs
@
property
def
params
(
self
):
return
json
.
loads
(
self
.
_node
.
params
)
@
property
def
type
(
self
):
return
self
.
_node
.
type
def
optimize_for_inference
(
dest_vars
,
**
kwargs
):
r
"""Applies optimize_for_inference pass for computing graph.
...
...
@@ -162,8 +254,100 @@ def optimize_for_inference(dest_vars, **kwargs):
return
[
VarNode
(
i
)
for
i
in
res_vars
]
def
dump_graph
(
*
args
):
return
_imperative_rt
.
dump_graph
([
i
.
_node
for
i
in
args
])
CompGraphDumpResult
=
collections
.
namedtuple
(
"CompGraphDumpResult"
,
[
"nr_opr"
,
"tot_bytes"
,
"tensor_value_bytes"
,
"content_hash"
,
"inputs"
,
"outputs"
,
"params"
,
],
)
def
dump_graph
(
output_vars
:
Union
[
Dict
[
str
,
VarNode
],
List
[
VarNode
]],
*
,
keep_var_name
:
int
=
1
,
keep_param_name
:
bool
=
False
,
keep_opr_priority
:
bool
=
False
,
strip_info_file
=
None
,
):
"""serialize the computing graph of `output_vars` and get byte result.
:param output_vars: output variables which are the graph's end point.
.. note::
The underlying C++ API only accepts a var list. If a dict is given,
the vars would be renamed to the given names.
:param keep_var_name: level for keeping variable names:
* 0: none of the names are kept
* 1: (default)keep names of output vars
* 2: keep names of all (output and internal) vars
:param keep_param_name: whether to keep param names, so param values can be
easily manipulated after loading model
:param keep_opr_priority: whether to keep priority setting for operators
:param strip_info_file: a string for path or a file handler. if is not None,
then the dump information for code strip would be written to ``strip_info_file``
:return: dump result as byte string, and an instance of namedtuple
:class:`CompGraphDumpResult`, whose fields are:
* ``nr_opr`` number of operators dumped
* ``tot_bytes`` total bytes for the whole graph
* ``tensor_value_bytes`` bytes consumed for dumping tensor values
* ``inputs`` names of input tensors
* ``params`` list of names of dumped params
* ``outputs`` names of output vars
"""
ov
=
[]
if
isinstance
(
output_vars
,
dict
):
used_vars
=
set
()
for
name
,
var
in
output_vars
.
items
():
assert
isinstance
(
var
,
VarNode
),
"bad output var: {!r}"
.
format
(
var
)
assert
var
.
id
not
in
used_vars
,
(
"var name is associated with a var object, so we can not have "
"two names given to the same var: {}"
.
format
(
var
)
)
used_vars
.
add
(
var
.
id
)
var
.
name
=
name
ov
.
append
(
var
.
_node
)
else
:
for
var
in
output_vars
:
assert
isinstance
(
var
,
VarNode
),
"bad output var: {!r}"
.
format
(
var
)
ov
.
append
(
var
.
_node
)
stat
=
[]
inputs
=
[]
outputs
=
[]
params
=
[]
dump_content
=
_imperative_rt
.
dump_graph
(
ov
,
keep_var_name
,
keep_param_name
,
keep_opr_priority
,
stat
,
inputs
,
outputs
,
params
,
)
dump_info
=
CompGraphDumpResult
(
*
stat
,
inputs
,
outputs
,
params
)
if
strip_info_file
is
not
None
:
if
isinstance
(
strip_info_file
,
str
):
strip_info_file
=
open
(
strip_info_file
,
"w"
)
strip_info
=
json
.
loads
(
_imperative_rt
.
get_info_for_strip
(
ov
))
strip_info
[
"hash"
]
=
dump_info
.
content_hash
json
.
dump
(
strip_info
,
strip_info_file
)
return
dump_content
,
dump_info
CompGraphLoadResult
=
collections
.
namedtuple
(
...
...
@@ -193,97 +377,6 @@ def load_graph(fpath):
return
CompGraphLoadResult
(
cg
,
dict
(
output_vars_map
),
output_vars_list
)
class
VarNode
(
TensorBase
):
def
__init__
(
self
,
node
:
_imperative_rt
.
VarNode
):
self
.
_node
=
node
if
hasattr
(
self
.
graph
,
"_var_cache"
):
self
.
graph
.
_var_cache
[
node
]
=
self
@
property
def
graph
(
self
)
->
Graph
:
return
self
.
_node
.
graph
@
property
def
op
(
self
):
if
hasattr
(
self
.
graph
,
"_wrap"
):
return
self
.
graph
.
_wrap
(
self
.
_node
.
owner
)
else
:
return
self
.
_node
.
owner
@
property
def
name
(
self
):
return
self
.
_node
.
name
@
property
def
id
(
self
):
return
self
.
_node
.
id
@
name
.
setter
def
name
(
self
,
name
):
self
.
_node
.
name
=
name
@
property
def
dtype
(
self
):
return
self
.
_node
.
dtype
@
property
def
device
(
self
):
return
as_device
(
self
.
_node
.
comp_node
)
@
property
def
shape
(
self
):
return
self
.
_node
.
shape
@
property
def
value
(
self
):
return
self
.
_node
.
value
class
OpNode
:
def
__init__
(
self
,
node
:
_imperative_rt
.
OperatorNode
):
self
.
_node
=
node
if
hasattr
(
self
.
graph
,
"_op_cache"
):
self
.
graph
.
_op_cache
[
node
]
=
self
@
property
def
graph
(
self
)
->
Graph
:
return
self
.
_node
.
graph
@
property
def
name
(
self
):
return
self
.
_node
.
name
@
property
def
id
(
self
):
return
self
.
_node
.
id
@
name
.
setter
def
name
(
self
,
name
):
self
.
_node
.
name
=
name
@
property
def
inputs
(
self
):
if
hasattr
(
self
.
graph
,
"_wrap"
):
return
tuple
(
map
(
self
.
graph
.
_wrap
,
self
.
_node
.
inputs
))
else
:
return
self
.
_node
.
inputs
@
property
def
outputs
(
self
):
if
hasattr
(
self
.
graph
,
"_wrap"
):
return
tuple
(
map
(
self
.
graph
.
_wrap
,
self
.
_node
.
outputs
))
else
:
return
self
.
_node
.
outputs
@
property
def
params
(
self
):
return
json
.
loads
(
self
.
_node
.
params
)
@
property
def
type
(
self
):
return
self
.
_node
.
type
def
_wrap
(
x
):
if
isinstance
(
x
,
collections
.
abc
.
Sequence
):
return
type
(
x
)(
map
(
_wrap
,
x
))
...
...
imperative/python/megengine/jit/tracing.py
浏览文件 @
fc74d5f2
...
...
@@ -589,7 +589,9 @@ class trace:
if
isinstance
(
file
,
str
):
permission
=
"wb"
if
append
==
False
else
"ab"
file
=
open
(
file
,
permission
)
file
.
write
(
G
.
dump_graph
(
*
dest_vars
))
dump_content
,
dump_info
=
G
.
dump_graph
(
dest_vars
)
file
.
write
(
dump_content
)
return
dump_info
def
_process_inputs
(
self
,
*
args
,
**
kwargs
):
if
self
.
_untraced
:
...
...
imperative/python/src/graph_rt.cpp
浏览文件 @
fc74d5f2
...
...
@@ -27,6 +27,7 @@ namespace py = pybind11;
using
namespace
mgb
;
using
namespace
imperative
;
namespace
ser
=
mgb
::
serialization
;
using
_OptimizeForInferenceOptions
=
mgb
::
gopt
::
OptimizeForInferenceOptions
;
using
_LayoutTransform
=
_OptimizeForInferenceOptions
::
LayoutTransform
;
...
...
@@ -183,7 +184,6 @@ void init_graph_rt(py::module m) {
return
"Opr:"
+
opr
->
name
();
});
py
::
class_
<
cg
::
AsyncExecutable
>
(
m
,
"AsyncExecutable"
)
.
def
(
"execute"
,
&
cg
::
AsyncExecutable
::
execute
,
py
::
call_guard
<
py
::
gil_scoped_release
>
())
.
def
(
"wait"
,
&
cg
::
AsyncExecutable
::
wait
,
py
::
call_guard
<
py
::
gil_scoped_release
>
());
...
...
@@ -206,15 +206,6 @@ void init_graph_rt(py::module m) {
}))
.
def
(
"get"
,
[](
_CompGraphProfilerImpl
&
profiler
)
{
return
profiler
.
_get_result
();
});
m
.
def
(
"dump_graph"
,
[](
const
std
::
vector
<
VarNode
*>&
dest_vars
)
{
using
namespace
mgb
::
serialization
;
std
::
vector
<
uint8_t
>
buf
;
auto
dumper
=
GraphDumper
::
make
(
OutputFile
::
make_vector_proxy
(
&
buf
));
SymbolVarArray
symvars
(
dest_vars
.
begin
(),
dest_vars
.
end
());
dumper
->
dump
(
symvars
);
return
py
::
bytes
(
reinterpret_cast
<
const
char
*>
(
&
buf
[
0
]),
buf
.
size
());
});
auto
GraphOptimizeOptions
=
py
::
class_
<
_OptimizeForInferenceOptions
>
(
m
,
"GraphOptimizeOptions"
)
.
def
(
py
::
init
())
.
def_readwrite
(
"f16_io_f32_comp"
,
&
_OptimizeForInferenceOptions
::
f16_io_f32_comp
)
...
...
@@ -245,23 +236,91 @@ void init_graph_rt(py::module m) {
return
vars
;
});
m
.
def
(
"get_info_for_strip"
,
[](
const
std
::
vector
<
VarNode
*>&
dest_vars
)
{
std
::
unordered_set
<
const
char
*>
opr_types
,
dtype_names
,
elemwise_modes
;
auto
on_opr
=
[
&
](
cg
::
OperatorNodeBase
*
opr
)
{
if
(
ser
::
GraphDumper
::
should_remove_in_dump
(
opr
))
return
;
opr_types
.
insert
(
opr
->
dyn_typeinfo
()
->
name
);
for
(
auto
i
:
opr
->
output
())
dtype_names
.
insert
(
i
->
dtype
().
name
());
if
(
opr
->
same_type
<
opr
::
Elemwise
>
())
{
auto
mode
=
opr
->
cast_final
<
opr
::
Elemwise
>
().
param
().
mode
;
elemwise_modes
.
insert
(
megdnn
::
Elemwise
::
ModeTrait
::
from_mode
(
mode
).
name
);
}
};
cg
::
DepOprIter
opr_iter
{
on_opr
};
for
(
auto
i
:
dest_vars
)
opr_iter
.
add
(
i
->
owner_opr
());
auto
to_json
=
[](
const
std
::
unordered_set
<
const
char
*>
&
v
)
{
std
::
vector
<
std
::
string
>
vs
(
v
.
begin
(),
v
.
end
());
std
::
sort
(
vs
.
begin
(),
vs
.
end
());
auto
ret
=
json
::
Array
::
make
();
for
(
auto
&&
i
:
vs
)
ret
->
add
(
json
::
String
::
make
(
i
));
return
ret
;
};
return
json
::
Object
::
make
({
{
"opr_types"
,
to_json
(
opr_types
)},
{
"dtypes"
,
to_json
(
dtype_names
)},
{
"elemwise_modes"
,
to_json
(
elemwise_modes
)},
});
});
m
.
def
(
"dump_graph"
,
[](
const
std
::
vector
<
VarNode
*>&
dest_vars
,
int
keep_var_name
,
bool
keep_param_name
,
bool
keep_opr_priority
,
py
::
list
&
stat
,
py
::
list
&
inputs
,
py
::
list
&
outputs
,
py
::
list
&
params
)
{
std
::
vector
<
uint8_t
>
buf
;
auto
dumper
=
ser
::
GraphDumper
::
make
(
ser
::
OutputFile
::
make_vector_proxy
(
&
buf
));
SymbolVarArray
symvars
(
dest_vars
.
begin
(),
dest_vars
.
end
());
ser
::
GraphDumper
::
DumpConfig
config
{
keep_var_name
,
keep_param_name
,
keep_opr_priority
};
auto
rst
=
dumper
->
dump
(
symvars
,
config
);
for
(
auto
i
:
rst
.
inputs
)
{
inputs
.
append
(
py
::
cast
(
i
));
}
for
(
auto
i
:
rst
.
outputs
)
{
outputs
.
append
(
py
::
cast
(
i
));
}
for
(
auto
i
:
rst
.
params
)
{
params
.
append
(
py
::
cast
(
i
));
}
auto
rst_stat
=
std
::
vector
{
rst
.
nr_opr
,
rst
.
tot_bytes
,
rst
.
tensor_value_bytes
,
rst
.
content_hash
};
for
(
auto
i
:
rst_stat
)
{
stat
.
append
(
py
::
cast
(
i
));
}
return
py
::
bytes
(
reinterpret_cast
<
const
char
*>
(
&
buf
[
0
]),
buf
.
size
());
});
m
.
def
(
"load_graph"
,
[](
std
::
string
&
buf
,
py
::
list
&
_output_var_map
,
py
::
list
&
_output_var_list
)
{
using
namespace
mgb
::
serialization
;
auto
file
=
InputFile
::
make_mem_proxy
(
buf
.
c_str
(),
buf
.
length
());
auto
format
=
GraphLoader
::
identify_graph_dump_format
(
*
file
);
auto
loader
=
GraphLoader
::
make
(
std
::
move
(
file
),
format
.
val
());
GraphLoader
::
LoadConfig
config
;
m
.
def
(
"load_graph"
,
[](
std
::
string
&
buf
,
py
::
list
&
output_var_map
,
py
::
list
&
output_var_list
)
{
auto
file
=
ser
::
InputFile
::
make_mem_proxy
(
buf
.
c_str
(),
buf
.
length
());
auto
format
=
ser
::
GraphLoader
::
identify_graph_dump_format
(
*
file
);
auto
loader
=
ser
::
GraphLoader
::
make
(
std
::
move
(
file
),
format
.
val
());
ser
::
GraphLoader
::
LoadConfig
config
;
auto
rst
=
loader
->
load
(
config
);
std
::
vector
<
std
::
pair
<
std
::
string
,
SymbolVar
>>
output_var_map
;
SymbolVarArray
output_var_list
;
output_var_map
=
{
rst
.
output_var_map
.
begin
(),
rst
.
output_var_map
.
end
()};
output_var_list
=
std
::
move
(
rst
.
output_var_list
);
for
(
auto
i
:
output_var_list
){
_output_var_list
.
append
(
i
.
node
());
for
(
auto
i
:
rst
.
output_var_map
)
{
output_var_map
.
append
(
py
::
make_tuple
(
i
.
first
,
i
.
second
.
node
()));
}
for
(
auto
i
:
output_var_map
)
{
_output_var_map
.
append
(
py
::
make_tuple
(
i
.
first
,
i
.
second
.
node
()
));
for
(
auto
i
:
rst
.
output_var_list
)
{
output_var_list
.
append
(
i
.
node
(
));
}
std
::
unordered_map
<
HostTensorND
*
,
const
std
::
string
*>
tensor2name
;
for
(
const
auto
&
pair
:
rst
.
tensor_map
)
{
...
...
@@ -277,8 +336,8 @@ void init_graph_rt(py::module m) {
h2d
.
output
(
0
)
->
name
(
*
it
->
second
);
};
cg
::
DepOprIter
iter
{
cb
};
for
(
const
auto
&
var
:
output_var_list
)
{
iter
.
add
(
var
.
node
()
->
owner_opr
()
);
for
(
const
auto
&
var
:
rst
.
output_var_list
)
{
iter
.
add
(
var
);
}
return
rst
.
graph
;
...
...
imperative/python/test/unit/test_tracing.py
浏览文件 @
fc74d5f2
...
...
@@ -12,12 +12,10 @@ from tempfile import mkstemp
import
numpy
as
np
import
pytest
import
megengine
import
megengine.module
as
M
import
megengine.core.tensor.megbrain_graph
as
G
from
megengine
import
cgtools
,
tensor
from
megengine.core._trace_option
import
set_tensor_shape
from
megengine.core.ops
import
builtin
as
ops
from
megengine.core.tensor
import
megbrain_graph
as
G
from
megengine.core.tensor.core
import
apply
from
megengine.core.tensor.raw_tensor
import
as_raw_tensor
from
megengine.functional
import
exp
,
log
...
...
@@ -121,7 +119,10 @@ def test_dump():
np
.
testing
.
assert_equal
(
f
(
as_raw_tensor
(
a
),
as_raw_tensor
(
b
)).
numpy
(),
y
)
file
=
io
.
BytesIO
()
f
.
dump
(
file
)
dump_info
=
f
.
dump
(
file
)
assert
dump_info
.
nr_opr
==
3
np
.
testing
.
assert_equal
(
dump_info
.
inputs
,
[
"h2d[0]"
,
"h2d[2]"
])
np
.
testing
.
assert_equal
(
dump_info
.
outputs
,
[
"ADD(h2d[0],h2d[2])[4]"
])
file
.
seek
(
0
)
result
=
load_and_inference
(
file
,
[
a
,
b
])
np
.
testing
.
assert_equal
(
result
[
0
],
y
)
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录