Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
BaiXuePrincess
Paddle
提交
1fa6900e
P
Paddle
项目概览
BaiXuePrincess
/
Paddle
与 Fork 源项目一致
Fork自
PaddlePaddle / Paddle
通知
1
Star
1
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
P
Paddle
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
未验证
提交
1fa6900e
编写于
12月 30, 2021
作者:
J
joanna.wozna.intel
提交者:
GitHub
12月 30, 2021
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Refactor cpu_quantize_pass (#38019)
上级
ed2cfecf
变更
1
隐藏空白更改
内联
并排
Showing
1 changed file
with
238 addition
and
663 deletion
+238
-663
paddle/fluid/framework/ir/mkldnn/cpu_quantize_pass_tester.cc
paddle/fluid/framework/ir/mkldnn/cpu_quantize_pass_tester.cc
+238
-663
未找到文件。
paddle/fluid/framework/ir/mkldnn/cpu_quantize_pass_tester.cc
浏览文件 @
1fa6900e
...
...
@@ -12,8 +12,9 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include "paddle/fluid/framework/ir/mkldnn/cpu_quantize_pass.h"
#include "paddle/fluid/framework/ir/mkldnn/cpu_quantize_pass.h"
// NOLINT
#include <gtest/gtest.h>
#include <unordered_map>
#include "paddle/fluid/framework/naive_executor.h"
#include "paddle/fluid/imperative/type_defs.h"
...
...
@@ -23,6 +24,10 @@ namespace paddle {
namespace
framework
{
namespace
ir
{
static
float
const
SCALE
=
2.
f
;
static
int
const
S8_MAX
=
127
;
static
int
const
U8_MAX
=
255
;
void
SetOp
(
ProgramDesc
*
prog
,
const
std
::
string
&
type
,
const
std
::
string
&
name
,
const
std
::
vector
<
std
::
string
>&
inputs
,
const
std
::
vector
<
std
::
string
>&
outputs
,
bool
use_mkldnn
,
...
...
@@ -31,6 +36,9 @@ void SetOp(ProgramDesc* prog, const std::string& type, const std::string& name,
op
->
SetType
(
type
);
op
->
SetAttr
(
"use_mkldnn"
,
use_mkldnn
);
op
->
SetAttr
(
"name"
,
name
);
if
(
type
!=
"dropout"
||
type
!=
"quantize"
||
type
!=
"dequantize"
)
{
op
->
SetAttr
(
"mkldnn_data_type"
,
mkldnn_data_type
);
}
if
(
type
==
"conv2d"
)
{
op
->
SetInput
(
"Input"
,
{
inputs
[
0
]});
...
...
@@ -47,18 +55,15 @@ void SetOp(ProgramDesc* prog, const std::string& type, const std::string& name,
op
->
SetAttr
(
"fuse_residual_connection"
,
false
);
}
op
->
SetOutput
(
"Output"
,
{
outputs
[
0
]});
op
->
SetAttr
(
"mkldnn_data_type"
,
mkldnn_data_type
);
op
->
SetAttr
(
"Scale_in"
,
1.0
f
);
op
->
SetAttr
(
"Scale_out"
,
1.0
f
);
op
->
SetAttr
(
"Scale_weights"
,
std
::
vector
<
float
>
{
1.0
f
});
}
else
if
(
type
==
"pool2d"
||
type
==
"transpose2"
||
type
==
"reshape2"
)
{
op
->
SetInput
(
"X"
,
{
inputs
[
0
]});
op
->
SetOutput
(
"Out"
,
{
outputs
[
0
]});
op
->
SetAttr
(
"mkldnn_data_type"
,
mkldnn_data_type
);
}
else
if
(
type
==
"slice"
)
{
op
->
SetInput
(
"Input"
,
{
inputs
[
0
]});
op
->
SetOutput
(
"Out"
,
{
outputs
[
0
]});
op
->
SetAttr
(
"mkldnn_data_type"
,
mkldnn_data_type
);
}
else
if
(
type
==
"dropout"
)
{
op
->
SetInput
(
"X"
,
{
inputs
[
0
]});
op
->
SetOutput
(
"Out"
,
{
outputs
[
0
]});
...
...
@@ -67,14 +72,12 @@ void SetOp(ProgramDesc* prog, const std::string& type, const std::string& name,
if
(
inputs
.
size
()
>
1
)
op
->
SetInput
(
"W"
,
{
inputs
[
1
]});
if
(
inputs
.
size
()
>
2
)
op
->
SetInput
(
"Bias"
,
{
inputs
[
2
]});
op
->
SetOutput
(
"Out"
,
{
outputs
[
0
]});
op
->
SetAttr
(
"mkldnn_data_type"
,
mkldnn_data_type
);
op
->
SetAttr
(
"Scale_in"
,
1.0
f
);
op
->
SetAttr
(
"Scale_out"
,
1.0
f
);
op
->
SetAttr
(
"Scale_weights"
,
std
::
vector
<
float
>
{
1.0
f
});
}
else
if
(
type
==
"concat"
)
{
op
->
SetInput
(
"X"
,
inputs
);
op
->
SetOutput
(
"Out"
,
outputs
);
op
->
SetAttr
(
"mkldnn_data_type"
,
mkldnn_data_type
);
}
else
if
(
type
==
"dequantize"
)
{
op
->
SetInput
(
"Input"
,
{
inputs
[
0
]});
op
->
SetOutput
(
"Output"
,
{
outputs
[
0
]});
...
...
@@ -83,7 +86,6 @@ void SetOp(ProgramDesc* prog, const std::string& type, const std::string& name,
op
->
SetInput
(
"X"
,
{
inputs
[
0
]});
if
(
inputs
.
size
()
>
1
)
op
->
SetInput
(
"Y"
,
{
inputs
[
1
]});
op
->
SetOutput
(
"Out"
,
{
outputs
[
0
]});
op
->
SetAttr
(
"mkldnn_data_type"
,
mkldnn_data_type
);
op
->
SetAttr
(
"Scale_x"
,
1.0
f
);
op
->
SetAttr
(
"Scale_y"
,
1.0
f
);
op
->
SetAttr
(
"Scale_out"
,
1.0
f
);
...
...
@@ -91,7 +93,6 @@ void SetOp(ProgramDesc* prog, const std::string& type, const std::string& name,
op
->
SetInput
(
"X"
,
{
inputs
[
0
]});
if
(
inputs
.
size
()
>
1
)
op
->
SetInput
(
"Y"
,
{
inputs
[
1
]});
op
->
SetOutput
(
"Out"
,
{
outputs
[
0
]});
op
->
SetAttr
(
"mkldnn_data_type"
,
mkldnn_data_type
);
op
->
SetAttr
(
"Scale_x"
,
1.0
f
);
op
->
SetAttr
(
"Scale_y"
,
1.0
f
);
op
->
SetAttr
(
"Scale_out"
,
1.0
f
);
...
...
@@ -101,7 +102,6 @@ void SetOp(ProgramDesc* prog, const std::string& type, const std::string& name,
op
->
SetInput
(
"WeightX"
,
{
inputs
[
2
]});
op
->
SetInput
(
"WeightH"
,
{
inputs
[
3
]});
op
->
SetOutput
(
"Hidden"
,
{
outputs
[
0
]});
op
->
SetAttr
(
"mkldnn_data_type"
,
mkldnn_data_type
);
op
->
SetAttr
(
"Scale_data"
,
1.0
f
);
op
->
SetAttr
(
"Shift_data"
,
0.0
f
);
op
->
SetAttr
(
"Weight_scale"
,
std
::
vector
<
float
>
{
1.0
f
});
...
...
@@ -114,7 +114,6 @@ void SetOp(ProgramDesc* prog, const std::string& type, const std::string& name,
op
->
SetOutput
(
"Hidden"
,
{
outputs
[
0
]});
op
->
SetOutput
(
"Cell"
,
{
outputs
[
1
]});
op
->
SetAttr
(
"mkldnn_data_type"
,
mkldnn_data_type
);
op
->
SetAttr
(
"Scale_data"
,
1.0
f
);
op
->
SetAttr
(
"Shift_data"
,
0.0
f
);
op
->
SetAttr
(
"Weight_scale"
,
std
::
vector
<
float
>
{
1.0
f
});
...
...
@@ -144,7 +143,7 @@ void PreparePass(std::unique_ptr<ir::Graph>* graph, const ProgramDesc& prog,
LoDTensor
tensor
;
tensor
.
Resize
({
1
});
auto
*
ptr
=
tensor
.
mutable_data
<
double
>
(
place
);
ptr
[
0
]
=
2.0
;
ptr
[
0
]
=
SCALE
;
(
*
scales
)[
v
]
=
std
::
make_pair
(
v
==
var_signed
,
std
::
move
(
tensor
));
}
...
...
@@ -158,7 +157,57 @@ void PreparePass(std::unique_ptr<ir::Graph>* graph, const ProgramDesc& prog,
*
current_nodes_num
=
(
*
graph
)
->
Nodes
().
size
();
}
namespace
{
void
CheckScales
(
const
OpDesc
*
op
,
float
scale
,
float
shift
)
{
std
::
string
type
=
op
->
Type
();
std
::
vector
<
std
::
string
>
scale_names
;
if
(
type
==
"conv2d"
||
type
==
"fc"
)
{
EXPECT_EQ
(
op
->
GetAttrIfExists
<
std
::
vector
<
float
>>
(
"Scale_weights"
)[
0
],
scale
);
scale_names
.
push_back
(
"Scale_in"
);
scale_names
.
push_back
(
"Scale_out"
);
}
else
if
(
type
==
"matmul"
||
type
==
"elementwise_add"
)
{
scale_names
.
push_back
(
"Scale_x"
);
scale_names
.
push_back
(
"Scale_y"
);
scale_names
.
push_back
(
"Scale_out"
);
}
else
if
(
type
==
"fusion_gru"
||
type
==
"fusion_lstm"
)
{
EXPECT_EQ
(
op
->
GetAttrIfExists
<
float
>
(
"Shift_data"
),
shift
);
EXPECT_EQ
(
op
->
GetAttrIfExists
<
std
::
vector
<
float
>>
(
"Scale_weights"
)[
0
],
scale
);
EXPECT_EQ
(
op
->
GetAttrIfExists
<
bool
>
(
"force_fp32_output"
),
true
);
scale_names
.
push_back
(
"Scale_data"
);
}
for
(
auto
const
&
scale_name
:
scale_names
)
{
EXPECT_EQ
(
op
->
GetAttrIfExists
<
float
>
(
scale_name
),
scale
);
}
}
void
MainTest
(
const
ProgramDesc
&
prog
,
const
std
::
vector
<
std
::
string
>
variable_names
,
std
::
unordered_map
<
std
::
string
,
int
>
expected_operators
,
const
int
added_nodes_count
,
float
scale
=
1.
f
,
float
shift
=
1.
f
,
std
::
string
var_without_scale
=
""
,
std
::
string
var_signed
=
""
)
{
std
::
unique_ptr
<
ir
::
Graph
>
graph
(
new
ir
::
Graph
(
prog
));
int
original_nodes_num
,
current_nodes_num
;
PreparePass
(
&
graph
,
prog
,
variable_names
,
&
original_nodes_num
,
&
current_nodes_num
,
var_without_scale
,
var_signed
);
std
::
unordered_map
<
std
::
string
,
int
>
actual_operators
;
for
(
auto
*
node
:
graph
->
Nodes
())
{
if
(
node
->
IsOp
())
{
auto
*
op
=
node
->
Op
();
if
(
expected_operators
.
count
(
op
->
Type
())
>
0
)
{
expected_operators
[
op
->
Type
()]
--
;
if
(
op
->
GetAttrIfExists
<
std
::
string
>
(
"mkldnn_data_type"
)
==
"int8"
)
CheckScales
(
op
,
scale
,
shift
);
}
}
}
for
(
auto
const
&
pair
:
expected_operators
)
{
EXPECT_EQ
(
pair
.
second
,
0
);
}
EXPECT_EQ
(
original_nodes_num
+
added_nodes_count
,
current_nodes_num
);
}
static
const
std
::
initializer_list
<
std
::
string
>
variable_names
{
"a"
,
"w1"
,
"c"
,
"d"
,
"w2"
,
"e"
,
"f"
,
"g"
,
"h"
,
"w3"
,
"b1"
,
"i"
,
"j"
,
"w4"
,
"b2"
,
"w5"
,
"b3"
};
...
...
@@ -199,48 +248,6 @@ ProgramDesc BuildProgramDesc(bool use_mkldnn,
return
prog
;
}
void
MainTest
(
const
ProgramDesc
&
prog
,
int
conv_count
,
int
pool_count
,
int
quant_count
,
int
dequant_count
,
int
added_nodes_count
,
float
scale
)
{
std
::
unique_ptr
<
ir
::
Graph
>
graph
(
new
ir
::
Graph
(
prog
));
int
original_nodes_num
,
current_nodes_num
;
PreparePass
(
&
graph
,
prog
,
variable_names
,
&
original_nodes_num
,
&
current_nodes_num
);
int
quantize_nodes_count
=
0
;
int
dequantize_nodes_count
=
0
;
int
conv2d_nodes_count
=
0
;
int
pool2d_nodes_count
=
0
;
for
(
auto
*
node
:
graph
->
Nodes
())
{
if
(
node
->
IsOp
())
{
auto
*
op
=
node
->
Op
();
if
(
op
->
Type
()
==
"conv2d"
)
{
conv2d_nodes_count
++
;
auto
op_name
=
BOOST_GET_CONST
(
std
::
string
,
op
->
GetAttr
(
"name"
));
EXPECT_EQ
(
BOOST_GET_CONST
(
float
,
op
->
GetAttr
(
"Scale_in"
)),
scale
)
<<
"Scale_in for node '"
+
op_name
+
"'."
;
EXPECT_EQ
(
BOOST_GET_CONST
(
float
,
op
->
GetAttr
(
"Scale_out"
)),
scale
)
<<
"Scale_out for node '"
+
op_name
+
"'."
;
EXPECT_EQ
(
BOOST_GET_CONST
(
std
::
vector
<
float
>
,
op
->
GetAttr
(
"Scale_weights"
))[
0
],
scale
)
<<
"Scale_weights for node '"
+
op_name
+
"'."
;
}
else
if
(
op
->
Type
()
==
"pool2d"
)
{
pool2d_nodes_count
++
;
}
else
if
(
op
->
Type
()
==
"quantize"
)
{
quantize_nodes_count
++
;
}
else
if
(
op
->
Type
()
==
"dequantize"
)
{
dequantize_nodes_count
++
;
}
}
}
EXPECT_EQ
(
conv2d_nodes_count
,
conv_count
);
EXPECT_EQ
(
pool2d_nodes_count
,
pool_count
);
EXPECT_EQ
(
quantize_nodes_count
,
quant_count
);
EXPECT_EQ
(
dequantize_nodes_count
,
dequant_count
);
EXPECT_EQ
(
original_nodes_num
+
added_nodes_count
,
current_nodes_num
);
}
TEST
(
CpuQuantizePass
,
quantize
)
{
bool
use_mkldnn
=
true
;
std
::
string
mkldnn_data_type
=
"int8"
;
...
...
@@ -256,16 +263,20 @@ TEST(CpuQuantizePass, quantize) {
// (d->QUANT7->IN7,w4, b2)->Conv4->DEQUANT6->OUT6->i
// Insert nodes: 8 Quant + 8 IN + 7 OUT + 7 DEQUANT
int
added_nodes
=
8
+
8
+
7
+
7
;
MainTest
(
BuildProgramDesc
(
use_mkldnn
,
mkldnn_data_type
),
4
,
2
,
8
,
7
,
added_nodes
,
2.0
f
*
127
);
std
::
unordered_map
<
std
::
string
,
int
>
expected_operators
=
{
{
"conv2d"
,
4
},
{
"pool2d"
,
2
},
{
"quantize"
,
8
},
{
"dequantize"
,
7
}};
MainTest
(
BuildProgramDesc
(
use_mkldnn
,
mkldnn_data_type
),
variable_names
,
expected_operators
,
added_nodes
,
SCALE
*
S8_MAX
);
}
TEST
(
CpuQuantizePass
,
do_not_quantize
)
{
bool
use_mkldnn
=
true
;
std
::
string
mkldnn_data_type
=
"float32"
;
int
added_nodes
=
0
;
MainTest
(
BuildProgramDesc
(
use_mkldnn
,
mkldnn_data_type
),
4
,
2
,
0
,
0
,
added_nodes
,
1.0
f
);
std
::
unordered_map
<
std
::
string
,
int
>
expected_operators
=
{
{
"conv2d"
,
4
},
{
"pool2d"
,
2
},
{
"quantize"
,
0
},
{
"dequantize"
,
0
}};
MainTest
(
BuildProgramDesc
(
use_mkldnn
,
mkldnn_data_type
),
variable_names
,
expected_operators
,
added_nodes
,
1.0
f
);
}
static
const
std
::
initializer_list
<
std
::
string
>
variable_names_concat
=
{
...
...
@@ -286,134 +297,16 @@ ProgramDesc BuildProgramDescConcat() {
return
prog
;
}
void
MainTestConcat
(
const
ProgramDesc
&
prog
,
int
pool_count
,
int
concat_count
,
int
quant_count
,
int
dequant_count
,
int
added_nodes_count
)
{
std
::
unique_ptr
<
ir
::
Graph
>
graph
(
new
ir
::
Graph
(
prog
));
int
original_nodes_num
,
current_nodes_num
;
PreparePass
(
&
graph
,
prog
,
variable_names_concat
,
&
original_nodes_num
,
&
current_nodes_num
);
int
quantize_nodes_count
=
0
;
int
dequantize_nodes_count
=
0
;
int
concat_nodes_count
=
0
;
int
pool2d_nodes_count
=
0
;
for
(
auto
*
node
:
graph
->
Nodes
())
{
if
(
node
->
IsOp
())
{
auto
*
op
=
node
->
Op
();
if
(
op
->
Type
()
==
"concat"
)
{
concat_nodes_count
++
;
}
else
if
(
op
->
Type
()
==
"pool2d"
)
{
pool2d_nodes_count
++
;
}
else
if
(
op
->
Type
()
==
"quantize"
)
{
quantize_nodes_count
++
;
}
else
if
(
op
->
Type
()
==
"dequantize"
)
{
dequantize_nodes_count
++
;
}
}
}
EXPECT_EQ
(
concat_nodes_count
,
concat_count
);
EXPECT_EQ
(
pool2d_nodes_count
,
pool_count
);
EXPECT_EQ
(
quantize_nodes_count
,
quant_count
);
EXPECT_EQ
(
dequantize_nodes_count
,
dequant_count
);
EXPECT_EQ
(
original_nodes_num
+
added_nodes_count
,
current_nodes_num
);
}
TEST
(
CpuQuantizePass
,
concat
)
{
// a1->Pool1->b1
// a2->Pool2->b2
// (b1->QUANT1->IN1, b2->QUANT2->IN2)->Concat->c
// c->OUT1->DEQUANT1->Pool3->d
int
pool_count
=
3
;
int
concat_count
=
1
;
int
quant_count
=
2
;
int
dequant_count
=
1
;
int
added_nodes_count
=
6
;
MainTestConcat
(
BuildProgramDescConcat
(),
pool_count
,
concat_count
,
quant_count
,
dequant_count
,
added_nodes_count
);
}
static
const
std
::
initializer_list
<
std
::
string
>
variable_names_transpose
=
{
"a"
,
"w1"
,
"b"
,
"c"
,
"w2"
,
"d"
,
"e"
,
"f"
};
// a->Conv1->b
// b->Transpose1->c
// c->Conv2->d
// d->Transpose2->e
// e->Dropout->f
ProgramDesc
BuildProgramDescTranspose
()
{
ProgramDesc
prog
;
for
(
auto
&
v
:
variable_names_transpose
)
{
auto
*
var
=
prog
.
MutableBlock
(
0
)
->
Var
(
v
);
if
(
v
.
find
(
"w"
)
==
0
)
{
var
->
SetPersistable
(
true
);
}
}
SetOp
(
&
prog
,
"conv2d"
,
"Conv1"
,
{
"a"
,
"w1"
},
{
"b"
},
true
,
"int8"
);
SetOp
(
&
prog
,
"transpose2"
,
"Transpose1"
,
{
"b"
},
{
"c"
},
true
,
"int8"
);
SetOp
(
&
prog
,
"conv2d"
,
"Conv1"
,
{
"c"
,
"w2"
},
{
"d"
},
true
,
"int8"
);
SetOp
(
&
prog
,
"transpose2"
,
"Transpose2"
,
{
"d"
},
{
"e"
},
true
,
"int8"
);
SetOp
(
&
prog
,
"dropout"
,
"Dropout"
,
{
"e"
},
{
"f"
},
true
,
"float32"
);
return
prog
;
}
void
MainTestTranspose
(
const
ProgramDesc
&
prog
,
int
conv_count
,
int
transpose_count
,
int
quant_count
,
int
dequant_count
,
int
added_nodes_count
,
float
scale
)
{
std
::
unique_ptr
<
ir
::
Graph
>
graph
(
new
ir
::
Graph
(
prog
));
int
original_nodes_num
,
current_nodes_num
;
PreparePass
(
&
graph
,
prog
,
variable_names_transpose
,
&
original_nodes_num
,
&
current_nodes_num
);
int
quantize_nodes_count
=
0
;
int
dequantize_nodes_count
=
0
;
int
transpose_nodes_count
=
0
;
int
conv_nodes_count
=
0
;
for
(
auto
*
node
:
graph
->
Nodes
())
{
if
(
node
->
IsOp
())
{
auto
*
op
=
node
->
Op
();
if
(
op
->
Type
()
==
"transpose2"
)
{
transpose_nodes_count
++
;
}
else
if
(
op
->
Type
()
==
"conv2d"
)
{
conv_nodes_count
++
;
auto
op_name
=
BOOST_GET_CONST
(
std
::
string
,
op
->
GetAttr
(
"name"
));
EXPECT_EQ
(
BOOST_GET_CONST
(
float
,
op
->
GetAttr
(
"Scale_in"
)),
scale
)
<<
"Scale_in for node '"
+
op_name
+
"'."
;
EXPECT_EQ
(
BOOST_GET_CONST
(
float
,
op
->
GetAttr
(
"Scale_out"
)),
scale
)
<<
"Scale_out for node '"
+
op_name
+
"'."
;
EXPECT_EQ
(
BOOST_GET_CONST
(
std
::
vector
<
float
>
,
op
->
GetAttr
(
"Scale_weights"
))[
0
],
scale
)
<<
"Scale_weights for node '"
+
op_name
+
"'."
;
}
else
if
(
op
->
Type
()
==
"quantize"
)
{
quantize_nodes_count
++
;
}
else
if
(
op
->
Type
()
==
"dequantize"
)
{
dequantize_nodes_count
++
;
}
}
}
EXPECT_EQ
(
transpose_nodes_count
,
transpose_count
);
EXPECT_EQ
(
conv_nodes_count
,
conv_count
);
EXPECT_EQ
(
quantize_nodes_count
,
quant_count
);
EXPECT_EQ
(
dequantize_nodes_count
,
dequant_count
);
EXPECT_EQ
(
original_nodes_num
+
added_nodes_count
,
current_nodes_num
);
}
TEST
(
CpuQuantizePass
,
transpose
)
{
// a1->Quant->a2->Conv1->b1->Dequant->b2
// b2->Quant->b3->Transpose->c1->Dequant->c2
// c2->Quant->c3->Conv2->d1->Dequant->d2
// d2->Quant->d3->Transpose->e1->Dequant->e2
// e2->Dropout->f
int
conv_count
=
2
;
int
transpose_count
=
2
;
int
quant_count
=
4
;
int
dequant_count
=
4
;
// 4 Quant + 4 IN + 4 DeQuant + 4 OUT
int
added_nodes_count
=
4
+
4
+
4
+
4
;
MainTestTranspose
(
BuildProgramDescTranspose
(),
conv_count
,
transpose_count
,
quant_count
,
dequant_count
,
added_nodes_count
,
2.0
f
*
127
);
int
added_nodes
=
6
;
std
::
unordered_map
<
std
::
string
,
int
>
expected_operators
=
{
{
"pool2d"
,
3
},
{
"concat"
,
1
},
{
"quantize"
,
2
},
{
"dequantize"
,
1
}};
MainTest
(
BuildProgramDescConcat
(),
variable_names_concat
,
expected_operators
,
added_nodes
);
}
static
const
std
::
initializer_list
<
std
::
string
>
variable_names_fusion_gru
=
{
...
...
@@ -422,7 +315,7 @@ static const std::initializer_list<std::string> variable_names_fusion_gru = {
// (x, wx, wh, b)->Fusion_gru->h
ProgramDesc
BuildProgramDescFusionGru
()
{
ProgramDesc
prog
;
for
(
auto
&
v
:
variable_names_
transpose
)
{
for
(
auto
&
v
:
variable_names_
fusion_gru
)
{
auto
*
var
=
prog
.
MutableBlock
(
0
)
->
Var
(
v
);
if
(
v
.
find
(
"wx"
)
==
0
||
v
.
find
(
"wh"
)
||
v
.
find
(
"b"
))
{
var
->
SetPersistable
(
true
);
...
...
@@ -441,7 +334,7 @@ static const std::initializer_list<std::string> variable_names_fusion_lstm = {
// (x, wx, wh, b)->Fusion_lstm_1->h
ProgramDesc
BuildProgramDescFusionLSTM
()
{
ProgramDesc
prog
;
for
(
auto
&
v
:
variable_names_
transpose
)
{
for
(
auto
&
v
:
variable_names_
fusion_lstm
)
{
auto
*
var
=
prog
.
MutableBlock
(
0
)
->
Var
(
v
);
if
(
v
.
find
(
"wx"
)
==
0
||
v
.
find
(
"wh"
)
||
v
.
find
(
"b"
))
{
var
->
SetPersistable
(
true
);
...
...
@@ -454,109 +347,180 @@ ProgramDesc BuildProgramDescFusionLSTM() {
return
prog
;
}
void
MainTestFusionGru
(
const
ProgramDesc
&
prog
,
int
gru_count
,
int
quant_count
,
int
dequant_count
,
int
added_nodes_count
,
float
scale
,
float
shift
)
{
std
::
unique_ptr
<
ir
::
Graph
>
graph
(
new
ir
::
Graph
(
prog
));
int
original_nodes_num
,
current_nodes_num
;
PreparePass
(
&
graph
,
prog
,
variable_names_fusion_gru
,
&
original_nodes_num
,
&
current_nodes_num
);
TEST
(
CpuQuantizePass
,
fusion_gru
)
{
// (x, wx, wh, b)->Fusion_gru->h
int
quantize_nodes_count
=
0
;
int
dequantize_nodes_count
=
0
;
int
gru_nodes_count
=
0
;
for
(
auto
*
node
:
graph
->
Nodes
())
{
if
(
node
->
IsOp
())
{
auto
*
op
=
node
->
Op
();
if
(
op
->
Type
()
==
"fusion_gru"
)
{
gru_nodes_count
++
;
// 1 Quant + 1 IN + 0 DeQuant + 0 OUT
int
added_nodes
=
1
+
1
+
0
+
0
;
std
::
unordered_map
<
std
::
string
,
int
>
expected_operators
=
{
{
"fusion_gru"
,
1
},
{
"quantize"
,
1
},
{
"dequantize"
,
0
}};
MainTest
(
BuildProgramDescFusionGru
(),
variable_names_fusion_gru
,
expected_operators
,
added_nodes
,
SCALE
*
S8_MAX
,
128
);
}
auto
op_name
=
BOOST_GET_CONST
(
std
::
string
,
op
->
GetAttr
(
"name"
));
EXPECT_EQ
(
BOOST_GET_CONST
(
float
,
op
->
GetAttr
(
"Scale_data"
)),
scale
)
<<
"Scale_data for node '"
+
op_name
+
"'."
;
EXPECT_EQ
(
BOOST_GET_CONST
(
float
,
op
->
GetAttr
(
"Shift_data"
)),
shift
)
<<
"Shift_data for node '"
+
op_name
+
"'."
;
EXPECT_EQ
(
BOOST_GET_CONST
(
std
::
vector
<
float
>
,
op
->
GetAttr
(
"Scale_weights"
))[
0
],
scale
)
<<
"Scale_weights for node '"
+
op_name
+
"'."
;
EXPECT_EQ
(
BOOST_GET_CONST
(
bool
,
op
->
GetAttr
(
"force_fp32_output"
)),
true
)
<<
"force_fp32_output for node '"
+
op_name
+
"'."
;
}
else
if
(
op
->
Type
()
==
"quantize"
)
{
quantize_nodes_count
++
;
}
else
if
(
op
->
Type
()
==
"dequantize"
)
{
dequantize_nodes_count
++
;
}
}
TEST
(
CpuQuantizePass
,
fusion_lstm
)
{
// (x, wx, wh, b)->Fusion_lstm->h
// 1 Quant + 1 IN + 0 DeQuant + 0 OUT
int
added_nodes
=
1
+
1
+
0
+
0
;
std
::
unordered_map
<
std
::
string
,
int
>
expected_operators
=
{
{
"fusion_lstm"
,
1
},
{
"quantize"
,
1
},
{
"dequantize"
,
0
}};
MainTest
(
BuildProgramDescFusionLSTM
(),
variable_names_fusion_lstm
,
expected_operators
,
added_nodes
,
SCALE
*
S8_MAX
,
128.
);
}
static
const
std
::
initializer_list
<
std
::
string
>
variable_names_immutable_ops
=
{
"a"
,
"w1"
,
"b"
,
"c"
,
"d"
};
// a->Dequantize->b
// b->Tested Op->c
// c->Dropout->d
void
TestImmutableOp
(
const
std
::
string
tested_op
)
{
ProgramDesc
prog
;
for
(
auto
&
v
:
variable_names_immutable_ops
)
{
prog
.
MutableBlock
(
0
)
->
Var
(
v
);
}
EXPECT_EQ
(
gru_nodes_count
,
gru_count
);
EXPECT_EQ
(
quantize_nodes_count
,
quant_count
);
EXPECT_EQ
(
dequantize_nodes_count
,
dequant_count
);
EXPECT_EQ
(
original_nodes_num
+
added_nodes_count
,
current_nodes_num
);
SetOp
(
&
prog
,
"dequantize"
,
"Dequantize1"
,
{
"a"
},
{
"b"
},
true
);
SetOp
(
&
prog
,
tested_op
,
tested_op
,
{
"b"
},
{
"c"
},
true
,
"int8"
);
SetOp
(
&
prog
,
"dropout"
,
"Dropout"
,
{
"c"
},
{
"d"
},
true
,
"float32"
);
// a->Dequantize->b
// b2->Quant->b3->Tested Op->c1->Dequant->c2
// c2->Dropout->d
// 1 Quant + 1 IN + 1 DeQuant + 1 OUT
int
added_nodes
=
4
;
std
::
unordered_map
<
std
::
string
,
int
>
expected_operators
=
{
{
tested_op
,
1
},
{
"quantize"
,
1
},
{
"dequantize"
,
2
}};
MainTest
(
prog
,
variable_names_immutable_ops
,
expected_operators
,
added_nodes
,
SCALE
*
S8_MAX
);
}
TEST
(
CpuQuantizePass
,
fusion_gru
)
{
// (x, wx, wh, b)->Fusion_gru->h
int
gru_count
=
1
;
int
quant_count
=
1
;
int
dequant_count
=
0
;
// 1 Quant + 1 IN + 0 DeQuant + 0 OUT
int
added_nodes_count
=
1
+
1
+
0
+
0
;
MainTestFusionGru
(
BuildProgramDescFusionGru
(),
gru_count
,
quant_count
,
dequant_count
,
added_nodes_count
,
2.
*
127
,
128.
);
// a->Dropout1->b
// b->Tested Op->c
// c->Dropout2->d
void
TestImmutableOpBetweenNonQuantizedOp
(
const
std
::
string
tested_op
)
{
ProgramDesc
prog
;
for
(
auto
&
v
:
variable_names_immutable_ops
)
{
prog
.
MutableBlock
(
0
)
->
Var
(
v
);
}
SetOp
(
&
prog
,
"dropout"
,
"Dropout1"
,
{
"a"
},
{
"b"
},
true
,
"float32"
);
SetOp
(
&
prog
,
tested_op
,
tested_op
,
{
"b"
},
{
"c"
},
true
,
"int8"
);
SetOp
(
&
prog
,
"dropout"
,
"Dropout2"
,
{
"c"
},
{
"d"
},
true
,
"float32"
);
// 0 Quant + 0 IN + 0 DeQuant + 0 OUT
int
added_nodes
=
0
;
std
::
unordered_map
<
std
::
string
,
int
>
expected_operators
=
{
{
tested_op
,
1
},
{
"dropout"
,
2
},
{
"quantize"
,
0
},
{
"dequantize"
,
0
}};
MainTest
(
prog
,
variable_names_immutable_ops
,
expected_operators
,
added_nodes
,
SCALE
*
S8_MAX
);
}
void
MainTestFusionLSTM
(
const
ProgramDesc
&
prog
,
int
expect_lstm_count
,
int
quant_count
,
int
dequant_count
,
int
added_nodes_count
,
float
scale
,
float
shift
)
{
std
::
unique_ptr
<
ir
::
Graph
>
graph
(
new
ir
::
Graph
(
prog
));
int
original_nodes_num
,
current_nodes_num
;
PreparePass
(
&
graph
,
prog
,
variable_names_fusion_lstm
,
&
original_nodes_num
,
&
current_nodes_num
);
TEST
(
CpuQuantizePass
,
reshape2
)
{
TestImmutableOp
(
"reshape2"
);
}
int
quantize_nodes_count
=
0
;
int
dequantize_nodes_count
=
0
;
int
lstm_nodes_count
=
0
;
for
(
auto
*
node
:
graph
->
Nodes
())
{
if
(
node
->
IsOp
())
{
auto
*
op
=
node
->
Op
();
if
(
op
->
Type
()
==
"fusion_lstm"
)
{
lstm_nodes_count
++
;
TEST
(
CpuQuantizePass
,
reshape2BetweenNonQuantizedOp
)
{
TestImmutableOpBetweenNonQuantizedOp
(
"reshape2"
);
}
auto
op_name
=
BOOST_GET_CONST
(
std
::
string
,
op
->
GetAttr
(
"name"
));
EXPECT_EQ
(
BOOST_GET_CONST
(
float
,
op
->
GetAttr
(
"Scale_data"
)),
scale
)
<<
"Scale_data for node '"
+
op_name
+
"'."
;
EXPECT_EQ
(
BOOST_GET_CONST
(
float
,
op
->
GetAttr
(
"Shift_data"
)),
shift
)
<<
"Shift_data for node '"
+
op_name
+
"'."
;
EXPECT_EQ
(
BOOST_GET_CONST
(
std
::
vector
<
float
>
,
op
->
GetAttr
(
"Scale_weights"
))[
0
],
scale
)
<<
"Scale_weights for node '"
+
op_name
+
"'."
;
EXPECT_EQ
(
BOOST_GET_CONST
(
bool
,
op
->
GetAttr
(
"force_fp32_output"
)),
true
)
<<
"force_fp32_output for node '"
+
op_name
+
"'."
;
}
else
if
(
op
->
Type
()
==
"quantize"
)
{
quantize_nodes_count
++
;
}
else
if
(
op
->
Type
()
==
"dequantize"
)
{
dequantize_nodes_count
++
;
}
}
TEST
(
CpuQuantizePass
,
transpose2
)
{
TestImmutableOp
(
"transpose2"
);
}
TEST
(
CpuQuantizePass
,
transpose2BetweenNonQuantizedOp
)
{
TestImmutableOpBetweenNonQuantizedOp
(
"transpose2"
);
}
TEST
(
CpuQuantizePass
,
slice
)
{
TestImmutableOp
(
"slice"
);
}
TEST
(
CpuQuantizePass
,
sliceBetweenNonQuantizedOp
)
{
TestImmutableOpBetweenNonQuantizedOp
(
"slice"
);
}
static
const
std
::
initializer_list
<
std
::
string
>
variable_names_matmul
=
{
"a"
,
"b"
,
"c"
,
"d"
,
"e"
,
"f"
};
ProgramDesc
BuildProgramDescMatmul
()
{
ProgramDesc
prog
;
for
(
auto
&
v
:
variable_names_matmul
)
{
prog
.
MutableBlock
(
0
)
->
Var
(
v
);
}
EXPECT_EQ
(
lstm_nodes_count
,
expect_lstm_count
);
EXPECT_EQ
(
quantize_nodes_count
,
quant_count
);
EXPECT_EQ
(
dequantize_nodes_count
,
dequant_count
);
EXPECT_EQ
(
original_nodes_num
+
added_nodes_count
,
current_nodes_num
);
SetOp
(
&
prog
,
"dequantize"
,
"Dequantize1"
,
{
"a"
},
{
"b"
},
true
);
SetOp
(
&
prog
,
"dequantize"
,
"Dequantize2"
,
{
"c"
},
{
"d"
},
true
);
SetOp
(
&
prog
,
"matmul"
,
"Matmul"
,
{
"b"
,
"d"
},
{
"e"
},
true
,
"int8"
);
SetOp
(
&
prog
,
"dropout"
,
"Dropout"
,
{
"e"
},
{
"f"
},
true
,
"float32"
);
return
prog
;
}
TEST
(
CpuQuantizePass
,
fusion_lstm
)
{
// (x, wx, wh, b)->Fusion_lstm->h
int
expect_lstm_count
=
1
;
int
expect_quant_count
=
1
;
int
dequant_count
=
0
;
// 1 Quant + 1 IN + 0 DeQuant + 0 OUT
int
added_nodes_count
=
1
+
1
+
0
+
0
;
MainTestFusionLSTM
(
BuildProgramDescFusionLSTM
(),
expect_lstm_count
,
expect_quant_count
,
dequant_count
,
added_nodes_count
,
2.
*
127
,
128.
);
ProgramDesc
BuildProgramDescMatmulNotQuantized
()
{
ProgramDesc
prog
;
for
(
auto
&
v
:
variable_names_matmul
)
{
prog
.
MutableBlock
(
0
)
->
Var
(
v
);
}
SetOp
(
&
prog
,
"dropout"
,
"Dropout"
,
{
"a"
},
{
"b"
},
false
);
SetOp
(
&
prog
,
"dequantize"
,
"Dequantize"
,
{
"c"
},
{
"d"
},
true
);
SetOp
(
&
prog
,
"matmul"
,
"Matmul"
,
{
"b"
,
"d"
},
{
"e"
},
true
,
"int8"
);
SetOp
(
&
prog
,
"dropout"
,
"Dropout"
,
{
"e"
},
{
"f"
},
true
,
"float32"
);
return
prog
;
}
TEST
(
CpuQuantizePass
,
matmul
)
{
// 2 Quant + 2 IN + 1 DeQuant + 1 OUT
int
added_nodes
=
6
;
std
::
unordered_map
<
std
::
string
,
int
>
expected_operators
=
{
{
"matmul"
,
1
},
{
"quantize"
,
2
},
{
"dequantize"
,
3
}};
MainTest
(
BuildProgramDescMatmul
(),
variable_names_matmul
,
expected_operators
,
added_nodes
,
SCALE
*
S8_MAX
);
}
TEST
(
CpuQuantizePass
,
matmul_not_quantized
)
{
// nothing change
int
added_nodes
=
0
;
std
::
unordered_map
<
std
::
string
,
int
>
expected_operators
=
{
{
"matmul"
,
1
},
{
"quantize"
,
0
},
{
"dequantize"
,
1
}};
MainTest
(
BuildProgramDescMatmulNotQuantized
(),
variable_names_matmul
,
expected_operators
,
added_nodes
,
1.0
f
);
}
static
const
std
::
initializer_list
<
std
::
string
>
variable_names_elementwise_add
=
{
"a"
,
"b"
,
"c"
,
"d"
,
"e"
,
"f"
};
ProgramDesc
BuildProgramDescElementwiseAdd
()
{
ProgramDesc
prog
;
for
(
auto
&
v
:
variable_names_elementwise_add
)
{
prog
.
MutableBlock
(
0
)
->
Var
(
v
);
}
SetOp
(
&
prog
,
"dequantize"
,
"Dequantize1"
,
{
"a"
},
{
"b"
},
true
);
SetOp
(
&
prog
,
"dequantize"
,
"Dequantize2"
,
{
"c"
},
{
"d"
},
true
);
SetOp
(
&
prog
,
"elementwise_add"
,
"ElementwiseAdd"
,
{
"b"
,
"d"
},
{
"e"
},
true
,
"int8"
);
SetOp
(
&
prog
,
"dropout"
,
"Dropout"
,
{
"e"
},
{
"f"
},
true
,
"float32"
);
return
prog
;
}
TEST
(
CpuQuantizePass
,
elementwise_add
)
{
// 2 Quant + 2 IN + 1 DeQuant + 1 OUT
int
added_nodes
=
6
;
std
::
unordered_map
<
std
::
string
,
int
>
expected_operators
=
{
{
"elementwise_add"
,
1
},
{
"quantize"
,
2
},
{
"dequantize"
,
3
}};
MainTest
(
BuildProgramDescElementwiseAdd
(),
variable_names_elementwise_add
,
expected_operators
,
added_nodes
,
SCALE
*
S8_MAX
);
}
TEST
(
CpuQuantizePass
,
elementwise_add_output_scale_missing
)
{
int
added_nodes
=
0
;
std
::
unordered_map
<
std
::
string
,
int
>
expected_operators
=
{
{
"elementwise_add"
,
1
},
{
"quantize"
,
0
},
{
"dequantize"
,
2
}};
MainTest
(
BuildProgramDescElementwiseAdd
(),
variable_names_elementwise_add
,
expected_operators
,
added_nodes
,
1.
f
,
1.
f
,
"e"
);
}
TEST
(
CpuQuantizePass
,
elementwise_add_unsigned_and_signed_input
)
{
int
added_nodes
=
0
;
std
::
unordered_map
<
std
::
string
,
int
>
expected_operators
=
{
{
"elementwise_add"
,
1
},
{
"quantize"
,
0
},
{
"dequantize"
,
2
}};
MainTest
(
BuildProgramDescElementwiseAdd
(),
variable_names_elementwise_add
,
expected_operators
,
added_nodes
,
1.
f
,
1.
f
,
""
,
"b"
);
}
const
std
::
vector
<
std
::
string
>
churn_out_vars
(
ProgramDesc
*
prog
,
...
...
@@ -681,395 +645,6 @@ TEST(CpuQuantizePass, multi_gru_3) {
MainTestMultiGru
(
layers
);
}
static
const
std
::
initializer_list
<
std
::
string
>
variable_names_reshape
=
{
"a"
,
"w1"
,
"b"
,
"c"
,
"d"
,
"e"
,
"f"
};
// a->Dequantize->b
// b->Reshape->c
// c->Dropout->d
ProgramDesc
BuildProgramDescReshape
()
{
ProgramDesc
prog
;
for
(
auto
&
v
:
variable_names_reshape
)
{
prog
.
MutableBlock
(
0
)
->
Var
(
v
);
}
SetOp
(
&
prog
,
"dequantize"
,
"Dequantize1"
,
{
"a"
},
{
"b"
},
true
);
SetOp
(
&
prog
,
"reshape2"
,
"Reshape2"
,
{
"b"
},
{
"c"
},
true
,
"int8"
);
SetOp
(
&
prog
,
"dropout"
,
"Dropout"
,
{
"c"
},
{
"d"
},
true
,
"float32"
);
return
prog
;
}
// a->Transpose->b
// b->Reshape->c
// c->Dropout->d
ProgramDesc
BuildProgramDescReshapeBetweenNonQuantizedOp
()
{
ProgramDesc
prog
;
for
(
auto
&
v
:
variable_names_reshape
)
{
prog
.
MutableBlock
(
0
)
->
Var
(
v
);
}
SetOp
(
&
prog
,
"transpose2"
,
"Transpose2"
,
{
"a"
},
{
"b"
},
true
,
"float32"
);
SetOp
(
&
prog
,
"reshape2"
,
"Reshape2"
,
{
"b"
},
{
"c"
},
true
,
"int8"
);
SetOp
(
&
prog
,
"dropout"
,
"Dropout"
,
{
"c"
},
{
"d"
},
true
,
"float32"
);
return
prog
;
}
void
MainTestReshape
(
const
ProgramDesc
&
prog
,
int
transpose_count
,
int
reshape_count
,
int
quant_count
,
int
dequant_count
,
int
added_nodes_count
,
float
scale
)
{
std
::
unique_ptr
<
ir
::
Graph
>
graph
(
new
ir
::
Graph
(
prog
));
int
original_nodes_num
,
current_nodes_num
;
PreparePass
(
&
graph
,
prog
,
variable_names_reshape
,
&
original_nodes_num
,
&
current_nodes_num
);
float
quant_scale
=
1.0
f
;
float
dequant_scale
=
1.0
f
;
int
quantize_nodes_count
=
0
;
int
dequantize_nodes_count
=
0
;
int
transpose_nodes_count
=
0
;
int
reshape_nodes_count
=
0
;
for
(
auto
*
node
:
graph
->
Nodes
())
{
if
(
node
->
IsOp
())
{
auto
*
op
=
node
->
Op
();
if
(
op
->
Type
()
==
"transpose2"
)
{
transpose_nodes_count
++
;
}
else
if
(
op
->
Type
()
==
"reshape2"
)
{
reshape_nodes_count
++
;
}
else
if
(
op
->
Type
()
==
"quantize"
)
{
quantize_nodes_count
++
;
quant_scale
=
BOOST_GET_CONST
(
float
,
op
->
GetAttr
(
"Scale"
));
EXPECT_EQ
(
quant_scale
,
scale
)
<<
"Scale for node '"
+
op
->
Type
()
+
"'."
;
}
else
if
(
op
->
Type
()
==
"dequantize"
)
{
dequantize_nodes_count
++
;
auto
op_name
=
op
->
GetAttrIfExists
<
std
::
string
>
(
"name"
);
VLOG
(
3
)
<<
op_name
<<
"
\n
"
;
if
(
op_name
!=
"Dequantize1"
)
{
dequant_scale
=
BOOST_GET_CONST
(
float
,
op
->
GetAttr
(
"Scale"
));
EXPECT_EQ
(
dequant_scale
,
scale
)
<<
"Scale for node '"
+
op
->
Type
()
+
"'."
;
}
}
}
}
EXPECT_EQ
(
transpose_nodes_count
,
transpose_count
);
EXPECT_EQ
(
reshape_nodes_count
,
reshape_count
);
EXPECT_EQ
(
quantize_nodes_count
,
quant_count
);
EXPECT_EQ
(
dequantize_nodes_count
,
dequant_count
);
EXPECT_EQ
(
original_nodes_num
+
added_nodes_count
,
current_nodes_num
);
}
TEST
(
CpuQuantizePass
,
reshape
)
{
// a->Dequantize->b
// b2->Quant->b3->Reshape2->c1->Dequant->c2
// c2->Dropout->d
int
reshape_count
=
1
;
int
transpose_count
=
0
;
int
quant_count
=
1
;
int
dequant_count
=
2
;
// 1 Quant + 1 IN + 1 DeQuant + 1 OUT
int
added_nodes_count
=
4
;
MainTestReshape
(
BuildProgramDescReshape
(),
transpose_count
,
reshape_count
,
quant_count
,
dequant_count
,
added_nodes_count
,
2.0
f
*
127
);
}
TEST
(
CpuQuantizePass
,
reshapeBetweenNonQuantizedOp
)
{
// a->Transpos2->b
// b->Reshape2->c
// c->Dropout->d
int
reshape_count
=
1
;
int
transpose_count
=
1
;
int
quant_count
=
0
;
int
dequant_count
=
0
;
// 0 Quant + 0 IN + 0 DeQuant + 0 OUT
int
added_nodes_count
=
0
;
MainTestReshape
(
BuildProgramDescReshapeBetweenNonQuantizedOp
(),
transpose_count
,
reshape_count
,
quant_count
,
dequant_count
,
added_nodes_count
,
2.0
f
*
127
);
}
static
const
std
::
initializer_list
<
std
::
string
>
variable_names_slice
=
{
"a"
,
"b"
,
"c"
,
"d"
};
// a->Dequantize->b
// b->Slice->c
// c->Dropout->d
ProgramDesc
BuildProgramDescSlice
()
{
ProgramDesc
prog
;
for
(
auto
&
v
:
variable_names_slice
)
{
prog
.
MutableBlock
(
0
)
->
Var
(
v
);
}
SetOp
(
&
prog
,
"dequantize"
,
"Dequantize1"
,
{
"a"
},
{
"b"
},
true
);
SetOp
(
&
prog
,
"slice"
,
"Slice"
,
{
"b"
},
{
"c"
},
true
,
"int8"
);
SetOp
(
&
prog
,
"dropout"
,
"Dropout"
,
{
"c"
},
{
"d"
},
true
,
"float32"
);
return
prog
;
}
// a->Transpose->b
// b->slice->c
// c->Dropout->d
ProgramDesc
BuildProgramDescSliceBetweenNonQuantizedOp
()
{
ProgramDesc
prog
;
for
(
auto
&
v
:
variable_names_slice
)
{
prog
.
MutableBlock
(
0
)
->
Var
(
v
);
}
SetOp
(
&
prog
,
"transpose2"
,
"Transpose2"
,
{
"a"
},
{
"b"
},
true
,
"float32"
);
SetOp
(
&
prog
,
"slice"
,
"Slice"
,
{
"b"
},
{
"c"
},
true
,
"int8"
);
SetOp
(
&
prog
,
"dropout"
,
"Dropout"
,
{
"c"
},
{
"d"
},
true
,
"float32"
);
return
prog
;
}
void
MainTestSlice
(
const
ProgramDesc
&
prog
,
int
transpose_count
,
int
slice_count
,
int
quant_count
,
int
dequant_count
,
int
added_nodes_count
,
float
scale
)
{
std
::
unique_ptr
<
ir
::
Graph
>
graph
(
new
ir
::
Graph
(
prog
));
int
original_nodes_num
,
current_nodes_num
;
PreparePass
(
&
graph
,
prog
,
variable_names_slice
,
&
original_nodes_num
,
&
current_nodes_num
);
float
quant_scale
=
1.0
f
;
float
dequant_scale
=
1.0
f
;
int
quantize_nodes_count
=
0
;
int
dequantize_nodes_count
=
0
;
int
transpose_nodes_count
=
0
;
int
slice_nodes_count
=
0
;
for
(
auto
*
node
:
graph
->
Nodes
())
{
if
(
node
->
IsOp
())
{
auto
*
op
=
node
->
Op
();
if
(
op
->
Type
()
==
"transpose2"
)
{
transpose_nodes_count
++
;
}
else
if
(
op
->
Type
()
==
"slice"
)
{
slice_nodes_count
++
;
}
else
if
(
op
->
Type
()
==
"quantize"
)
{
quantize_nodes_count
++
;
quant_scale
=
BOOST_GET_CONST
(
float
,
op
->
GetAttr
(
"Scale"
));
EXPECT_EQ
(
quant_scale
,
scale
)
<<
"Scale for node '"
+
op
->
Type
()
+
"'."
;
}
else
if
(
op
->
Type
()
==
"dequantize"
)
{
dequantize_nodes_count
++
;
auto
op_name
=
op
->
GetAttrIfExists
<
std
::
string
>
(
"name"
);
VLOG
(
3
)
<<
op_name
<<
"
\n
"
;
if
(
op_name
!=
"Dequantize1"
)
{
dequant_scale
=
BOOST_GET_CONST
(
float
,
op
->
GetAttr
(
"Scale"
));
EXPECT_EQ
(
dequant_scale
,
scale
)
<<
"Scale for node '"
+
op
->
Type
()
+
"'."
;
}
}
}
}
EXPECT_EQ
(
transpose_nodes_count
,
transpose_count
);
EXPECT_EQ
(
slice_nodes_count
,
slice_count
);
EXPECT_EQ
(
quantize_nodes_count
,
quant_count
);
EXPECT_EQ
(
dequantize_nodes_count
,
dequant_count
);
EXPECT_EQ
(
original_nodes_num
+
added_nodes_count
,
current_nodes_num
);
}
TEST
(
CpuQuantizePass
,
slice
)
{
// a->Dequantize->b
// b2->Quant->b3->slice->c1->Dequant->c2
// c2->Dropout->d
int
slice_count
=
1
;
int
transpose_count
=
0
;
int
quant_count
=
1
;
int
dequant_count
=
2
;
// 1 Quant + 1 IN + 1 DeQuant + 1 OUT
int
added_nodes_count
=
4
;
MainTestSlice
(
BuildProgramDescSlice
(),
transpose_count
,
slice_count
,
quant_count
,
dequant_count
,
added_nodes_count
,
2.0
f
*
127
);
}
TEST
(
CpuQuantizePass
,
sliceBetweenNonQuantizedOp
)
{
// a->Transpos2->b
// b->slice->c
// c->Dropout->d
int
slice_count
=
1
;
int
transpose_count
=
1
;
int
quant_count
=
0
;
int
dequant_count
=
0
;
// 0 Quant + 0 IN + 0 DeQuant + 0 OUT
int
added_nodes_count
=
0
;
MainTestSlice
(
BuildProgramDescSliceBetweenNonQuantizedOp
(),
transpose_count
,
slice_count
,
quant_count
,
dequant_count
,
added_nodes_count
,
2.0
f
*
127
);
}
static
const
std
::
initializer_list
<
std
::
string
>
variable_names_matmul
=
{
"a"
,
"b"
,
"c"
,
"d"
,
"e"
,
"f"
};
ProgramDesc
BuildProgramDescMatmul
()
{
ProgramDesc
prog
;
for
(
auto
&
v
:
variable_names_matmul
)
{
prog
.
MutableBlock
(
0
)
->
Var
(
v
);
}
SetOp
(
&
prog
,
"dequantize"
,
"Dequantize1"
,
{
"a"
},
{
"b"
},
true
);
SetOp
(
&
prog
,
"dequantize"
,
"Dequantize2"
,
{
"c"
},
{
"d"
},
true
);
SetOp
(
&
prog
,
"matmul"
,
"Matmul"
,
{
"b"
,
"d"
},
{
"e"
},
true
,
"int8"
);
SetOp
(
&
prog
,
"dropout"
,
"Dropout"
,
{
"e"
},
{
"f"
},
true
,
"float32"
);
return
prog
;
}
ProgramDesc
BuildProgramDescMatmulNotQuantized
()
{
ProgramDesc
prog
;
for
(
auto
&
v
:
variable_names_matmul
)
{
prog
.
MutableBlock
(
0
)
->
Var
(
v
);
}
SetOp
(
&
prog
,
"dropout"
,
"Dropout"
,
{
"a"
},
{
"b"
},
false
);
SetOp
(
&
prog
,
"dequantize"
,
"Dequantize"
,
{
"c"
},
{
"d"
},
true
);
SetOp
(
&
prog
,
"matmul"
,
"Matmul"
,
{
"b"
,
"d"
},
{
"e"
},
true
,
"int8"
);
SetOp
(
&
prog
,
"dropout"
,
"Dropout"
,
{
"e"
},
{
"f"
},
true
,
"float32"
);
return
prog
;
}
void
MainTestMatmul
(
const
ProgramDesc
&
prog
,
int
matmul_count
,
int
quant_count
,
int
dequant_count
,
int
added_nodes_count
,
float
scale
)
{
std
::
unique_ptr
<
ir
::
Graph
>
graph
(
new
ir
::
Graph
(
prog
));
int
original_nodes_num
,
current_nodes_num
;
PreparePass
(
&
graph
,
prog
,
variable_names_matmul
,
&
original_nodes_num
,
&
current_nodes_num
);
int
quantize_nodes_count
=
0
;
int
dequantize_nodes_count
=
0
;
int
matmul_nodes_count
=
0
;
for
(
auto
*
node
:
graph
->
Nodes
())
{
if
(
node
->
IsOp
())
{
auto
*
op
=
node
->
Op
();
if
(
op
->
Type
()
==
"matmul"
)
{
matmul_nodes_count
++
;
auto
op_name
=
BOOST_GET_CONST
(
std
::
string
,
op
->
GetAttr
(
"name"
));
EXPECT_EQ
(
BOOST_GET_CONST
(
float
,
op
->
GetAttr
(
"Scale_x"
)),
scale
)
<<
"Scale_x for node '"
+
op_name
+
"'."
;
EXPECT_EQ
(
BOOST_GET_CONST
(
float
,
op
->
GetAttr
(
"Scale_y"
)),
scale
)
<<
"Scale_y for node '"
+
op_name
+
"'."
;
EXPECT_EQ
(
BOOST_GET_CONST
(
float
,
op
->
GetAttr
(
"Scale_out"
)),
scale
)
<<
"Scale_out for node '"
+
op_name
+
"'."
;
}
else
if
(
op
->
Type
()
==
"quantize"
)
{
quantize_nodes_count
++
;
}
else
if
(
op
->
Type
()
==
"dequantize"
)
{
dequantize_nodes_count
++
;
}
}
}
EXPECT_EQ
(
matmul_nodes_count
,
matmul_count
);
EXPECT_EQ
(
quantize_nodes_count
,
quant_count
);
EXPECT_EQ
(
dequantize_nodes_count
,
dequant_count
);
EXPECT_EQ
(
original_nodes_num
+
added_nodes_count
,
current_nodes_num
);
}
TEST
(
CpuQuantizePass
,
matmul
)
{
int
matmul_count
=
1
;
int
quant_count
=
2
;
int
dequant_count
=
3
;
// 2 Quant + 2 IN + 1 DeQuant + 1 OUT
int
added_nodes_count
=
6
;
MainTestMatmul
(
BuildProgramDescMatmul
(),
matmul_count
,
quant_count
,
dequant_count
,
added_nodes_count
,
2.0
f
*
127
);
}
TEST
(
CpuQuantizePass
,
matmul_not_quantized
)
{
int
matmul_count
=
1
;
int
quant_count
=
0
;
int
dequant_count
=
1
;
// nothing change
int
added_nodes_count
=
0
;
MainTestMatmul
(
BuildProgramDescMatmulNotQuantized
(),
matmul_count
,
quant_count
,
dequant_count
,
added_nodes_count
,
1.0
f
);
}
static
const
std
::
initializer_list
<
std
::
string
>
variable_names_elementwise_add
=
{
"a"
,
"b"
,
"c"
,
"d"
,
"e"
,
"f"
};
ProgramDesc
BuildProgramDescElementwiseAdd
()
{
ProgramDesc
prog
;
for
(
auto
&
v
:
variable_names_elementwise_add
)
{
prog
.
MutableBlock
(
0
)
->
Var
(
v
);
}
SetOp
(
&
prog
,
"dequantize"
,
"Dequantize1"
,
{
"a"
},
{
"b"
},
true
);
SetOp
(
&
prog
,
"dequantize"
,
"Dequantize2"
,
{
"c"
},
{
"d"
},
true
);
SetOp
(
&
prog
,
"elementwise_add"
,
"ElementwiseAdd"
,
{
"b"
,
"d"
},
{
"e"
},
true
,
"int8"
);
SetOp
(
&
prog
,
"dropout"
,
"Dropout"
,
{
"e"
},
{
"f"
},
true
,
"float32"
);
return
prog
;
}
void
MainTestElementwiseAdd
(
const
ProgramDesc
&
prog
,
int
elementwise_add_count
,
int
quant_count
,
int
dequant_count
,
int
added_nodes_count
,
float
scale
,
bool
output_scale_missing
=
false
,
bool
unsigned_and_signed_input
=
false
)
{
std
::
unique_ptr
<
ir
::
Graph
>
graph
(
new
ir
::
Graph
(
prog
));
int
original_nodes_num
,
current_nodes_num
;
PreparePass
(
&
graph
,
prog
,
variable_names_elementwise_add
,
&
original_nodes_num
,
&
current_nodes_num
,
output_scale_missing
?
"e"
:
""
,
unsigned_and_signed_input
?
"b"
:
""
);
int
quantize_nodes_count
=
0
;
int
dequantize_nodes_count
=
0
;
int
elementwise_add_nodes_count
=
0
;
for
(
auto
*
node
:
graph
->
Nodes
())
{
if
(
node
->
IsOp
())
{
auto
*
op
=
node
->
Op
();
if
(
op
->
Type
()
==
"elementwise_add"
)
{
elementwise_add_nodes_count
++
;
if
(
unsigned_and_signed_input
)
scale
=
1.0
f
;
auto
op_name
=
BOOST_GET_CONST
(
std
::
string
,
op
->
GetAttr
(
"name"
));
EXPECT_EQ
(
BOOST_GET_CONST
(
float
,
op
->
GetAttr
(
"Scale_x"
)),
scale
)
<<
"Scale_x for node '"
+
op_name
+
"'."
;
EXPECT_EQ
(
BOOST_GET_CONST
(
float
,
op
->
GetAttr
(
"Scale_y"
)),
scale
)
<<
"Scale_y for node '"
+
op_name
+
"'."
;
if
(
output_scale_missing
)
scale
=
1.0
;
EXPECT_EQ
(
BOOST_GET_CONST
(
float
,
op
->
GetAttr
(
"Scale_out"
)),
scale
)
<<
"Scale_out for node '"
+
op_name
+
"'."
;
}
else
if
(
op
->
Type
()
==
"quantize"
)
{
quantize_nodes_count
++
;
}
else
if
(
op
->
Type
()
==
"dequantize"
)
{
dequantize_nodes_count
++
;
}
}
}
EXPECT_EQ
(
elementwise_add_nodes_count
,
elementwise_add_count
);
EXPECT_EQ
(
quantize_nodes_count
,
quant_count
);
EXPECT_EQ
(
dequantize_nodes_count
,
dequant_count
);
EXPECT_EQ
(
original_nodes_num
+
added_nodes_count
,
current_nodes_num
);
}
TEST
(
CpuQuantizePass
,
elementwise_add
)
{
int
elementwise_add_count
=
1
;
int
quant_count
=
2
;
int
dequant_count
=
3
;
// 2 Quant + 2 IN + 1 DeQuant + 1 OUT
int
added_nodes_count
=
6
;
MainTestElementwiseAdd
(
BuildProgramDescElementwiseAdd
(),
elementwise_add_count
,
quant_count
,
dequant_count
,
added_nodes_count
,
2.0
f
*
127
);
}
TEST
(
CpuQuantizePass
,
elementwise_add_output_scale_missing
)
{
int
elementwise_add_count
=
1
;
int
quant_count
=
0
;
int
dequant_count
=
2
;
int
added_nodes_count
=
0
;
MainTestElementwiseAdd
(
BuildProgramDescElementwiseAdd
(),
elementwise_add_count
,
quant_count
,
dequant_count
,
added_nodes_count
,
1.
f
,
true
);
}
TEST
(
CpuQuantizePass
,
elementwise_add_unsigned_and_signed_input
)
{
int
elementwise_add_count
=
1
;
int
quant_count
=
0
;
int
dequant_count
=
2
;
int
added_nodes_count
=
0
;
MainTestElementwiseAdd
(
BuildProgramDescElementwiseAdd
(),
elementwise_add_count
,
quant_count
,
dequant_count
,
added_nodes_count
,
2.0
f
*
127
,
false
,
true
);
}
}
// namespace
}
// namespace ir
}
// namespace framework
}
// namespace paddle
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录