Skip to content

Commit

Permalink
Merge pull request #6 from mvafin/mvafin/composed_weights
Browse files Browse the repository at this point in the history
Read model with composed weights
  • Loading branch information
slyalin authored Apr 2, 2021
2 parents 658ae1e + 9bcdf79 commit fd64d1d
Show file tree
Hide file tree
Showing 12 changed files with 314 additions and 39 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#pragma once

#include <frontend_manager/frontend_manager.hpp>
#include <fstream>

#include "place.hpp"

Expand All @@ -29,11 +30,14 @@ class NGRAPH_API InputModelPDPD : public InputModel
{
// TODO: replace it by already deserialized proto hidden under some Impl class
// TODO: avoid using explicit format-dependent data stuctures here, hide it under some Impl class
std::string path;


friend class FrontEndPDPD;

public:
std::string path;
std::string model_file;
std::ifstream weights_stream;
bool weights_composed = false;

InputModelPDPD (const std::string& _path) : path(_path) {}
};
Expand Down
95 changes: 68 additions & 27 deletions ngraph/frontend/paddlepaddle/src/frontend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,29 +77,39 @@ make_ng_node(std::map<std::string, google::protobuf::RepeatedPtrField<std::strin
return outputs[0].get_node_shared_ptr();
}

std::shared_ptr<ngraph::opset6::Constant>
read_tensor(const paddle::framework::proto::VarDesc &var, const std::string &model_dir) {
std::shared_ptr<ngraph::opset6::Constant> read_tensor(const paddle::framework::proto::VarDesc& var,
std::shared_ptr<ngraph::frontend::InputModelPDPD> model)
{
std::cout << "Reading tensor " << var.name() << std::endl;
MY_ASSERT(var.type().type() == paddle::framework::proto::VarType::LOD_TENSOR);
auto tensor = var.type().lod_tensor().tensor();
auto tensor_length = std::accumulate(
tensor.dims().cbegin(), tensor.dims().cend(), 1, std::multiplies<int64_t>());
std::vector<float> tensor_data(tensor_length, 0);

std::ifstream is(model_dir + "/" + var.name(), std::ios::in | std::ifstream::binary);
if (!is || !is.is_open()) {
std::cout << "File not opened" << std::endl;
std::ifstream is;
std::ifstream* stream_ptr;
if (model->weights_composed) {
stream_ptr = &model->weights_stream;
} else {
is = std::ifstream(model->path + "/" + var.name(), std::ios::in | std::ifstream::binary);
if (!is || !is.is_open())
{
std::cout << "File not opened" << std::endl;
}
stream_ptr = &is;
}
// get length of file:
is.seekg(0, std::ios::end);
auto length = is.tellg();
auto tensor_length = std::accumulate(tensor.dims().cbegin(), tensor.dims().cend(), 1,
std::multiplies<int64_t>());
std::cout << "length: " << length << ", ten_len: " << tensor_length << std::endl;
is.seekg((size_t) length - tensor_length * 4, std::ios::beg);
std::vector<char> leading_zeros(16, 0);
stream_ptr->read(&leading_zeros[0], 16);
uint32_t dims_len = 0;
stream_ptr->read(reinterpret_cast<char*>(&dims_len), 4);
std::vector<char> dims_struct(dims_len, 0);
stream_ptr->read(&dims_struct[0], dims_len);
stream_ptr->read(reinterpret_cast<char*>(&tensor_data[0]), tensor_length * 4);

std::vector<float> tensor_data(tensor_length, 0);
is.read(reinterpret_cast<char *>(&tensor_data[0]), tensor_length * 4);
is.close();
auto shape = std::vector<size_t>(tensor.dims().cbegin(), tensor.dims().cend());
return ngraph::opset6::Constant::create(ngraph::element::f32, ngraph::Shape(shape), tensor_data);
return ngraph::opset6::Constant::create(
ngraph::element::f32, ngraph::Shape(shape), tensor_data);
}

bool endsWith(const std::string &str, const std::string &suffix) {
Expand All @@ -109,30 +119,40 @@ bool endsWith(const std::string &str, const std::string &suffix) {
return false;
}

std::shared_ptr<ngraph::Function> convert_model(const std::string &model_dir) {
std::cout << "Convert Model Start" << std::endl;
std::shared_ptr<ngraph::Function>
convert_model(std::shared_ptr<ngraph::frontend::InputModelPDPD> model)
{
std::cout << "Convert Model Start" << std::endl;

paddle::framework::proto::ProgramDesc fw_model;
std::ifstream pb_stream(model_dir + "/__model__", std::ios::binary);
std::ifstream pb_stream(model->model_file, std::ios::binary);
std::cout << "Model Parsed: " << fw_model.ParseFromIstream(&pb_stream) << std::endl;

std::map<std::string, std::shared_ptr<ngraph::Node>> nodes_dict;
ngraph::ParameterVector parameter_nodes;
ngraph::ResultVector result_nodes;

std::cout << "Blocks number: " << fw_model.blocks().size() << std::endl;
const auto &global_block = fw_model.blocks()[0];
for (const auto &var : global_block.vars()) {
if (endsWith(var.name(), "feed") || endsWith(var.name(), "fetch"))
const auto& global_block = fw_model.blocks()[0];
// We need to read variables in sorted by name order. This is the order variables written in composed file.
std::map<std::string, paddle::framework::proto::VarDesc> sorted_vars;
for (auto& var : global_block.vars())
{
sorted_vars[var.name()] = var;
}
for (const auto& name_var : sorted_vars)
{
if (endsWith(name_var.first, "feed") || endsWith(name_var.first, "fetch"))
continue;
if (!var.persistable())
if (!name_var.second.persistable())
continue;
nodes_dict[var.name()] = read_tensor(var, model_dir);
nodes_dict[name_var.first] = read_tensor(name_var.second, model);
}
std::cout << "Reading consts finished" << std::endl;

std::map<std::string, CreatorFunction> CREATORS_MAP = get_supported_ops();

for (const auto &block : fw_model.blocks()) {
for (const auto& block : fw_model.blocks()) {
std::map<std::string, paddle::framework::proto::VarType> vars_dict;
for (const auto &var : block.vars()) {
vars_dict[var.name()] = var.type();
Expand All @@ -159,6 +179,7 @@ std::shared_ptr<ngraph::Function> convert_model(const std::string &model_dir) {
auto dtype = tensor_desc.data_type();
std::vector<size_t> shape;
// set all -1 dims to 1
// TODO: remove when input shape can be specified
for (auto dim : tensor_desc.dims()) {
if (dim >= 0) {
shape.push_back(dim);
Expand Down Expand Up @@ -196,9 +217,29 @@ std::shared_ptr<ngraph::Function> convert_model(const std::string &model_dir) {
}

std::shared_ptr<ngraph::Function> ngraph::frontend::FrontEndPDPD::convert(InputModel::Ptr model) const {
std::string path = std::dynamic_pointer_cast<ngraph::frontend::InputModelPDPD>(model)->path;
std::cerr << "[ INFO ] PFrontEndPDPD::convert invoked\n";
auto f = pdpd::convert_model(path);
auto pdpd_model = std::dynamic_pointer_cast<ngraph::frontend::InputModelPDPD>(model);
std::string ext = ".pdmodel";
if (pdpd_model->path.length() >= ext.length() &&
(0 ==
pdpd_model->path.compare(pdpd_model->path.length() - ext.length(), ext.length(), ext)))
{
pdpd_model->weights_composed = true;
pdpd_model->model_file = pdpd_model->path;
auto weights_file =
pdpd_model->path.replace(pdpd_model->path.size() - ext.size(), ext.size(), ".pdiparams");
pdpd_model->weights_stream = std::ifstream(weights_file, std::ios::binary);
if (!pdpd_model->weights_stream || !pdpd_model->weights_stream.is_open())
{
std::cout << "File not opened" << std::endl;
}
}
else
{
pdpd_model->weights_composed = false;
pdpd_model->model_file = pdpd_model->path + "/__model__";
}
auto f = pdpd::convert_model(pdpd_model);
std::cerr << "[ INFO ] Resulting nGraph function contains " << f->get_ops().size() << "\n";
return f;
}
Expand Down
1 change: 1 addition & 0 deletions ngraph/frontend/paddlepaddle/src/node_context.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ class NodeContext
auto found = name_map.find(name);
if(found != name_map.end())
return !found->second.empty();
return false;
}

size_t get_ng_input_size (const std::string& name) const { return name_map.at(name).size(); }
Expand Down
40 changes: 40 additions & 0 deletions ngraph/frontend/paddlepaddle/src/op/matmul.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
//*****************************************************************************
// Copyright 2017-2021 Intel Corporation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//*****************************************************************************

#include <ngraph/opsets/opset6.hpp>
#include "matmul.hpp"
#include "utility.hpp"

namespace ngraph {
namespace frontend {
namespace pdpd {
namespace op {

OutputVector matmul(const NodeContext& node) {
auto x = node.get_ng_input("X");
auto y = node.get_ng_input("Y");
auto alpha = node.get_attribute<float>("alpha");
auto transpose_a = node.get_attribute<bool>("transpose_a");
auto transpose_b = node.get_attribute<bool>("transpose_b");
auto mm = std::make_shared<ngraph::opset6::MatMul>(x, y, transpose_a, transpose_b);
auto alpha_node = ngraph::opset6::Constant::create(ngraph::element::f32, {1}, {alpha});
return {std::make_shared<ngraph::opset6::Multiply>(mm, alpha_node)};
}

} // namespace op
} // namespace pdpd
} // namespace frontend
} // namespace ngraph
30 changes: 30 additions & 0 deletions ngraph/frontend/paddlepaddle/src/op/matmul.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
//*****************************************************************************
// Copyright 2017-2021 Intel Corporation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//*****************************************************************************

#pragma once
#include "node_context.hpp"

namespace ngraph {
namespace frontend {
namespace pdpd {
namespace op {

OutputVector matmul(const NodeContext& node);

} // namespace op
} // namespace pdpd
} // namespace frontend
} // namespace ngraph
16 changes: 13 additions & 3 deletions ngraph/frontend/paddlepaddle/src/op/pool2d.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,17 +27,27 @@ OutputVector pool2d (const NodeContext& node) {
auto data = node.get_ng_input("X");
auto pooling_type = node.get_attribute<std::string>("pooling_type");
auto global_pooling = node.get_attribute<bool>("global_pooling");
auto adaptive = node.get_attribute<bool>("adaptive");
auto kernel_shape = node.get_attribute<std::vector<int32_t>>("ksize");
if (pooling_type == "max" && !global_pooling) {
auto strides = node.get_attribute<std::vector<int32_t>>("strides");
auto paddings = node.get_attribute<std::vector<int32_t>>("paddings");
auto kernel_shape = node.get_attribute<std::vector<int32_t>>("ksize");
auto rounding_type = node.get_attribute<bool>("ceil_mode")
? ngraph::op::RoundingType::CEIL
: ngraph::op::RoundingType::FLOOR;
return {std::make_shared<ngraph::opset6::MaxPool>(
data,
ngraph::Strides(strides.begin(), strides.end()),
ngraph::Shape(paddings.begin(), paddings.end()),
ngraph::Shape(paddings.begin(), paddings.end()),
ngraph::Shape(kernel_shape.begin(), kernel_shape.end()))};
} else if (pooling_type == "avg" && global_pooling) {
ngraph::Shape(kernel_shape.begin(), kernel_shape.end()),
rounding_type)};
}
else if (pooling_type == "avg" &&
(global_pooling || adaptive && all_of(kernel_shape.begin(),
kernel_shape.end(),
[](int32_t s) { return s == 1; })))
{
// TODO : resolve axes according to rank
auto axes = ngraph::opset6::Constant::create(ngraph::element::i64, {2}, {2, 3});
return {std::make_shared<ngraph::opset6::ReduceMean>(data, axes, true)};
Expand Down
41 changes: 41 additions & 0 deletions ngraph/frontend/paddlepaddle/src/op/reshape2.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
//*****************************************************************************
// Copyright 2017-2021 Intel Corporation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//*****************************************************************************

#include <ngraph/opsets/opset6.hpp>
#include "reshape2.hpp"
#include "utility.hpp"

namespace ngraph {
namespace frontend {
namespace pdpd {
namespace op {

OutputVector reshape2(const NodeContext& node) {
auto data = node.get_ng_input("X");
if (!node.has_ng_input("Shape") && !node.has_ng_input("ShapeTensor"))
{
auto shape_attr = node.get_attribute<std::vector<int32_t>>("shape");
auto shape_node = ngraph::opset6::Constant::create(ngraph::element::i32, {shape_attr.size()}, shape_attr);
return {std::make_shared<ngraph::opset6::Reshape>(data, shape_node, true)};
} else {
NOT_IMPLEMENTED("reshape2 with shape as input");
}
}

} // namespace op
} // namespace pdpd
} // namespace frontend
} // namespace ngraph
30 changes: 30 additions & 0 deletions ngraph/frontend/paddlepaddle/src/op/reshape2.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
//*****************************************************************************
// Copyright 2017-2021 Intel Corporation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//*****************************************************************************

#pragma once
#include "node_context.hpp"

namespace ngraph {
namespace frontend {
namespace pdpd {
namespace op {

OutputVector reshape2(const NodeContext& node);

} // namespace op
} // namespace pdpd
} // namespace frontend
} // namespace ngraph
39 changes: 39 additions & 0 deletions ngraph/frontend/paddlepaddle/src/op/softmax.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
//*****************************************************************************
// Copyright 2017-2021 Intel Corporation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//*****************************************************************************

#include <ngraph/opsets/opset6.hpp>
#include "softmax.hpp"
#include "utility.hpp"

namespace ngraph {
namespace frontend {
namespace pdpd {
namespace op {
OutputVector softmax(const NodeContext& node) {
auto data = node.get_ng_input("X");
auto axis = node.get_attribute<int32_t>("axis");
if (axis < 0)
{
MY_ASSERT(data.get_partial_shape().rank().is_static(), "Softmax rank must be static");
auto data_rank = data.get_partial_shape().rank().get_length();
axis = data_rank + axis;
}
return {std::make_shared<ngraph::opset6::Softmax>(data, axis)};
}
} // namespace op
} // namespace pdpd
} // namespace frontend
} // namespace ngraph
Loading

0 comments on commit fd64d1d

Please sign in to comment.