Skip to content
This repository has been archived by the owner on Jan 24, 2024. It is now read-only.

Commit

Permalink
Load paddle fc and run (#209)
Browse files Browse the repository at this point in the history
  • Loading branch information
Superjomn authored Sep 9, 2020
1 parent f52ef4a commit 34ffb2b
Show file tree
Hide file tree
Showing 20 changed files with 275 additions and 72 deletions.
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,7 @@
cmake-build*
build*
.idea*
*.html
*.html
*.rej
*.orig
*.patch
4 changes: 3 additions & 1 deletion cinn/backends/llvm/llvm_optimizer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,9 @@ void LLVMModuleOptimizer::operator()(llvm::Module *m) {
fpm->doInitialization();
std::for_each(m->begin(), m->end(), [&fpm](auto &fn) { fpm->run(fn); });
fpm->doFinalization();
mpm->run(*m);

// TODO(Superjomn) Enable this. This is quite slow when turned on.
// mpm->run(*m);
}

} // namespace cinn::backends
6 changes: 4 additions & 2 deletions cinn/frontend/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ set(srcs
)

if(NOT WITH_CUDA)
cc_test(test_frontend_syntax SRCS syntax_test.cc DEPS core)
cc_test(test_frontend_syntax SRCS syntax_test.cc DEPS core
ARGS --model_dir=${THIRD_PARTY_PATH}/model/lite_naive_model)
else()
nv_test(test_frontend_syntax SRCS syntax_test.cc DEPS core)
nv_test(test_frontend_syntax SRCS syntax_test.cc DEPS core
ARGS --model_dir=${THIRD_PARTY_PATH}/model/lite_naive_model)
endif()


Expand Down
16 changes: 7 additions & 9 deletions cinn/frontend/paddle/model_parser.cc
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ void TensorFromStream(std::istream &is, hlir::framework::Tensor *tensor) {
}

// read tensor
std::vector<uint32_t> dims_vec;
std::vector<int32_t> dims_vec;
std::copy(desc.dims().begin(), desc.dims().end(), std::back_inserter(dims_vec));
hlir::framework::Shape dims(dims_vec);
tensor->Resize(dims);
Expand Down Expand Up @@ -82,17 +82,15 @@ void LoadLoDTensor(std::istream &is, hlir::framework::Variable *var) {
// Load LoD information
uint64_t lod_level{};
is.read(reinterpret_cast<char *>(&lod_level), sizeof(lod_level));
/*
auto &lod = *tensor->mutable_lod();
lod.resize(lod_level);

for (uint64_t i = 0; i < lod_level; ++i) {
uint64_t size;
is.read(reinterpret_cast<char *>(&size), sizeof(size));
std::vector<uint64_t> tmp(size / sizeof(uint64_t));
is.read(reinterpret_cast<char *>(tmp.data()), static_cast<std::streamsize>(size));
lod[i] = tmp;
// lod[i] = tmp;
}
*/

TensorFromStream(is, &tensor);
}

Expand Down Expand Up @@ -157,7 +155,7 @@ void LoadCombinedParamsPb(const std::string &path,
// Load vars
auto load_var_func = [&](std::istream &is) {
for (size_t i = 0; i < paramlist.size(); ++i) {
auto *var = scope->Var<hlir::framework::Tensor>(paramlist[i]);
auto *var = scope->Var<hlir::framework::Tensor>(utils::TransValidVarName(paramlist[i]));
// Error checking
CHECK(static_cast<bool>(is)) << "There is a problem with loading model parameters";
LoadLoDTensor(is, var);
Expand Down Expand Up @@ -218,15 +216,15 @@ void LoadModelPb(const std::string &model_dir,
std::ifstream file(file_path, std::ios::binary);
switch (var.type().type()) {
case framework_proto::VarType_Type_LOD_TENSOR:
LoadLoDTensor(file, scope->Var<hlir::framework::Tensor>(var.name()));
LoadLoDTensor(file, scope->Var<hlir::framework::Tensor>(utils::TransValidVarName(var.name())));
break;
default:
LOG(FATAL) << "unknown weight type";
}
}
}

VLOG(4) << "Load protobuf model in '" << model_dir << "'' successfully";
VLOG(4) << "Load protobuf model in [" << model_dir << "] successfully";
}

} // namespace cinn::frontend::paddle
163 changes: 153 additions & 10 deletions cinn/frontend/syntax.cc
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
#include "cinn/frontend/syntax.h"

