Skip to content

Commit

Permalink
Merge pull request PaddlePaddle#46 from jiweibo/lite_engine
Browse files Browse the repository at this point in the history
Lite engine unitest
  • Loading branch information
Shixiaowei02 authored Dec 29, 2019
2 parents 1a7715d + ba4381b commit 3e27186
Show file tree
Hide file tree
Showing 4 changed files with 133 additions and 101 deletions.
1 change: 1 addition & 0 deletions paddle/fluid/inference/lite/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ cc_library(lite_engine SRCS engine.cc DEPS lite_full_static framework_proto)
cc_library(lite_tensor_utils SRCS tensor_utils.cc DEPS memcpy lite_full_static framework_proto boost)
cc_test(test_lite_engine SRCS test_engine.cc DEPS lite_engine protobuf framework_proto glog gtest analysis)
cc_test(test_lite_tensor_utils SRCS test_tensor_utils.cc DEPS lite_engine paddle_fluid lite_tensor_utils)
cc_test(test_lite_model SRCS test_lite_model.cc DEPS lite_engine paddle_fluid lite_tensor_utils)
77 changes: 51 additions & 26 deletions paddle/fluid/inference/lite/test_engine.cc
Original file line number Diff line number Diff line change
Expand Up @@ -13,77 +13,102 @@
// limitations under the License.

#include <gtest/gtest.h>
#include <fstream>
#include <ios>

#include "lite/api/paddle_use_kernels.h"
#include "lite/api/paddle_use_ops.h"
#include "lite/api/paddle_use_passes.h"

#include "paddle/fluid/inference/lite/engine.h"
#include "paddle/fluid/inference/utils/singleton.h"
#include "paddle/fluid/operators/lite/ut_helper.h"

#include "paddle/fluid/framework/block_desc.h"
#include "paddle/fluid/framework/op_desc.h"
#include "paddle/fluid/framework/program_desc.h"
#include "paddle/fluid/framework/scope.h"

