Skip to content

Commit c486c21

Browse files
author
wozna
committed
Add more precise tests
test=develop
1 parent f469749 commit c486c21

2 files changed

Lines changed: 155 additions & 64 deletions

File tree

paddle/fluid/framework/ir/mkldnn/cpu_quantize_squash_pass.cc

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ void CPUQuantizeSquashPass::FindNodesToKeep(
4949
AddStatis(found_count);
5050
}
5151

52-
void CPUQuantizeSquashPass::Squash(
52+
void CPUQuantizeSquashPass::DequantQuantSquash(
5353
Graph* graph,
5454
std::unordered_map<const Node*, int>* nodes_keep_counter) const {
5555
GraphPatternDetector gpd;
@@ -141,15 +141,18 @@ void CPUQuantizeSquashPass::ConvRequantSquash(Graph* graph) const {
141141
GET_IR_NODE_FROM_SUBGRAPH(requant_op, requant_op, conv_requant_pattern);
142142
GET_IR_NODE_FROM_SUBGRAPH(requant_out, requant_out, conv_requant_pattern);
143143

144-
float requant_scale_out =
145-
boost::get<float>(requant_op->Op()->GetAttr("Scale_out"));
146-
conv_op->Op()->SetAttr("Scale_out", requant_scale_out);
147-
conv_op->Op()->SetOutput("Output",
148-
std::vector<std::string>({requant_out->Name()}));
149-
IR_NODE_LINK_TO(conv_op, requant_out);
150-
GraphSafeRemoveNodes(graph, {conv_out, requant_op});
151-
152-
found_requant_squash_count++;
144+
// if conv2d has one output squash
145+
if (conv_out->outputs.size() == 1) {
146+
float requant_scale_out =
147+
boost::get<float>(requant_op->Op()->GetAttr("Scale_out"));
148+
conv_op->Op()->SetAttr("Scale_out", requant_scale_out);
149+
conv_op->Op()->SetOutput("Output",
150+
std::vector<std::string>({requant_out->Name()}));
151+
IR_NODE_LINK_TO(conv_op, requant_out);
152+
GraphSafeRemoveNodes(graph, {conv_out, requant_op});
153+
154+
found_requant_squash_count++;
155+
}
153156
};
154157
gpd(graph, handler);
155158
AddStatis(found_requant_squash_count);
@@ -163,7 +166,8 @@ void CPUQuantizeSquashPass::ApplyImpl(ir::Graph* graph) const {
163166

164167
std::unordered_map<const Node*, int> nodes_keep_counter;
165168
FindNodesToKeep(graph, &nodes_keep_counter);
166-
Squash(graph, &nodes_keep_counter);
169+
DequantQuantSquash(graph, &nodes_keep_counter);
170+
ConvRequantSquash(graph);
167171
}
168172

169173
} // namespace ir

paddle/fluid/framework/ir/mkldnn/cpu_quantize_squash_pass_tester.cc

Lines changed: 140 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ void SetOp(ProgramDesc* prog, const std::string& type, const std::string& name,
3030
op->SetAttr("use_mkldnn", use_mkldnn);
3131
op->SetAttr("name", name);
3232
if (type == "conv2d") {
33+
op->SetAttr("Scale_out", scale);
3334
op->SetInput("Input", {inputs[0]});
3435
if (inputs.size() > 1) op->SetInput("Filter", {inputs[1]});
3536
if (inputs.size() > 2) op->SetInput("Bias", {inputs[2]});
@@ -53,10 +54,11 @@ void SetOp(ProgramDesc* prog, const std::string& type, const std::string& name,
5354
}
5455

5556
// (a,w1,b1)->Conv1->d
56-
// d->Dequant->e
57-
// e->Quant->f
57+
// d->Dequant(scale1)->e
58+
// e->Quant(scale2)->f
5859
// (f,w2,b2)->Conv2->i
59-
ProgramDesc BuildProgramDesc(bool use_mkldnn, float scale1, float scale2) {
60+
ProgramDesc BuildProgramDesc(bool use_mkldnn, float scale_out, float scale1,
61+
float scale2) {
6062
ProgramDesc prog;
6163
for (auto& v : std::initializer_list<std::string>(
6264
{"a", "w1", "b1", "d", "e", "f", "w2", "b2", "i"})) {
@@ -66,58 +68,58 @@ ProgramDesc BuildProgramDesc(bool use_mkldnn, float scale1, float scale2) {
6668
}
6769
}
6870

69-
SetOp(&prog, "conv2d", "Conv1", {"a", "w1", "b1"}, {"d"}, use_mkldnn);
71+
SetOp(&prog, "conv2d", "Conv1", {"a", "w1", "b1"}, {"d"}, use_mkldnn,
72+
scale_out);
7073
SetOp(&prog, "dequantize", "Dequant", {"d"}, {"e"}, use_mkldnn, scale1);
7174
SetOp(&prog, "quantize", "Quant", {"e"}, {"f"}, use_mkldnn, scale2);
72-
SetOp(&prog, "conv2d", "Conv2", {"f", "w2", "b2"}, {"i"}, use_mkldnn);
75+
SetOp(&prog, "conv2d", "Conv2", {"f", "w2", "b2"}, {"i"}, use_mkldnn,
76+
scale_out);
7377
return prog;
7478
}
7579

7680
static const std::initializer_list<std::string> variable_names{
7781
"a", "b", "c", "d", "e", "f", "g", "h"};
82+
7883
// a->Conv1->b
79-
// b->Dequant->c
80-
//
81-
// c->Quant1->d and d->Conv2->e
82-
//
84+
// b->Dequant(scale1)->c
85+
// c->Quant1(scale2)->d and d->Conv2->e
8386
// c->Conv3->f
84-
//
85-
// c->Quant2->g and g->Conv4->h
86-
//
87-
ProgramDesc BuildProgramDesc2(bool use_mkldnn, float scale1, float scale2,
88-
float scale3) {
87+
// c->Quant2(scale3)->g and g->Conv4->h
88+
ProgramDesc BuildProgramDesc2(bool use_mkldnn, float scale_out, float scale1,
89+
float scale2, float scale3) {
8990
ProgramDesc prog;
9091
for (auto& v : variable_names) {
9192
prog.MutableBlock(0)->Var(v);
9293
}
9394

94-
SetOp(&prog, "conv2d", "Conv1", {"a"}, {"b"}, use_mkldnn);
95+
SetOp(&prog, "conv2d", "Conv1", {"a"}, {"b"}, use_mkldnn, scale_out);
9596
SetOp(&prog, "dequantize", "Dequant", {"b"}, {"c"}, use_mkldnn, scale1);
9697

9798
SetOp(&prog, "quantize", "Quant1", {"c"}, {"d"}, use_mkldnn, scale2);
98-
SetOp(&prog, "conv2d", "Conv2", {"d"}, {"e"}, use_mkldnn);
99+
SetOp(&prog, "conv2d", "Conv2", {"d"}, {"e"}, use_mkldnn, scale_out);
99100

100-
SetOp(&prog, "conv2d", "Conv3", {"c"}, {"f"}, use_mkldnn);
101+
SetOp(&prog, "conv2d", "Conv3", {"c"}, {"f"}, use_mkldnn, scale_out);
101102

102103
SetOp(&prog, "quantize", "Quant2", {"c"}, {"g"}, use_mkldnn, scale3);
103-
SetOp(&prog, "conv2d", "Conv4", {"g"}, {"h"}, use_mkldnn);
104+
SetOp(&prog, "conv2d", "Conv4", {"g"}, {"h"}, use_mkldnn, scale_out);
104105

105106
return prog;
106107
}
107108

108-
// a->Conv1->b->Requant->c
109-
// d->Conv2->e->Requant->f
109+
// a->Conv1->b->Requant(scale1)->c
110+
// d->Conv2->e->Requant(scale2)->f
110111
// {c,f}->Concat
111-
ProgramDesc BuildProgramDesc3(bool use_mkldnn, float scale1, float scale2) {
112+
ProgramDesc BuildProgramDesc3(bool use_mkldnn, float scale_out, float scale1,
113+
float scale2) {
112114
ProgramDesc prog;
113115
for (auto& v : variable_names) {
114116
prog.MutableBlock(0)->Var(v);
115117
}
116118

117-
SetOp(&prog, "conv2d", "Conv1", {"a"}, {"b"}, use_mkldnn);
119+
SetOp(&prog, "conv2d", "Conv1", {"a"}, {"b"}, use_mkldnn, scale_out);
118120
SetOp(&prog, "requantize", "Requant1", {"b"}, {"c"}, use_mkldnn, scale1);
119121

120-
SetOp(&prog, "conv2d", "Conv2", {"d"}, {"e"}, use_mkldnn);
122+
SetOp(&prog, "conv2d", "Conv2", {"d"}, {"e"}, use_mkldnn, scale_out);
121123
SetOp(&prog, "requantize", "Requant2", {"e"}, {"f"}, use_mkldnn, scale2);
122124

123125
SetOp(&prog, "concat", "Concat", {"c"}, {"f"}, use_mkldnn);
@@ -126,10 +128,11 @@ ProgramDesc BuildProgramDesc3(bool use_mkldnn, float scale1, float scale2) {
126128
}
127129

128130
// a->Concat->b
129-
// b->Dequant->c
130-
// c->Quant->d
131+
// b->Dequant(scale1)->c
132+
// c->Quant(scale2)->d
131133
// d->Conv->e
132-
ProgramDesc BuildProgramDesc4(bool use_mkldnn, float scale1, float scale2) {
134+
ProgramDesc BuildProgramDesc4(bool use_mkldnn, float scale_out, float scale1,
135+
float scale2) {
133136
ProgramDesc prog;
134137
for (auto& v : variable_names) {
135138
prog.MutableBlock(0)->Var(v);
@@ -138,7 +141,22 @@ ProgramDesc BuildProgramDesc4(bool use_mkldnn, float scale1, float scale2) {
138141
SetOp(&prog, "concat", "Concat", {"a"}, {"b"}, use_mkldnn);
139142
SetOp(&prog, "dequantize", "Dequant", {"b"}, {"c"}, use_mkldnn, scale1);
140143
SetOp(&prog, "quantize", "Quant", {"c"}, {"d"}, use_mkldnn, scale2);
141-
SetOp(&prog, "conv2d", "Conv2", {"d"}, {"e"}, use_mkldnn);
144+
SetOp(&prog, "conv2d", "Conv2", {"d"}, {"e"}, use_mkldnn, scale_out);
145+
return prog;
146+
}
147+
148+
// a->Conv1->b
149+
// b->Requant1(Scale1)->c
150+
// b->Requant2(Scale2)->d
151+
ProgramDesc BuildProgramDesc5(bool use_mkldnn, float scale_out, float scale1,
152+
float scale2) {
153+
ProgramDesc prog;
154+
for (auto& v : variable_names) {
155+
prog.MutableBlock(0)->Var(v);
156+
}
157+
SetOp(&prog, "conv2d", "Conv1", {"a"}, {"b"}, use_mkldnn, scale_out);
158+
SetOp(&prog, "requantize", "Requant1", {"b"}, {"c"}, use_mkldnn, scale1);
159+
SetOp(&prog, "requantize", "Requant2", {"b"}, {"d"}, use_mkldnn, scale2);
142160
return prog;
143161
}
144162

@@ -165,16 +183,17 @@ void CountNodeTest(const ProgramDesc& prog, int removed_nodes_num) {
165183

166184
graph->SetNotOwned(kParamScopeAttr, &scope);
167185
auto pass = PassRegistry::Instance().Get("cpu_quantize_squash_pass");
168-
graph.reset(pass->Apply(graph.release()));
169186

170187
int original_nodes_num = graph->Nodes().size();
188+
graph.reset(pass->Apply(graph.release()));
171189
int current_nodes_num = graph->Nodes().size();
172190

173191
EXPECT_EQ(original_nodes_num - removed_nodes_num, current_nodes_num);
174192
}
175193

176-
// check if scale_out is equal
177-
void EqualScaleTest(const ProgramDesc& prog, float scale) {
194+
// check op->scale_out
195+
void EqualScaleOutTest(const ProgramDesc& prog, const std::string& name,
196+
float scale) {
178197
std::unique_ptr<ir::Graph> graph(new ir::Graph(prog));
179198

180199
// Init scope, as it is used in pass
@@ -192,78 +211,146 @@ void EqualScaleTest(const ProgramDesc& prog, float scale) {
192211
graph.reset(pass->Apply(graph.release()));
193212

194213
for (auto* node : graph->Nodes()) {
195-
if (node->IsOp() && node->Op()->Type() == "conv2d") {
196-
auto* op = node->Op();
214+
if (node->IsOp() &&
215+
boost::get<std::string>(node->Op()->GetAttr("name")) == name) {
197216
float scale_out = boost::get<float>(node->Op()->GetAttr("Scale_out"));
198217
EXPECT_EQ(scale_out, scale);
199218
}
200219
}
201220
}
202221

222+
// check requant_op scales
223+
void CheckRequantScalesTest(const ProgramDesc& prog, float scale_in,
224+
float scale_out) {
225+
std::unique_ptr<ir::Graph> graph(new ir::Graph(prog));
226+
227+
// Init scope, as it is used in pass
228+
auto place = paddle::platform::CPUPlace();
229+
NaiveExecutor exe{place};
230+
Scope scope;
231+
exe.CreateVariables(prog, 0, true, &scope);
232+
233+
for (auto& v : variable_names) {
234+
InitTensorHolder(&scope, place, v.c_str());
235+
}
236+
237+
graph->SetNotOwned(kParamScopeAttr, &scope);
238+
auto pass = PassRegistry::Instance().Get("cpu_quantize_squash_pass");
239+
graph.reset(pass->Apply(graph.release()));
240+
241+
for (auto* node : graph->Nodes()) {
242+
if (node->IsOp() && node->Op()->Type() == "requantize") {
243+
float op_scale_in = boost::get<float>(node->Op()->GetAttr("Scale_in"));
244+
EXPECT_EQ(op_scale_in, scale_in);
245+
float op_scale_out = boost::get<float>(node->Op()->GetAttr("Scale_out"));
246+
EXPECT_EQ(op_scale_out, scale_out);
247+
}
248+
}
249+
}
250+
203251
// From Conv1->d->Dequant->e->Quant->f->Conv2
204252
// To Conv1->d->Conv2
205253
TEST(CpuQuantizeSquashPass, equal_scales) {
254+
auto scale_out = 1.0f;
206255
auto scale = 1.2345f;
207256
auto use_mkldnn = true;
208257
// Remove 4 nodes: Dequant, Quant, e, f
209258
auto remove_nodes = 4;
210-
CountNodeTest(BuildProgramDesc(use_mkldnn, scale, scale), remove_nodes);
259+
CountNodeTest(BuildProgramDesc(use_mkldnn, scale_out, scale, scale),
260+
remove_nodes);
211261
}
212262

213263
// From Conv1->d->Dequant->e->Quant->f->Conv2
214264
// First change to Conv1->d->Requant->f->Conv2
215265
// Then Conv1->f->Conv2
216-
TEST(CpuQuantizeSquashPass, inequal_scales) {
266+
TEST(CpuQuantizeSquashPass, unequal_scales) {
267+
auto scale_out = 1.0f;
217268
auto scale1 = 1.2345f;
218269
auto scale2 = 21.0f;
219270
auto use_mkldnn = true;
220-
// Remove 3 nodes: Dequant, Quant, e
221-
// Insert 1 node: requantize
222-
auto remove_nodes = 2;
223-
CountNodeTest(BuildProgramDesc(use_mkldnn, scale1, scale2), remove_nodes);
271+
// Remove 4 nodes: Dequant, Quant, e, d
272+
auto remove_nodes = 4;
273+
CountNodeTest(BuildProgramDesc(use_mkldnn, scale_out, scale1, scale2),
274+
remove_nodes);
275+
276+
EqualScaleOutTest(BuildProgramDesc(use_mkldnn, scale_out, scale1, scale2),
277+
"Conv1", scale2);
224278
}
225279

226-
TEST(CpuQuantizeSquashPass, branch_to_equal_inequal_and_fp32) {
227-
// Delete both quantize ops,
228-
// bypass dequantize in both branches,
229-
// insert requantize on one branch
280+
// from
281+
// a->Conv1->b->Dequant(Scale1)->c
282+
// c->Quant1(Scale1)->d and d->Conv2->e
283+
// c->Quant2(Scale2)->g and g->Conv4->h
284+
// c->Conv3->f
285+
// to
286+
// a->Conv1->b
287+
// b->Conv2->e
288+
// b->Requant(Scale_in = Scale1; Scale_out = Scale2)->g->Conv4->h
289+
// b->Dequant(Scale1)->c->Conv3->f
290+
TEST(CpuQuantizeSquashPass, branch_to_equal_unequal_and_fp32) {
291+
auto scale_out = 1.0f;
230292
auto scale = 1.2345f;
231293
auto scale2 = 21.0f;
232294
auto use_mkldnn = true;
233-
// Remove 4 nodes: Dequant, Quant1, Quant2, g
234-
auto remove_nodes = 4;
235-
CountNodeTest(BuildProgramDesc2(use_mkldnn, scale, scale, scale2),
295+
// Remove 3 nodes: Quant1, c, Quant2,
296+
// Insert 1 node: Requant
297+
auto remove_nodes = 2;
298+
CountNodeTest(BuildProgramDesc2(use_mkldnn, scale_out, scale, scale, scale2),
236299
remove_nodes);
300+
CheckRequantScalesTest(
301+
BuildProgramDesc2(use_mkldnn, scale_out, scale, scale, scale2), scale,
302+
scale2);
237303
}
238304

239305
// a->Conv1->b->Requant->c
240306
// d->Conv2->e->Requant->f
241307
// {c,f}->Concat
242308
TEST(CpuQuantizeSquashPass, equal_scales_squash_requantize) {
243309
// Delete both requantize op
310+
auto scale_out = 1.0f;
244311
auto scale = 1.2345f;
245312
auto use_mkldnn = true;
246313
// Remove 4 nodes: b, Requant1, e, Requant2
247314
auto remove_nodes = 4;
248-
CountNodeTest(BuildProgramDesc3(use_mkldnn, scale, scale), remove_nodes);
315+
CountNodeTest(BuildProgramDesc3(use_mkldnn, scale_out, scale, scale),
316+
remove_nodes);
249317

250318
// check equal scale conv->scale_out and requant->scale_out
251-
EqualScaleTest(BuildProgramDesc3(use_mkldnn, scale, scale), scale);
319+
EqualScaleOutTest(BuildProgramDesc3(use_mkldnn, scale_out, scale, scale),
320+
"Conv1", scale);
321+
EqualScaleOutTest(BuildProgramDesc3(use_mkldnn, scale_out, scale, scale),
322+
"Conv2", scale);
252323
}
253324

254-
// a->Concat->b
255-
// b->Dequant->c
256-
// c->Quant->d
257-
// d->Conv->e
325+
// a->Concat->b->Dequant->c->Quant->d->Conv->e
326+
// to a->Concat->b->Requant->d->Conv->e
258327
TEST(CpuQuantizeSquashPass,
259-
inequal_scales_squash_dequantize_quantize_into_requantize) {
328+
unequal_scales_squash_dequantize_quantize_into_requantize) {
329+
auto scale_out = 1.0f;
260330
auto scale = 1.2345f;
261331
auto scale2 = 21.0f;
262332
auto use_mkldnn = true;
263333
// Remove 3 nodes: Dequant1, c, Quant
264334
// Insert 1 node: Requant
265335
auto remove_nodes = 2;
266-
CountNodeTest(BuildProgramDesc4(use_mkldnn, scale, scale2), remove_nodes);
336+
CountNodeTest(BuildProgramDesc4(use_mkldnn, scale_out, scale, scale2),
337+
remove_nodes);
338+
CheckRequantScalesTest(
339+
BuildProgramDesc4(use_mkldnn, scale_out, scale, scale2), scale, scale2);
340+
}
341+
342+
// a->Conv1->b
343+
// b->Requant1(Scale1)->c
344+
// b->Requant2(Scale2)->d
345+
TEST(CpuQuantizeSquashPass, more_than_one_conv_out_outputs) {
346+
auto scale_out = 1.0f;
347+
auto scale = 1.2345f;
348+
auto scale2 = 21.0f;
349+
auto use_mkldnn = true;
350+
// nothing change
351+
auto remove_nodes = 0;
352+
CountNodeTest(BuildProgramDesc5(use_mkldnn, scale_out, scale, scale2),
353+
remove_nodes);
267354
}
268355

269356
} // namespace ir

0 commit comments

Comments
 (0)