|
|
|
@ -50,7 +50,7 @@ void SetOp(ProgramDesc* prog, const std::string& type, const std::string& name,
|
|
|
|
|
op->SetAttr("Scale_in", 1.0f);
|
|
|
|
|
op->SetAttr("Scale_out", 1.0f);
|
|
|
|
|
op->SetAttr("Scale_weights", std::vector<float>{1.0f});
|
|
|
|
|
} else if (type == "pool2d" || type == "transpose2") {
|
|
|
|
|
} else if (type == "pool2d" || type == "transpose2" || type == "reshape2") {
|
|
|
|
|
op->SetInput("X", {inputs[0]});
|
|
|
|
|
op->SetOutput("Out", {outputs[0]});
|
|
|
|
|
op->SetAttr("use_quantizer", use_quantizer);
|
|
|
|
@ -70,9 +70,48 @@ void SetOp(ProgramDesc* prog, const std::string& type, const std::string& name,
|
|
|
|
|
op->SetInput("X", inputs);
|
|
|
|
|
op->SetOutput("Out", outputs);
|
|
|
|
|
op->SetAttr("use_quantizer", use_quantizer);
|
|
|
|
|
} else if (type == "dequantize") {
|
|
|
|
|
op->SetInput("Input", {inputs[0]});
|
|
|
|
|
op->SetOutput("Output", {outputs[0]});
|
|
|
|
|
op->SetAttr("Scale", 1.0f);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void InitTensorHolder(Scope* scope, const paddle::platform::Place& place,
|
|
|
|
|
const char* var_name) {
|
|
|
|
|
auto x = scope->Var(var_name);
|
|
|
|
|
auto tensor = x->GetMutable<LoDTensor>();
|
|
|
|
|
tensor->mutable_data(place, proto::VarType::FP32, 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PreparePass(std::unique_ptr<ir::Graph>* graph, const ProgramDesc& prog,
|
|
|
|
|
const std::initializer_list<std::string> variable_names,
|
|
|
|
|
int* original_nodes_num, int* current_nodes_num) {
|
|
|
|
|
auto place = paddle::platform::CPUPlace();
|
|
|
|
|
NaiveExecutor exe{place};
|
|
|
|
|
Scope scope;
|
|
|
|
|
exe.CreateVariables(prog, 0, true, &scope);
|
|
|
|
|
auto* scales = new VarQuantScale();
|
|
|
|
|
for (auto& v : variable_names) {
|
|
|
|
|
InitTensorHolder(&scope, place, v.c_str());
|
|
|
|
|
LoDTensor tensor;
|
|
|
|
|
tensor.Resize({1});
|
|
|
|
|
auto* ptr = tensor.mutable_data<double>(place);
|
|
|
|
|
ptr[0] = 2.0;
|
|
|
|
|
|
|
|
|
|
(*scales)[v] = std::make_pair(false, std::move(tensor));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
(*graph)->SetNotOwned(kParamScopeAttr, &scope);
|
|
|
|
|
std::unique_ptr<Pass> pass =
|
|
|
|
|
PassRegistry::Instance().Get("cpu_quantize_pass");
|
|
|
|
|
pass->Set("quant_var_scales", scales);
|
|
|
|
|
|
|
|
|
|
*original_nodes_num = (*graph)->Nodes().size();
|
|
|
|
|
(*graph).reset(pass->Apply((*graph).release()));
|
|
|
|
|
*current_nodes_num = (*graph)->Nodes().size();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
static const std::initializer_list<std::string> variable_names{
|
|
|
|
|
"a", "w1", "c", "d", "w2", "e", "f", "g", "h",
|
|
|
|
@ -113,41 +152,6 @@ ProgramDesc BuildProgramDesc(bool use_mkldnn, bool use_quantizer) {
|
|
|
|
|
return prog;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void InitTensorHolder(Scope* scope, const paddle::platform::Place& place,
|
|
|
|
|
const char* var_name) {
|
|
|
|
|
auto x = scope->Var(var_name);
|
|
|
|
|
auto tensor = x->GetMutable<LoDTensor>();
|
|
|
|
|
tensor->mutable_data(place, proto::VarType::FP32, 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PreparePass(std::unique_ptr<ir::Graph>* graph, const ProgramDesc& prog,
|
|
|
|
|
const std::initializer_list<std::string> variable_names,
|
|
|
|
|
int* original_nodes_num, int* current_nodes_num) {
|
|
|
|
|
auto place = paddle::platform::CPUPlace();
|
|
|
|
|
NaiveExecutor exe{place};
|
|
|
|
|
Scope scope;
|
|
|
|
|
exe.CreateVariables(prog, 0, true, &scope);
|
|
|
|
|
auto* scales = new VarQuantScale();
|
|
|
|
|
for (auto& v : variable_names) {
|
|
|
|
|
InitTensorHolder(&scope, place, v.c_str());
|
|
|
|
|
LoDTensor tensor;
|
|
|
|
|
tensor.Resize({1});
|
|
|
|
|
auto* ptr = tensor.mutable_data<double>(place);
|
|
|
|
|
ptr[0] = 2.0;
|
|
|
|
|
|
|
|
|
|
(*scales)[v] = std::make_pair(false, std::move(tensor));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
(*graph)->SetNotOwned(kParamScopeAttr, &scope);
|
|
|
|
|
std::unique_ptr<Pass> pass =
|
|
|
|
|
PassRegistry::Instance().Get("cpu_quantize_pass");
|
|
|
|
|
pass->Set("quant_var_scales", scales);
|
|
|
|
|
|
|
|
|
|
*original_nodes_num = (*graph)->Nodes().size();
|
|
|
|
|
(*graph).reset(pass->Apply((*graph).release()));
|
|
|
|
|
*current_nodes_num = (*graph)->Nodes().size();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MainTest(const ProgramDesc& prog, int conv_count, int pool_count,
|
|
|
|
|
int quant_count, int dequant_count, int added_nodes_count,
|
|
|
|
|
float scale) {
|
|
|
|
@ -217,9 +221,6 @@ TEST(CpuQuantizePass, do_not_quantize) {
|
|
|
|
|
1.0f);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
static const std::initializer_list<std::string> variable_names_concat = {
|
|
|
|
|
"a1", "b1", "a2", "b2", "c", "d"};
|
|
|
|
|
|
|
|
|
@ -283,9 +284,7 @@ TEST(CpuQuantizePass, concat) {
|
|
|
|
|
MainTestConcat(BuildProgramDescConcat(), pool_count, concat_count,
|
|
|
|
|
quant_count, dequant_count, added_nodes_count);
|
|
|
|
|
}
|
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
static const std::initializer_list<std::string> variable_names_transpose = {
|
|
|
|
|
"a", "w1", "b", "c", "w2", "d", "e", "f"};
|
|
|
|
|
|
|
|
|
@ -365,11 +364,119 @@ TEST(CpuQuantizePass, transpose) {
|
|
|
|
|
int quant_count = 4;
|
|
|
|
|
int dequant_count = 4;
|
|
|
|
|
// 4 Quant + 4 IN + 4 DeQuant + 4 OUT
|
|
|
|
|
int added_nodes_count = 16;
|
|
|
|
|
int added_nodes_count = 4 + 4 + 4 + 4;
|
|
|
|
|
MainTestTranspose(BuildProgramDescTranspose(), conv_count, transpose_count,
|
|
|
|
|
quant_count, dequant_count, added_nodes_count, 2.0f * 127);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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_transpose) {
|
|
|
|
|
prog.MutableBlock(0)->Var(v);
|
|
|
|
|
}
|
|
|
|
|
SetOp(&prog, "dequantize", "Dequantize1", {"a"}, {"b"}, true);
|
|
|
|
|
SetOp(&prog, "reshape2", "Reshape2", {"b"}, {"c"}, true, true);
|
|
|
|
|
SetOp(&prog, "dropout", "Dropout", {"c"}, {"d"}, true, false);
|
|
|
|
|
|
|
|
|
|
return prog;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// a->Transpose->b
|
|
|
|
|
// b->Reshape->c
|
|
|
|
|
// c->Dropout->d
|
|
|
|
|
ProgramDesc BuildProgramDescReshapeBetweenNonQuantizedOp() {
|
|
|
|
|
ProgramDesc prog;
|
|
|
|
|
for (auto& v : variable_names_transpose) {
|
|
|
|
|
prog.MutableBlock(0)->Var(v);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SetOp(&prog, "transpose2", "Transpose2", {"a"}, {"b"}, true, false);
|
|
|
|
|
SetOp(&prog, "reshape2", "Reshape2", {"b"}, {"c"}, true, true);
|
|
|
|
|
SetOp(&prog, "dropout", "Dropout", {"c"}, {"d"}, true, false);
|
|
|
|
|
|
|
|
|
|
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,
|
|
|
|
|
¤t_nodes_num);
|
|
|
|
|
|
|
|
|
|
float quant_scale = 1.0f;
|
|
|
|
|
float dequant_scale = 1.0f;
|
|
|
|
|
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<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");
|
|
|
|
|
std::cout << op_name << " \n";
|
|
|
|
|
if (op_name != "Dequantize1") {
|
|
|
|
|
dequant_scale = boost::get<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.0f * 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.0f * 127);
|
|
|
|
|
}
|
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
|
|
} // namespace ir
|
|
|
|
|
} // namespace framework
|
|
|
|
|
} // namespace paddle
|
|
|
|
|