namespace paddle {
namespace inference {
namespace lite {

namespace {

void AddTensorToBlockDesc(framework::proto::BlockDesc* block,
const std::string& name,
const std::vector<int64_t>& shape) {
using framework::proto::VarType;
auto* var = block->add_vars();
framework::VarDesc desc(name);
desc.SetType(VarType::LOD_TENSOR);
desc.SetDataType(VarType::FP32);
desc.SetShape(shape);
*var = *desc.Proto();
}
using inference::lite::AddTensorToBlockDesc;
using inference::lite::CreateTensor;
using inference::lite::serialize_params;

void make_fake_model(std::string* model, std::string* param) {
framework::ProgramDesc program;
LOG(INFO) << "program.block size is " << program.Size();
auto* block_ = program.Proto()->mutable_blocks(0);
LOG(INFO) << "create block desc";
framework::BlockDesc block_desc(&program, block_);
LOG(INFO) << "create feed op";
auto* feed0 = block_desc.AppendOp();
feed0->SetType("feed");
feed0->SetInput("X", {"feed"});
feed0->SetOutput("Out", {"x"});
feed0->SetAttr("col", 1);
AddTensorToBlockDesc(block_, "x", std::vector<int64_t>({2, 4, 1, 1}));
feed0->SetAttr("col", 0);
auto* feed1 = block_desc.AppendOp();
feed1->SetType("feed");
feed1->SetInput("X", {"feed"});
feed1->SetOutput("Out", {"y"});
feed1->SetAttr("col", 1);
LOG(INFO) << "create elementwise_add op";
auto* elt_add = block_desc.AppendOp();
elt_add->SetType("elementwise_add");
elt_add->SetInput("X", std::vector<std::string>({"x"}));
elt_add->SetInput("Y", std::vector<std::string>({"y"}));
elt_add->SetOutput("Out", std::vector<std::string>({"z"}));
elt_add->SetAttr("axis", -1);
LOG(INFO) << "create fetch op";
auto* fetch = block_desc.AppendOp();
fetch->SetType("fetch");
fetch->SetInput("X", std::vector<std::string>({"z"}));
fetch->SetOutput("Out", std::vector<std::string>({"out"}));
fetch->SetAttr("col", 0);
// Set inputs' variable shape in BlockDesc
AddTensorToBlockDesc(block_, "x", std::vector<int64_t>({2, 4}), true);
AddTensorToBlockDesc(block_, "y", std::vector<int64_t>({2, 4}), true);
AddTensorToBlockDesc(block_, "z", std::vector<int64_t>({2, 4}), false);
AddTensorToBlockDesc(block_, "out", std::vector<int64_t>({2, 4}), false);

*block_->add_ops() = *feed0->Proto();
ASSERT_EQ(block_->ops_size(), 1);
*block_->add_ops() = *feed1->Proto();
*block_->add_ops() = *elt_add->Proto();
*block_->add_ops() = *fetch->Proto();

framework::Scope scope;
#ifdef PADDLE_WITH_CUDA
platform::CUDAPlace place;
platform::CUDADeviceContext ctx(place);
#else
platform::CPUPlace place;
platform::CPUDeviceContext ctx(place);
#endif
// Prepare variables.
std::vector<std::string> repetitive_params{"x", "y"};
CreateTensor(&scope, "x", std::vector<int64_t>({2, 4}));
CreateTensor(&scope, "y", std::vector<int64_t>({2, 4}));
ASSERT_EQ(block_->ops_size(), 4);
*model = program.Proto()->SerializeAsString();
serialize_params(param, &scope, repetitive_params);
}

} // namespace

TEST(EngineManager, manual) {
TEST(EngineManager, engine) {
ASSERT_EQ(
inference::Singleton<inference::lite::EngineManager>::Global().Empty(),
true);

inference::lite::EngineConfig config;
make_fake_model(&(config.model), &(config.param));
LOG(INFO) << "prepare config";

const std::string unique_key("engine_0");
config.model_from_memory = true;
config.prefer_place = {TARGET(kX86), PRECISION(kFloat)};
config.valid_places = {
paddle::lite::Place({TARGET(kX86), PRECISION(kFloat)}),
paddle::lite::Place({TARGET(kHost), PRECISION(kAny)}),
#ifdef PADDLE_WITH_CUDA
paddle::lite::Place({TARGET(kCUDA), PRECISION(kFloat)}),
#endif
paddle::lite::Place({TARGET(kX86), PRECISION(kFloat)}),
paddle::lite::Place({TARGET(kHost), PRECISION(kAny)}),
};

LOG(INFO) << "Create EngineManager";
Expand All @@ -99,7 +124,6 @@ TEST(EngineManager, manual) {
paddle::lite::Predictor* engine_0 =
inference::Singleton<inference::lite::EngineManager>::Global().Get(
unique_key);

CHECK_NOTNULL(engine_0);
inference::Singleton<inference::lite::EngineManager>::Global().DeleteAll();
CHECK(inference::Singleton<inference::lite::EngineManager>::Global().Get(
Expand All @@ -108,4 +132,5 @@ TEST(EngineManager, manual) {
}

} // namespace lite
} // namespace inference
} // namespace paddle
97 changes: 26 additions & 71 deletions paddle/fluid/operators/lite/lite_engine_op_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -27,44 +27,26 @@
#include "lite/api/paddle_use_passes.h"

USE_NO_KERNEL_OP(lite_engine)

using paddle::inference::lite::AddTensorToBlockDesc;
using paddle::inference::lite::CreateTensor;
using paddle::inference::lite::serialize_params;
namespace paddle {
namespace operators {

namespace {
void CreateTensor(framework::Scope* scope, const std::string& name,
const std::vector<int64_t>& shape) {
auto* var = scope->Var(name);
auto* tensor = var->GetMutable<framework::LoDTensor>();
auto dims = framework::make_ddim(shape);
tensor->Resize(dims);
#ifdef PADDLE_WITH_CUDA
platform::CUDAPlace place;
#else
platform::CPUPlace place;
#endif
inference::lite::RandomizeTensor(tensor, place);
}

void AddTensorToBlockDesc(framework::proto::BlockDesc* block,
const std::string& name,
const std::vector<int64_t>& shape, bool persistable) {
using framework::proto::VarType;
auto* var = block->add_vars();
framework::VarDesc desc(name);
desc.SetType(VarType::LOD_TENSOR);
desc.SetDataType(VarType::FP32);
desc.SetShape(shape);
desc.SetPersistable(persistable);
*var = *desc.Proto();
}
} // namespace

TEST(LiteEngineOp, manual) {
TEST(LiteEngineOp, engine_op) {
framework::ProgramDesc program;
auto* block_ = program.Proto()->mutable_blocks(0);

LOG(INFO) << "create block desc";
framework::BlockDesc block_desc(&program, block_);
auto* feed0 = block_desc.AppendOp();
feed0->SetType("feed");
feed0->SetInput("X", {"feed"});
feed0->SetOutput("Out", {"x"});
feed0->SetAttr("col", 0);
auto* feed1 = block_desc.AppendOp();
feed1->SetType("feed");
feed1->SetInput("X", {"feed"});
feed1->SetOutput("Out", {"y"});
feed1->SetAttr("col", 1);
LOG(INFO) << "create elementwise_add op";
auto* elt_add = block_desc.AppendOp();
elt_add->SetType("elementwise_add");
Expand All @@ -83,10 +65,10 @@ TEST(LiteEngineOp, manual) {
AddTensorToBlockDesc(block_, "y", std::vector<int64_t>({2, 4}), true);
AddTensorToBlockDesc(block_, "z", std::vector<int64_t>({2, 4}), false);
AddTensorToBlockDesc(block_, "out", std::vector<int64_t>({2, 4}), false);

*block_->add_ops() = *feed1->Proto();
*block_->add_ops() = *feed0->Proto();
*block_->add_ops() = *elt_add->Proto();
*block_->add_ops() = *fetch->Proto();

framework::Scope scope;
#ifdef PADDLE_WITH_CUDA
platform::CUDAPlace place;
Expand All @@ -96,69 +78,42 @@ TEST(LiteEngineOp, manual) {
platform::CPUDeviceContext ctx(place);
#endif
// Prepare variables.
CreateTensor(&scope, "x", std::vector<int64_t>({2, 4}));
CreateTensor(&scope, "y", std::vector<int64_t>({2, 4}));
CreateTensor(&scope, "z", std::vector<int64_t>({2, 4}));
CreateTensor(&scope, "out", std::vector<int64_t>({2, 4}));
CreateTensor(&scope, "x", std::vector<int64_t>({2, 4}), false);
CreateTensor(&scope, "y", std::vector<int64_t>({2, 4}), false);
CreateTensor(&scope, "out", std::vector<int64_t>({2, 4}), false);

ASSERT_EQ(block_->ops_size(), 2);
ASSERT_EQ(block_->ops_size(), 4);

auto serialize_params = [](std::string* str, framework::Scope* scope,
const std::vector<std::string>& params) {
std::ostringstream os;
#ifdef PADDLE_WITH_CUDA
platform::CUDAPlace place;
platform::CUDADeviceContext ctx(place);
#else
platform::CPUDeviceContext ctx;
#endif
for (const auto& param : params) {
PADDLE_ENFORCE_NOT_NULL(scope->FindVar(param),
"Block should already have a '%s' variable",
param);
auto* tensor = scope->FindVar(param)->GetMutable<framework::LoDTensor>();
framework::SerializeToStream(os, *tensor, ctx);
}
*str = os.str();
};
std::vector<std::string> repetitive_params{"x", "y"};
inference::lite::EngineConfig config;
config.prefer_place = {
#ifdef PADDLE_WITH_CUDA
TARGET(kCUDA), PRECISION(kFloat),
#else
TARGET(kX86), PRECISION(kFloat)
#endif
};
config.valid_places = {
paddle::lite::Place({TARGET(kHost), PRECISION(kAny)}),
paddle::lite::Place({TARGET(kX86), PRECISION(kFloat)}),
#ifdef PADDLE_WITH_CUDA
paddle::lite::Place({TARGET(kCUDA), PRECISION(kFloat)}),
#endif
paddle::lite::Place({TARGET(kHost), PRECISION(kAny)}),
paddle::lite::Place({TARGET(kX86), PRECISION(kFloat)}),
};
serialize_params(&(config.param), &scope, repetitive_params);
config.model = program.Proto()->SerializeAsString();

LOG(INFO) << "create lite_engine desc";
framework::OpDesc engine_op_desc(nullptr);
engine_op_desc.SetType("lite_engine");
engine_op_desc.SetInput("Xs", std::vector<std::string>({"x", "y"}));
engine_op_desc.SetOutput("Ys", std::vector<std::string>({"out"}));
std::string engine_key = "engine_0";
engine_op_desc.SetAttr("engine_key", engine_key);
engine_op_desc.SetAttr("enable_int8", false);
engine_op_desc.SetAttr("use_gpu", true);
engine_op_desc.SetBlockAttr("sub_block", &block_desc);

inference::Singleton<inference::lite::EngineManager>::Global().Create(
engine_key, config);

LOG(INFO) << "create engine op";
auto engine_op = framework::OpRegistry::CreateOp(engine_op_desc);
LOG(INFO) << "engine_op " << engine_op.get();

// Execute them.
LOG(INFO) << "engine_op run";
engine_op->Run(scope, place);
LOG(INFO) << "done";
}
} // namespace operators
} // namespace paddle
59 changes: 55 additions & 4 deletions paddle/fluid/operators/lite/ut_helper.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@
#pragma once

#include <gtest/gtest.h>

#include <string>
#include <vector>

#include "paddle/fluid/framework/block_desc.h"
#include "paddle/fluid/framework/lod_tensor.h"
#include "paddle/fluid/framework/op_registry.h"
Expand All @@ -24,6 +28,36 @@ namespace paddle {
namespace inference {
namespace lite {

void AddTensorToBlockDesc(framework::proto::BlockDesc* block,
const std::string& name,
const std::vector<int64_t>& shape,
bool persistable = false) {
using framework::proto::VarType;
auto* var = block->add_vars();
framework::VarDesc desc(name);
desc.SetType(VarType::LOD_TENSOR);
desc.SetDataType(VarType::FP32);
desc.SetShape(shape);
desc.SetPersistable(persistable);
*var = *desc.Proto();
}
void serialize_params(std::string* str, framework::Scope* scope,
const std::vector<std::string>& params) {
std::ostringstream os;
#ifdef PADDLE_WITH_CUDA
platform::CUDAPlace place;
platform::CUDADeviceContext ctx(place);
#else
platform::CPUDeviceContext ctx;
#endif
for (const auto& param : params) {
PADDLE_ENFORCE_NOT_NULL(scope->FindVar(param),
"Block should already have a '%s' variable", param);
auto* tensor = scope->FindVar(param)->GetMutable<framework::LoDTensor>();
framework::SerializeToStream(os, *tensor, ctx);
}
*str = os.str();
}
/*
* Get a random float value between [low, high]
*/
Expand All @@ -33,24 +67,41 @@ float random(float low, float high) {
std::uniform_real_distribution<double> dist(low, high);
return dist(mt);
}

void RandomizeTensor(framework::LoDTensor* tensor,
const platform::Place& place) {
auto dims = tensor->dims();
size_t num_elements = analysis::AccuDims(dims, dims.size());
PADDLE_ENFORCE_GT(num_elements, 0);

platform::CPUPlace cpu_place;
framework::LoDTensor temp_tensor;
temp_tensor.Resize(dims);
auto* temp_data = temp_tensor.mutable_data<float>(cpu_place);

for (size_t i = 0; i < num_elements; i++) {
*(temp_data + i) = random(0., 1.);
// LOG(INFO) << "weights: " << *(temp_data + i);
}

TensorCopySync(temp_tensor, place, tensor);
}

void CreateTensor(framework::Scope* scope, const std::string& name,
const std::vector<int64_t>& shape, bool in_cuda = true) {
auto* var = scope->Var(name);
auto* tensor = var->GetMutable<framework::LoDTensor>();
auto dims = framework::make_ddim(shape);
tensor->Resize(dims);
platform::Place place;
if (in_cuda) {
#ifdef PADDLE_WITH_CUDA
place = platform::CUDAPlace(0);
#else
LOG(FATAL) << "You must define PADDLE_WITH_CUDA for using CUDAPlace.";
#endif
} else {
place = platform::CPUPlace();
}
RandomizeTensor(tensor, place);
}

} // namespace lite
} // namespace inference
} // namespace paddle

0 comments on commit 3e27186

Please sign in to comment.