|
|
@ -14,6 +14,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
#include "paddle/fluid/framework/ir/mkldnn/cpu_quantize_pass.h"
|
|
|
|
#include "paddle/fluid/framework/ir/mkldnn/cpu_quantize_pass.h"
|
|
|
|
#include <gtest/gtest.h>
|
|
|
|
#include <gtest/gtest.h>
|
|
|
|
|
|
|
|
|
|
|
|
#include "paddle/fluid/framework/naive_executor.h"
|
|
|
|
#include "paddle/fluid/framework/naive_executor.h"
|
|
|
|
#include "paddle/fluid/imperative/type_defs.h"
|
|
|
|
#include "paddle/fluid/imperative/type_defs.h"
|
|
|
|
#include "paddle/fluid/platform/place.h"
|
|
|
|
#include "paddle/fluid/platform/place.h"
|
|
|
@ -82,6 +83,14 @@ void SetOp(ProgramDesc* prog, const std::string& type, const std::string& name,
|
|
|
|
op->SetAttr("Scale_x", 1.0f);
|
|
|
|
op->SetAttr("Scale_x", 1.0f);
|
|
|
|
op->SetAttr("Scale_y", 1.0f);
|
|
|
|
op->SetAttr("Scale_y", 1.0f);
|
|
|
|
op->SetAttr("Scale_out", 1.0f);
|
|
|
|
op->SetAttr("Scale_out", 1.0f);
|
|
|
|
|
|
|
|
} else if (type == "elementwise_add") {
|
|
|
|
|
|
|
|
op->SetInput("X", {inputs[0]});
|
|
|
|
|
|
|
|
if (inputs.size() > 1) op->SetInput("Y", {inputs[1]});
|
|
|
|
|
|
|
|
op->SetOutput("Out", {outputs[0]});
|
|
|
|
|
|
|
|
op->SetAttr("use_quantizer", use_quantizer);
|
|
|
|
|
|
|
|
op->SetAttr("Scale_x", 1.0f);
|
|
|
|
|
|
|
|
op->SetAttr("Scale_y", 1.0f);
|
|
|
|
|
|
|
|
op->SetAttr("Scale_out", 1.0f);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -95,7 +104,8 @@ void InitTensorHolder(Scope* scope, const paddle::platform::Place& place,
|
|
|
|
void PreparePass(std::unique_ptr<ir::Graph>* graph, const ProgramDesc& prog,
|
|
|
|
void PreparePass(std::unique_ptr<ir::Graph>* graph, const ProgramDesc& prog,
|
|
|
|
const std::initializer_list<std::string> variable_names,
|
|
|
|
const std::initializer_list<std::string> variable_names,
|
|
|
|
int* original_nodes_num, int* current_nodes_num,
|
|
|
|
int* original_nodes_num, int* current_nodes_num,
|
|
|
|
std::string var_without_scale = "") {
|
|
|
|
std::string var_without_scale = "",
|
|
|
|
|
|
|
|
std::string var_signed = "") {
|
|
|
|
auto place = paddle::platform::CPUPlace();
|
|
|
|
auto place = paddle::platform::CPUPlace();
|
|
|
|
NaiveExecutor exe{place};
|
|
|
|
NaiveExecutor exe{place};
|
|
|
|
Scope scope;
|
|
|
|
Scope scope;
|
|
|
@ -108,8 +118,7 @@ void PreparePass(std::unique_ptr<ir::Graph>* graph, const ProgramDesc& prog,
|
|
|
|
tensor.Resize({1});
|
|
|
|
tensor.Resize({1});
|
|
|
|
auto* ptr = tensor.mutable_data<double>(place);
|
|
|
|
auto* ptr = tensor.mutable_data<double>(place);
|
|
|
|
ptr[0] = 2.0;
|
|
|
|
ptr[0] = 2.0;
|
|
|
|
|
|
|
|
(*scales)[v] = std::make_pair(v == var_signed, std::move(tensor));
|
|
|
|
(*scales)[v] = std::make_pair(false, std::move(tensor));
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
(*graph)->SetNotOwned(kParamScopeAttr, &scope);
|
|
|
|
(*graph)->SetNotOwned(kParamScopeAttr, &scope);
|
|
|
@ -387,7 +396,7 @@ static const std::initializer_list<std::string> variable_names_reshape = {
|
|
|
|
// c->Dropout->d
|
|
|
|
// c->Dropout->d
|
|
|
|
ProgramDesc BuildProgramDescReshape() {
|
|
|
|
ProgramDesc BuildProgramDescReshape() {
|
|
|
|
ProgramDesc prog;
|
|
|
|
ProgramDesc prog;
|
|
|
|
for (auto& v : variable_names_transpose) {
|
|
|
|
for (auto& v : variable_names_reshape) {
|
|
|
|
prog.MutableBlock(0)->Var(v);
|
|
|
|
prog.MutableBlock(0)->Var(v);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
SetOp(&prog, "dequantize", "Dequantize1", {"a"}, {"b"}, true);
|
|
|
|
SetOp(&prog, "dequantize", "Dequantize1", {"a"}, {"b"}, true);
|
|
|
@ -402,7 +411,7 @@ ProgramDesc BuildProgramDescReshape() {
|
|
|
|
// c->Dropout->d
|
|
|
|
// c->Dropout->d
|
|
|
|
ProgramDesc BuildProgramDescReshapeBetweenNonQuantizedOp() {
|
|
|
|
ProgramDesc BuildProgramDescReshapeBetweenNonQuantizedOp() {
|
|
|
|
ProgramDesc prog;
|
|
|
|
ProgramDesc prog;
|
|
|
|
for (auto& v : variable_names_transpose) {
|
|
|
|
for (auto& v : variable_names_reshape) {
|
|
|
|
prog.MutableBlock(0)->Var(v);
|
|
|
|
prog.MutableBlock(0)->Var(v);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -491,7 +500,7 @@ static const std::initializer_list<std::string> variable_names_matmul = {
|
|
|
|
|
|
|
|
|
|
|
|
ProgramDesc BuildProgramDescMatmul() {
|
|
|
|
ProgramDesc BuildProgramDescMatmul() {
|
|
|
|
ProgramDesc prog;
|
|
|
|
ProgramDesc prog;
|
|
|
|
for (auto& v : variable_names_transpose) {
|
|
|
|
for (auto& v : variable_names_matmul) {
|
|
|
|
prog.MutableBlock(0)->Var(v);
|
|
|
|
prog.MutableBlock(0)->Var(v);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
SetOp(&prog, "dequantize", "Dequantize1", {"a"}, {"b"}, true);
|
|
|
|
SetOp(&prog, "dequantize", "Dequantize1", {"a"}, {"b"}, true);
|
|
|
@ -504,7 +513,7 @@ ProgramDesc BuildProgramDescMatmul() {
|
|
|
|
|
|
|
|
|
|
|
|
ProgramDesc BuildProgramDescMatmulNotQuantized() {
|
|
|
|
ProgramDesc BuildProgramDescMatmulNotQuantized() {
|
|
|
|
ProgramDesc prog;
|
|
|
|
ProgramDesc prog;
|
|
|
|
for (auto& v : variable_names_transpose) {
|
|
|
|
for (auto& v : variable_names_matmul) {
|
|
|
|
prog.MutableBlock(0)->Var(v);
|
|
|
|
prog.MutableBlock(0)->Var(v);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
SetOp(&prog, "dropout", "Dropout", {"a"}, {"b"}, false);
|
|
|
|
SetOp(&prog, "dropout", "Dropout", {"a"}, {"b"}, false);
|
|
|
@ -569,6 +578,97 @@ TEST(CpuQuantizePass, matmul_not_quantized) {
|
|
|
|
MainTestMatmul(BuildProgramDescMatmulNotQuantized(), matmul_count,
|
|
|
|
MainTestMatmul(BuildProgramDescMatmulNotQuantized(), matmul_count,
|
|
|
|
quant_count, dequant_count, added_nodes_count, 1.0f);
|
|
|
|
quant_count, dequant_count, added_nodes_count, 1.0f);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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,
|
|
|
|
|
|
|
|
true);
|
|
|
|
|
|
|
|
SetOp(&prog, "dropout", "Dropout", {"e"}, {"f"}, true, false);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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,
|
|
|
|
|
|
|
|
¤t_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.0f;
|
|
|
|
|
|
|
|
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.0f * 127);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
TEST(CpuQuantizePass, elementwise_add_output_scale_missing) {
|
|
|
|
|
|
|
|
int elementwise_add_count = 1;
|
|
|
|
|
|
|
|
int quant_count = 2;
|
|
|
|
|
|
|
|
int dequant_count = 2;
|
|
|
|
|
|
|
|
// 2 Quant + 2 IN
|
|
|
|
|
|
|
|
int added_nodes_count = 4;
|
|
|
|
|
|
|
|
MainTestElementwiseAdd(BuildProgramDescElementwiseAdd(),
|
|
|
|
|
|
|
|
elementwise_add_count, quant_count, dequant_count,
|
|
|
|
|
|
|
|
added_nodes_count, 2.0f * 127, 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.0f * 127, false, true);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
} // namespace
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
|
|
|
|
} // namespace ir
|
|
|
|
} // namespace ir
|
|
|
|