@@ -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
7680static 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
205253TEST (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
242308TEST (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
258327TEST (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