#include <memory>
#include <tuple>
#include <utility>

#include "cinn/frontend/paddle/model_parser.h"
#include "cinn/hlir/framework/node.h"
#include "cinn/hlir/framework/op.h"
#include "cinn/utils/string.h"

namespace cinn {
namespace frontend {
using hlir::framework::Scope;

void Instruction::PrepareOutputs() {
auto* op_def = hlir::framework::OpRegistry::Global()->Find(get()->op_type);
Expand Down Expand Up @@ -79,18 +84,148 @@ std::ostream& operator<<(std::ostream& os, const Instruction& instr) {
return os;
}

// Add an Instruction to a program given a Paddle-format \p op_desc.
void ProgramAddOp(Program* program, const paddle::cpp::OpDesc& op_desc) {}
class PaddleModelToProgram {
public:
explicit PaddleModelToProgram(Scope* scope) : scope_(scope), program_(new Program) {
CHECK(scope_);

AddOpMapper_feed();
AddOpMapper_fetch();
AddOpMapper_mul();
AddOpMapper_scale();
}

std::unique_ptr<Program> operator()(const std::string& model_dir, bool is_combined) {
paddle::cpp::ProgramDesc program_desc;
paddle::LoadModelPb(model_dir, "__model__", "", scope_, &program_desc, is_combined);
CHECK_EQ(program_desc.BlocksSize(), 1) << "CINN can only support the model with a single block";
auto* block_desc = program_desc.GetBlock<paddle::cpp::BlockDesc>(0);

for (int i = 0; i < block_desc->OpsSize(); i++) {
auto* op_desc = block_desc->GetOp<paddle::cpp::OpDesc>(i);
AddOp(*op_desc);
}
return std::move(program_);
}

// Add an Instruction to a program given a Paddle-format \p op_desc.
void AddOp(const paddle::cpp::OpDesc& op_desc);

// @{
inline void AddOpMapper_feed();
inline void AddOpMapper_fetch();
inline void AddOpMapper_scale();
inline void AddOpMapper_mul();
// @}

const std::unordered_map<std::string, Variable>& var_map() const { return var_map_; }

void LoadPaddleProgram(const std::string& model_dir, bool is_combined) {
hlir::framework::Scope scope;
paddle::cpp::ProgramDesc program_desc;
paddle::LoadModelPb(model_dir, "__model__", "", &scope, &program_desc, is_combined);
CHECK_EQ(program_desc.BlocksSize(), 1) << "CINN can only support the model with a single block";
auto* block_desc = program_desc.GetBlock<paddle::cpp::BlockDesc>(0);
for (int i = 0; i < block_desc->OpsSize(); i++) {
auto* op_desc = block_desc->GetOp<paddle::cpp::OpDesc>(i);
protected:
void AddVar(const std::string& name, const Variable& var) {
CHECK(utils::IsVarNameValid(name));
CHECK(!var_map_.count(name)) << "Duplicate variable [" << name << "] found";
var_map_[name] = var;
}

Variable GetVar(const std::string& name);

private:
std::unordered_map<std::string, std::function<void(const paddle::cpp::OpDesc&)>> op_mappers_;
std::unique_ptr<Program> program_;
std::unordered_map<std::string, Variable> var_map_;
Scope* scope_{};
};

void PaddleModelToProgram::AddOpMapper_feed() {
op_mappers_["feed"] = [&](const paddle::cpp::OpDesc& op_desc) {
auto outs = op_desc.Output("Out");
CHECK_EQ(outs.size(), 1UL);
VLOG(2) << "Model get feed [" << outs[0] << "]";
Placeholder input(Float(32), {}, outs[0]);
AddVar(outs[0], input);
};
}

void PaddleModelToProgram::AddOpMapper_fetch() {
op_mappers_["fetch"] = [&](const paddle::cpp::OpDesc& op_desc) {
// do nothing
};
}

void PaddleModelToProgram::AddOpMapper_scale() {
op_mappers_["scale"] = [&](const paddle::cpp::OpDesc& op_desc) {
auto x_name = op_desc.Input("X").front();
auto x = GetVar(utils::TransValidVarName(x_name));
float scale{};
if (op_desc.HasAttr("scale")) { // the old model format
scale = op_desc.GetAttr<float>("scale");
} else { // the newly refactored format
// load scale tensor
auto* scale_tensor_var = scope_->FindVar(op_desc.Input("ScaleTensor").front());
CHECK(scale_tensor_var) << "No scale tensor found in the scope";
auto& scale_tensor = std::get<hlir::framework::Tensor>(*scale_tensor_var);
scale = scale_tensor.mutable_data<float>(common::DefaultHostTarget())[0];
}

auto out = program_->scale(x, scale);
auto out_name = op_desc.Output("Out").front();
AddVar(utils::TransValidVarName(out_name), out);
};
}

void PaddleModelToProgram::AddOpMapper_mul() {
op_mappers_["mul"] = [&](const paddle::cpp::OpDesc& op_desc) {
auto x_name = op_desc.Input("X").front();
auto y_name = op_desc.Input("Y").front();
auto x = GetVar(utils::TransValidVarName(x_name));
auto y = GetVar(utils::TransValidVarName(y_name));
int x_num_col_dims = op_desc.GetAttr<int>("x_num_col_dims");
int y_num_col_dims = op_desc.GetAttr<int>("y_num_col_dims");
VLOG(4) << "Mul x_num_col_dims: " << x_num_col_dims;
VLOG(4) << "Mul y_num_col_dims: " << y_num_col_dims;
auto out = program_->mul(x, y, false, false, x_num_col_dims, y_num_col_dims);
auto out_name = op_desc.Output("Out").front();
AddVar(utils::TransValidVarName(out_name), out);
};
}

void PaddleModelToProgram::AddOp(const paddle::cpp::OpDesc& op_desc) {
const auto& op_type = op_desc.Type();
auto it = op_mappers_.find(op_type);
if (it != op_mappers_.end()) {
it->second(op_desc);
return;
}
// feed op's output is a input of the model
LOG(FATAL) << "Not supported op [" << op_desc.Type() << "] found";
}

Variable PaddleModelToProgram::GetVar(const std::string& name) {
CHECK(utils::IsVarNameValid(name)) << "Name [" << name << "] is not valid";

auto it = var_map_.find(name);
if (it != var_map_.end()) return it->second;

auto* var = scope_->FindVar(name);
if (var) {
auto& tensor = std::get<hlir::framework::Tensor>(*var);
Variable var;
var.set_id(name);
var->shape = tensor.shape().data();
// TODO(Superjomn) Make this determined by model.
var->type = Float(32);
AddVar(name, var);
return var;
}

LOG(FATAL) << "No var called [" << name << "] exists";
return Variable();
}

std::tuple<std::unique_ptr<Program>, std::unordered_map<std::string, Variable>> LoadPaddleProgram(
const std::string& model_dir, Scope* scope, bool is_combined) {
PaddleModelToProgram _(scope);
return std::make_tuple(_(model_dir, is_combined), _.var_map());
}

void Program::SetInputs(const std::vector<Variable>& xs) {
Expand Down Expand Up @@ -131,6 +266,14 @@ Variable Program::relu6(const Variable& a) {
AppendInstruction(instr);
return instr.GetOutput(0);
}

Variable Program::scale(const Variable& a, float ratio) {
Instruction instr("scale", {a});
instr.SetAttr("scale", ratio);
AppendInstruction(instr);
return instr.GetOutput(0);
}

Variable Program::mul(
const Variable& a, const Variable& b, bool trans_a, bool trans_b, int x_num_col_dims, int y_num_col_dims) {
Instruction instr("mul", {a, b});
Expand Down
19 changes: 15 additions & 4 deletions cinn/frontend/syntax.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "cinn/common/object.h"
#include "cinn/common/type.h"
#include "cinn/hlir/framework/node.h"
#include "cinn/hlir/framework/scope.h"

namespace cinn {
namespace frontend {
Expand All @@ -36,12 +37,14 @@ struct _Variable_ : public common::Object {
struct Variable : public common::Shared<_Variable_> {
/**
* Constructor.
* @param id The identifier of the variable, if null, a random ID will be assigned.
* @param id_hint The identifier of the variable, if null, a random ID will be assigned.
*/
explicit Variable(std::string_view id = "") : common::Shared<_Variable_>(common::make_shared<_Variable_>()) {
get()->id = id.empty() ? common::Context::Global().NewName("var") : id;
explicit Variable(std::string_view id_hint = "") : common::Shared<_Variable_>(common::make_shared<_Variable_>()) {
get()->id = id_hint.empty() ? common::Context::Global().NewName("var") : id_hint;
}

void set_id(const std::string& id) { operator->()->id = id; }

_Variable_* operator->() { return get(); }
const _Variable_* operator->() const { return get(); }
};
Expand Down Expand Up @@ -180,6 +183,8 @@ struct Program {
Variable relu(const Variable& a);
Variable relu6(const Variable& a);

Variable scale(const Variable& a, float ratio);

/**
* The convolution2D layer calculates the output based on the input, filter
* and strides, paddings, dilations, groups parameters.
Expand Down Expand Up @@ -231,7 +236,13 @@ struct Program {
std::vector<Variable> inputs_;
};

void LoadPaddleProgram(const std::string& model_dir, bool is_combined);
/**
* Load a Paddle model and return a frontend program.
* @param model_dir The directory of the model.
* @param is_combined Whether the parameters in the Paddle model is combined.
*/
std::tuple<std::unique_ptr<Program>, std::unordered_map<std::string, Variable>> LoadPaddleProgram(
const std::string& model_dir, hlir::framework::Scope* scope, bool is_combined);

std::ostream& operator<<(std::ostream& os, const Variable& x);
std::ostream& operator<<(std::ostream& os, const Instruction& instr);
Expand Down
23 changes: 23 additions & 0 deletions cinn/frontend/syntax_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,13 @@
#include "cinn/hlir/op/use_ops.h"
#include "cinn/hlir/pass/use_pass.h"

DEFINE_string(model_dir, "", "");

namespace cinn {
namespace frontend {

using hlir::framework::Scope;

std::unique_ptr<Program> CreateAddProgram() {
const int M = 32;
const int N = 24;
Expand Down Expand Up @@ -135,5 +139,24 @@ TEST(syntax, program_execute_fc) {
runtime_program->Execute();
}

// Load a simple Paddle model, execute it
TEST(load_paddle_model, fc_execute) {
auto scope = std::make_shared<Scope>();

auto [program, var_map] = LoadPaddleProgram(FLAGS_model_dir, scope.get(), false /*is_combined*/);
var_map["a"]->shape = {20, 100};
program->SetInputs({var_map["a"]});
program->Validate();

auto graph = std::make_shared<hlir::framework::Graph>(*program);

hlir::framework::ApplyPass(graph.get(), "InferShape");
Target target = common::DefaultHostTarget();
scope = BuildScope(target, graph, scope);

hlir::framework::GraphCompiler gc(target, scope, graph);
auto runtime_program = gc.Build();
}

} // namespace frontend
} // namespace cinn
2 changes: 1 addition & 1 deletion cinn/hlir/framework/graph.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ namespace hlir {
namespace framework {

Graph::Graph(const frontend::Program& prog) {
std::unordered_map<std::string, std::vector<int>> shape_dict;
std::unordered_map<std::string, shape_t> shape_dict;
std::unordered_map<std::string, common::Type> dtype_dict;
int counter = 0;
for (size_t i = 0; i < prog.size(); i++) {
Expand Down
Loading

0 comments on commit 34ffb2b

Please sign in to comment.