Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
xxadev
tensorflow
提交
e5353c94
T
tensorflow
项目概览
xxadev
/
tensorflow
与 Fork 源项目一致
从无法访问的项目Fork
通知
3
Star
1
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
T
tensorflow
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
e5353c94
编写于
7月 27, 2017
作者:
A
A. Unique TensorFlower
提交者:
TensorFlower Gardener
7月 27, 2017
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Don't prune nodes that have reference inputs.
PiperOrigin-RevId: 163390862
上级
22651083
变更
5
隐藏空白更改
内联
并排
Showing
5 changed file
with
105 addition
and
15 deletion
+105
-15
tensorflow/core/grappler/optimizers/BUILD
tensorflow/core/grappler/optimizers/BUILD
+1
-0
tensorflow/core/grappler/optimizers/graph_rewriter.cc
tensorflow/core/grappler/optimizers/graph_rewriter.cc
+36
-3
tensorflow/core/grappler/optimizers/graph_rewriter.h
tensorflow/core/grappler/optimizers/graph_rewriter.h
+14
-1
tensorflow/core/grappler/optimizers/model_pruner.cc
tensorflow/core/grappler/optimizers/model_pruner.cc
+14
-11
tensorflow/core/grappler/optimizers/model_pruner_test.cc
tensorflow/core/grappler/optimizers/model_pruner_test.cc
+40
-0
未找到文件。
tensorflow/core/grappler/optimizers/BUILD
浏览文件 @
e5353c94
...
...
@@ -134,6 +134,7 @@ cc_library(
],
visibility
=
[
"//visibility:public"
],
deps
=
[
"//tensorflow/core:framework"
,
"//tensorflow/core:protos_all_cc"
,
"//tensorflow/core/grappler:grappler_item"
,
"//tensorflow/core/grappler:utils"
,
...
...
tensorflow/core/grappler/optimizers/graph_rewriter.cc
浏览文件 @
e5353c94
...
...
@@ -18,6 +18,8 @@ limitations under the License.
#include <unordered_set>
#include "tensorflow/core/framework/function.pb.h"
#include "tensorflow/core/framework/node_def.pb.h"
#include "tensorflow/core/framework/node_def_util.h"
#include "tensorflow/core/framework/op.h"
#include "tensorflow/core/framework/op_def.pb.h"
#include "tensorflow/core/grappler/grappler_item.h"
#include "tensorflow/core/grappler/utils.h"
...
...
@@ -26,8 +28,24 @@ namespace tensorflow {
namespace
grappler
{
GraphRewriter
::
GraphRewriter
(
const
GrapplerItem
&
item
)
{
OpRegistryInterface
*
op_registry
=
OpRegistry
::
Global
();
for
(
auto
&
node
:
item
.
graph
.
node
())
{
nodes_
[
node
.
name
()]
=
&
node
;
NodeInfo
*
info
=
new
NodeInfo
();
info
->
def
=
&
node
;
const
OpRegistrationData
*
op_reg_data
=
nullptr
;
Status
s
=
op_registry
->
LookUp
(
node
.
op
(),
&
op_reg_data
);
// TODO(bsteiner): make this not a best-effort lookup and evaluation?
if
(
s
.
ok
())
{
s
=
InOutTypesForNode
(
node
,
op_reg_data
->
op_def
,
&
info
->
inputs
,
&
info
->
outputs
);
if
(
!
s
.
ok
())
{
info
->
inputs
.
clear
();
info
->
outputs
.
clear
();
}
}
nodes_
[
node
.
name
()].
reset
(
info
);
}
std
::
unordered_set
<
string
>
function_names
;
...
...
@@ -73,11 +91,16 @@ bool GraphRewriter::IsDrivenByAnotherDevice(const NodeDef& node) const {
return
cross_device_receivers_
.
find
(
&
node
)
!=
cross_device_receivers_
.
end
();
}
bool
GraphRewriter
::
ReceivesRefValue
(
const
NodeDef
&
node
)
const
{
return
ref_receivers_
.
find
(
&
node
)
!=
ref_receivers_
.
end
();
}
void
GraphRewriter
::
RecordConnectivity
(
const
NodeDef
&
node
,
const
std
::
unordered_set
<
string
>&
function_names
)
{
const
bool
is_function
=
function_names
.
find
(
node
.
op
())
!=
function_names
.
end
();
bool
ref_receiver
=
false
;
for
(
const
auto
&
input
:
node
.
input
())
{
int
position
=
0
;
string
input_node_name
=
ParseNodeName
(
input
,
&
position
);
...
...
@@ -85,7 +108,8 @@ void GraphRewriter::RecordConnectivity(
if
(
itr
==
nodes_
.
end
())
{
continue
;
}
const
NodeDef
*
fanin
=
itr
->
second
;
const
NodeInfo
*
fanin_info
=
itr
->
second
.
get
();
const
NodeDef
*
fanin
=
fanin_info
->
def
;
if
(
position
<
0
)
{
// This is a control edge
control_dependency_drivers_
.
insert
(
fanin
);
...
...
@@ -97,11 +121,20 @@ void GraphRewriter::RecordConnectivity(
if
(
is_function
)
{
function_neighbors_
.
insert
(
fanin
);
}
if
(
position
<
fanin_info
->
outputs
.
size
()
&&
IsRefType
(
fanin_info
->
outputs
[
position
]))
{
ref_receiver
=
true
;
}
}
if
(
fanin
->
device
()
!=
node
.
device
())
{
cross_device_receivers_
.
insert
(
&
node
);
}
}
if
(
ref_receiver
)
{
ref_receivers_
.
insert
(
&
node
);
}
}
void
GraphRewriter
::
ForwardInputsInternal
(
...
...
@@ -125,7 +158,7 @@ void GraphRewriter::ForwardInputsInternal(
*
new_node
->
add_input
()
=
input
;
continue
;
}
const
NodeDef
*
input_node
=
itr
->
second
;
const
NodeDef
*
input_node
=
itr
->
second
->
def
;
if
(
nodes_to_delete
.
find
(
input_node
)
!=
nodes_to_delete
.
end
())
{
ForwardInputsInternal
(
*
input_node
,
nodes_to_delete
,
new_node
);
}
else
{
...
...
tensorflow/core/grappler/optimizers/graph_rewriter.h
浏览文件 @
e5353c94
...
...
@@ -55,6 +55,9 @@ class GraphRewriter {
// device.
bool
IsDrivenByAnotherDevice
(
const
NodeDef
&
node
)
const
;
// Returns true if the node has input from a stateful op.
bool
ReceivesRefValue
(
const
NodeDef
&
node
)
const
;
private:
void
RecordConnectivity
(
const
NodeDef
&
node
,
const
std
::
unordered_set
<
string
>&
function_names
);
...
...
@@ -63,11 +66,21 @@ class GraphRewriter {
const
std
::
unordered_set
<
const
NodeDef
*>&
nodes_to_delete
,
NodeDef
*
new_node
);
std
::
unordered_map
<
string
,
const
NodeDef
*>
nodes_
;
struct
NodeInfo
{
const
NodeDef
*
def
;
// These are filled in when the NodeInfo is built, but not that they
// may be empty - if the op could not be loaded from the registry.
DataTypeVector
inputs
;
DataTypeVector
outputs
;
};
std
::
unordered_map
<
string
,
std
::
unique_ptr
<
NodeInfo
>>
nodes_
;
std
::
unordered_map
<
string
,
const
NodeDef
*>
optimized_nodes_
;
std
::
unordered_set
<
const
NodeDef
*>
control_dependency_drivers_
;
std
::
unordered_set
<
const
NodeDef
*>
function_neighbors_
;
std
::
unordered_set
<
const
NodeDef
*>
cross_device_receivers_
;
std
::
unordered_set
<
const
NodeDef
*>
ref_receivers_
;
};
}
// end namespace grappler
...
...
tensorflow/core/grappler/optimizers/model_pruner.cc
浏览文件 @
e5353c94
...
...
@@ -74,20 +74,23 @@ Status ModelPruner::Optimize(Cluster* cluster, const GrapplerItem& item,
continue
;
}
// Don't remove nodes that drive control dependencies.
// Don't remove nodes that are driven by control dependencies either since
// we can't ensure (yet) that we won't increase the number of control
// dependency edges by deleting them (for example, removing a node driven by
// 10 control edges and driving 10 control edges would result in the
// creation of 100 edges).
// Don't modify nodes that are connected to functions since that can result
// in inlining failures later on.
// Don't prune nodes that are driven by another device since these could be
// used to reduce cross device communication.
// - Don't remove nodes that drive control dependencies.
// - Don't remove nodes that are driven by control dependencies either since
// we can't ensure (yet) that we won't increase the number of control
// dependency edges by deleting them (for example, removing a node driven
// by 10 control edges and driving 10 control edges would result in the
// creation of 100 edges).
// - Don't modify nodes that are connected to functions since that can
// result in inlining failures later on.
// - Don't prune nodes that are driven by another device since these could
// be used to reduce cross device communication.
// - Don't remove nodes that receive reference values, as those can be
// converting references to non-references.
if
(
!
rewriter
.
DrivesControlDependency
(
node
)
&&
!
rewriter
.
IsDrivenByControlDependency
(
node
)
&&
!
rewriter
.
IsConnectedToFunction
(
node
)
&&
!
rewriter
.
IsDrivenByAnotherDevice
(
node
))
{
!
rewriter
.
IsDrivenByAnotherDevice
(
node
)
&&
!
rewriter
.
ReceivesRefValue
(
node
))
{
nodes_to_delete
.
insert
(
&
node
);
}
}
...
...
tensorflow/core/grappler/optimizers/model_pruner_test.cc
浏览文件 @
e5353c94
...
...
@@ -199,6 +199,46 @@ TEST_F(ModelPrunerTest, PruningSkipsCtrlDependencies) {
EXPECT_EQ
(
"^c"
,
new_e
.
input
(
1
));
}
TEST_F
(
ModelPrunerTest
,
PruningSkipsRefOutputs
)
{
tensorflow
::
Scope
s
=
tensorflow
::
Scope
::
NewRootScope
();
// Make graph of Identity(Identity(Identity(Identity(Variable)))).
Output
a
=
ops
::
Variable
(
s
.
WithOpName
(
"a"
),
{},
DT_INT64
);
Output
b
=
ops
::
Identity
(
s
.
WithOpName
(
"b"
),
a
);
Output
c
=
ops
::
Identity
(
s
.
WithOpName
(
"c"
),
b
);
Output
d
=
ops
::
Identity
(
s
.
WithOpName
(
"d"
),
c
);
Output
e
=
ops
::
Identity
(
s
.
WithOpName
(
"e"
),
d
);
// Run pruner.
GrapplerItem
item
;
TF_CHECK_OK
(
s
.
ToGraphDef
(
&
item
.
graph
));
ModelPruner
pruner
;
GraphDef
output
;
Status
status
=
pruner
.
Optimize
(
nullptr
,
item
,
&
output
);
TF_EXPECT_OK
(
status
);
// Get the updated nodes.
ASSERT_EQ
(
5
,
output
.
node_size
());
const
NodeDef
&
new_a
=
output
.
node
(
0
);
const
NodeDef
&
new_b
=
output
.
node
(
1
);
const
NodeDef
&
new_c
=
output
.
node
(
2
);
const
NodeDef
&
new_d
=
output
.
node
(
3
);
const
NodeDef
&
new_e
=
output
.
node
(
4
);
EXPECT_EQ
(
"a"
,
new_a
.
name
());
EXPECT_EQ
(
"b"
,
new_b
.
name
());
EXPECT_EQ
(
"c"
,
new_c
.
name
());
EXPECT_EQ
(
"d"
,
new_d
.
name
());
EXPECT_EQ
(
"e"
,
new_e
.
name
());
// Verify the connections. Identity "b" can't be removed from the chain
// because it is converting a reference input to a non-reference, so c,d,e all
// refer to it as an input.
EXPECT_EQ
(
"a"
,
new_b
.
input
(
0
));
EXPECT_EQ
(
"b"
,
new_c
.
input
(
0
));
EXPECT_EQ
(
"b"
,
new_d
.
input
(
0
));
EXPECT_EQ
(
"b"
,
new_e
.
input
(
0
));
}
TEST_F
(
ModelPrunerTest
,
PruningPerservesCtrlDependencies
)
{
// Build a simple graph with a few trivially prunable ops.
tensorflow
::
Scope
s
=
tensorflow
::
Scope
::
NewRootScope
();
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录