From c59f569f90b28ee8c907cb51d05130e1f1d0aad3 Mon Sep 17 00:00:00 2001 From: qiaolongfei Date: Mon, 6 Nov 2017 09:51:02 -0800 Subject: [PATCH 01/27] init trieconcat_op --- paddle/operators/trieconcat_op.cc | 108 ++++++++++++++++++ paddle/operators/trieconcat_op.h | 21 ++++ .../tests/test_understand_sentiment_conv.py | 2 + 3 files changed, 131 insertions(+) create mode 100644 paddle/operators/trieconcat_op.cc create mode 100644 paddle/operators/trieconcat_op.h diff --git a/paddle/operators/trieconcat_op.cc b/paddle/operators/trieconcat_op.cc new file mode 100644 index 0000000000000..542bccbcf340e --- /dev/null +++ b/paddle/operators/trieconcat_op.cc @@ -0,0 +1,108 @@ +/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserve. + +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 "paddle/operators/trieconcat_op.h" + +namespace paddle { +namespace operators { + +using value_type = float; +using LoDTensor = framework::LoDTensor; + +void PackTwoLoDTensor(const LoDTensor &pre, const LoDTensor &cur, + std::vector> *ended_result, + std::vector> *extending_result) { + PADDLE_ENFORCE_EQ(pre.lod()[0].size(), cur.lod()[0].size(), + "the number of source sentences size should be the same"); + PADDLE_ENFORCE_EQ( + pre.lod()[1].size(), cur.lod()[1].size(), + "the number of prefix and it's Candidate words should be the same"); + const size_t batch_size = pre.lod()[0].size() - 1; + for (size_t i = 0; i < batch_size; ++i) { + int64_t source_start = pre.lod()[0][i]; + int64_t source_end = pre.lod()[0][i + 1]; + } +} + +class TrieConcatOp : public framework::OperatorBase { + public: + TrieConcatOp(const std::string &type, + const framework::VariableNameMap &inputs, + const framework::VariableNameMap &outputs, + const framework::AttributeMap &attrs) + : OperatorBase(type, inputs, outputs, attrs) {} + void Run(const framework::Scope &scope, + const platform::DeviceContext &dev_ctx) const override { + // TODO(qiao) trie concat a vector of LodTensors to a LodTensor + framework::ExecutionContext ctx(*this, scope, dev_ctx); + const std::vector *input = + ctx.Input>("X"); + const size_t step_num = input->size(); + PADDLE_ENFORCE_LT(step_num, 0, "beam search stop should be larger than 0"); + for (auto &in : *input) { + PADDLE_ENFORCE_EQ(in.lod().size(), 2UL, "Level of LodTensor should be 2"); + } + // prepare output + auto *output = ctx.Output("Out"); + output->mutable_data(ctx.GetPlace()); + + const size_t batch_size = input->at(0).lod()[0].size() - 1; + + std::vector> ended_result; + ended_result.reserve(batch_size); + std::vector> extending_result; + extending_result.reserve(batch_size); + } +}; + +class TrieConcatOpProtoMaker : public framework::OpProtoAndCheckerMaker { + public: + TrieConcatOpProtoMaker(framework::OpProto *proto, + framework::OpAttrChecker *op_checker) + : OpProtoAndCheckerMaker(proto, op_checker) { + AddInput("X", "(vector)The input vector of tensors"); + AddOutput("Out", "(Tensor)The output tensor"); + AddComment(R"DOC( +The Tensor will be permuted according to the axis values given. +)DOC"); + } +}; + +class TrieConcatInferShape : public framework::InferShapeBase { + public: + void operator()(framework::InferShapeContext *context) const override { + PADDLE_ENFORCE(context->HasInput("X"), "TrieConcatOp must has input X"); + PADDLE_ENFORCE(context->HasOutput("out"), + "TrieConcatOp must has output Out"); + } +}; + +class TrieConcatInferVarType : public framework::VarTypeInference { + public: + void operator()(const framework::OpDescBind &op_desc, + framework::BlockDescBind *block) const override { + for (auto &o : op_desc.Output("Out")) { + block->Var(o)->SetType(framework::VarDesc::LOD_TENSOR); + } + } +}; + +} // namespace operators +} // namespace paddle + +REGISTER_OPERATOR(trie_concat, paddle::operators::TrieConcatOp, + paddle::operators::TrieConcatOpProtoMaker, + paddle::operators::TrieConcatInferShape, + paddle::operators::TrieConcatInferVarType, + paddle::framework::EmptyGradOpMaker); diff --git a/paddle/operators/trieconcat_op.h b/paddle/operators/trieconcat_op.h new file mode 100644 index 0000000000000..31b076d1c8a09 --- /dev/null +++ b/paddle/operators/trieconcat_op.h @@ -0,0 +1,21 @@ +/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserve. + +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 "paddle/framework/op_registry.h" + +namespace paddle { +namespace operators {} // namespace operators +} // namespace paddle diff --git a/python/paddle/v2/framework/tests/test_understand_sentiment_conv.py b/python/paddle/v2/framework/tests/test_understand_sentiment_conv.py index dcbb34ccfcff6..ff01e909f6d00 100644 --- a/python/paddle/v2/framework/tests/test_understand_sentiment_conv.py +++ b/python/paddle/v2/framework/tests/test_understand_sentiment_conv.py @@ -63,6 +63,8 @@ def main(): cost, acc = convolution_net(input_dim=dict_dim, class_dim=class_dim) + print(g_program) + train_data = paddle.batch( paddle.reader.shuffle( paddle.dataset.imdb.train(word_dict), buf_size=1000), From cf4287bae811b6f2de1aa1990f9a9745cdbc8ae9 Mon Sep 17 00:00:00 2001 From: qiaolongfei Date: Mon, 6 Nov 2017 22:25:13 -0800 Subject: [PATCH 02/27] add basic implementation --- paddle/operators/trieconcat_op.cc | 208 ++++++++++++++++++++++++------ 1 file changed, 167 insertions(+), 41 deletions(-) diff --git a/paddle/operators/trieconcat_op.cc b/paddle/operators/trieconcat_op.cc index 542bccbcf340e..04d6b5a141457 100644 --- a/paddle/operators/trieconcat_op.cc +++ b/paddle/operators/trieconcat_op.cc @@ -20,68 +20,194 @@ namespace operators { using value_type = float; using LoDTensor = framework::LoDTensor; -void PackTwoLoDTensor(const LoDTensor &pre, const LoDTensor &cur, - std::vector> *ended_result, - std::vector> *extending_result) { - PADDLE_ENFORCE_EQ(pre.lod()[0].size(), cur.lod()[0].size(), - "the number of source sentences size should be the same"); - PADDLE_ENFORCE_EQ( - pre.lod()[1].size(), cur.lod()[1].size(), - "the number of prefix and it's Candidate words should be the same"); - const size_t batch_size = pre.lod()[0].size() - 1; - for (size_t i = 0; i < batch_size; ++i) { - int64_t source_start = pre.lod()[0][i]; - int64_t source_end = pre.lod()[0][i + 1]; +const int64_t kInitLength = 1024; +const int64_t kEndId = 0; + +struct BeamNode { + BeamNode(int64_t word_id, float prob) : word_id_(word_id), prob_(prob) {} + + BeamNode* father_ = nullptr; + std::vector kids_; + int64_t word_id_; + float prob_; +}; + +void RemoveFromEnd(BeamNode* end) { + PADDLE_ENFORCE_EQ(end->kids_.size(), 0UL, "end should not have any kids"); + auto* father = end->father_; + if (father != nullptr) { + auto kids = father->kids_; + kids.erase(std::remove(kids.begin(), kids.end(), end), kids.end()); + delete end; + if (father->kids_.size() == 0) { + RemoveFromEnd(father); + } } } +template +struct AppendToLoDTensor { + void operator()(const std::vector data, LoDTensor* dst) { + std::vector sentances = dst->lod()[1]; + T* dst_data = + dst->data() + (sentances[sentances.size() - 1] - 1) * sizeof(T); + memcpy(dst_data, &data, data.size() * sizeof(int)); + dst->mutable_lod()->at(0).push_back(sentances[sentances.size() - 1] + + data.size()); + } +}; + +class PackTwoBeamStepOut { + public: + std::vector operator()(size_t batch_start, + const std::vector& pre_results, + const LoDTensor& cur_ids, + const LoDTensor& cur_probs, + LoDTensor* result_seq_ids, + LoDTensor* result_probs) { + // PADDLE_ENFORCE_EQ(cur_ids.lod(), cur_probs.lod(), + // "lod of ids and probs should be the same"); + std::vector result; + std::vector candidate_offset = cur_ids.lod()[0]; + for (size_t i = 0; i < pre_results.size(); ++i) { + size_t candidate_start = candidate_offset[batch_start + i]; + size_t candidate_end = candidate_offset[batch_start + i + 1]; + if (candidate_start == candidate_end) { + VLOG(3) << "this prefix does not have candidate"; + auto* prefix_end = pre_results[i]; + if (prefix_end->word_id_ == kEndId) { + VLOG(3) << "find an end Id, append to result tensor"; + std::vector sequence_ids; + std::vector sequence_probs; + BeamNode* tmp = prefix_end; + while (tmp != nullptr) { + sequence_ids.push_back(tmp->word_id_); + sequence_probs.push_back(tmp->prob_); + tmp = tmp->father_; + } + // copy ended sentance to result lod tensor. + AppendToLoDTensor sequence_id_appender; + sequence_id_appender(sequence_ids, result_seq_ids); + AppendToLoDTensor sequence_prob_appender; + sequence_prob_appender(sequence_probs, result_probs); + } else { + VLOG(3) << "this sentence has no more candidate, prune it"; + } + // remove from Beam Tree + RemoveFromEnd(prefix_end); + } else { + for (size_t candidate_index = candidate_start; + candidate_index < candidate_end; ++candidate_index) { + int64_t word_id = cur_ids.data()[candidate_index]; + PADDLE_ENFORCE_NE(word_id, kEndId, + "End id should not have candidate anymore"); + float prob = cur_probs.data()[candidate_index]; + auto* candidate = new BeamNode(word_id, prob); + auto* prefix = pre_results[i]; + candidate->father_ = prefix; + prefix->kids_.push_back(candidate); + result.push_back(candidate); + } + } + } + return result; + } +}; + class TrieConcatOp : public framework::OperatorBase { public: - TrieConcatOp(const std::string &type, - const framework::VariableNameMap &inputs, - const framework::VariableNameMap &outputs, - const framework::AttributeMap &attrs) + TrieConcatOp(const std::string& type, + const framework::VariableNameMap& inputs, + const framework::VariableNameMap& outputs, + const framework::AttributeMap& attrs) : OperatorBase(type, inputs, outputs, attrs) {} - void Run(const framework::Scope &scope, - const platform::DeviceContext &dev_ctx) const override { - // TODO(qiao) trie concat a vector of LodTensors to a LodTensor + void Run(const framework::Scope& scope, + const platform::DeviceContext& dev_ctx) const override { framework::ExecutionContext ctx(*this, scope, dev_ctx); - const std::vector *input = - ctx.Input>("X"); - const size_t step_num = input->size(); - PADDLE_ENFORCE_LT(step_num, 0, "beam search stop should be larger than 0"); - for (auto &in : *input) { - PADDLE_ENFORCE_EQ(in.lod().size(), 2UL, "Level of LodTensor should be 2"); + const std::vector* ids = + ctx.Input>("Ids"); + const std::vector* scores = + ctx.Input>("Scores"); + const size_t step_num = ids->size(); + PADDLE_ENFORCE_LT(step_num, 0, "beam search steps should be larger than 0"); + const size_t batch_size = ids->at(0).lod()[0].size() - 1; + PADDLE_ENFORCE_LT(batch_size, 0UL, "batch size should be larger than 0"); + + for (size_t i = 0; i < step_num; ++i) { + PADDLE_ENFORCE_EQ(ids->at(i).lod().size(), 2UL, + "Level of LodTensor should be 2"); + // PADDLE_ENFORCE_EQ(ids->at(i).lod(), scores->at(i).lod(), + // "score and ids should have the same lod info"); } + // prepare output - auto *output = ctx.Output("Out"); - output->mutable_data(ctx.GetPlace()); + LoDTensor* sentenceIds = ctx.Output("SentenceIds"); + LoDTensor* sentenceScores = ctx.Output("SentenceScores"); - const size_t batch_size = input->at(0).lod()[0].size() - 1; + sentenceIds->Resize({kInitLength}); + sentenceIds->mutable_data(ids->at(0).place()); + sentenceScores->Resize({kInitLength}); + sentenceScores->mutable_data(ids->at(0).place()); + + std::vector> batch_beam_nodes; + batch_beam_nodes.reserve(batch_size); + for (size_t batch_idx = 0; batch_idx < batch_size; ++batch_idx) { + std::vector beam_nodes; + size_t batch_start = ids->at(0).lod()[0][batch_idx]; + size_t batch_end = ids->at(0).lod()[0][batch_idx + 1]; + for (size_t word_id_idx = batch_start; word_id_idx < batch_end; + ++word_id_idx) { + beam_nodes.push_back( + new BeamNode(ids->at(0).data()[word_id_idx], + scores->at(0).data()[word_id_idx])); + } + batch_beam_nodes[batch_idx] = beam_nodes; + } + + // pack all step result together + PackTwoBeamStepOut packer; + for (size_t step_id = 1; step_id < step_num; ++step_id) { + for (size_t batch_idx = 0; batch_idx < batch_size; ++batch_idx) { + size_t batch_start = ids->at(step_id).lod()[0][batch_idx]; + std::vector result = + packer(batch_start, batch_beam_nodes[batch_idx], ids->at(step_id), + scores->at(step_id), sentenceIds, sentenceScores); + batch_beam_nodes[batch_idx] = result; + } + } - std::vector> ended_result; - ended_result.reserve(batch_size); - std::vector> extending_result; - extending_result.reserve(batch_size); + // process the last result + // batch_beam_nodes to result tensor } }; class TrieConcatOpProtoMaker : public framework::OpProtoAndCheckerMaker { public: - TrieConcatOpProtoMaker(framework::OpProto *proto, - framework::OpAttrChecker *op_checker) + TrieConcatOpProtoMaker(framework::OpProto* proto, + framework::OpAttrChecker* op_checker) : OpProtoAndCheckerMaker(proto, op_checker) { - AddInput("X", "(vector)The input vector of tensors"); - AddOutput("Out", "(Tensor)The output tensor"); + AddInput("Ids", + "(vector) " + "score of the candidate words in each step"); + AddInput("Scores", + "(vector) " + "score of the candidate words in each step"); + AddOutput("SentenceIds", + "(LodTensor)" + "All possible result sentences of word ids"); + AddOutput("SentenceScores", + "(LodTensor)" + "" + "All possible result sentences of word scores"); AddComment(R"DOC( -The Tensor will be permuted according to the axis values given. +Pack the result of Beam search op into SentenceIds and SentenceScores. )DOC"); } }; class TrieConcatInferShape : public framework::InferShapeBase { public: - void operator()(framework::InferShapeContext *context) const override { + void operator()(framework::InferShapeContext* context) const override { PADDLE_ENFORCE(context->HasInput("X"), "TrieConcatOp must has input X"); PADDLE_ENFORCE(context->HasOutput("out"), "TrieConcatOp must has output Out"); @@ -90,9 +216,9 @@ class TrieConcatInferShape : public framework::InferShapeBase { class TrieConcatInferVarType : public framework::VarTypeInference { public: - void operator()(const framework::OpDescBind &op_desc, - framework::BlockDescBind *block) const override { - for (auto &o : op_desc.Output("Out")) { + void operator()(const framework::OpDescBind& op_desc, + framework::BlockDescBind* block) const override { + for (auto& o : op_desc.Output("Out")) { block->Var(o)->SetType(framework::VarDesc::LOD_TENSOR); } } From e0bdab92c0fb73fa1dcab0011a2c3651216b9c4d Mon Sep 17 00:00:00 2001 From: qiaolongfei Date: Tue, 7 Nov 2017 10:19:25 -0800 Subject: [PATCH 03/27] add test --- paddle/framework/tensor_test.cc | 20 ++++++++ paddle/operators/trieconcat_op.cc | 64 +++++++++++++++----------- paddle/operators/trieconcat_op_test.cc | 22 +++++++++ 3 files changed, 79 insertions(+), 27 deletions(-) create mode 100644 paddle/operators/trieconcat_op_test.cc diff --git a/paddle/framework/tensor_test.cc b/paddle/framework/tensor_test.cc index 1bb0fb71b0799..18309103a4125 100644 --- a/paddle/framework/tensor_test.cc +++ b/paddle/framework/tensor_test.cc @@ -267,6 +267,26 @@ TEST(Tensor, CopyFrom) { #endif } +TEST(Tensor, Append) { + using namespace paddle::framework; + using namespace paddle::platform; + { + Tensor src_tensor; + double* src_ptr = + src_tensor.mutable_data(make_ddim({3, 3}), CPUPlace()); + + double arr[9] = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + double arr1[4] = {1, 2, 3, 4}; + double arr2[5] = {5, 6, 7, 8, 9}; + memcpy(src_ptr, arr1, 4 * sizeof(double)); + memcpy(src_ptr + 4, arr2, 5 * sizeof(double)); + + for (size_t i = 0; i < 9; ++i) { + EXPECT_EQ(src_ptr[i], arr[i]); + } + } +} + TEST(Tensor, CopyFromVector) { using namespace paddle::framework; using namespace paddle::platform; diff --git a/paddle/operators/trieconcat_op.cc b/paddle/operators/trieconcat_op.cc index 04d6b5a141457..0d5c00c626850 100644 --- a/paddle/operators/trieconcat_op.cc +++ b/paddle/operators/trieconcat_op.cc @@ -45,15 +45,27 @@ void RemoveFromEnd(BeamNode* end) { } } -template -struct AppendToLoDTensor { - void operator()(const std::vector data, LoDTensor* dst) { +struct AppendBeamNodeToLoDTensor { + template + void AppendVector(const std::vector data, LoDTensor* dst) { std::vector sentances = dst->lod()[1]; - T* dst_data = - dst->data() + (sentances[sentances.size() - 1] - 1) * sizeof(T); + // TODO(check) + T* dst_data = dst->data() + sentances[sentances.size() - 1]; memcpy(dst_data, &data, data.size() * sizeof(int)); - dst->mutable_lod()->at(0).push_back(sentances[sentances.size() - 1] + - data.size()); + dst->mutable_lod()->at(0).push_back(sentances.back() + data.size()); + } + + void operator()(BeamNode* node, LoDTensor* dst_ids, LoDTensor* dst_probs) { + std::vector sequence_ids; + std::vector sequence_probs; + BeamNode* tmp = node; + while (tmp != nullptr) { + sequence_ids.push_back(tmp->word_id_); + sequence_probs.push_back(tmp->prob_); + tmp = tmp->father_; + } + AppendVector(sequence_ids, dst_ids); + AppendVector(sequence_probs, dst_probs); } }; @@ -77,19 +89,8 @@ class PackTwoBeamStepOut { auto* prefix_end = pre_results[i]; if (prefix_end->word_id_ == kEndId) { VLOG(3) << "find an end Id, append to result tensor"; - std::vector sequence_ids; - std::vector sequence_probs; - BeamNode* tmp = prefix_end; - while (tmp != nullptr) { - sequence_ids.push_back(tmp->word_id_); - sequence_probs.push_back(tmp->prob_); - tmp = tmp->father_; - } - // copy ended sentance to result lod tensor. - AppendToLoDTensor sequence_id_appender; - sequence_id_appender(sequence_ids, result_seq_ids); - AppendToLoDTensor sequence_prob_appender; - sequence_prob_appender(sequence_probs, result_probs); + AppendBeamNodeToLoDTensor appender; + appender(prefix_end, result_seq_ids, result_probs); } else { VLOG(3) << "this sentence has no more candidate, prune it"; } @@ -147,8 +148,9 @@ class TrieConcatOp : public framework::OperatorBase { sentenceIds->Resize({kInitLength}); sentenceIds->mutable_data(ids->at(0).place()); sentenceScores->Resize({kInitLength}); - sentenceScores->mutable_data(ids->at(0).place()); + sentenceScores->mutable_data(ids->at(0).place()); + // beam_nodes for each source sentence. std::vector> batch_beam_nodes; batch_beam_nodes.reserve(batch_size); for (size_t batch_idx = 0; batch_idx < batch_size; ++batch_idx) { @@ -164,20 +166,28 @@ class TrieConcatOp : public framework::OperatorBase { batch_beam_nodes[batch_idx] = beam_nodes; } - // pack all step result together + // pack all steps for one batch first, then another batch PackTwoBeamStepOut packer; - for (size_t step_id = 1; step_id < step_num; ++step_id) { - for (size_t batch_idx = 0; batch_idx < batch_size; ++batch_idx) { + AppendBeamNodeToLoDTensor appender; + for (size_t batch_idx = 0; batch_idx < batch_size; ++batch_idx) { + for (size_t step_id = 1; step_id < step_num; ++step_id) { size_t batch_start = ids->at(step_id).lod()[0][batch_idx]; std::vector result = packer(batch_start, batch_beam_nodes[batch_idx], ids->at(step_id), scores->at(step_id), sentenceIds, sentenceScores); batch_beam_nodes[batch_idx] = result; } - } - // process the last result - // batch_beam_nodes to result tensor + // append last beam_node to result + for (auto* beam_node : batch_beam_nodes[batch_idx]) { + appender(beam_node, sentenceIds, sentenceScores); + } + + // update batch_lod_level + sentenceIds->mutable_lod()->at(0).push_back(sentenceIds->lod()[1].size()); + sentenceScores->mutable_lod()->at(0).push_back( + sentenceScores->lod()[1].size()); + } } }; diff --git a/paddle/operators/trieconcat_op_test.cc b/paddle/operators/trieconcat_op_test.cc new file mode 100644 index 0000000000000..64dcfbda34326 --- /dev/null +++ b/paddle/operators/trieconcat_op_test.cc @@ -0,0 +1,22 @@ +/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserved. + + 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 "" +#include "gtest/gtest.h" +#include "paddle/operators/op_registry.h" + +USE_NO_KERNEL_OP(save); +USE_NO_KERNEL_OP(load); + +TEST(TrieConcatOp, CPU) {} \ No newline at end of file From 067b30edd8ad4e46ff7b4a85e59f9a2e83b89094 Mon Sep 17 00:00:00 2001 From: qiaolongfei Date: Tue, 7 Nov 2017 13:47:34 -0800 Subject: [PATCH 04/27] add more test --- paddle/operators/CMakeLists.txt | 1 + paddle/operators/trieconcat_op.cc | 114 ++-------------- paddle/operators/trieconcat_op.h | 111 +++++++++++++++- paddle/operators/trieconcat_op_test.cc | 173 ++++++++++++++++++++++++- 4 files changed, 287 insertions(+), 112 deletions(-) diff --git a/paddle/operators/CMakeLists.txt b/paddle/operators/CMakeLists.txt index f22f86468db7b..b4f961d50cebc 100644 --- a/paddle/operators/CMakeLists.txt +++ b/paddle/operators/CMakeLists.txt @@ -200,6 +200,7 @@ set(GLOB_OP_LIB ${OP_LIBRARY} CACHE INTERNAL "Global OP library") cc_test(gather_test SRCS gather_test.cc DEPS tensor) cc_test(net_op_test SRCS net_op_test.cc DEPS net_op) cc_test(scatter_test SRCS scatter_test.cc DEPS tensor) +cc_test(trieconcat_op_test SRCS trieconcat_op_test.cc DEPS lod_tensor) cc_test(strided_memcpy_test SRCS strided_memcpy_test.cc DEPS tensor paddle_memory) cc_test(dynamic_recurrent_op_test SRCS dynamic_recurrent_op_test.cc rnn/recurrent_op_utils.cc diff --git a/paddle/operators/trieconcat_op.cc b/paddle/operators/trieconcat_op.cc index 0d5c00c626850..3f9eaa30dbfd5 100644 --- a/paddle/operators/trieconcat_op.cc +++ b/paddle/operators/trieconcat_op.cc @@ -17,104 +17,6 @@ limitations under the License. */ namespace paddle { namespace operators { -using value_type = float; -using LoDTensor = framework::LoDTensor; - -const int64_t kInitLength = 1024; -const int64_t kEndId = 0; - -struct BeamNode { - BeamNode(int64_t word_id, float prob) : word_id_(word_id), prob_(prob) {} - - BeamNode* father_ = nullptr; - std::vector kids_; - int64_t word_id_; - float prob_; -}; - -void RemoveFromEnd(BeamNode* end) { - PADDLE_ENFORCE_EQ(end->kids_.size(), 0UL, "end should not have any kids"); - auto* father = end->father_; - if (father != nullptr) { - auto kids = father->kids_; - kids.erase(std::remove(kids.begin(), kids.end(), end), kids.end()); - delete end; - if (father->kids_.size() == 0) { - RemoveFromEnd(father); - } - } -} - -struct AppendBeamNodeToLoDTensor { - template - void AppendVector(const std::vector data, LoDTensor* dst) { - std::vector sentances = dst->lod()[1]; - // TODO(check) - T* dst_data = dst->data() + sentances[sentances.size() - 1]; - memcpy(dst_data, &data, data.size() * sizeof(int)); - dst->mutable_lod()->at(0).push_back(sentances.back() + data.size()); - } - - void operator()(BeamNode* node, LoDTensor* dst_ids, LoDTensor* dst_probs) { - std::vector sequence_ids; - std::vector sequence_probs; - BeamNode* tmp = node; - while (tmp != nullptr) { - sequence_ids.push_back(tmp->word_id_); - sequence_probs.push_back(tmp->prob_); - tmp = tmp->father_; - } - AppendVector(sequence_ids, dst_ids); - AppendVector(sequence_probs, dst_probs); - } -}; - -class PackTwoBeamStepOut { - public: - std::vector operator()(size_t batch_start, - const std::vector& pre_results, - const LoDTensor& cur_ids, - const LoDTensor& cur_probs, - LoDTensor* result_seq_ids, - LoDTensor* result_probs) { - // PADDLE_ENFORCE_EQ(cur_ids.lod(), cur_probs.lod(), - // "lod of ids and probs should be the same"); - std::vector result; - std::vector candidate_offset = cur_ids.lod()[0]; - for (size_t i = 0; i < pre_results.size(); ++i) { - size_t candidate_start = candidate_offset[batch_start + i]; - size_t candidate_end = candidate_offset[batch_start + i + 1]; - if (candidate_start == candidate_end) { - VLOG(3) << "this prefix does not have candidate"; - auto* prefix_end = pre_results[i]; - if (prefix_end->word_id_ == kEndId) { - VLOG(3) << "find an end Id, append to result tensor"; - AppendBeamNodeToLoDTensor appender; - appender(prefix_end, result_seq_ids, result_probs); - } else { - VLOG(3) << "this sentence has no more candidate, prune it"; - } - // remove from Beam Tree - RemoveFromEnd(prefix_end); - } else { - for (size_t candidate_index = candidate_start; - candidate_index < candidate_end; ++candidate_index) { - int64_t word_id = cur_ids.data()[candidate_index]; - PADDLE_ENFORCE_NE(word_id, kEndId, - "End id should not have candidate anymore"); - float prob = cur_probs.data()[candidate_index]; - auto* candidate = new BeamNode(word_id, prob); - auto* prefix = pre_results[i]; - candidate->father_ = prefix; - prefix->kids_.push_back(candidate); - result.push_back(candidate); - } - } - } - return result; - } -}; - class TrieConcatOp : public framework::OperatorBase { public: TrieConcatOp(const std::string& type, @@ -150,7 +52,8 @@ class TrieConcatOp : public framework::OperatorBase { sentenceScores->Resize({kInitLength}); sentenceScores->mutable_data(ids->at(0).place()); - // beam_nodes for each source sentence. + BeamHelpter beam_helper; + // init beam_nodes for each source sentence. std::vector> batch_beam_nodes; batch_beam_nodes.reserve(batch_size); for (size_t batch_idx = 0; batch_idx < batch_size; ++batch_idx) { @@ -163,24 +66,23 @@ class TrieConcatOp : public framework::OperatorBase { new BeamNode(ids->at(0).data()[word_id_idx], scores->at(0).data()[word_id_idx])); } - batch_beam_nodes[batch_idx] = beam_nodes; + batch_beam_nodes.push_back(beam_nodes); } // pack all steps for one batch first, then another batch - PackTwoBeamStepOut packer; - AppendBeamNodeToLoDTensor appender; for (size_t batch_idx = 0; batch_idx < batch_size; ++batch_idx) { for (size_t step_id = 1; step_id < step_num; ++step_id) { size_t batch_start = ids->at(step_id).lod()[0][batch_idx]; - std::vector result = - packer(batch_start, batch_beam_nodes[batch_idx], ids->at(step_id), - scores->at(step_id), sentenceIds, sentenceScores); + std::vector result = beam_helper.PackTwoBeamStepOut( + batch_start, batch_beam_nodes[batch_idx], ids->at(step_id), + scores->at(step_id), sentenceIds, sentenceScores); batch_beam_nodes[batch_idx] = result; } // append last beam_node to result for (auto* beam_node : batch_beam_nodes[batch_idx]) { - appender(beam_node, sentenceIds, sentenceScores); + beam_helper.AppendBeamNodeToLoDTensor(beam_node, sentenceIds, + sentenceScores); } // update batch_lod_level diff --git a/paddle/operators/trieconcat_op.h b/paddle/operators/trieconcat_op.h index 31b076d1c8a09..5eaebd6ea4761 100644 --- a/paddle/operators/trieconcat_op.h +++ b/paddle/operators/trieconcat_op.h @@ -17,5 +17,114 @@ limitations under the License. */ #include "paddle/framework/op_registry.h" namespace paddle { -namespace operators {} // namespace operators +namespace operators { + +using value_type = float; +using LoDTensor = framework::LoDTensor; + +const int64_t kInitLength = 1024; +const int64_t kEndId = 0; + +struct BeamNode { + BeamNode(int64_t word_id, float prob) : word_id_(word_id), prob_(prob) {} + + void AppendTo(BeamNode* father) { + father_ = father; + father->kids_.push_back(this); + } + + BeamNode* father_ = nullptr; + std::vector kids_; + int64_t word_id_; + float prob_; +}; + +struct BeamHelpter { + // remove this prefix from the beam tree + void RemoveFromEnd(BeamNode* end) { + PADDLE_ENFORCE_EQ(end->kids_.size(), 0UL, "end should not have any kids"); + auto* father = end->father_; + if (father != nullptr) { + // should use reference + auto& kids = father->kids_; + kids.erase(std::remove(kids.begin(), kids.end(), end), kids.end()); + VLOG(3) << "Delete BeamNode with word_id:" << end->word_id_; + delete end; + if (father->kids_.size() == 0) { + RemoveFromEnd(father); + } + } else { + VLOG(3) << "Delete BeamNode root with word_id:" << end->word_id_; + delete end; + } + } + + template + void AppendVector(const std::vector vec, LoDTensor* dst) { + std::vector sentences = dst->lod().at(1); + T* tensor_data = dst->data() + sentences.back(); + memcpy(tensor_data, vec.data(), vec.size() * sizeof(T)); + dst->mutable_lod()->at(1).push_back(sentences.back() + vec.size()); + } + + void AppendBeamNodeToLoDTensor(BeamNode* node, LoDTensor* dst_ids, + LoDTensor* dst_probs) { + std::vector sequence_ids; + std::vector sequence_probs; + BeamNode* tmp = node; + while (tmp != nullptr) { + sequence_ids.push_back(tmp->word_id_); + sequence_probs.push_back(tmp->prob_); + tmp = tmp->father_; + } + + std::reverse(std::begin(sequence_ids), std::end(sequence_ids)); + std::reverse(std::begin(sequence_probs), std::end(sequence_probs)); + + AppendVector(sequence_ids, dst_ids); + AppendVector(sequence_probs, dst_probs); + } + + std::vector PackTwoBeamStepOut( + size_t batch_start, const std::vector& pre_results, + const LoDTensor& cur_ids, const LoDTensor& cur_probs, + LoDTensor* result_seq_ids, LoDTensor* result_probs) { + // PADDLE_ENFORCE_EQ(cur_ids.lod(), cur_probs.lod(), + // "lod of ids and probs should be the same"); + std::vector result; + std::vector candidate_offset = cur_ids.lod()[0]; + for (size_t i = 0; i < pre_results.size(); ++i) { + size_t candidate_start = candidate_offset[batch_start + i]; + size_t candidate_end = candidate_offset[batch_start + i + 1]; + if (candidate_start == candidate_end) { + VLOG(3) << "this prefix does not have candidate"; + auto* prefix_end = pre_results[i]; + if (prefix_end->word_id_ == kEndId) { + VLOG(3) << "find an end Id, append to result tensor"; + AppendBeamNodeToLoDTensor(prefix_end, result_seq_ids, result_probs); + } else { + VLOG(3) << "this sentence has no more candidate, prune it"; + } + // remove from Beam Tree + RemoveFromEnd(prefix_end); + } else { + for (size_t candidate_index = candidate_start; + candidate_index < candidate_end; ++candidate_index) { + int64_t word_id = cur_ids.data()[candidate_index]; + PADDLE_ENFORCE_NE(word_id, kEndId, + "End id should not have candidate anymore"); + float prob = cur_probs.data()[candidate_index]; + auto* candidate = new BeamNode(word_id, prob); + auto* prefix = pre_results[i]; + candidate->father_ = prefix; + prefix->kids_.push_back(candidate); + result.push_back(candidate); + } + } + } + return result; + } +}; + +} // namespace operators } // namespace paddle diff --git a/paddle/operators/trieconcat_op_test.cc b/paddle/operators/trieconcat_op_test.cc index 64dcfbda34326..f561d1a76e775 100644 --- a/paddle/operators/trieconcat_op_test.cc +++ b/paddle/operators/trieconcat_op_test.cc @@ -12,11 +12,174 @@ See the License for the specific language governing permissions and limitations under the License. */ -#include "" +#include "paddle/operators/trieconcat_op.h" #include "gtest/gtest.h" -#include "paddle/operators/op_registry.h" +#include "paddle/framework/lod_tensor.h" +#include "paddle/platform/place.h" -USE_NO_KERNEL_OP(save); -USE_NO_KERNEL_OP(load); +TEST(TrieConcatOp, RemoveFromEnd) { + using BeamHelper = paddle::operators::BeamHelpter; + using BeamNode = paddle::operators::BeamNode; -TEST(TrieConcatOp, CPU) {} \ No newline at end of file + BeamHelper helper; + + BeamNode* root = new BeamNode(0, 0); + BeamNode* b1 = new BeamNode(1, 1); + BeamNode* b2 = new BeamNode(2, 2); + BeamNode* b3 = new BeamNode(3, 3); + + b1->AppendTo(root); + b2->AppendTo(root); + b3->AppendTo(b1); + + helper.RemoveFromEnd(b3); + helper.RemoveFromEnd(b2); +} + +TEST(TrieConcatOp, AppendVector) { + using LoD = paddle::framework::LoD; + using CPUPlace = paddle::platform::CPUPlace; + using LoDTensor = paddle::framework::LoDTensor; + using BeamHelper = paddle::operators::BeamHelpter; + + CPUPlace place; + + LoD lod; + lod.push_back(std::vector{}); + lod.push_back(std::vector{0, 3, 6}); + + LoDTensor tensor; + tensor.set_lod(lod); + + tensor.Resize({10}); + float* dst_ptr = tensor.mutable_data(place); + for (int i = 0; i < 6; ++i) { + dst_ptr[i] = i; + } + + std::vector vec = {6.0, 7.0, 8.0, 9.0}; + + BeamHelper helper; + helper.AppendVector(vec, &tensor); + + ASSERT_EQ(tensor.lod()[1][3], 10UL); + for (int i = 0; i < 10; ++i) { + ASSERT_EQ(tensor.data()[i], static_cast(i)); + } +} + +TEST(TrieConcatOp, AppendBeamNodeToLoDTensor) { + using LoD = paddle::framework::LoD; + using CPUPlace = paddle::platform::CPUPlace; + using LoDTensor = paddle::framework::LoDTensor; + using BeamHelper = paddle::operators::BeamHelpter; + using BeamNode = paddle::operators::BeamNode; + + BeamNode* root = new BeamNode(0, 0); + BeamNode* b1 = new BeamNode(1, 1); + BeamNode* end = new BeamNode(2, 2); + b1->AppendTo(root); + end->AppendTo(b1); + + BeamHelper helper; + + CPUPlace place; + + LoD lod; + lod.push_back(std::vector{}); + lod.push_back(std::vector{0, 3, 6}); + + // id tensor + LoDTensor tensor_ids; + tensor_ids.set_lod(lod); + + tensor_ids.Resize({10}); + int64_t* ids_ptr = tensor_ids.mutable_data(place); + for (int i = 0; i < 6; ++i) { + ids_ptr[i] = static_cast(i); + } + + // probs tensor + LoDTensor tensor_probs; + tensor_probs.set_lod(lod); + + tensor_probs.Resize({10}); + float* probs_ptr = tensor_probs.mutable_data(place); + for (int i = 0; i < 6; ++i) { + probs_ptr[i] = static_cast(i); + } + + helper.AppendBeamNodeToLoDTensor(end, &tensor_ids, &tensor_probs); + + // debug string tensor_ids + for (auto& item : tensor_ids.lod()[1]) { + std::cout << item << " "; + } + std::cout << std::endl; + + for (size_t i = 0; i < tensor_ids.lod()[1].back(); ++i) { + std::cout << ids_ptr[i] << " "; + } + std::cout << std::endl; + + // make sure ids and probs are the same + auto sentence_ids = tensor_ids.lod().at(1); + auto sentences_probs = tensor_probs.lod().at(1); + ASSERT_EQ(sentence_ids.size(), sentences_probs.size()); + for (size_t i = 0; i < sentence_ids.size(); ++i) { + ASSERT_EQ(sentence_ids.at(i), sentences_probs.at(i)); + } + for (size_t i = 0; i < sentence_ids.back(); ++i) { + ASSERT_EQ(static_cast(ids_ptr[i]), probs_ptr[i]); + } + + ASSERT_EQ(tensor_ids.lod()[1].size(), 4UL); + ASSERT_EQ(tensor_ids.lod()[1].back(), 9UL); + size_t sentence_len = tensor_ids.lod()[1].size() - 1; + ASSERT_EQ(sentence_len, 3UL); + size_t added_sentence_start = tensor_ids.lod().at(1).at(sentence_len - 1); + ASSERT_EQ(added_sentence_start, 6UL); + for (size_t i = added_sentence_start; i < tensor_ids.lod().at(1).back(); + ++i) { + ASSERT_EQ(ids_ptr[i], static_cast(i - added_sentence_start)); + } +} + +// TEST(TrieConcatOp, CPU) { +// using LoD = paddle::framework::LoD; +// using CPUPlace = paddle::platform::CPUPlace; +// using LoDTensor = paddle::framework::LoDTensor; +// +// CPUPlace place; +// +// size_t step_num = 3; +// size_t beam_size = 3; +// size_t batch_size = 2; +// +// std::vector beam_out_Ids; +// std::vector beam_out_Probs; +// +// LoD lod_step_0; +// lod_step_0.push_back(std::vector{0, 3, 6}); +// lod_step_0.push_back(std::vector{0, 1, 2, 3, 4, 5, 6}); +// +// // Ids +// LoDTensor ids_step_0; +// ids_step_0.set_lod(lod_step_0); +// ids_step_0.Resize({6}); +// // malloc memory +// int64_t* dst_ptr = ids_step_0.mutable_data(place); +// for (int i = 0; i < 6; ++i) { +// dst_ptr[i] = i; +// } +// +// LoDTensor probs_step_0; +// probs_step_0.set_lod(lod_step_0); +// probs_step_0.Resize({6}); +// // malloc memory +// float* dst_ptr = probs_step_0.mutable_data(place); +// for (int i = 0; i < 6; ++i) { +// dst_ptr[i] = i; +// } +// +//} \ No newline at end of file From c2c51475625b73394ff8406209cbbd58481f2a46 Mon Sep 17 00:00:00 2001 From: qiaolongfei Date: Tue, 7 Nov 2017 17:44:59 -0800 Subject: [PATCH 05/27] update unit test --- paddle/operators/trieconcat_op.cc | 22 +-- paddle/operators/trieconcat_op.h | 139 ++++++++++++++----- paddle/operators/trieconcat_op_test.cc | 180 ++++++++----------------- 3 files changed, 176 insertions(+), 165 deletions(-) diff --git a/paddle/operators/trieconcat_op.cc b/paddle/operators/trieconcat_op.cc index 3f9eaa30dbfd5..96654e13c01be 100644 --- a/paddle/operators/trieconcat_op.cc +++ b/paddle/operators/trieconcat_op.cc @@ -33,8 +33,8 @@ class TrieConcatOp : public framework::OperatorBase { ctx.Input>("Scores"); const size_t step_num = ids->size(); PADDLE_ENFORCE_LT(step_num, 0, "beam search steps should be larger than 0"); - const size_t batch_size = ids->at(0).lod()[0].size() - 1; - PADDLE_ENFORCE_LT(batch_size, 0UL, "batch size should be larger than 0"); + const size_t source_num = ids->at(0).lod().at(0).size() - 1; + PADDLE_ENFORCE_LT(source_num, 0UL, "source num should be larger than 0"); for (size_t i = 0; i < step_num; ++i) { PADDLE_ENFORCE_EQ(ids->at(i).lod().size(), 2UL, @@ -55,11 +55,11 @@ class TrieConcatOp : public framework::OperatorBase { BeamHelpter beam_helper; // init beam_nodes for each source sentence. std::vector> batch_beam_nodes; - batch_beam_nodes.reserve(batch_size); - for (size_t batch_idx = 0; batch_idx < batch_size; ++batch_idx) { + batch_beam_nodes.reserve(source_num); + for (size_t source_idx = 0; source_idx < source_num; ++source_idx) { std::vector beam_nodes; - size_t batch_start = ids->at(0).lod()[0][batch_idx]; - size_t batch_end = ids->at(0).lod()[0][batch_idx + 1]; + size_t batch_start = ids->at(0).lod()[0][source_idx]; + size_t batch_end = ids->at(0).lod()[0][source_idx + 1]; for (size_t word_id_idx = batch_start; word_id_idx < batch_end; ++word_id_idx) { beam_nodes.push_back( @@ -70,17 +70,17 @@ class TrieConcatOp : public framework::OperatorBase { } // pack all steps for one batch first, then another batch - for (size_t batch_idx = 0; batch_idx < batch_size; ++batch_idx) { + for (size_t source_idx = 0; source_idx < source_num; ++source_idx) { for (size_t step_id = 1; step_id < step_num; ++step_id) { - size_t batch_start = ids->at(step_id).lod()[0][batch_idx]; + size_t batch_start = ids->at(step_id).lod()[0][source_idx]; std::vector result = beam_helper.PackTwoBeamStepOut( - batch_start, batch_beam_nodes[batch_idx], ids->at(step_id), + batch_start, batch_beam_nodes[source_idx], ids->at(step_id), scores->at(step_id), sentenceIds, sentenceScores); - batch_beam_nodes[batch_idx] = result; + batch_beam_nodes.at(source_idx) = result; } // append last beam_node to result - for (auto* beam_node : batch_beam_nodes[batch_idx]) { + for (auto* beam_node : batch_beam_nodes[source_idx]) { beam_helper.AppendBeamNodeToLoDTensor(beam_node, sentenceIds, sentenceScores); } diff --git a/paddle/operators/trieconcat_op.h b/paddle/operators/trieconcat_op.h index 5eaebd6ea4761..7cf0a25c8d800 100644 --- a/paddle/operators/trieconcat_op.h +++ b/paddle/operators/trieconcat_op.h @@ -25,6 +25,11 @@ using LoDTensor = framework::LoDTensor; const int64_t kInitLength = 1024; const int64_t kEndId = 0; +// all the lod have 2 level, the first it source level, +// each source have multiple possible sentences in the second level +const size_t kSourceLevel = 0; +const size_t kSentenceLevel = 1; + struct BeamNode { BeamNode(int64_t word_id, float prob) : word_id_(word_id), prob_(prob) {} @@ -59,55 +64,50 @@ struct BeamHelpter { } } - template - void AppendVector(const std::vector vec, LoDTensor* dst) { - std::vector sentences = dst->lod().at(1); - T* tensor_data = dst->data() + sentences.back(); - memcpy(tensor_data, vec.data(), vec.size() * sizeof(T)); - dst->mutable_lod()->at(1).push_back(sentences.back() + vec.size()); - } - - void AppendBeamNodeToLoDTensor(BeamNode* node, LoDTensor* dst_ids, - LoDTensor* dst_probs) { + void AppendBeamNodeToResult(size_t source_idx, BeamNode* node) { std::vector sequence_ids; std::vector sequence_probs; + BeamNode* tmp = node; while (tmp != nullptr) { - sequence_ids.push_back(tmp->word_id_); - sequence_probs.push_back(tmp->prob_); + sequence_ids.emplace_back(tmp->word_id_); + sequence_probs.emplace_back(tmp->prob_); tmp = tmp->father_; } std::reverse(std::begin(sequence_ids), std::end(sequence_ids)); std::reverse(std::begin(sequence_probs), std::end(sequence_probs)); - AppendVector(sequence_ids, dst_ids); - AppendVector(sequence_probs, dst_probs); + result_id[source_idx].emplace_back(sequence_ids); + result_prob[source_idx].push_back(sequence_probs); } std::vector PackTwoBeamStepOut( - size_t batch_start, const std::vector& pre_results, - const LoDTensor& cur_ids, const LoDTensor& cur_probs, - LoDTensor* result_seq_ids, LoDTensor* result_probs) { - // PADDLE_ENFORCE_EQ(cur_ids.lod(), cur_probs.lod(), - // "lod of ids and probs should be the same"); + size_t source_idx, size_t source_start, + const std::vector& prefixes, const LoDTensor& cur_ids, + const LoDTensor& cur_probs) { std::vector result; - std::vector candidate_offset = cur_ids.lod()[0]; - for (size_t i = 0; i < pre_results.size(); ++i) { - size_t candidate_start = candidate_offset[batch_start + i]; - size_t candidate_end = candidate_offset[batch_start + i + 1]; + std::vector candidate_offset = cur_ids.lod()[kSentenceLevel]; + for (size_t prefix_idx = 0; prefix_idx < prefixes.size(); ++prefix_idx) { + size_t candidate_start = candidate_offset[source_start + prefix_idx]; + size_t candidate_end = candidate_offset[source_start + prefix_idx + 1]; + auto* prefix = prefixes[prefix_idx]; if (candidate_start == candidate_end) { - VLOG(3) << "this prefix does not have candidate"; - auto* prefix_end = pre_results[i]; - if (prefix_end->word_id_ == kEndId) { + VLOG(3) << "this prefix does not have candidate any more"; + if (prefix->word_id_ == kEndId) { VLOG(3) << "find an end Id, append to result tensor"; - AppendBeamNodeToLoDTensor(prefix_end, result_seq_ids, result_probs); + AppendBeamNodeToResult(source_idx, prefix); } else { - VLOG(3) << "this sentence has no more candidate, prune it"; + VLOG(3) << "this sentence has no more candidate and is not end with " + "end id, prune it"; } - // remove from Beam Tree - RemoveFromEnd(prefix_end); + // remove this sentence from Beam Tree. + RemoveFromEnd(prefix); } else { + // two level lod + // [0 2 6] source level + // [0 1 1 2 3 4] sentence level + for (size_t candidate_index = candidate_start; candidate_index < candidate_end; ++candidate_index) { int64_t word_id = cur_ids.data()[candidate_index]; @@ -115,15 +115,88 @@ struct BeamHelpter { "End id should not have candidate anymore"); float prob = cur_probs.data()[candidate_index]; auto* candidate = new BeamNode(word_id, prob); - auto* prefix = pre_results[i]; - candidate->father_ = prefix; - prefix->kids_.push_back(candidate); + candidate->AppendTo(prefix); result.push_back(candidate); } } } return result; } + + template + void InitOutputLodTensor(LoDTensor* out) { + // tensor have two level + out->mutable_lod()->push_back(std::vector{0}); + out->mutable_lod()->push_back(std::vector{0}); + out->Resize({kInitLength}); + out->mutable_data(out->place()); + } + + void InitFirstStepBeamNodes( + const LoDTensor& tensor_id, const LoDTensor& tensor_prob, + std::unordered_map>* batch_beam_nodes) { + // init beam_nodes for each source sentence. + // in the first level, each sentence should have be a prefix + // [0 3 6] level 0 + // [0 1 2 3 4 5 6] level 1 + // [0 0 0 0 0 0] data + PADDLE_ENFORCE_EQ(tensor_id.lod().at(kSourceLevel).back(), + tensor_id.lod().at(kSentenceLevel).back()); + + const size_t source_num = tensor_id.lod().at(kSourceLevel).size() - 1; + + for (size_t source_idx = 0; source_idx < source_num; ++source_idx) { + std::vector init_beam_nodes; + size_t source_start = tensor_id.lod().at(kSourceLevel).at(source_idx); + size_t source_end = tensor_id.lod().at(kSourceLevel).at(source_idx + 1); + + for (size_t word_id_idx = source_start; word_id_idx < source_end; + ++word_id_idx) { + init_beam_nodes.push_back( + new BeamNode(tensor_id.data()[word_id_idx], + tensor_prob.data()[word_id_idx])); + } + (*batch_beam_nodes)[source_idx] = init_beam_nodes; + } + } + + void PackAllSteps(const std::vector& step_ids, + const std::vector& step_probs, + LoDTensor* id_tensor, LoDTensor* prob_tensor) { + PADDLE_ENFORCE_EQ(step_ids.size(), step_probs.size(), + "step_ids and step_probs should be the same"); + size_t step_num = step_ids.size(); + size_t source_num = step_ids.at(0).lod().at(1).size() - 1; + + InitOutputLodTensor(id_tensor); + InitOutputLodTensor(prob_tensor); + + std::unordered_map> batch_beam_nodes; + InitFirstStepBeamNodes(step_ids.at(0), step_probs.at(0), &batch_beam_nodes); + + // pack all steps for one batch first, then another batch + for (size_t source_idx = 0; source_idx < source_num; ++source_idx) { + for (size_t step_id = 1; step_id < step_num; ++step_id) { + size_t source_start = + step_ids.at(step_id).lod()[kSourceLevel][source_idx]; + std::vector result = PackTwoBeamStepOut( + source_idx, source_start, batch_beam_nodes.at(source_idx), + step_ids.at(step_id), step_probs.at(step_id)); + batch_beam_nodes.at(source_idx) = result; + } + + // append last beam_node to result + for (auto* beam_node : batch_beam_nodes.at(source_idx)) { + AppendBeamNodeToResult(source_idx, beam_node); + RemoveFromEnd(beam_node); + } + batch_beam_nodes.clear(); + } + } + + public: + std::unordered_map>> result_id; + std::unordered_map>> result_prob; }; } // namespace operators diff --git a/paddle/operators/trieconcat_op_test.cc b/paddle/operators/trieconcat_op_test.cc index f561d1a76e775..a1e0f3b42a8da 100644 --- a/paddle/operators/trieconcat_op_test.cc +++ b/paddle/operators/trieconcat_op_test.cc @@ -36,150 +36,88 @@ TEST(TrieConcatOp, RemoveFromEnd) { helper.RemoveFromEnd(b2); } -TEST(TrieConcatOp, AppendVector) { - using LoD = paddle::framework::LoD; - using CPUPlace = paddle::platform::CPUPlace; - using LoDTensor = paddle::framework::LoDTensor; +TEST(TrieConcatOp, AppendBeamNodeToResult) { using BeamHelper = paddle::operators::BeamHelpter; + using BeamNode = paddle::operators::BeamNode; - CPUPlace place; - - LoD lod; - lod.push_back(std::vector{}); - lod.push_back(std::vector{0, 3, 6}); - - LoDTensor tensor; - tensor.set_lod(lod); - - tensor.Resize({10}); - float* dst_ptr = tensor.mutable_data(place); - for (int i = 0; i < 6; ++i) { - dst_ptr[i] = i; - } - - std::vector vec = {6.0, 7.0, 8.0, 9.0}; + BeamNode* root = new BeamNode(0, 0); + BeamNode* b1 = new BeamNode(1, 1); + BeamNode* end = new BeamNode(2, 2); + b1->AppendTo(root); + end->AppendTo(b1); BeamHelper helper; - helper.AppendVector(vec, &tensor); - ASSERT_EQ(tensor.lod()[1][3], 10UL); - for (int i = 0; i < 10; ++i) { - ASSERT_EQ(tensor.data()[i], static_cast(i)); + helper.AppendBeamNodeToResult(0, end); + + ASSERT_EQ(helper.result_prob.at(0).size(), 1UL); + for (size_t i = 0; i < helper.result_prob.at(0).at(0).size(); ++i) { + float prob = helper.result_prob.at(0).at(0).at(i); + ASSERT_EQ(prob, static_cast(i)); + ASSERT_EQ(static_cast(helper.result_id.at(0).at(0).at(i)), prob); + std::cout << prob << " "; + std::cout << std::endl; } } -TEST(TrieConcatOp, AppendBeamNodeToLoDTensor) { +TEST(TrieConcatOp, InitFirstStepBeamNodes) { + using BeamHelper = paddle::operators::BeamHelpter; + using BeamNode = paddle::operators::BeamNode; using LoD = paddle::framework::LoD; using CPUPlace = paddle::platform::CPUPlace; using LoDTensor = paddle::framework::LoDTensor; - using BeamHelper = paddle::operators::BeamHelpter; - using BeamNode = paddle::operators::BeamNode; - BeamNode* root = new BeamNode(0, 0); - BeamNode* b1 = new BeamNode(1, 1); - BeamNode* end = new BeamNode(2, 2); - b1->AppendTo(root); - end->AppendTo(b1); + CPUPlace place; - BeamHelper helper; + std::vector prefixes; + prefixes.push_back(new BeamNode(0, 0)); + prefixes.push_back(new BeamNode(1, 1)); + prefixes.push_back(new BeamNode(2, 2)); - CPUPlace place; + std::vector beam_out_Ids; + std::vector beam_out_Probs; LoD lod; - lod.push_back(std::vector{}); lod.push_back(std::vector{0, 3, 6}); - - // id tensor - LoDTensor tensor_ids; - tensor_ids.set_lod(lod); - - tensor_ids.Resize({10}); - int64_t* ids_ptr = tensor_ids.mutable_data(place); - for (int i = 0; i < 6; ++i) { - ids_ptr[i] = static_cast(i); + lod.push_back(std::vector{0, 1, 2, 3, 4, 5, 6}); + + // Ids + LoDTensor tensor_id; + tensor_id.set_lod(lod); + tensor_id.Resize({6}); + // malloc memory + int64_t* id_ptr = tensor_id.mutable_data(place); + for (int64_t i = 0; i < 6; ++i) { + id_ptr[i] = i; } - // probs tensor - LoDTensor tensor_probs; - tensor_probs.set_lod(lod); - - tensor_probs.Resize({10}); - float* probs_ptr = tensor_probs.mutable_data(place); + // Probs + LoDTensor tensor_prob; + tensor_prob.set_lod(lod); + tensor_prob.Resize({6}); + // malloc memory + float* prob_ptr = tensor_prob.mutable_data(place); for (int i = 0; i < 6; ++i) { - probs_ptr[i] = static_cast(i); - } - - helper.AppendBeamNodeToLoDTensor(end, &tensor_ids, &tensor_probs); - - // debug string tensor_ids - for (auto& item : tensor_ids.lod()[1]) { - std::cout << item << " "; + prob_ptr[i] = static_cast(i); } - std::cout << std::endl; - for (size_t i = 0; i < tensor_ids.lod()[1].back(); ++i) { - std::cout << ids_ptr[i] << " "; - } - std::cout << std::endl; - - // make sure ids and probs are the same - auto sentence_ids = tensor_ids.lod().at(1); - auto sentences_probs = tensor_probs.lod().at(1); - ASSERT_EQ(sentence_ids.size(), sentences_probs.size()); - for (size_t i = 0; i < sentence_ids.size(); ++i) { - ASSERT_EQ(sentence_ids.at(i), sentences_probs.at(i)); - } - for (size_t i = 0; i < sentence_ids.back(); ++i) { - ASSERT_EQ(static_cast(ids_ptr[i]), probs_ptr[i]); + BeamHelper helper; + std::unordered_map> result; + helper.InitFirstStepBeamNodes(tensor_id, tensor_prob, &result); + + ASSERT_EQ(result.size(), 2UL); + ASSERT_EQ(result.at(0).size(), 3UL); + for (size_t i = 0; i < result.at(0).size(); ++i) { + auto* beam_node = result.at(0).at(i); + ASSERT_EQ(beam_node->word_id_, static_cast(i)); + ASSERT_EQ(beam_node->prob_, static_cast(i)); } - - ASSERT_EQ(tensor_ids.lod()[1].size(), 4UL); - ASSERT_EQ(tensor_ids.lod()[1].back(), 9UL); - size_t sentence_len = tensor_ids.lod()[1].size() - 1; - ASSERT_EQ(sentence_len, 3UL); - size_t added_sentence_start = tensor_ids.lod().at(1).at(sentence_len - 1); - ASSERT_EQ(added_sentence_start, 6UL); - for (size_t i = added_sentence_start; i < tensor_ids.lod().at(1).back(); - ++i) { - ASSERT_EQ(ids_ptr[i], static_cast(i - added_sentence_start)); + ASSERT_EQ(result.at(1).size(), 3UL); + for (size_t i = 0; i < result.at(1).size(); ++i) { + auto* beam_node = result.at(1).at(i); + ASSERT_EQ(beam_node->word_id_, static_cast(i + 3)); + ASSERT_EQ(beam_node->prob_, static_cast(i + 3)); } } -// TEST(TrieConcatOp, CPU) { -// using LoD = paddle::framework::LoD; -// using CPUPlace = paddle::platform::CPUPlace; -// using LoDTensor = paddle::framework::LoDTensor; -// -// CPUPlace place; -// -// size_t step_num = 3; -// size_t beam_size = 3; -// size_t batch_size = 2; -// -// std::vector beam_out_Ids; -// std::vector beam_out_Probs; -// -// LoD lod_step_0; -// lod_step_0.push_back(std::vector{0, 3, 6}); -// lod_step_0.push_back(std::vector{0, 1, 2, 3, 4, 5, 6}); -// -// // Ids -// LoDTensor ids_step_0; -// ids_step_0.set_lod(lod_step_0); -// ids_step_0.Resize({6}); -// // malloc memory -// int64_t* dst_ptr = ids_step_0.mutable_data(place); -// for (int i = 0; i < 6; ++i) { -// dst_ptr[i] = i; -// } -// -// LoDTensor probs_step_0; -// probs_step_0.set_lod(lod_step_0); -// probs_step_0.Resize({6}); -// // malloc memory -// float* dst_ptr = probs_step_0.mutable_data(place); -// for (int i = 0; i < 6; ++i) { -// dst_ptr[i] = i; -// } -// -//} \ No newline at end of file +TEST(TrieConcatOp, PackAllSteps) {} From 03ec48af643e444b204f8fbd5bed9f7931b5a710 Mon Sep 17 00:00:00 2001 From: qiaolongfei Date: Wed, 8 Nov 2017 00:18:20 -0800 Subject: [PATCH 06/27] add PackAllSteps test --- paddle/operators/trieconcat_op.h | 48 ++++--- paddle/operators/trieconcat_op_test.cc | 170 +++++++++++++++++++++++-- 2 files changed, 186 insertions(+), 32 deletions(-) diff --git a/paddle/operators/trieconcat_op.h b/paddle/operators/trieconcat_op.h index 7cf0a25c8d800..e6e9371882434 100644 --- a/paddle/operators/trieconcat_op.h +++ b/paddle/operators/trieconcat_op.h @@ -83,40 +83,45 @@ struct BeamHelpter { } std::vector PackTwoBeamStepOut( - size_t source_idx, size_t source_start, - const std::vector& prefixes, const LoDTensor& cur_ids, - const LoDTensor& cur_probs) { + size_t source_idx, const std::vector& prefixes, + const LoDTensor& cur_ids, const LoDTensor& cur_probs) { std::vector result; + + size_t source_start = cur_ids.lod()[kSourceLevel][source_idx]; + size_t source_end = cur_ids.lod()[kSourceLevel][source_idx + 1]; + PADDLE_ENFORCE_EQ(source_end - source_start, prefixes.size(), + "prefix and candidate set number should be the same"); std::vector candidate_offset = cur_ids.lod()[kSentenceLevel]; for (size_t prefix_idx = 0; prefix_idx < prefixes.size(); ++prefix_idx) { size_t candidate_start = candidate_offset[source_start + prefix_idx]; size_t candidate_end = candidate_offset[source_start + prefix_idx + 1]; auto* prefix = prefixes[prefix_idx]; + PADDLE_ENFORCE_NE(prefix->word_id_, kEndId, + "prefix should not contain end id"); if (candidate_start == candidate_end) { - VLOG(3) << "this prefix does not have candidate any more"; - if (prefix->word_id_ == kEndId) { - VLOG(3) << "find an end Id, append to result tensor"; - AppendBeamNodeToResult(source_idx, prefix); - } else { - VLOG(3) << "this sentence has no more candidate and is not end with " - "end id, prune it"; - } + VLOG(3) << "this sentence has no more candidate, prune it"; // remove this sentence from Beam Tree. RemoveFromEnd(prefix); } else { // two level lod // [0 2 6] source level // [0 1 1 2 3 4] sentence level - + PADDLE_ENFORCE_NE(prefix->word_id_, kEndId, + "End id should not have candidate anymore"); for (size_t candidate_index = candidate_start; candidate_index < candidate_end; ++candidate_index) { int64_t word_id = cur_ids.data()[candidate_index]; - PADDLE_ENFORCE_NE(word_id, kEndId, - "End id should not have candidate anymore"); float prob = cur_probs.data()[candidate_index]; auto* candidate = new BeamNode(word_id, prob); candidate->AppendTo(prefix); - result.push_back(candidate); + // if candidate is end id, then put it into result and remove it from + // beam tree. + if (word_id == kEndId) { + AppendBeamNodeToResult(source_idx, candidate); + RemoveFromEnd(candidate); + } else { + result.push_back(candidate); + } } } } @@ -168,6 +173,9 @@ struct BeamHelpter { size_t step_num = step_ids.size(); size_t source_num = step_ids.at(0).lod().at(1).size() - 1; + std::cout << "step_num" + << ":" << step_num << std::endl; + InitOutputLodTensor(id_tensor); InitOutputLodTensor(prob_tensor); @@ -177,12 +185,10 @@ struct BeamHelpter { // pack all steps for one batch first, then another batch for (size_t source_idx = 0; source_idx < source_num; ++source_idx) { for (size_t step_id = 1; step_id < step_num; ++step_id) { - size_t source_start = - step_ids.at(step_id).lod()[kSourceLevel][source_idx]; - std::vector result = PackTwoBeamStepOut( - source_idx, source_start, batch_beam_nodes.at(source_idx), - step_ids.at(step_id), step_probs.at(step_id)); - batch_beam_nodes.at(source_idx) = result; + std::vector result = + PackTwoBeamStepOut(source_idx, batch_beam_nodes.at(source_idx), + step_ids.at(step_id), step_probs.at(step_id)); + batch_beam_nodes[source_idx] = result; } // append last beam_node to result diff --git a/paddle/operators/trieconcat_op_test.cc b/paddle/operators/trieconcat_op_test.cc index a1e0f3b42a8da..ccd9863aca617 100644 --- a/paddle/operators/trieconcat_op_test.cc +++ b/paddle/operators/trieconcat_op_test.cc @@ -55,8 +55,6 @@ TEST(TrieConcatOp, AppendBeamNodeToResult) { float prob = helper.result_prob.at(0).at(0).at(i); ASSERT_EQ(prob, static_cast(i)); ASSERT_EQ(static_cast(helper.result_id.at(0).at(0).at(i)), prob); - std::cout << prob << " "; - std::cout << std::endl; } } @@ -69,14 +67,6 @@ TEST(TrieConcatOp, InitFirstStepBeamNodes) { CPUPlace place; - std::vector prefixes; - prefixes.push_back(new BeamNode(0, 0)); - prefixes.push_back(new BeamNode(1, 1)); - prefixes.push_back(new BeamNode(2, 2)); - - std::vector beam_out_Ids; - std::vector beam_out_Probs; - LoD lod; lod.push_back(std::vector{0, 3, 6}); lod.push_back(std::vector{0, 1, 2, 3, 4, 5, 6}); @@ -120,4 +110,162 @@ TEST(TrieConcatOp, InitFirstStepBeamNodes) { } } -TEST(TrieConcatOp, PackAllSteps) {} +TEST(TrieConcatOp, PackTwoBeamStepOut) { + using BeamHelper = paddle::operators::BeamHelpter; + using BeamNode = paddle::operators::BeamNode; + using LoD = paddle::framework::LoD; + using CPUPlace = paddle::platform::CPUPlace; + using LoDTensor = paddle::framework::LoDTensor; + + CPUPlace place; + + // we have 2 source prefix to handle + LoD lod; + lod.push_back(std::vector{0, 3, 5}); + // the first source prefix have 4 candidate, the second have 2 candidate + lod.push_back(std::vector{0, 1, 1, 4, 4, 6}); + + // Ids + LoDTensor tensor_id; + tensor_id.set_lod(lod); + tensor_id.Resize({6}); + // malloc memory + int64_t* id_ptr = tensor_id.mutable_data(place); + for (int64_t i = 0; i < 6; ++i) { + id_ptr[i] = i; + } + + // Probs + LoDTensor tensor_prob; + tensor_prob.set_lod(lod); + tensor_prob.Resize({6}); + // malloc memory + float* prob_ptr = tensor_prob.mutable_data(place); + for (int i = 0; i < 6; ++i) { + prob_ptr[i] = static_cast(i); + } + + // result should be: + // [1 0] + // vector should be: + // [3 1] [3 2] [3 3] + + // three prefix + std::vector prefixes1; + prefixes1.push_back(new BeamNode(1, 1)); + prefixes1.push_back(new BeamNode(2, 2)); + prefixes1.push_back(new BeamNode(3, 3)); + + BeamHelper helper1; + std::vector vec = + helper1.PackTwoBeamStepOut(0, prefixes1, tensor_id, tensor_prob); + ASSERT_EQ(vec.size(), 3UL); + for (size_t i = 0; i < 3; ++i) { + ASSERT_EQ(vec.at(i)->word_id_, static_cast(i + 1)); + ASSERT_EQ(vec.at(i)->prob_, static_cast(i + 1)); + } + + ASSERT_EQ(helper1.result_id.at(0).size(), 1UL); + std::vector id_res = {1, 0}; + ASSERT_EQ(helper1.result_id.at(0).at(0), id_res); + + ASSERT_EQ(helper1.result_prob.at(0).size(), 1UL); + std::vector prob_res = {1, 0}; + ASSERT_EQ(helper1.result_prob.at(0).at(0), prob_res); + + // two prefix + // result should be: + // [2 4] [2 5] + std::vector prefixes2; + prefixes2.push_back(new BeamNode(1, 1)); + prefixes2.push_back(new BeamNode(2, 2)); + + BeamHelper helper2; + std::vector vec2 = + helper2.PackTwoBeamStepOut(1, prefixes2, tensor_id, tensor_prob); + ASSERT_EQ(vec2.size(), 2UL); + for (size_t i = 0; i < 2; ++i) { + ASSERT_EQ(vec2.at(i)->word_id_, static_cast(i + 4)); + ASSERT_EQ(vec2.at(i)->father_->word_id_, static_cast(2)); + ASSERT_EQ(vec2.at(i)->prob_, static_cast(i + 4)); + ASSERT_EQ(vec2.at(i)->father_->prob_, static_cast(2)); + } + ASSERT_EQ(helper2.result_id.size(), 0UL); + ASSERT_EQ(helper2.result_prob.size(), 0UL); +} + +namespace paddle { +namespace test { +using LoD = paddle::framework::LoD; +using CPUPlace = paddle::platform::CPUPlace; +using LoDTensor = paddle::framework::LoDTensor; + +void GenerateExample(const std::vector& level_0, + const std::vector& level_1, + const std::vector& data, std::vector* ids, + std::vector* probs) { + PADDLE_ENFORCE_EQ(level_0.back(), level_1.size() - 1, ""); + PADDLE_ENFORCE_EQ(level_1.back(), data.size(), ""); + + CPUPlace place; + + LoD lod; + lod.push_back(level_0); + lod.push_back(level_1); + + // Ids + LoDTensor tensor_id; + tensor_id.set_lod(lod); + tensor_id.Resize({static_cast(data.size())}); + // malloc memory + int64_t* id_ptr = tensor_id.mutable_data(place); + for (size_t i = 0; i < data.size(); ++i) { + id_ptr[i] = static_cast(data.at(i)); + } + + // Probs + LoDTensor tensor_prob; + tensor_prob.set_lod(lod); + tensor_prob.Resize({static_cast(data.size())}); + // malloc memory + float* prob_ptr = tensor_prob.mutable_data(place); + for (size_t i = 0; i < 6; ++i) { + prob_ptr[i] = static_cast(data.at(i)); + } + + ids->push_back(tensor_id); + probs->push_back(tensor_prob); +} + +} // namespace test +} // namespace paddle + +TEST(TrieConcatOp, PackAllSteps) { + using BeamHelper = paddle::operators::BeamHelpter; + using CPUPlace = paddle::platform::CPUPlace; + using LoDTensor = paddle::framework::LoDTensor; + + CPUPlace place; + + // we will constuct a sample data with 3 steps and 2 source sentences + std::vector ids; + std::vector probs; + + paddle::test::GenerateExample( + std::vector{0, 3, 6}, std::vector{0, 1, 2, 3, 4, 5, 6}, + std::vector{1, 2, 3, 4, 5, 6}, &ids, &probs); + paddle::test::GenerateExample( + std::vector{0, 3, 6}, std::vector{0, 1, 1, 3, 5, 5, 6}, + std::vector{0, 1, 2, 3, 4, 5}, &ids, &probs); + paddle::test::GenerateExample(std::vector{0, 2, 5}, + std::vector{0, 1, 2, 3, 4, 5}, + std::vector{0, 1, 2, 3, 4}, &ids, &probs); + + ASSERT_EQ(ids.size(), 3UL); + ASSERT_EQ(probs.size(), 3UL); + + BeamHelper helper; + LoDTensor id_tensor; + LoDTensor prob_tensor; + helper.PackAllSteps(ids, probs, &id_tensor, &prob_tensor); +} \ No newline at end of file From 4b0987458b6a8460addf8d3f94028fb6575eb7dd Mon Sep 17 00:00:00 2001 From: qiaolongfei Date: Wed, 8 Nov 2017 08:56:07 -0800 Subject: [PATCH 07/27] fix PackAllSteps --- paddle/operators/trieconcat_op.h | 26 ++++++++++++++------------ paddle/operators/trieconcat_op_test.cc | 2 +- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/paddle/operators/trieconcat_op.h b/paddle/operators/trieconcat_op.h index e6e9371882434..e07493fdc38ce 100644 --- a/paddle/operators/trieconcat_op.h +++ b/paddle/operators/trieconcat_op.h @@ -134,7 +134,7 @@ struct BeamHelpter { out->mutable_lod()->push_back(std::vector{0}); out->mutable_lod()->push_back(std::vector{0}); out->Resize({kInitLength}); - out->mutable_data(out->place()); + out->mutable_data(paddle::platform::CPUPlace()); } void InitFirstStepBeamNodes( @@ -171,13 +171,10 @@ struct BeamHelpter { PADDLE_ENFORCE_EQ(step_ids.size(), step_probs.size(), "step_ids and step_probs should be the same"); size_t step_num = step_ids.size(); - size_t source_num = step_ids.at(0).lod().at(1).size() - 1; + size_t source_num = step_ids.at(0).lod().at(kSourceLevel).size() - 1; - std::cout << "step_num" - << ":" << step_num << std::endl; - - InitOutputLodTensor(id_tensor); - InitOutputLodTensor(prob_tensor); + // InitOutputLodTensor(id_tensor); + // InitOutputLodTensor(prob_tensor); std::unordered_map> batch_beam_nodes; InitFirstStepBeamNodes(step_ids.at(0), step_probs.at(0), &batch_beam_nodes); @@ -185,10 +182,16 @@ struct BeamHelpter { // pack all steps for one batch first, then another batch for (size_t source_idx = 0; source_idx < source_num; ++source_idx) { for (size_t step_id = 1; step_id < step_num; ++step_id) { - std::vector result = - PackTwoBeamStepOut(source_idx, batch_beam_nodes.at(source_idx), - step_ids.at(step_id), step_probs.at(step_id)); - batch_beam_nodes[source_idx] = result; + auto prefixes = batch_beam_nodes.at(source_idx); + if (prefixes.size() > 0UL) { + std::vector result = + PackTwoBeamStepOut(source_idx, prefixes, step_ids.at(step_id), + step_probs.at(step_id)); + batch_beam_nodes[source_idx] = result; + } else { + VLOG(3) << "source_idx: " << source_idx << " step_id: " << step_id + << " have no more candidate"; + } } // append last beam_node to result @@ -196,7 +199,6 @@ struct BeamHelpter { AppendBeamNodeToResult(source_idx, beam_node); RemoveFromEnd(beam_node); } - batch_beam_nodes.clear(); } } diff --git a/paddle/operators/trieconcat_op_test.cc b/paddle/operators/trieconcat_op_test.cc index ccd9863aca617..71af5349afc09 100644 --- a/paddle/operators/trieconcat_op_test.cc +++ b/paddle/operators/trieconcat_op_test.cc @@ -229,7 +229,7 @@ void GenerateExample(const std::vector& level_0, tensor_prob.Resize({static_cast(data.size())}); // malloc memory float* prob_ptr = tensor_prob.mutable_data(place); - for (size_t i = 0; i < 6; ++i) { + for (size_t i = 0; i < data.size(); ++i) { prob_ptr[i] = static_cast(data.at(i)); } From 79dcbd437d803f12fd09a9ed5a9b280a9d2a8f90 Mon Sep 17 00:00:00 2001 From: qiaolongfei Date: Wed, 8 Nov 2017 10:54:55 -0800 Subject: [PATCH 08/27] all test passed --- paddle/operators/trieconcat_op.h | 61 +++++++++++++++++++++----- paddle/operators/trieconcat_op_test.cc | 13 ++++++ 2 files changed, 62 insertions(+), 12 deletions(-) diff --git a/paddle/operators/trieconcat_op.h b/paddle/operators/trieconcat_op.h index e07493fdc38ce..d2139811ce81c 100644 --- a/paddle/operators/trieconcat_op.h +++ b/paddle/operators/trieconcat_op.h @@ -128,15 +128,6 @@ struct BeamHelpter { return result; } - template - void InitOutputLodTensor(LoDTensor* out) { - // tensor have two level - out->mutable_lod()->push_back(std::vector{0}); - out->mutable_lod()->push_back(std::vector{0}); - out->Resize({kInitLength}); - out->mutable_data(paddle::platform::CPUPlace()); - } - void InitFirstStepBeamNodes( const LoDTensor& tensor_id, const LoDTensor& tensor_prob, std::unordered_map>* batch_beam_nodes) { @@ -165,6 +156,53 @@ struct BeamHelpter { } } + void ConvertMapToLodTensor( + const std::unordered_map>>& + result_id, + const std::unordered_map>>& + result_prob, + LoDTensor* id_tensor, LoDTensor* prob_tensor) const { + size_t source_num = result_id.size(); + + std::vector source_level_lod = {0}; + std::vector sentence_level_lod = {0}; + std::vector id_data; + std::vector prob_data; + for (size_t source_idx = 0; source_idx < source_num; ++source_idx) { + auto& all_sentence_ids = result_id.at(source_idx); + auto& all_sentence_probs = result_prob.at(source_idx); + for (size_t sentence_idx = 0; sentence_idx < all_sentence_ids.size(); + ++sentence_idx) { + auto& sentence_ids = all_sentence_ids.at(sentence_idx); + id_data.insert(id_data.end(), sentence_ids.begin(), sentence_ids.end()); + auto& sentence_probs = all_sentence_probs.at(sentence_idx); + prob_data.insert(prob_data.end(), sentence_probs.begin(), + sentence_probs.end()); + sentence_level_lod.push_back(sentence_level_lod.back() + + sentence_ids.size()); + } + source_level_lod.push_back(source_level_lod.back() + + all_sentence_ids.size()); + } + + auto cpu_place = new paddle::platform::CPUPlace(); + paddle::platform::CPUDeviceContext cpu_ctx(*cpu_place); + + framework::LoD lod; + lod.push_back(source_level_lod); + lod.push_back(sentence_level_lod); + + id_tensor->set_lod(lod); + id_tensor->Resize({static_cast(id_data.size())}); + id_tensor->mutable_data(paddle::platform::CPUPlace()); + id_tensor->CopyFromVector(id_data, cpu_ctx); + + prob_tensor->set_lod(lod); + prob_tensor->Resize({static_cast(prob_data.size())}); + prob_tensor->mutable_data(paddle::platform::CPUPlace()); + prob_tensor->CopyFromVector(prob_data, cpu_ctx); + } + void PackAllSteps(const std::vector& step_ids, const std::vector& step_probs, LoDTensor* id_tensor, LoDTensor* prob_tensor) { @@ -173,9 +211,6 @@ struct BeamHelpter { size_t step_num = step_ids.size(); size_t source_num = step_ids.at(0).lod().at(kSourceLevel).size() - 1; - // InitOutputLodTensor(id_tensor); - // InitOutputLodTensor(prob_tensor); - std::unordered_map> batch_beam_nodes; InitFirstStepBeamNodes(step_ids.at(0), step_probs.at(0), &batch_beam_nodes); @@ -200,6 +235,8 @@ struct BeamHelpter { RemoveFromEnd(beam_node); } } + + ConvertMapToLodTensor(result_id, result_prob, id_tensor, prob_tensor); } public: diff --git a/paddle/operators/trieconcat_op_test.cc b/paddle/operators/trieconcat_op_test.cc index 71af5349afc09..7776fa5c3897f 100644 --- a/paddle/operators/trieconcat_op_test.cc +++ b/paddle/operators/trieconcat_op_test.cc @@ -244,6 +244,7 @@ TEST(TrieConcatOp, PackAllSteps) { using BeamHelper = paddle::operators::BeamHelpter; using CPUPlace = paddle::platform::CPUPlace; using LoDTensor = paddle::framework::LoDTensor; + using LoD = paddle::framework::LoD; CPUPlace place; @@ -268,4 +269,16 @@ TEST(TrieConcatOp, PackAllSteps) { LoDTensor id_tensor; LoDTensor prob_tensor; helper.PackAllSteps(ids, probs, &id_tensor, &prob_tensor); + + LoD lod = id_tensor.lod(); + for (size_t level = 0; level < 2; ++level) { + for (size_t i = 0; i < lod[level].size(); ++i) { + std::cout << lod[level][i] << " "; + } + std::cout << std::endl; + } + for (int64_t i = 0; i < id_tensor.dims()[0]; ++i) { + std::cout << id_tensor.data()[i] << " "; + } + std::cout << std::endl; } \ No newline at end of file From 799d6dbabc6b0f9e19c050d84c55384e4e0498ec Mon Sep 17 00:00:00 2001 From: qiaolongfei Date: Wed, 8 Nov 2017 11:18:44 -0800 Subject: [PATCH 09/27] clean code --- paddle/framework/tensor_test.cc | 20 ------ paddle/operators/trieconcat_op.cc | 69 +++++-------------- paddle/operators/trieconcat_op_test.cc | 4 ++ .../tests/test_understand_sentiment_conv.py | 2 - 4 files changed, 20 insertions(+), 75 deletions(-) diff --git a/paddle/framework/tensor_test.cc b/paddle/framework/tensor_test.cc index 18309103a4125..1bb0fb71b0799 100644 --- a/paddle/framework/tensor_test.cc +++ b/paddle/framework/tensor_test.cc @@ -267,26 +267,6 @@ TEST(Tensor, CopyFrom) { #endif } -TEST(Tensor, Append) { - using namespace paddle::framework; - using namespace paddle::platform; - { - Tensor src_tensor; - double* src_ptr = - src_tensor.mutable_data(make_ddim({3, 3}), CPUPlace()); - - double arr[9] = {1, 2, 3, 4, 5, 6, 7, 8, 9}; - double arr1[4] = {1, 2, 3, 4}; - double arr2[5] = {5, 6, 7, 8, 9}; - memcpy(src_ptr, arr1, 4 * sizeof(double)); - memcpy(src_ptr + 4, arr2, 5 * sizeof(double)); - - for (size_t i = 0; i < 9; ++i) { - EXPECT_EQ(src_ptr[i], arr[i]); - } - } -} - TEST(Tensor, CopyFromVector) { using namespace paddle::framework; using namespace paddle::platform; diff --git a/paddle/operators/trieconcat_op.cc b/paddle/operators/trieconcat_op.cc index 96654e13c01be..3cf741a8cadcf 100644 --- a/paddle/operators/trieconcat_op.cc +++ b/paddle/operators/trieconcat_op.cc @@ -29,7 +29,7 @@ class TrieConcatOp : public framework::OperatorBase { framework::ExecutionContext ctx(*this, scope, dev_ctx); const std::vector* ids = ctx.Input>("Ids"); - const std::vector* scores = + const std::vector* probs = ctx.Input>("Scores"); const size_t step_num = ids->size(); PADDLE_ENFORCE_LT(step_num, 0, "beam search steps should be larger than 0"); @@ -39,57 +39,14 @@ class TrieConcatOp : public framework::OperatorBase { for (size_t i = 0; i < step_num; ++i) { PADDLE_ENFORCE_EQ(ids->at(i).lod().size(), 2UL, "Level of LodTensor should be 2"); - // PADDLE_ENFORCE_EQ(ids->at(i).lod(), scores->at(i).lod(), - // "score and ids should have the same lod info"); } // prepare output LoDTensor* sentenceIds = ctx.Output("SentenceIds"); - LoDTensor* sentenceScores = ctx.Output("SentenceScores"); - - sentenceIds->Resize({kInitLength}); - sentenceIds->mutable_data(ids->at(0).place()); - sentenceScores->Resize({kInitLength}); - sentenceScores->mutable_data(ids->at(0).place()); + LoDTensor* sentenceProbs = ctx.Output("SentenceScores"); BeamHelpter beam_helper; - // init beam_nodes for each source sentence. - std::vector> batch_beam_nodes; - batch_beam_nodes.reserve(source_num); - for (size_t source_idx = 0; source_idx < source_num; ++source_idx) { - std::vector beam_nodes; - size_t batch_start = ids->at(0).lod()[0][source_idx]; - size_t batch_end = ids->at(0).lod()[0][source_idx + 1]; - for (size_t word_id_idx = batch_start; word_id_idx < batch_end; - ++word_id_idx) { - beam_nodes.push_back( - new BeamNode(ids->at(0).data()[word_id_idx], - scores->at(0).data()[word_id_idx])); - } - batch_beam_nodes.push_back(beam_nodes); - } - - // pack all steps for one batch first, then another batch - for (size_t source_idx = 0; source_idx < source_num; ++source_idx) { - for (size_t step_id = 1; step_id < step_num; ++step_id) { - size_t batch_start = ids->at(step_id).lod()[0][source_idx]; - std::vector result = beam_helper.PackTwoBeamStepOut( - batch_start, batch_beam_nodes[source_idx], ids->at(step_id), - scores->at(step_id), sentenceIds, sentenceScores); - batch_beam_nodes.at(source_idx) = result; - } - - // append last beam_node to result - for (auto* beam_node : batch_beam_nodes[source_idx]) { - beam_helper.AppendBeamNodeToLoDTensor(beam_node, sentenceIds, - sentenceScores); - } - - // update batch_lod_level - sentenceIds->mutable_lod()->at(0).push_back(sentenceIds->lod()[1].size()); - sentenceScores->mutable_lod()->at(0).push_back( - sentenceScores->lod()[1].size()); - } + beam_helper.PackAllSteps(*ids, *probs, sentenceIds, sentenceProbs); } }; @@ -99,17 +56,16 @@ class TrieConcatOpProtoMaker : public framework::OpProtoAndCheckerMaker { framework::OpAttrChecker* op_checker) : OpProtoAndCheckerMaker(proto, op_checker) { AddInput("Ids", - "(vector) " + "(vector)" "score of the candidate words in each step"); AddInput("Scores", - "(vector) " + "(vector)" "score of the candidate words in each step"); AddOutput("SentenceIds", "(LodTensor)" "All possible result sentences of word ids"); AddOutput("SentenceScores", "(LodTensor)" - "" "All possible result sentences of word scores"); AddComment(R"DOC( Pack the result of Beam search op into SentenceIds and SentenceScores. @@ -120,9 +76,13 @@ Pack the result of Beam search op into SentenceIds and SentenceScores. class TrieConcatInferShape : public framework::InferShapeBase { public: void operator()(framework::InferShapeContext* context) const override { - PADDLE_ENFORCE(context->HasInput("X"), "TrieConcatOp must has input X"); - PADDLE_ENFORCE(context->HasOutput("out"), - "TrieConcatOp must has output Out"); + PADDLE_ENFORCE(context->HasInput("Ids"), "TrieConcatOp must has input Ids"); + PADDLE_ENFORCE(context->HasInput("Scores"), + "TrieConcatOp must has input Scores"); + PADDLE_ENFORCE(context->HasOutput("SentenceIds"), + "TrieConcatOp must has output SentenceIds"); + PADDLE_ENFORCE(context->HasOutput("SentenceScores"), + "TrieConcatOp must has output SentenceScores"); } }; @@ -130,7 +90,10 @@ class TrieConcatInferVarType : public framework::VarTypeInference { public: void operator()(const framework::OpDescBind& op_desc, framework::BlockDescBind* block) const override { - for (auto& o : op_desc.Output("Out")) { + for (auto& o : op_desc.Output("SentenceIds")) { + block->Var(o)->SetType(framework::VarDesc::LOD_TENSOR); + } + for (auto& o : op_desc.Output("SentenceScores")) { block->Var(o)->SetType(framework::VarDesc::LOD_TENSOR); } } diff --git a/paddle/operators/trieconcat_op_test.cc b/paddle/operators/trieconcat_op_test.cc index 7776fa5c3897f..c468ab68a314f 100644 --- a/paddle/operators/trieconcat_op_test.cc +++ b/paddle/operators/trieconcat_op_test.cc @@ -281,4 +281,8 @@ TEST(TrieConcatOp, PackAllSteps) { std::cout << id_tensor.data()[i] << " "; } std::cout << std::endl; + for (int64_t i = 0; i < prob_tensor.dims()[0]; ++i) { + std::cout << prob_tensor.data()[i] << " "; + } + std::cout << std::endl; } \ No newline at end of file diff --git a/python/paddle/v2/framework/tests/test_understand_sentiment_conv.py b/python/paddle/v2/framework/tests/test_understand_sentiment_conv.py index f6210a45de032..eb377e9264b60 100644 --- a/python/paddle/v2/framework/tests/test_understand_sentiment_conv.py +++ b/python/paddle/v2/framework/tests/test_understand_sentiment_conv.py @@ -63,8 +63,6 @@ def main(): cost, acc = convolution_net(input_dim=dict_dim, class_dim=class_dim) - print(g_program) - train_data = paddle.batch( paddle.reader.shuffle( paddle.dataset.imdb.train(word_dict), buf_size=1000), From beaf64329e04f97dacd50071705ba0b5b0263019 Mon Sep 17 00:00:00 2001 From: qiaolongfei Date: Wed, 8 Nov 2017 11:46:06 -0800 Subject: [PATCH 10/27] remove state inside helper --- paddle/operators/trieconcat_op.h | 36 ++++++++++++++---------- paddle/operators/trieconcat_op_test.cc | 38 +++++++++++++++----------- 2 files changed, 43 insertions(+), 31 deletions(-) diff --git a/paddle/operators/trieconcat_op.h b/paddle/operators/trieconcat_op.h index d2139811ce81c..43bf86aa8dd39 100644 --- a/paddle/operators/trieconcat_op.h +++ b/paddle/operators/trieconcat_op.h @@ -22,7 +22,6 @@ namespace operators { using value_type = float; using LoDTensor = framework::LoDTensor; -const int64_t kInitLength = 1024; const int64_t kEndId = 0; // all the lod have 2 level, the first it source level, @@ -64,11 +63,15 @@ struct BeamHelpter { } } - void AppendBeamNodeToResult(size_t source_idx, BeamNode* node) { + void AppendBeamNodeToResult( + size_t source_idx, const BeamNode* node, + std::unordered_map>>* result_id, + std::unordered_map>>* + result_prob) { std::vector sequence_ids; std::vector sequence_probs; - BeamNode* tmp = node; + const BeamNode* tmp = node; while (tmp != nullptr) { sequence_ids.emplace_back(tmp->word_id_); sequence_probs.emplace_back(tmp->prob_); @@ -78,13 +81,16 @@ struct BeamHelpter { std::reverse(std::begin(sequence_ids), std::end(sequence_ids)); std::reverse(std::begin(sequence_probs), std::end(sequence_probs)); - result_id[source_idx].emplace_back(sequence_ids); - result_prob[source_idx].push_back(sequence_probs); + (*result_id)[source_idx].emplace_back(sequence_ids); + (*result_prob)[source_idx].push_back(sequence_probs); } std::vector PackTwoBeamStepOut( size_t source_idx, const std::vector& prefixes, - const LoDTensor& cur_ids, const LoDTensor& cur_probs) { + const LoDTensor& cur_ids, const LoDTensor& cur_probs, + std::unordered_map>>* result_id, + std::unordered_map>>* + result_prob) { std::vector result; size_t source_start = cur_ids.lod()[kSourceLevel][source_idx]; @@ -117,7 +123,8 @@ struct BeamHelpter { // if candidate is end id, then put it into result and remove it from // beam tree. if (word_id == kEndId) { - AppendBeamNodeToResult(source_idx, candidate); + AppendBeamNodeToResult(source_idx, candidate, result_id, + result_prob); RemoveFromEnd(candidate); } else { result.push_back(candidate); @@ -212,6 +219,9 @@ struct BeamHelpter { size_t source_num = step_ids.at(0).lod().at(kSourceLevel).size() - 1; std::unordered_map> batch_beam_nodes; + std::unordered_map>> result_id; + std::unordered_map>> result_prob; + InitFirstStepBeamNodes(step_ids.at(0), step_probs.at(0), &batch_beam_nodes); // pack all steps for one batch first, then another batch @@ -219,9 +229,9 @@ struct BeamHelpter { for (size_t step_id = 1; step_id < step_num; ++step_id) { auto prefixes = batch_beam_nodes.at(source_idx); if (prefixes.size() > 0UL) { - std::vector result = - PackTwoBeamStepOut(source_idx, prefixes, step_ids.at(step_id), - step_probs.at(step_id)); + std::vector result = PackTwoBeamStepOut( + source_idx, prefixes, step_ids.at(step_id), + step_probs.at(step_id), &result_id, &result_prob); batch_beam_nodes[source_idx] = result; } else { VLOG(3) << "source_idx: " << source_idx << " step_id: " << step_id @@ -231,17 +241,13 @@ struct BeamHelpter { // append last beam_node to result for (auto* beam_node : batch_beam_nodes.at(source_idx)) { - AppendBeamNodeToResult(source_idx, beam_node); + AppendBeamNodeToResult(source_idx, beam_node, &result_id, &result_prob); RemoveFromEnd(beam_node); } } ConvertMapToLodTensor(result_id, result_prob, id_tensor, prob_tensor); } - - public: - std::unordered_map>> result_id; - std::unordered_map>> result_prob; }; } // namespace operators diff --git a/paddle/operators/trieconcat_op_test.cc b/paddle/operators/trieconcat_op_test.cc index c468ab68a314f..b797c20dca7a2 100644 --- a/paddle/operators/trieconcat_op_test.cc +++ b/paddle/operators/trieconcat_op_test.cc @@ -47,14 +47,16 @@ TEST(TrieConcatOp, AppendBeamNodeToResult) { end->AppendTo(b1); BeamHelper helper; + std::unordered_map>> result_id; + std::unordered_map>> result_prob; - helper.AppendBeamNodeToResult(0, end); + helper.AppendBeamNodeToResult(0, end, &result_id, &result_prob); - ASSERT_EQ(helper.result_prob.at(0).size(), 1UL); - for (size_t i = 0; i < helper.result_prob.at(0).at(0).size(); ++i) { - float prob = helper.result_prob.at(0).at(0).at(i); + ASSERT_EQ(result_prob.at(0).size(), 1UL); + for (size_t i = 0; i < result_prob.at(0).at(0).size(); ++i) { + float prob = result_prob.at(0).at(0).at(i); ASSERT_EQ(prob, static_cast(i)); - ASSERT_EQ(static_cast(helper.result_id.at(0).at(0).at(i)), prob); + ASSERT_EQ(static_cast(result_id.at(0).at(0).at(i)), prob); } } @@ -157,21 +159,23 @@ TEST(TrieConcatOp, PackTwoBeamStepOut) { prefixes1.push_back(new BeamNode(3, 3)); BeamHelper helper1; - std::vector vec = - helper1.PackTwoBeamStepOut(0, prefixes1, tensor_id, tensor_prob); + std::unordered_map>> result_id_1; + std::unordered_map>> result_prob_1; + std::vector vec = helper1.PackTwoBeamStepOut( + 0, prefixes1, tensor_id, tensor_prob, &result_id_1, &result_prob_1); ASSERT_EQ(vec.size(), 3UL); for (size_t i = 0; i < 3; ++i) { ASSERT_EQ(vec.at(i)->word_id_, static_cast(i + 1)); ASSERT_EQ(vec.at(i)->prob_, static_cast(i + 1)); } - ASSERT_EQ(helper1.result_id.at(0).size(), 1UL); + ASSERT_EQ(result_id_1.at(0).size(), 1UL); std::vector id_res = {1, 0}; - ASSERT_EQ(helper1.result_id.at(0).at(0), id_res); + ASSERT_EQ(result_id_1.at(0).at(0), id_res); - ASSERT_EQ(helper1.result_prob.at(0).size(), 1UL); + ASSERT_EQ(result_prob_1.at(0).size(), 1UL); std::vector prob_res = {1, 0}; - ASSERT_EQ(helper1.result_prob.at(0).at(0), prob_res); + ASSERT_EQ(result_prob_1.at(0).at(0), prob_res); // two prefix // result should be: @@ -181,8 +185,10 @@ TEST(TrieConcatOp, PackTwoBeamStepOut) { prefixes2.push_back(new BeamNode(2, 2)); BeamHelper helper2; - std::vector vec2 = - helper2.PackTwoBeamStepOut(1, prefixes2, tensor_id, tensor_prob); + std::unordered_map>> result_id_2; + std::unordered_map>> result_prob_2; + std::vector vec2 = helper2.PackTwoBeamStepOut( + 1, prefixes2, tensor_id, tensor_prob, &result_id_2, &result_prob_2); ASSERT_EQ(vec2.size(), 2UL); for (size_t i = 0; i < 2; ++i) { ASSERT_EQ(vec2.at(i)->word_id_, static_cast(i + 4)); @@ -190,8 +196,8 @@ TEST(TrieConcatOp, PackTwoBeamStepOut) { ASSERT_EQ(vec2.at(i)->prob_, static_cast(i + 4)); ASSERT_EQ(vec2.at(i)->father_->prob_, static_cast(2)); } - ASSERT_EQ(helper2.result_id.size(), 0UL); - ASSERT_EQ(helper2.result_prob.size(), 0UL); + ASSERT_EQ(result_id_2.size(), 0UL); + ASSERT_EQ(result_prob_2.size(), 0UL); } namespace paddle { @@ -285,4 +291,4 @@ TEST(TrieConcatOp, PackAllSteps) { std::cout << prob_tensor.data()[i] << " "; } std::cout << std::endl; -} \ No newline at end of file +} From 549d8fe463024cdfdbaf0cbc1d8afa62c886af9f Mon Sep 17 00:00:00 2001 From: qiaolongfei Date: Wed, 8 Nov 2017 13:41:43 -0800 Subject: [PATCH 11/27] rename prob to score --- paddle/operators/trieconcat_op.cc | 6 +- paddle/operators/trieconcat_op.h | 70 ++++++++--------- paddle/operators/trieconcat_op_test.cc | 100 ++++++++++++------------- 3 files changed, 89 insertions(+), 87 deletions(-) diff --git a/paddle/operators/trieconcat_op.cc b/paddle/operators/trieconcat_op.cc index 3cf741a8cadcf..52eced6f351fa 100644 --- a/paddle/operators/trieconcat_op.cc +++ b/paddle/operators/trieconcat_op.cc @@ -29,7 +29,7 @@ class TrieConcatOp : public framework::OperatorBase { framework::ExecutionContext ctx(*this, scope, dev_ctx); const std::vector* ids = ctx.Input>("Ids"); - const std::vector* probs = + const std::vector* scores = ctx.Input>("Scores"); const size_t step_num = ids->size(); PADDLE_ENFORCE_LT(step_num, 0, "beam search steps should be larger than 0"); @@ -43,10 +43,10 @@ class TrieConcatOp : public framework::OperatorBase { // prepare output LoDTensor* sentenceIds = ctx.Output("SentenceIds"); - LoDTensor* sentenceProbs = ctx.Output("SentenceScores"); + LoDTensor* sentenceScores = ctx.Output("SentenceScores"); BeamHelpter beam_helper; - beam_helper.PackAllSteps(*ids, *probs, sentenceIds, sentenceProbs); + beam_helper.PackAllSteps(*ids, *scores, sentenceIds, sentenceScores); } }; diff --git a/paddle/operators/trieconcat_op.h b/paddle/operators/trieconcat_op.h index 43bf86aa8dd39..3353a5d34fe61 100644 --- a/paddle/operators/trieconcat_op.h +++ b/paddle/operators/trieconcat_op.h @@ -30,7 +30,7 @@ const size_t kSourceLevel = 0; const size_t kSentenceLevel = 1; struct BeamNode { - BeamNode(int64_t word_id, float prob) : word_id_(word_id), prob_(prob) {} + BeamNode(int64_t word_id, float score) : word_id_(word_id), score_(score) {} void AppendTo(BeamNode* father) { father_ = father; @@ -40,7 +40,7 @@ struct BeamNode { BeamNode* father_ = nullptr; std::vector kids_; int64_t word_id_; - float prob_; + float score_; }; struct BeamHelpter { @@ -67,30 +67,30 @@ struct BeamHelpter { size_t source_idx, const BeamNode* node, std::unordered_map>>* result_id, std::unordered_map>>* - result_prob) { + result_score) { std::vector sequence_ids; - std::vector sequence_probs; + std::vector sequence_scores; const BeamNode* tmp = node; while (tmp != nullptr) { sequence_ids.emplace_back(tmp->word_id_); - sequence_probs.emplace_back(tmp->prob_); + sequence_scores.emplace_back(tmp->score_); tmp = tmp->father_; } std::reverse(std::begin(sequence_ids), std::end(sequence_ids)); - std::reverse(std::begin(sequence_probs), std::end(sequence_probs)); + std::reverse(std::begin(sequence_scores), std::end(sequence_scores)); (*result_id)[source_idx].emplace_back(sequence_ids); - (*result_prob)[source_idx].push_back(sequence_probs); + (*result_score)[source_idx].push_back(sequence_scores); } std::vector PackTwoBeamStepOut( size_t source_idx, const std::vector& prefixes, - const LoDTensor& cur_ids, const LoDTensor& cur_probs, + const LoDTensor& cur_ids, const LoDTensor& cur_scores, std::unordered_map>>* result_id, std::unordered_map>>* - result_prob) { + result_score) { std::vector result; size_t source_start = cur_ids.lod()[kSourceLevel][source_idx]; @@ -117,14 +117,14 @@ struct BeamHelpter { for (size_t candidate_index = candidate_start; candidate_index < candidate_end; ++candidate_index) { int64_t word_id = cur_ids.data()[candidate_index]; - float prob = cur_probs.data()[candidate_index]; - auto* candidate = new BeamNode(word_id, prob); + float score = cur_scores.data()[candidate_index]; + auto* candidate = new BeamNode(word_id, score); candidate->AppendTo(prefix); // if candidate is end id, then put it into result and remove it from // beam tree. if (word_id == kEndId) { AppendBeamNodeToResult(source_idx, candidate, result_id, - result_prob); + result_score); RemoveFromEnd(candidate); } else { result.push_back(candidate); @@ -136,7 +136,7 @@ struct BeamHelpter { } void InitFirstStepBeamNodes( - const LoDTensor& tensor_id, const LoDTensor& tensor_prob, + const LoDTensor& tensor_id, const LoDTensor& tensor_score, std::unordered_map>* batch_beam_nodes) { // init beam_nodes for each source sentence. // in the first level, each sentence should have be a prefix @@ -157,7 +157,7 @@ struct BeamHelpter { ++word_id_idx) { init_beam_nodes.push_back( new BeamNode(tensor_id.data()[word_id_idx], - tensor_prob.data()[word_id_idx])); + tensor_score.data()[word_id_idx])); } (*batch_beam_nodes)[source_idx] = init_beam_nodes; } @@ -167,24 +167,24 @@ struct BeamHelpter { const std::unordered_map>>& result_id, const std::unordered_map>>& - result_prob, - LoDTensor* id_tensor, LoDTensor* prob_tensor) const { + result_score, + LoDTensor* id_tensor, LoDTensor* score_tensor) const { size_t source_num = result_id.size(); std::vector source_level_lod = {0}; std::vector sentence_level_lod = {0}; std::vector id_data; - std::vector prob_data; + std::vector score_data; for (size_t source_idx = 0; source_idx < source_num; ++source_idx) { auto& all_sentence_ids = result_id.at(source_idx); - auto& all_sentence_probs = result_prob.at(source_idx); + auto& all_sentence_scores = result_score.at(source_idx); for (size_t sentence_idx = 0; sentence_idx < all_sentence_ids.size(); ++sentence_idx) { auto& sentence_ids = all_sentence_ids.at(sentence_idx); id_data.insert(id_data.end(), sentence_ids.begin(), sentence_ids.end()); - auto& sentence_probs = all_sentence_probs.at(sentence_idx); - prob_data.insert(prob_data.end(), sentence_probs.begin(), - sentence_probs.end()); + auto& sentence_scores = all_sentence_scores.at(sentence_idx); + score_data.insert(score_data.end(), sentence_scores.begin(), + sentence_scores.end()); sentence_level_lod.push_back(sentence_level_lod.back() + sentence_ids.size()); } @@ -204,25 +204,26 @@ struct BeamHelpter { id_tensor->mutable_data(paddle::platform::CPUPlace()); id_tensor->CopyFromVector(id_data, cpu_ctx); - prob_tensor->set_lod(lod); - prob_tensor->Resize({static_cast(prob_data.size())}); - prob_tensor->mutable_data(paddle::platform::CPUPlace()); - prob_tensor->CopyFromVector(prob_data, cpu_ctx); + score_tensor->set_lod(lod); + score_tensor->Resize({static_cast(score_data.size())}); + score_tensor->mutable_data(paddle::platform::CPUPlace()); + score_tensor->CopyFromVector(score_data, cpu_ctx); } void PackAllSteps(const std::vector& step_ids, - const std::vector& step_probs, - LoDTensor* id_tensor, LoDTensor* prob_tensor) { - PADDLE_ENFORCE_EQ(step_ids.size(), step_probs.size(), - "step_ids and step_probs should be the same"); + const std::vector& step_scores, + LoDTensor* id_tensor, LoDTensor* score_tensor) { + PADDLE_ENFORCE_EQ(step_ids.size(), step_scores.size(), + "step_ids and step_scores should be the same"); size_t step_num = step_ids.size(); size_t source_num = step_ids.at(0).lod().at(kSourceLevel).size() - 1; std::unordered_map> batch_beam_nodes; std::unordered_map>> result_id; - std::unordered_map>> result_prob; + std::unordered_map>> result_score; - InitFirstStepBeamNodes(step_ids.at(0), step_probs.at(0), &batch_beam_nodes); + InitFirstStepBeamNodes(step_ids.at(0), step_scores.at(0), + &batch_beam_nodes); // pack all steps for one batch first, then another batch for (size_t source_idx = 0; source_idx < source_num; ++source_idx) { @@ -231,7 +232,7 @@ struct BeamHelpter { if (prefixes.size() > 0UL) { std::vector result = PackTwoBeamStepOut( source_idx, prefixes, step_ids.at(step_id), - step_probs.at(step_id), &result_id, &result_prob); + step_scores.at(step_id), &result_id, &result_score); batch_beam_nodes[source_idx] = result; } else { VLOG(3) << "source_idx: " << source_idx << " step_id: " << step_id @@ -241,12 +242,13 @@ struct BeamHelpter { // append last beam_node to result for (auto* beam_node : batch_beam_nodes.at(source_idx)) { - AppendBeamNodeToResult(source_idx, beam_node, &result_id, &result_prob); + AppendBeamNodeToResult(source_idx, beam_node, &result_id, + &result_score); RemoveFromEnd(beam_node); } } - ConvertMapToLodTensor(result_id, result_prob, id_tensor, prob_tensor); + ConvertMapToLodTensor(result_id, result_score, id_tensor, score_tensor); } }; diff --git a/paddle/operators/trieconcat_op_test.cc b/paddle/operators/trieconcat_op_test.cc index b797c20dca7a2..f837aaa62edc6 100644 --- a/paddle/operators/trieconcat_op_test.cc +++ b/paddle/operators/trieconcat_op_test.cc @@ -48,15 +48,15 @@ TEST(TrieConcatOp, AppendBeamNodeToResult) { BeamHelper helper; std::unordered_map>> result_id; - std::unordered_map>> result_prob; + std::unordered_map>> result_score; - helper.AppendBeamNodeToResult(0, end, &result_id, &result_prob); + helper.AppendBeamNodeToResult(0, end, &result_id, &result_score); - ASSERT_EQ(result_prob.at(0).size(), 1UL); - for (size_t i = 0; i < result_prob.at(0).at(0).size(); ++i) { - float prob = result_prob.at(0).at(0).at(i); - ASSERT_EQ(prob, static_cast(i)); - ASSERT_EQ(static_cast(result_id.at(0).at(0).at(i)), prob); + ASSERT_EQ(result_score.at(0).size(), 1UL); + for (size_t i = 0; i < result_score.at(0).at(0).size(); ++i) { + float score = result_score.at(0).at(0).at(i); + ASSERT_EQ(score, static_cast(i)); + ASSERT_EQ(static_cast(result_id.at(0).at(0).at(i)), score); } } @@ -83,32 +83,32 @@ TEST(TrieConcatOp, InitFirstStepBeamNodes) { id_ptr[i] = i; } - // Probs - LoDTensor tensor_prob; - tensor_prob.set_lod(lod); - tensor_prob.Resize({6}); + // Scores + LoDTensor tensor_score; + tensor_score.set_lod(lod); + tensor_score.Resize({6}); // malloc memory - float* prob_ptr = tensor_prob.mutable_data(place); + float* score_ptr = tensor_score.mutable_data(place); for (int i = 0; i < 6; ++i) { - prob_ptr[i] = static_cast(i); + score_ptr[i] = static_cast(i); } BeamHelper helper; std::unordered_map> result; - helper.InitFirstStepBeamNodes(tensor_id, tensor_prob, &result); + helper.InitFirstStepBeamNodes(tensor_id, tensor_score, &result); ASSERT_EQ(result.size(), 2UL); ASSERT_EQ(result.at(0).size(), 3UL); for (size_t i = 0; i < result.at(0).size(); ++i) { auto* beam_node = result.at(0).at(i); ASSERT_EQ(beam_node->word_id_, static_cast(i)); - ASSERT_EQ(beam_node->prob_, static_cast(i)); + ASSERT_EQ(beam_node->score_, static_cast(i)); } ASSERT_EQ(result.at(1).size(), 3UL); for (size_t i = 0; i < result.at(1).size(); ++i) { auto* beam_node = result.at(1).at(i); ASSERT_EQ(beam_node->word_id_, static_cast(i + 3)); - ASSERT_EQ(beam_node->prob_, static_cast(i + 3)); + ASSERT_EQ(beam_node->score_, static_cast(i + 3)); } } @@ -137,14 +137,14 @@ TEST(TrieConcatOp, PackTwoBeamStepOut) { id_ptr[i] = i; } - // Probs - LoDTensor tensor_prob; - tensor_prob.set_lod(lod); - tensor_prob.Resize({6}); + // Scores + LoDTensor tensor_score; + tensor_score.set_lod(lod); + tensor_score.Resize({6}); // malloc memory - float* prob_ptr = tensor_prob.mutable_data(place); + float* score_ptr = tensor_score.mutable_data(place); for (int i = 0; i < 6; ++i) { - prob_ptr[i] = static_cast(i); + score_ptr[i] = static_cast(i); } // result should be: @@ -160,22 +160,22 @@ TEST(TrieConcatOp, PackTwoBeamStepOut) { BeamHelper helper1; std::unordered_map>> result_id_1; - std::unordered_map>> result_prob_1; + std::unordered_map>> result_score_1; std::vector vec = helper1.PackTwoBeamStepOut( - 0, prefixes1, tensor_id, tensor_prob, &result_id_1, &result_prob_1); + 0, prefixes1, tensor_id, tensor_score, &result_id_1, &result_score_1); ASSERT_EQ(vec.size(), 3UL); for (size_t i = 0; i < 3; ++i) { ASSERT_EQ(vec.at(i)->word_id_, static_cast(i + 1)); - ASSERT_EQ(vec.at(i)->prob_, static_cast(i + 1)); + ASSERT_EQ(vec.at(i)->score_, static_cast(i + 1)); } ASSERT_EQ(result_id_1.at(0).size(), 1UL); std::vector id_res = {1, 0}; ASSERT_EQ(result_id_1.at(0).at(0), id_res); - ASSERT_EQ(result_prob_1.at(0).size(), 1UL); - std::vector prob_res = {1, 0}; - ASSERT_EQ(result_prob_1.at(0).at(0), prob_res); + ASSERT_EQ(result_score_1.at(0).size(), 1UL); + std::vector score_res = {1, 0}; + ASSERT_EQ(result_score_1.at(0).at(0), score_res); // two prefix // result should be: @@ -186,18 +186,18 @@ TEST(TrieConcatOp, PackTwoBeamStepOut) { BeamHelper helper2; std::unordered_map>> result_id_2; - std::unordered_map>> result_prob_2; + std::unordered_map>> result_score_2; std::vector vec2 = helper2.PackTwoBeamStepOut( - 1, prefixes2, tensor_id, tensor_prob, &result_id_2, &result_prob_2); + 1, prefixes2, tensor_id, tensor_score, &result_id_2, &result_score_2); ASSERT_EQ(vec2.size(), 2UL); for (size_t i = 0; i < 2; ++i) { ASSERT_EQ(vec2.at(i)->word_id_, static_cast(i + 4)); ASSERT_EQ(vec2.at(i)->father_->word_id_, static_cast(2)); - ASSERT_EQ(vec2.at(i)->prob_, static_cast(i + 4)); - ASSERT_EQ(vec2.at(i)->father_->prob_, static_cast(2)); + ASSERT_EQ(vec2.at(i)->score_, static_cast(i + 4)); + ASSERT_EQ(vec2.at(i)->father_->score_, static_cast(2)); } ASSERT_EQ(result_id_2.size(), 0UL); - ASSERT_EQ(result_prob_2.size(), 0UL); + ASSERT_EQ(result_score_2.size(), 0UL); } namespace paddle { @@ -209,7 +209,7 @@ using LoDTensor = paddle::framework::LoDTensor; void GenerateExample(const std::vector& level_0, const std::vector& level_1, const std::vector& data, std::vector* ids, - std::vector* probs) { + std::vector* scores) { PADDLE_ENFORCE_EQ(level_0.back(), level_1.size() - 1, ""); PADDLE_ENFORCE_EQ(level_1.back(), data.size(), ""); @@ -229,18 +229,18 @@ void GenerateExample(const std::vector& level_0, id_ptr[i] = static_cast(data.at(i)); } - // Probs - LoDTensor tensor_prob; - tensor_prob.set_lod(lod); - tensor_prob.Resize({static_cast(data.size())}); + // Scores + LoDTensor tensor_score; + tensor_score.set_lod(lod); + tensor_score.Resize({static_cast(data.size())}); // malloc memory - float* prob_ptr = tensor_prob.mutable_data(place); + float* score_ptr = tensor_score.mutable_data(place); for (size_t i = 0; i < data.size(); ++i) { - prob_ptr[i] = static_cast(data.at(i)); + score_ptr[i] = static_cast(data.at(i)); } ids->push_back(tensor_id); - probs->push_back(tensor_prob); + scores->push_back(tensor_score); } } // namespace test @@ -256,25 +256,25 @@ TEST(TrieConcatOp, PackAllSteps) { // we will constuct a sample data with 3 steps and 2 source sentences std::vector ids; - std::vector probs; + std::vector scores; paddle::test::GenerateExample( std::vector{0, 3, 6}, std::vector{0, 1, 2, 3, 4, 5, 6}, - std::vector{1, 2, 3, 4, 5, 6}, &ids, &probs); + std::vector{1, 2, 3, 4, 5, 6}, &ids, &scores); paddle::test::GenerateExample( std::vector{0, 3, 6}, std::vector{0, 1, 1, 3, 5, 5, 6}, - std::vector{0, 1, 2, 3, 4, 5}, &ids, &probs); + std::vector{0, 1, 2, 3, 4, 5}, &ids, &scores); paddle::test::GenerateExample(std::vector{0, 2, 5}, std::vector{0, 1, 2, 3, 4, 5}, - std::vector{0, 1, 2, 3, 4}, &ids, &probs); + std::vector{0, 1, 2, 3, 4}, &ids, &scores); ASSERT_EQ(ids.size(), 3UL); - ASSERT_EQ(probs.size(), 3UL); + ASSERT_EQ(scores.size(), 3UL); BeamHelper helper; LoDTensor id_tensor; - LoDTensor prob_tensor; - helper.PackAllSteps(ids, probs, &id_tensor, &prob_tensor); + LoDTensor score_tensor; + helper.PackAllSteps(ids, scores, &id_tensor, &score_tensor); LoD lod = id_tensor.lod(); for (size_t level = 0; level < 2; ++level) { @@ -287,8 +287,8 @@ TEST(TrieConcatOp, PackAllSteps) { std::cout << id_tensor.data()[i] << " "; } std::cout << std::endl; - for (int64_t i = 0; i < prob_tensor.dims()[0]; ++i) { - std::cout << prob_tensor.data()[i] << " "; + for (int64_t i = 0; i < score_tensor.dims()[0]; ++i) { + std::cout << score_tensor.data()[i] << " "; } std::cout << std::endl; } From e802ebca8642c05b5c39928c2a4782754f0eac0a Mon Sep 17 00:00:00 2001 From: qiaolongfei Date: Wed, 8 Nov 2017 15:39:48 -0800 Subject: [PATCH 12/27] optimize RemoveFromEnd --- paddle/operators/trieconcat_op.h | 28 ++++++++++++++------------ paddle/operators/trieconcat_op_test.cc | 26 ++++++++++++++++-------- 2 files changed, 33 insertions(+), 21 deletions(-) diff --git a/paddle/operators/trieconcat_op.h b/paddle/operators/trieconcat_op.h index 3353a5d34fe61..0350aed4bea33 100644 --- a/paddle/operators/trieconcat_op.h +++ b/paddle/operators/trieconcat_op.h @@ -24,8 +24,10 @@ using LoDTensor = framework::LoDTensor; const int64_t kEndId = 0; -// all the lod have 2 level, the first it source level, -// each source have multiple possible sentences in the second level +// all the lod have 2 levels. +// The First is source level, the second is sentence level. +// source level describe how many candidate words for this source. +// sentence level describe these candidates belong to which prefix const size_t kSourceLevel = 0; const size_t kSentenceLevel = 1; @@ -37,15 +39,8 @@ struct BeamNode { father->kids_.push_back(this); } - BeamNode* father_ = nullptr; - std::vector kids_; - int64_t word_id_; - float score_; -}; - -struct BeamHelpter { // remove this prefix from the beam tree - void RemoveFromEnd(BeamNode* end) { + static void RemoveFromEnd(BeamNode* end) { PADDLE_ENFORCE_EQ(end->kids_.size(), 0UL, "end should not have any kids"); auto* father = end->father_; if (father != nullptr) { @@ -63,6 +58,13 @@ struct BeamHelpter { } } + BeamNode* father_ = nullptr; + std::vector kids_; + int64_t word_id_; + float score_; +}; + +struct BeamHelpter { void AppendBeamNodeToResult( size_t source_idx, const BeamNode* node, std::unordered_map>>* result_id, @@ -107,7 +109,7 @@ struct BeamHelpter { if (candidate_start == candidate_end) { VLOG(3) << "this sentence has no more candidate, prune it"; // remove this sentence from Beam Tree. - RemoveFromEnd(prefix); + BeamNode::RemoveFromEnd(prefix); } else { // two level lod // [0 2 6] source level @@ -125,7 +127,7 @@ struct BeamHelpter { if (word_id == kEndId) { AppendBeamNodeToResult(source_idx, candidate, result_id, result_score); - RemoveFromEnd(candidate); + BeamNode::RemoveFromEnd(candidate); } else { result.push_back(candidate); } @@ -244,7 +246,7 @@ struct BeamHelpter { for (auto* beam_node : batch_beam_nodes.at(source_idx)) { AppendBeamNodeToResult(source_idx, beam_node, &result_id, &result_score); - RemoveFromEnd(beam_node); + BeamNode::RemoveFromEnd(beam_node); } } diff --git a/paddle/operators/trieconcat_op_test.cc b/paddle/operators/trieconcat_op_test.cc index f837aaa62edc6..f1ea0c72d89e0 100644 --- a/paddle/operators/trieconcat_op_test.cc +++ b/paddle/operators/trieconcat_op_test.cc @@ -18,11 +18,8 @@ #include "paddle/platform/place.h" TEST(TrieConcatOp, RemoveFromEnd) { - using BeamHelper = paddle::operators::BeamHelpter; using BeamNode = paddle::operators::BeamNode; - BeamHelper helper; - BeamNode* root = new BeamNode(0, 0); BeamNode* b1 = new BeamNode(1, 1); BeamNode* b2 = new BeamNode(2, 2); @@ -32,8 +29,8 @@ TEST(TrieConcatOp, RemoveFromEnd) { b2->AppendTo(root); b3->AppendTo(b1); - helper.RemoveFromEnd(b3); - helper.RemoveFromEnd(b2); + BeamNode::RemoveFromEnd(b3); + BeamNode::RemoveFromEnd(b2); } TEST(TrieConcatOp, AppendBeamNodeToResult) { @@ -272,23 +269,36 @@ TEST(TrieConcatOp, PackAllSteps) { ASSERT_EQ(scores.size(), 3UL); BeamHelper helper; + LoDTensor id_tensor; LoDTensor score_tensor; helper.PackAllSteps(ids, scores, &id_tensor, &score_tensor); LoD lod = id_tensor.lod(); + std::vector expect_source_lod = {0, 3, 6}; + EXPECT_EQ(lod[0], expect_source_lod); + std::vector expect_sentence_lod = {0, 2, 5, 8, 11, 14, 17}; + EXPECT_EQ(lod[1], expect_sentence_lod); + std::vector expect_data = {1, 0, 3, 1, 0, 3, 2, 1, 4, + 3, 2, 4, 4, 3, 6, 5, 4}; + ASSERT_EQ(id_tensor.dims()[0], static_cast(expect_data.size())); + for (size_t i = 0; i < expect_data.size(); ++i) { + ASSERT_EQ(id_tensor.data()[i], + static_cast(expect_data[i])); + } + for (size_t level = 0; level < 2; ++level) { for (size_t i = 0; i < lod[level].size(); ++i) { - std::cout << lod[level][i] << " "; + std::cout << lod[level][i] << ", "; } std::cout << std::endl; } for (int64_t i = 0; i < id_tensor.dims()[0]; ++i) { - std::cout << id_tensor.data()[i] << " "; + std::cout << id_tensor.data()[i] << ", "; } std::cout << std::endl; for (int64_t i = 0; i < score_tensor.dims()[0]; ++i) { - std::cout << score_tensor.data()[i] << " "; + std::cout << score_tensor.data()[i] << ", "; } std::cout << std::endl; } From 96959ff74846a2e8502415c4ecaae14913d3d617 Mon Sep 17 00:00:00 2001 From: qiaolongfei Date: Wed, 8 Nov 2017 15:56:58 -0800 Subject: [PATCH 13/27] use deconstructor to delete BeamNode recursively --- paddle/operators/trieconcat_op.h | 45 +++++++++++--------------- paddle/operators/trieconcat_op_test.cc | 10 +++--- 2 files changed, 24 insertions(+), 31 deletions(-) diff --git a/paddle/operators/trieconcat_op.h b/paddle/operators/trieconcat_op.h index 0350aed4bea33..b71fbd1f841cf 100644 --- a/paddle/operators/trieconcat_op.h +++ b/paddle/operators/trieconcat_op.h @@ -34,32 +34,25 @@ const size_t kSentenceLevel = 1; struct BeamNode { BeamNode(int64_t word_id, float score) : word_id_(word_id), score_(score) {} - void AppendTo(BeamNode* father) { - father_ = father; - father->kids_.push_back(this); - } - - // remove this prefix from the beam tree - static void RemoveFromEnd(BeamNode* end) { - PADDLE_ENFORCE_EQ(end->kids_.size(), 0UL, "end should not have any kids"); - auto* father = end->father_; - if (father != nullptr) { - // should use reference - auto& kids = father->kids_; - kids.erase(std::remove(kids.begin(), kids.end(), end), kids.end()); - VLOG(3) << "Delete BeamNode with word_id:" << end->word_id_; - delete end; - if (father->kids_.size() == 0) { - RemoveFromEnd(father); + ~BeamNode() { + if (parent_) { + parent_->DropKid(this); + if (parent_->kids_.size() == 0UL) { + delete parent_; } - } else { - VLOG(3) << "Delete BeamNode root with word_id:" << end->word_id_; - delete end; } + VLOG(3) << "Delete BeamNode root with word_id:" << this->word_id_; } - BeamNode* father_ = nullptr; - std::vector kids_; + void AppendTo(BeamNode* father) { + parent_ = father; + father->kids_.insert(this); + } + + void DropKid(BeamNode* kid) { kids_.erase(kid); } + + BeamNode* parent_ = nullptr; + std::unordered_set kids_; int64_t word_id_; float score_; }; @@ -77,7 +70,7 @@ struct BeamHelpter { while (tmp != nullptr) { sequence_ids.emplace_back(tmp->word_id_); sequence_scores.emplace_back(tmp->score_); - tmp = tmp->father_; + tmp = tmp->parent_; } std::reverse(std::begin(sequence_ids), std::end(sequence_ids)); @@ -109,7 +102,7 @@ struct BeamHelpter { if (candidate_start == candidate_end) { VLOG(3) << "this sentence has no more candidate, prune it"; // remove this sentence from Beam Tree. - BeamNode::RemoveFromEnd(prefix); + delete prefix; } else { // two level lod // [0 2 6] source level @@ -127,7 +120,7 @@ struct BeamHelpter { if (word_id == kEndId) { AppendBeamNodeToResult(source_idx, candidate, result_id, result_score); - BeamNode::RemoveFromEnd(candidate); + delete candidate; } else { result.push_back(candidate); } @@ -246,7 +239,7 @@ struct BeamHelpter { for (auto* beam_node : batch_beam_nodes.at(source_idx)) { AppendBeamNodeToResult(source_idx, beam_node, &result_id, &result_score); - BeamNode::RemoveFromEnd(beam_node); + delete beam_node; } } diff --git a/paddle/operators/trieconcat_op_test.cc b/paddle/operators/trieconcat_op_test.cc index f1ea0c72d89e0..71a908914dd1c 100644 --- a/paddle/operators/trieconcat_op_test.cc +++ b/paddle/operators/trieconcat_op_test.cc @@ -17,7 +17,7 @@ #include "paddle/framework/lod_tensor.h" #include "paddle/platform/place.h" -TEST(TrieConcatOp, RemoveFromEnd) { +TEST(TrieConcatOp, DeleteBeamNode) { using BeamNode = paddle::operators::BeamNode; BeamNode* root = new BeamNode(0, 0); @@ -29,8 +29,8 @@ TEST(TrieConcatOp, RemoveFromEnd) { b2->AppendTo(root); b3->AppendTo(b1); - BeamNode::RemoveFromEnd(b3); - BeamNode::RemoveFromEnd(b2); + delete b3; + delete b2; } TEST(TrieConcatOp, AppendBeamNodeToResult) { @@ -189,9 +189,9 @@ TEST(TrieConcatOp, PackTwoBeamStepOut) { ASSERT_EQ(vec2.size(), 2UL); for (size_t i = 0; i < 2; ++i) { ASSERT_EQ(vec2.at(i)->word_id_, static_cast(i + 4)); - ASSERT_EQ(vec2.at(i)->father_->word_id_, static_cast(2)); + ASSERT_EQ(vec2.at(i)->parent_->word_id_, static_cast(2)); ASSERT_EQ(vec2.at(i)->score_, static_cast(i + 4)); - ASSERT_EQ(vec2.at(i)->father_->score_, static_cast(2)); + ASSERT_EQ(vec2.at(i)->parent_->score_, static_cast(2)); } ASSERT_EQ(result_id_2.size(), 0UL); ASSERT_EQ(result_score_2.size(), 0UL); From 31b871e108e14c58164168c8ddc94483e6dbdc8b Mon Sep 17 00:00:00 2001 From: qiaolongfei Date: Thu, 9 Nov 2017 14:10:16 -0800 Subject: [PATCH 14/27] optimize interface --- paddle/operators/trieconcat_op.cc | 2 +- paddle/operators/trieconcat_op.h | 334 ++++++++++++------------- paddle/operators/trieconcat_op_test.cc | 292 ++++++++------------- 3 files changed, 267 insertions(+), 361 deletions(-) diff --git a/paddle/operators/trieconcat_op.cc b/paddle/operators/trieconcat_op.cc index 52eced6f351fa..4cecb6b287427 100644 --- a/paddle/operators/trieconcat_op.cc +++ b/paddle/operators/trieconcat_op.cc @@ -45,7 +45,7 @@ class TrieConcatOp : public framework::OperatorBase { LoDTensor* sentenceIds = ctx.Output("SentenceIds"); LoDTensor* sentenceScores = ctx.Output("SentenceScores"); - BeamHelpter beam_helper; + BeamHelper beam_helper; beam_helper.PackAllSteps(*ids, *scores, sentenceIds, sentenceScores); } }; diff --git a/paddle/operators/trieconcat_op.h b/paddle/operators/trieconcat_op.h index b71fbd1f841cf..90ae3c2087434 100644 --- a/paddle/operators/trieconcat_op.h +++ b/paddle/operators/trieconcat_op.h @@ -57,195 +57,183 @@ struct BeamNode { float score_; }; -struct BeamHelpter { - void AppendBeamNodeToResult( - size_t source_idx, const BeamNode* node, - std::unordered_map>>* result_id, - std::unordered_map>>* - result_score) { - std::vector sequence_ids; - std::vector sequence_scores; - - const BeamNode* tmp = node; - while (tmp != nullptr) { - sequence_ids.emplace_back(tmp->word_id_); - sequence_scores.emplace_back(tmp->score_); - tmp = tmp->parent_; - } +using BeamNodeVector = std::vector; - std::reverse(std::begin(sequence_ids), std::end(sequence_ids)); - std::reverse(std::begin(sequence_scores), std::end(sequence_scores)); +struct Sentence { + std::vector word_ids; + std::vector scores; +}; - (*result_id)[source_idx].emplace_back(sequence_ids); - (*result_score)[source_idx].push_back(sequence_scores); - } +using SentenceVector = std::vector; - std::vector PackTwoBeamStepOut( - size_t source_idx, const std::vector& prefixes, - const LoDTensor& cur_ids, const LoDTensor& cur_scores, - std::unordered_map>>* result_id, - std::unordered_map>>* - result_score) { - std::vector result; - - size_t source_start = cur_ids.lod()[kSourceLevel][source_idx]; - size_t source_end = cur_ids.lod()[kSourceLevel][source_idx + 1]; - PADDLE_ENFORCE_EQ(source_end - source_start, prefixes.size(), - "prefix and candidate set number should be the same"); - std::vector candidate_offset = cur_ids.lod()[kSentenceLevel]; - for (size_t prefix_idx = 0; prefix_idx < prefixes.size(); ++prefix_idx) { - size_t candidate_start = candidate_offset[source_start + prefix_idx]; - size_t candidate_end = candidate_offset[source_start + prefix_idx + 1]; - auto* prefix = prefixes[prefix_idx]; - PADDLE_ENFORCE_NE(prefix->word_id_, kEndId, - "prefix should not contain end id"); - if (candidate_start == candidate_end) { - VLOG(3) << "this sentence has no more candidate, prune it"; - // remove this sentence from Beam Tree. - delete prefix; - } else { - // two level lod - // [0 2 6] source level - // [0 1 1 2 3 4] sentence level - PADDLE_ENFORCE_NE(prefix->word_id_, kEndId, - "End id should not have candidate anymore"); - for (size_t candidate_index = candidate_start; - candidate_index < candidate_end; ++candidate_index) { - int64_t word_id = cur_ids.data()[candidate_index]; - float score = cur_scores.data()[candidate_index]; - auto* candidate = new BeamNode(word_id, score); - candidate->AppendTo(prefix); - // if candidate is end id, then put it into result and remove it from - // beam tree. - if (word_id == kEndId) { - AppendBeamNodeToResult(source_idx, candidate, result_id, - result_score); - delete candidate; - } else { - result.push_back(candidate); - } - } - } - } - return result; - } +struct BeamHelper { + // make a BeamNode into sentence. + Sentence MakeSentence(const BeamNode* node) const; - void InitFirstStepBeamNodes( - const LoDTensor& tensor_id, const LoDTensor& tensor_score, - std::unordered_map>* batch_beam_nodes) { - // init beam_nodes for each source sentence. - // in the first level, each sentence should have be a prefix - // [0 3 6] level 0 - // [0 1 2 3 4 5 6] level 1 - // [0 0 0 0 0 0] data - PADDLE_ENFORCE_EQ(tensor_id.lod().at(kSourceLevel).back(), - tensor_id.lod().at(kSentenceLevel).back()); - - const size_t source_num = tensor_id.lod().at(kSourceLevel).size() - 1; - - for (size_t source_idx = 0; source_idx < source_num; ++source_idx) { - std::vector init_beam_nodes; - size_t source_start = tensor_id.lod().at(kSourceLevel).at(source_idx); - size_t source_end = tensor_id.lod().at(kSourceLevel).at(source_idx + 1); - - for (size_t word_id_idx = source_start; word_id_idx < source_end; - ++word_id_idx) { - init_beam_nodes.push_back( - new BeamNode(tensor_id.data()[word_id_idx], - tensor_score.data()[word_id_idx])); - } - (*batch_beam_nodes)[source_idx] = init_beam_nodes; - } - } + std::vector PackTwoSteps( + const LoDTensor& cur_ids, const LoDTensor& cur_scores, + const std::vector prefixes_list, + std::unordered_map* sentence_vector_list) const; void ConvertMapToLodTensor( - const std::unordered_map>>& - result_id, - const std::unordered_map>>& - result_score, - LoDTensor* id_tensor, LoDTensor* score_tensor) const { - size_t source_num = result_id.size(); - - std::vector source_level_lod = {0}; - std::vector sentence_level_lod = {0}; - std::vector id_data; - std::vector score_data; - for (size_t source_idx = 0; source_idx < source_num; ++source_idx) { - auto& all_sentence_ids = result_id.at(source_idx); - auto& all_sentence_scores = result_score.at(source_idx); - for (size_t sentence_idx = 0; sentence_idx < all_sentence_ids.size(); - ++sentence_idx) { - auto& sentence_ids = all_sentence_ids.at(sentence_idx); - id_data.insert(id_data.end(), sentence_ids.begin(), sentence_ids.end()); - auto& sentence_scores = all_sentence_scores.at(sentence_idx); - score_data.insert(score_data.end(), sentence_scores.begin(), - sentence_scores.end()); - sentence_level_lod.push_back(sentence_level_lod.back() + - sentence_ids.size()); - } - source_level_lod.push_back(source_level_lod.back() + - all_sentence_ids.size()); - } - - auto cpu_place = new paddle::platform::CPUPlace(); - paddle::platform::CPUDeviceContext cpu_ctx(*cpu_place); - - framework::LoD lod; - lod.push_back(source_level_lod); - lod.push_back(sentence_level_lod); + std::unordered_map sentence_vector_list, + LoDTensor* id_tensor, LoDTensor* score_tensor) const; - id_tensor->set_lod(lod); - id_tensor->Resize({static_cast(id_data.size())}); - id_tensor->mutable_data(paddle::platform::CPUPlace()); - id_tensor->CopyFromVector(id_data, cpu_ctx); + void PackAllSteps(const std::vector& step_ids, + const std::vector& step_scores, + LoDTensor* id_tensor, LoDTensor* score_tensor) const; +}; - score_tensor->set_lod(lod); - score_tensor->Resize({static_cast(score_data.size())}); - score_tensor->mutable_data(paddle::platform::CPUPlace()); - score_tensor->CopyFromVector(score_data, cpu_ctx); +Sentence BeamHelper::MakeSentence(const BeamNode* node) const { + const BeamNode* tmp = node; + Sentence sentence; + while (tmp != nullptr) { + sentence.word_ids.emplace_back(tmp->word_id_); + sentence.scores.emplace_back(tmp->score_); + tmp = tmp->parent_; } - void PackAllSteps(const std::vector& step_ids, - const std::vector& step_scores, - LoDTensor* id_tensor, LoDTensor* score_tensor) { - PADDLE_ENFORCE_EQ(step_ids.size(), step_scores.size(), - "step_ids and step_scores should be the same"); - size_t step_num = step_ids.size(); - size_t source_num = step_ids.at(0).lod().at(kSourceLevel).size() - 1; - - std::unordered_map> batch_beam_nodes; - std::unordered_map>> result_id; - std::unordered_map>> result_score; - - InitFirstStepBeamNodes(step_ids.at(0), step_scores.at(0), - &batch_beam_nodes); - - // pack all steps for one batch first, then another batch - for (size_t source_idx = 0; source_idx < source_num; ++source_idx) { - for (size_t step_id = 1; step_id < step_num; ++step_id) { - auto prefixes = batch_beam_nodes.at(source_idx); - if (prefixes.size() > 0UL) { - std::vector result = PackTwoBeamStepOut( - source_idx, prefixes, step_ids.at(step_id), - step_scores.at(step_id), &result_id, &result_score); - batch_beam_nodes[source_idx] = result; + std::reverse(std::begin(sentence.word_ids), std::end(sentence.word_ids)); + std::reverse(std::begin(sentence.scores), std::end(sentence.scores)); + + return sentence; +} + +std::vector BeamHelper::PackTwoSteps( + const LoDTensor& cur_ids, const LoDTensor& cur_scores, + const std::vector prefixes_list, + std::unordered_map* sentence_vector_list) const { + std::vector result; + + for (size_t src_idx = 0; src_idx < cur_ids.lod()[kSourceLevel].size() - 1; + ++src_idx) { + size_t src_start = cur_ids.lod().at(kSourceLevel).at(src_idx); + size_t src_end = cur_ids.lod().at(kSourceLevel).at(src_idx + 1); + + BeamNodeVector beam_nodes; + + // if prefixes is nullptr, it means this is the first step. + if (prefixes_list.size() == 0UL) { + PADDLE_ENFORCE_EQ(cur_ids.lod().at(kSourceLevel).back(), + cur_ids.lod().at(kSentenceLevel).back(), + "in the first step"); + for (size_t id_idx = src_start; id_idx < src_end; ++id_idx) { + beam_nodes.push_back(new BeamNode(cur_ids.data()[id_idx], + cur_scores.data()[id_idx])); + } + } else { + const BeamNodeVector& prefixes = prefixes_list[src_idx]; + SentenceVector& sentence_vector = (*sentence_vector_list)[src_idx]; + + PADDLE_ENFORCE_EQ(src_end - src_start, prefixes.size(), + "prefix and candidate set number should be the same"); + + std::vector candidate_offset = cur_ids.lod()[kSentenceLevel]; + for (size_t prefix_idx = 0; prefix_idx < prefixes.size(); ++prefix_idx) { + auto* prefix = prefixes[prefix_idx]; + size_t candidate_start = candidate_offset[src_start + prefix_idx]; + size_t candidate_end = candidate_offset[src_start + prefix_idx + 1]; + if (candidate_start == candidate_end) { + if (prefix->word_id_ == kEndId) { + VLOG(3) << "this sentence has Ended, prune it"; + sentence_vector.push_back(MakeSentence(prefix)); + } + VLOG(3) << "this sentence has no more candidate, prune it"; + // remove this sentence from Beam Tree. + delete prefix; } else { - VLOG(3) << "source_idx: " << source_idx << " step_id: " << step_id - << " have no more candidate"; + // two level lod + // [0 2 6] source level + // [0 1 1 2 3 4] sentence level + PADDLE_ENFORCE_NE(prefix->word_id_, kEndId, + "End id should not have candidate anymore"); + for (size_t candidate_idx = candidate_start; + candidate_idx < candidate_end; ++candidate_idx) { + auto* candidate = + new BeamNode(cur_ids.data()[candidate_idx], + cur_scores.data()[candidate_idx]); + candidate->AppendTo(prefix); + beam_nodes.push_back(candidate); + } } } - - // append last beam_node to result - for (auto* beam_node : batch_beam_nodes.at(source_idx)) { - AppendBeamNodeToResult(source_idx, beam_node, &result_id, - &result_score); - delete beam_node; - } } + result.push_back(beam_nodes); + } + return result; +} + +void BeamHelper::ConvertMapToLodTensor( + std::unordered_map sentence_vector_list, + LoDTensor* id_tensor, LoDTensor* score_tensor) const { + size_t src_num = sentence_vector_list.size(); + + std::vector source_level_lod = {0}; + std::vector sentence_level_lod = {0}; + std::vector id_data; + std::vector score_data; + for (size_t src_idx = 0; src_idx < src_num; ++src_idx) { + for (Sentence& sentence : sentence_vector_list[src_idx]) { + id_data.insert(id_data.end(), sentence.word_ids.begin(), + sentence.word_ids.end()); + score_data.insert(score_data.end(), sentence.scores.begin(), + sentence.scores.end()); + sentence_level_lod.push_back(sentence_level_lod.back() + + sentence.word_ids.size()); + } + source_level_lod.push_back(source_level_lod.back() + + sentence_vector_list[src_idx].size()); + } - ConvertMapToLodTensor(result_id, result_score, id_tensor, score_tensor); + auto cpu_place = new paddle::platform::CPUPlace(); + paddle::platform::CPUDeviceContext cpu_ctx(*cpu_place); + + framework::LoD lod; + lod.push_back(source_level_lod); + lod.push_back(sentence_level_lod); + + id_tensor->set_lod(lod); + id_tensor->Resize({static_cast(id_data.size())}); + id_tensor->mutable_data(paddle::platform::CPUPlace()); + id_tensor->CopyFromVector(id_data, cpu_ctx); + + score_tensor->set_lod(lod); + score_tensor->Resize({static_cast(score_data.size())}); + score_tensor->mutable_data(paddle::platform::CPUPlace()); + score_tensor->CopyFromVector(score_data, cpu_ctx); +} + +void BeamHelper::PackAllSteps(const std::vector& step_ids, + const std::vector& step_scores, + LoDTensor* id_tensor, + LoDTensor* score_tensor) const { + PADDLE_ENFORCE_GT(step_ids.size(), 0, "step num should be larger than 0"); + PADDLE_ENFORCE_EQ(step_ids.size(), step_scores.size(), + "step_ids and step_scores should be the same"); + size_t step_num = step_ids.size(); + size_t src_num = step_ids.at(0).lod().at(kSourceLevel).size() - 1; + + PADDLE_ENFORCE_GT(src_num, 0, "source num should be larger than 0"); + + std::vector beamnode_vector_list; + std::unordered_map sentence_vector_list; + + // pack all steps for one batch first, then another batch + for (size_t step_id = 0; step_id < step_num; ++step_id) { + beamnode_vector_list = + PackTwoSteps(step_ids.at(step_id), step_scores.at(step_id), + beamnode_vector_list, &sentence_vector_list); } -}; + // append last beam_node to result + for (size_t src_idx = 0; src_idx < src_num; ++src_idx) { + for (auto* beam_node : beamnode_vector_list.at(src_idx)) { + sentence_vector_list[src_idx].push_back(MakeSentence(beam_node)); + delete beam_node; + } + } + + ConvertMapToLodTensor(sentence_vector_list, id_tensor, score_tensor); +} } // namespace operators } // namespace paddle diff --git a/paddle/operators/trieconcat_op_test.cc b/paddle/operators/trieconcat_op_test.cc index 71a908914dd1c..e1d532919fe3a 100644 --- a/paddle/operators/trieconcat_op_test.cc +++ b/paddle/operators/trieconcat_op_test.cc @@ -17,6 +17,52 @@ #include "paddle/framework/lod_tensor.h" #include "paddle/platform/place.h" +namespace paddle { +namespace test { +using LoD = paddle::framework::LoD; +using CPUPlace = paddle::platform::CPUPlace; +using LoDTensor = paddle::framework::LoDTensor; + +void GenerateExample(const std::vector& level_0, + const std::vector& level_1, + const std::vector& data, std::vector* ids, + std::vector* scores) { + PADDLE_ENFORCE_EQ(level_0.back(), level_1.size() - 1, ""); + PADDLE_ENFORCE_EQ(level_1.back(), data.size(), ""); + + CPUPlace place; + + LoD lod; + lod.push_back(level_0); + lod.push_back(level_1); + + // Ids + LoDTensor tensor_id; + tensor_id.set_lod(lod); + tensor_id.Resize({static_cast(data.size())}); + // malloc memory + int64_t* id_ptr = tensor_id.mutable_data(place); + for (size_t i = 0; i < data.size(); ++i) { + id_ptr[i] = static_cast(data.at(i)); + } + + // Scores + LoDTensor tensor_score; + tensor_score.set_lod(lod); + tensor_score.Resize({static_cast(data.size())}); + // malloc memory + float* score_ptr = tensor_score.mutable_data(place); + for (size_t i = 0; i < data.size(); ++i) { + score_ptr[i] = static_cast(data.at(i)); + } + + ids->push_back(tensor_id); + scores->push_back(tensor_score); +} + +} // namespace test +} // namespace paddle + TEST(TrieConcatOp, DeleteBeamNode) { using BeamNode = paddle::operators::BeamNode; @@ -33,9 +79,10 @@ TEST(TrieConcatOp, DeleteBeamNode) { delete b2; } -TEST(TrieConcatOp, AppendBeamNodeToResult) { - using BeamHelper = paddle::operators::BeamHelpter; +TEST(TrieConcatOp, MakeSentence) { + using BeamHelper = paddle::operators::BeamHelper; using BeamNode = paddle::operators::BeamNode; + using Sentence = paddle::operators::Sentence; BeamNode* root = new BeamNode(0, 0); BeamNode* b1 = new BeamNode(1, 1); @@ -44,207 +91,89 @@ TEST(TrieConcatOp, AppendBeamNodeToResult) { end->AppendTo(b1); BeamHelper helper; - std::unordered_map>> result_id; - std::unordered_map>> result_score; + Sentence sentence = helper.MakeSentence(end); - helper.AppendBeamNodeToResult(0, end, &result_id, &result_score); + std::vector expect_ids = {0, 1, 2}; + ASSERT_EQ(sentence.word_ids, expect_ids); - ASSERT_EQ(result_score.at(0).size(), 1UL); - for (size_t i = 0; i < result_score.at(0).at(0).size(); ++i) { - float score = result_score.at(0).at(0).at(i); - ASSERT_EQ(score, static_cast(i)); - ASSERT_EQ(static_cast(result_id.at(0).at(0).at(i)), score); - } + std::vector expect_scores = {0, 1, 2}; + ASSERT_EQ(sentence.scores, expect_scores); } -TEST(TrieConcatOp, InitFirstStepBeamNodes) { - using BeamHelper = paddle::operators::BeamHelpter; - using BeamNode = paddle::operators::BeamNode; - using LoD = paddle::framework::LoD; +TEST(TrieConcatOp, PackTwoStepsFistStep) { + using BeamHelper = paddle::operators::BeamHelper; using CPUPlace = paddle::platform::CPUPlace; using LoDTensor = paddle::framework::LoDTensor; + using BeamNodeVector = paddle::operators::BeamNodeVector; + using SentenceVector = paddle::operators::SentenceVector; CPUPlace place; - LoD lod; - lod.push_back(std::vector{0, 3, 6}); - lod.push_back(std::vector{0, 1, 2, 3, 4, 5, 6}); + std::vector ids; + std::vector scores; - // Ids - LoDTensor tensor_id; - tensor_id.set_lod(lod); - tensor_id.Resize({6}); - // malloc memory - int64_t* id_ptr = tensor_id.mutable_data(place); - for (int64_t i = 0; i < 6; ++i) { - id_ptr[i] = i; - } + paddle::test::GenerateExample( + std::vector{0, 2, 6}, std::vector{0, 1, 2, 3, 4, 5, 6}, + std::vector{1, 2, 3, 4, 5, 6}, &ids, &scores); - // Scores - LoDTensor tensor_score; - tensor_score.set_lod(lod); - tensor_score.Resize({6}); - // malloc memory - float* score_ptr = tensor_score.mutable_data(place); - for (int i = 0; i < 6; ++i) { - score_ptr[i] = static_cast(i); - } + std::vector beamnode_vector_list; + std::unordered_map sentence_vector_list; BeamHelper helper; - std::unordered_map> result; - helper.InitFirstStepBeamNodes(tensor_id, tensor_score, &result); - - ASSERT_EQ(result.size(), 2UL); - ASSERT_EQ(result.at(0).size(), 3UL); - for (size_t i = 0; i < result.at(0).size(); ++i) { - auto* beam_node = result.at(0).at(i); - ASSERT_EQ(beam_node->word_id_, static_cast(i)); - ASSERT_EQ(beam_node->score_, static_cast(i)); - } - ASSERT_EQ(result.at(1).size(), 3UL); - for (size_t i = 0; i < result.at(1).size(); ++i) { - auto* beam_node = result.at(1).at(i); - ASSERT_EQ(beam_node->word_id_, static_cast(i + 3)); - ASSERT_EQ(beam_node->score_, static_cast(i + 3)); - } + beamnode_vector_list = helper.PackTwoSteps( + ids[0], scores[0], beamnode_vector_list, &sentence_vector_list); + ASSERT_EQ(beamnode_vector_list.size(), 2UL); + ASSERT_EQ(beamnode_vector_list[0].size(), 2UL); + ASSERT_EQ(beamnode_vector_list[1].size(), 4UL); } -TEST(TrieConcatOp, PackTwoBeamStepOut) { - using BeamHelper = paddle::operators::BeamHelpter; +TEST(TrieConcatOp, PackTwoSteps) { + using BeamHelper = paddle::operators::BeamHelper; using BeamNode = paddle::operators::BeamNode; - using LoD = paddle::framework::LoD; + using BeamNodeVector = paddle::operators::BeamNodeVector; + using SentenceVector = paddle::operators::SentenceVector; using CPUPlace = paddle::platform::CPUPlace; using LoDTensor = paddle::framework::LoDTensor; CPUPlace place; - // we have 2 source prefix to handle - LoD lod; - lod.push_back(std::vector{0, 3, 5}); - // the first source prefix have 4 candidate, the second have 2 candidate - lod.push_back(std::vector{0, 1, 1, 4, 4, 6}); - - // Ids - LoDTensor tensor_id; - tensor_id.set_lod(lod); - tensor_id.Resize({6}); - // malloc memory - int64_t* id_ptr = tensor_id.mutable_data(place); - for (int64_t i = 0; i < 6; ++i) { - id_ptr[i] = i; - } - - // Scores - LoDTensor tensor_score; - tensor_score.set_lod(lod); - tensor_score.Resize({6}); - // malloc memory - float* score_ptr = tensor_score.mutable_data(place); - for (int i = 0; i < 6; ++i) { - score_ptr[i] = static_cast(i); - } - - // result should be: - // [1 0] - // vector should be: - // [3 1] [3 2] [3 3] - - // three prefix - std::vector prefixes1; - prefixes1.push_back(new BeamNode(1, 1)); - prefixes1.push_back(new BeamNode(2, 2)); - prefixes1.push_back(new BeamNode(3, 3)); + // first source has three prefix + BeamNodeVector source0_prefixes; + source0_prefixes.push_back(new BeamNode(1, 1)); + source0_prefixes.push_back(new BeamNode(0, 0)); + source0_prefixes.push_back(new BeamNode(3, 3)); - BeamHelper helper1; - std::unordered_map>> result_id_1; - std::unordered_map>> result_score_1; - std::vector vec = helper1.PackTwoBeamStepOut( - 0, prefixes1, tensor_id, tensor_score, &result_id_1, &result_score_1); - ASSERT_EQ(vec.size(), 3UL); - for (size_t i = 0; i < 3; ++i) { - ASSERT_EQ(vec.at(i)->word_id_, static_cast(i + 1)); - ASSERT_EQ(vec.at(i)->score_, static_cast(i + 1)); - } - - ASSERT_EQ(result_id_1.at(0).size(), 1UL); - std::vector id_res = {1, 0}; - ASSERT_EQ(result_id_1.at(0).at(0), id_res); - - ASSERT_EQ(result_score_1.at(0).size(), 1UL); - std::vector score_res = {1, 0}; - ASSERT_EQ(result_score_1.at(0).at(0), score_res); - - // two prefix - // result should be: - // [2 4] [2 5] - std::vector prefixes2; - prefixes2.push_back(new BeamNode(1, 1)); - prefixes2.push_back(new BeamNode(2, 2)); - - BeamHelper helper2; - std::unordered_map>> result_id_2; - std::unordered_map>> result_score_2; - std::vector vec2 = helper2.PackTwoBeamStepOut( - 1, prefixes2, tensor_id, tensor_score, &result_id_2, &result_score_2); - ASSERT_EQ(vec2.size(), 2UL); - for (size_t i = 0; i < 2; ++i) { - ASSERT_EQ(vec2.at(i)->word_id_, static_cast(i + 4)); - ASSERT_EQ(vec2.at(i)->parent_->word_id_, static_cast(2)); - ASSERT_EQ(vec2.at(i)->score_, static_cast(i + 4)); - ASSERT_EQ(vec2.at(i)->parent_->score_, static_cast(2)); - } - ASSERT_EQ(result_id_2.size(), 0UL); - ASSERT_EQ(result_score_2.size(), 0UL); -} + // second source has two prefix + BeamNodeVector source1_prefixes; + source1_prefixes.push_back(new BeamNode(4, 4)); + source1_prefixes.push_back(new BeamNode(5, 5)); -namespace paddle { -namespace test { -using LoD = paddle::framework::LoD; -using CPUPlace = paddle::platform::CPUPlace; -using LoDTensor = paddle::framework::LoDTensor; - -void GenerateExample(const std::vector& level_0, - const std::vector& level_1, - const std::vector& data, std::vector* ids, - std::vector* scores) { - PADDLE_ENFORCE_EQ(level_0.back(), level_1.size() - 1, ""); - PADDLE_ENFORCE_EQ(level_1.back(), data.size(), ""); + std::vector beamnode_vector_list; + std::unordered_map sentence_vector_list; - CPUPlace place; + beamnode_vector_list.push_back(source0_prefixes); + beamnode_vector_list.push_back(source1_prefixes); - LoD lod; - lod.push_back(level_0); - lod.push_back(level_1); + // generate data for one step + std::vector ids; + std::vector scores; - // Ids - LoDTensor tensor_id; - tensor_id.set_lod(lod); - tensor_id.Resize({static_cast(data.size())}); - // malloc memory - int64_t* id_ptr = tensor_id.mutable_data(place); - for (size_t i = 0; i < data.size(); ++i) { - id_ptr[i] = static_cast(data.at(i)); - } + paddle::test::GenerateExample(std::vector{0, 3, 5}, + std::vector{0, 1, 1, 3, 4, 5}, + std::vector{0, 1, 2, 3, 4}, &ids, &scores); - // Scores - LoDTensor tensor_score; - tensor_score.set_lod(lod); - tensor_score.Resize({static_cast(data.size())}); - // malloc memory - float* score_ptr = tensor_score.mutable_data(place); - for (size_t i = 0; i < data.size(); ++i) { - score_ptr[i] = static_cast(data.at(i)); - } + BeamHelper helper1; + beamnode_vector_list = helper1.PackTwoSteps( + ids[0], scores[0], beamnode_vector_list, &sentence_vector_list); - ids->push_back(tensor_id); - scores->push_back(tensor_score); + ASSERT_EQ(sentence_vector_list[0].size(), 1UL); + ASSERT_EQ(sentence_vector_list[1].size(), 0UL); + ASSERT_EQ(beamnode_vector_list[0].size(), 3UL); + ASSERT_EQ(beamnode_vector_list[1].size(), 2UL); } -} // namespace test -} // namespace paddle - TEST(TrieConcatOp, PackAllSteps) { - using BeamHelper = paddle::operators::BeamHelpter; + using BeamHelper = paddle::operators::BeamHelper; using CPUPlace = paddle::platform::CPUPlace; using LoDTensor = paddle::framework::LoDTensor; using LoD = paddle::framework::LoD; @@ -261,8 +190,8 @@ TEST(TrieConcatOp, PackAllSteps) { paddle::test::GenerateExample( std::vector{0, 3, 6}, std::vector{0, 1, 1, 3, 5, 5, 6}, std::vector{0, 1, 2, 3, 4, 5}, &ids, &scores); - paddle::test::GenerateExample(std::vector{0, 2, 5}, - std::vector{0, 1, 2, 3, 4, 5}, + paddle::test::GenerateExample(std::vector{0, 3, 6}, + std::vector{0, 0, 1, 2, 3, 4, 5}, std::vector{0, 1, 2, 3, 4}, &ids, &scores); ASSERT_EQ(ids.size(), 3UL); @@ -286,19 +215,8 @@ TEST(TrieConcatOp, PackAllSteps) { ASSERT_EQ(id_tensor.data()[i], static_cast(expect_data[i])); } - - for (size_t level = 0; level < 2; ++level) { - for (size_t i = 0; i < lod[level].size(); ++i) { - std::cout << lod[level][i] << ", "; - } - std::cout << std::endl; - } for (int64_t i = 0; i < id_tensor.dims()[0]; ++i) { - std::cout << id_tensor.data()[i] << ", "; - } - std::cout << std::endl; - for (int64_t i = 0; i < score_tensor.dims()[0]; ++i) { - std::cout << score_tensor.data()[i] << ", "; + ASSERT_EQ(score_tensor.data()[i], + static_cast(id_tensor.data()[i])); } - std::cout << std::endl; } From 37bb50c6b0df0e6e6f12eadc4a710d188e261ec7 Mon Sep 17 00:00:00 2001 From: qiaolongfei Date: Thu, 9 Nov 2017 14:28:55 -0800 Subject: [PATCH 15/27] add comment to interface --- paddle/operators/trieconcat_op.h | 43 +++++++++++++++++++++++--- paddle/operators/trieconcat_op_test.cc | 20 ++++++------ 2 files changed, 49 insertions(+), 14 deletions(-) diff --git a/paddle/operators/trieconcat_op.h b/paddle/operators/trieconcat_op.h index 90ae3c2087434..008567e78541d 100644 --- a/paddle/operators/trieconcat_op.h +++ b/paddle/operators/trieconcat_op.h @@ -67,18 +67,52 @@ struct Sentence { using SentenceVector = std::vector; struct BeamHelper { - // make a BeamNode into sentence. + /** + * make a node and all it's related prefixes into a Sentence. + */ Sentence MakeSentence(const BeamNode* node) const; + /** + * Param: + * cur_ids: LoDTensor of One step for word ID + * cur_scores: LoDTensor of One Step for word score + * prefixes_list: prefixes for each source sentence. + * sentence_vector_list: result sentence_vector for each source sentence. + * Return: + * a new prefixes list for each source of current step + */ std::vector PackTwoSteps( const LoDTensor& cur_ids, const LoDTensor& cur_scores, const std::vector prefixes_list, std::unordered_map* sentence_vector_list) const; - void ConvertMapToLodTensor( + /** + * convert the result sentence_vector for each source sentence into two + * LodTensor. + * One is all candidate sentences with word id, one is all candidate sentences + * with word score. + * Param: + * sentence_vector_list: sentence_vector for each source sentence. + * id_tensor: result LoDTensor for sentences of id. + * score_tensor: result LoDTensor for sentences of score. + */ + void ConvertSentenceVectorToLodTensor( std::unordered_map sentence_vector_list, LoDTensor* id_tensor, LoDTensor* score_tensor) const; + /** + * Pack all steps of id/score LodTensor into sentence LoDTensor + * it's main logic is: + * ```python + * prefix + * result_sentence + * result_lod_tensor + * + * for (step in steps): + * prefix = PackTwoSteps(prefix, step, &result_sentence) + * ConvertSentenceVectorToLodTensor(result_sentence, &result_lod_tensor) + * ``` + */ void PackAllSteps(const std::vector& step_ids, const std::vector& step_scores, LoDTensor* id_tensor, LoDTensor* score_tensor) const; @@ -163,7 +197,7 @@ std::vector BeamHelper::PackTwoSteps( return result; } -void BeamHelper::ConvertMapToLodTensor( +void BeamHelper::ConvertSentenceVectorToLodTensor( std::unordered_map sentence_vector_list, LoDTensor* id_tensor, LoDTensor* score_tensor) const { size_t src_num = sentence_vector_list.size(); @@ -232,7 +266,8 @@ void BeamHelper::PackAllSteps(const std::vector& step_ids, } } - ConvertMapToLodTensor(sentence_vector_list, id_tensor, score_tensor); + ConvertSentenceVectorToLodTensor(sentence_vector_list, id_tensor, + score_tensor); } } // namespace operators diff --git a/paddle/operators/trieconcat_op_test.cc b/paddle/operators/trieconcat_op_test.cc index e1d532919fe3a..f1599a9ddc3c7 100644 --- a/paddle/operators/trieconcat_op_test.cc +++ b/paddle/operators/trieconcat_op_test.cc @@ -1,16 +1,16 @@ -/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserved. +/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserve. - 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 +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 + 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. */ +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 "paddle/operators/trieconcat_op.h" #include "gtest/gtest.h" From d4341dde4208be297ab5d70c29e850211d854ff5 Mon Sep 17 00:00:00 2001 From: qiaolongfei Date: Thu, 9 Nov 2017 15:36:52 -0800 Subject: [PATCH 16/27] optimizer data structure --- paddle/operators/trieconcat_op.h | 48 ++++++++++++++------------ paddle/operators/trieconcat_op_test.cc | 14 ++++---- 2 files changed, 34 insertions(+), 28 deletions(-) diff --git a/paddle/operators/trieconcat_op.h b/paddle/operators/trieconcat_op.h index 008567e78541d..ce256ef330ff5 100644 --- a/paddle/operators/trieconcat_op.h +++ b/paddle/operators/trieconcat_op.h @@ -68,7 +68,7 @@ using SentenceVector = std::vector; struct BeamHelper { /** - * make a node and all it's related prefixes into a Sentence. + * make a BeamNode and all it's related prefix BeanNode into a Sentence. */ Sentence MakeSentence(const BeamNode* node) const; @@ -83,8 +83,8 @@ struct BeamHelper { */ std::vector PackTwoSteps( const LoDTensor& cur_ids, const LoDTensor& cur_scores, - const std::vector prefixes_list, - std::unordered_map* sentence_vector_list) const; + const std::vector& prefixes_list, + std::vector* sentence_vector_list) const; /** * convert the result sentence_vector for each source sentence into two @@ -97,8 +97,8 @@ struct BeamHelper { * score_tensor: result LoDTensor for sentences of score. */ void ConvertSentenceVectorToLodTensor( - std::unordered_map sentence_vector_list, - LoDTensor* id_tensor, LoDTensor* score_tensor) const; + std::vector sentence_vector_list, LoDTensor* id_tensor, + LoDTensor* score_tensor) const; /** * Pack all steps of id/score LodTensor into sentence LoDTensor @@ -119,12 +119,11 @@ struct BeamHelper { }; Sentence BeamHelper::MakeSentence(const BeamNode* node) const { - const BeamNode* tmp = node; Sentence sentence; - while (tmp != nullptr) { - sentence.word_ids.emplace_back(tmp->word_id_); - sentence.scores.emplace_back(tmp->score_); - tmp = tmp->parent_; + while (node != nullptr) { + sentence.word_ids.emplace_back(node->word_id_); + sentence.scores.emplace_back(node->score_); + node = node->parent_; } std::reverse(std::begin(sentence.word_ids), std::end(sentence.word_ids)); @@ -135,8 +134,8 @@ Sentence BeamHelper::MakeSentence(const BeamNode* node) const { std::vector BeamHelper::PackTwoSteps( const LoDTensor& cur_ids, const LoDTensor& cur_scores, - const std::vector prefixes_list, - std::unordered_map* sentence_vector_list) const { + const std::vector& prefixes_list, + std::vector* sentence_vector_list) const { std::vector result; for (size_t src_idx = 0; src_idx < cur_ids.lod()[kSourceLevel].size() - 1; @@ -146,8 +145,9 @@ std::vector BeamHelper::PackTwoSteps( BeamNodeVector beam_nodes; - // if prefixes is nullptr, it means this is the first step. - if (prefixes_list.size() == 0UL) { + // if prefixes size is 0, it means this is the first step. In this step, + // all candidate id is the start of candidate sentences. + if (prefixes_list.empty()) { PADDLE_ENFORCE_EQ(cur_ids.lod().at(kSourceLevel).back(), cur_ids.lod().at(kSentenceLevel).back(), "in the first step"); @@ -198,14 +198,17 @@ std::vector BeamHelper::PackTwoSteps( } void BeamHelper::ConvertSentenceVectorToLodTensor( - std::unordered_map sentence_vector_list, - LoDTensor* id_tensor, LoDTensor* score_tensor) const { + std::vector sentence_vector_list, LoDTensor* id_tensor, + LoDTensor* score_tensor) const { size_t src_num = sentence_vector_list.size(); + PADDLE_ENFORCE_NE(src_num, 0, "src_num should not be 0"); + std::vector source_level_lod = {0}; std::vector sentence_level_lod = {0}; std::vector id_data; std::vector score_data; + for (size_t src_idx = 0; src_idx < src_num; ++src_idx) { for (Sentence& sentence : sentence_vector_list[src_idx]) { id_data.insert(id_data.end(), sentence.word_ids.begin(), @@ -241,16 +244,17 @@ void BeamHelper::PackAllSteps(const std::vector& step_ids, const std::vector& step_scores, LoDTensor* id_tensor, LoDTensor* score_tensor) const { - PADDLE_ENFORCE_GT(step_ids.size(), 0, "step num should be larger than 0"); + PADDLE_ENFORCE(!step_ids.empty(), "step num should be larger than 0"); PADDLE_ENFORCE_EQ(step_ids.size(), step_scores.size(), "step_ids and step_scores should be the same"); - size_t step_num = step_ids.size(); - size_t src_num = step_ids.at(0).lod().at(kSourceLevel).size() - 1; + const size_t step_num = step_ids.size(); + const size_t src_num = step_ids.at(0).lod().at(kSourceLevel).size() - 1; - PADDLE_ENFORCE_GT(src_num, 0, "source num should be larger than 0"); + PADDLE_ENFORCE_GT(src_num, 0UL, "source num should be larger than 0"); - std::vector beamnode_vector_list; - std::unordered_map sentence_vector_list; + std::vector + beamnode_vector_list; // previous prefixes for each step + std::vector sentence_vector_list(src_num, SentenceVector()); // pack all steps for one batch first, then another batch for (size_t step_id = 0; step_id < step_num; ++step_id) { diff --git a/paddle/operators/trieconcat_op_test.cc b/paddle/operators/trieconcat_op_test.cc index f1599a9ddc3c7..1bda51e690445 100644 --- a/paddle/operators/trieconcat_op_test.cc +++ b/paddle/operators/trieconcat_op_test.cc @@ -14,8 +14,6 @@ limitations under the License. */ #include "paddle/operators/trieconcat_op.h" #include "gtest/gtest.h" -#include "paddle/framework/lod_tensor.h" -#include "paddle/platform/place.h" namespace paddle { namespace test { @@ -27,8 +25,11 @@ void GenerateExample(const std::vector& level_0, const std::vector& level_1, const std::vector& data, std::vector* ids, std::vector* scores) { - PADDLE_ENFORCE_EQ(level_0.back(), level_1.size() - 1, ""); - PADDLE_ENFORCE_EQ(level_1.back(), data.size(), ""); + PADDLE_ENFORCE_EQ(level_0.back(), level_1.size() - 1, + "source level is used to describe candidate set"); + PADDLE_ENFORCE_EQ(level_1.back(), data.size(), + "the lowest level is used to describe data" + ", so it's last element should be data length"); CPUPlace place; @@ -92,6 +93,7 @@ TEST(TrieConcatOp, MakeSentence) { BeamHelper helper; Sentence sentence = helper.MakeSentence(end); + delete end; std::vector expect_ids = {0, 1, 2}; ASSERT_EQ(sentence.word_ids, expect_ids); @@ -117,7 +119,7 @@ TEST(TrieConcatOp, PackTwoStepsFistStep) { std::vector{1, 2, 3, 4, 5, 6}, &ids, &scores); std::vector beamnode_vector_list; - std::unordered_map sentence_vector_list; + std::vector sentence_vector_list(2, SentenceVector()); BeamHelper helper; beamnode_vector_list = helper.PackTwoSteps( @@ -149,7 +151,7 @@ TEST(TrieConcatOp, PackTwoSteps) { source1_prefixes.push_back(new BeamNode(5, 5)); std::vector beamnode_vector_list; - std::unordered_map sentence_vector_list; + std::vector sentence_vector_list(2, SentenceVector()); beamnode_vector_list.push_back(source0_prefixes); beamnode_vector_list.push_back(source1_prefixes); From 66ba3309d5d7156bd068c018e14685851cdcc653 Mon Sep 17 00:00:00 2001 From: qiaolongfei Date: Thu, 9 Nov 2017 17:04:06 -0800 Subject: [PATCH 17/27] use template to define the type of score --- paddle/operators/trieconcat_op.h | 86 +++++++++++++------------ paddle/operators/trieconcat_op_test.cc | 87 ++++++++++++-------------- 2 files changed, 86 insertions(+), 87 deletions(-) diff --git a/paddle/operators/trieconcat_op.h b/paddle/operators/trieconcat_op.h index ce256ef330ff5..8acbc64b4ea9f 100644 --- a/paddle/operators/trieconcat_op.h +++ b/paddle/operators/trieconcat_op.h @@ -19,7 +19,6 @@ limitations under the License. */ namespace paddle { namespace operators { -using value_type = float; using LoDTensor = framework::LoDTensor; const int64_t kEndId = 0; @@ -31,8 +30,9 @@ const int64_t kEndId = 0; const size_t kSourceLevel = 0; const size_t kSentenceLevel = 1; +template struct BeamNode { - BeamNode(int64_t word_id, float score) : word_id_(word_id), score_(score) {} + BeamNode(int64_t word_id, T score) : word_id_(word_id), score_(score) {} ~BeamNode() { if (parent_) { @@ -54,23 +54,27 @@ struct BeamNode { BeamNode* parent_ = nullptr; std::unordered_set kids_; int64_t word_id_; - float score_; + T score_; }; -using BeamNodeVector = std::vector; +template +using BeamNodeVector = std::vector*>; +template struct Sentence { std::vector word_ids; - std::vector scores; + std::vector scores; }; -using SentenceVector = std::vector; +template +using SentenceVector = std::vector>; +template struct BeamHelper { /** * make a BeamNode and all it's related prefix BeanNode into a Sentence. */ - Sentence MakeSentence(const BeamNode* node) const; + Sentence MakeSentence(const BeamNode* node) const; /** * Param: @@ -81,10 +85,10 @@ struct BeamHelper { * Return: * a new prefixes list for each source of current step */ - std::vector PackTwoSteps( + std::vector> PackTwoSteps( const LoDTensor& cur_ids, const LoDTensor& cur_scores, - const std::vector& prefixes_list, - std::vector* sentence_vector_list) const; + const std::vector>& prefixes_list, + std::vector>* sentence_vector_list) const; /** * convert the result sentence_vector for each source sentence into two @@ -97,7 +101,7 @@ struct BeamHelper { * score_tensor: result LoDTensor for sentences of score. */ void ConvertSentenceVectorToLodTensor( - std::vector sentence_vector_list, LoDTensor* id_tensor, + std::vector> sentence_vector_list, LoDTensor* id_tensor, LoDTensor* score_tensor) const; /** @@ -110,7 +114,7 @@ struct BeamHelper { * * for (step in steps): * prefix = PackTwoSteps(prefix, step, &result_sentence) - * ConvertSentenceVectorToLodTensor(result_sentence, &result_lod_tensor) + * ConvertSentenceVectorToLodTensor(result_sentence, &result_lod_tensor) * ``` */ void PackAllSteps(const std::vector& step_ids, @@ -118,8 +122,9 @@ struct BeamHelper { LoDTensor* id_tensor, LoDTensor* score_tensor) const; }; -Sentence BeamHelper::MakeSentence(const BeamNode* node) const { - Sentence sentence; +template +Sentence BeamHelper::MakeSentence(const BeamNode* node) const { + Sentence sentence; while (node != nullptr) { sentence.word_ids.emplace_back(node->word_id_); sentence.scores.emplace_back(node->score_); @@ -132,18 +137,19 @@ Sentence BeamHelper::MakeSentence(const BeamNode* node) const { return sentence; } -std::vector BeamHelper::PackTwoSteps( +template +std::vector> BeamHelper::PackTwoSteps( const LoDTensor& cur_ids, const LoDTensor& cur_scores, - const std::vector& prefixes_list, - std::vector* sentence_vector_list) const { - std::vector result; + const std::vector>& prefixes_list, + std::vector>* sentence_vector_list) const { + std::vector> result; for (size_t src_idx = 0; src_idx < cur_ids.lod()[kSourceLevel].size() - 1; ++src_idx) { size_t src_start = cur_ids.lod().at(kSourceLevel).at(src_idx); size_t src_end = cur_ids.lod().at(kSourceLevel).at(src_idx + 1); - BeamNodeVector beam_nodes; + BeamNodeVector beam_nodes; // if prefixes size is 0, it means this is the first step. In this step, // all candidate id is the start of candidate sentences. @@ -152,12 +158,12 @@ std::vector BeamHelper::PackTwoSteps( cur_ids.lod().at(kSentenceLevel).back(), "in the first step"); for (size_t id_idx = src_start; id_idx < src_end; ++id_idx) { - beam_nodes.push_back(new BeamNode(cur_ids.data()[id_idx], - cur_scores.data()[id_idx])); + beam_nodes.push_back(new BeamNode(cur_ids.data()[id_idx], + cur_scores.data()[id_idx])); } } else { - const BeamNodeVector& prefixes = prefixes_list[src_idx]; - SentenceVector& sentence_vector = (*sentence_vector_list)[src_idx]; + const BeamNodeVector& prefixes = prefixes_list[src_idx]; + SentenceVector& sentence_vector = (*sentence_vector_list)[src_idx]; PADDLE_ENFORCE_EQ(src_end - src_start, prefixes.size(), "prefix and candidate set number should be the same"); @@ -176,16 +182,13 @@ std::vector BeamHelper::PackTwoSteps( // remove this sentence from Beam Tree. delete prefix; } else { - // two level lod - // [0 2 6] source level - // [0 1 1 2 3 4] sentence level PADDLE_ENFORCE_NE(prefix->word_id_, kEndId, "End id should not have candidate anymore"); for (size_t candidate_idx = candidate_start; candidate_idx < candidate_end; ++candidate_idx) { auto* candidate = - new BeamNode(cur_ids.data()[candidate_idx], - cur_scores.data()[candidate_idx]); + new BeamNode(cur_ids.data()[candidate_idx], + cur_scores.data()[candidate_idx]); candidate->AppendTo(prefix); beam_nodes.push_back(candidate); } @@ -197,8 +200,9 @@ std::vector BeamHelper::PackTwoSteps( return result; } -void BeamHelper::ConvertSentenceVectorToLodTensor( - std::vector sentence_vector_list, LoDTensor* id_tensor, +template +void BeamHelper::ConvertSentenceVectorToLodTensor( + std::vector> sentence_vector_list, LoDTensor* id_tensor, LoDTensor* score_tensor) const { size_t src_num = sentence_vector_list.size(); @@ -207,10 +211,10 @@ void BeamHelper::ConvertSentenceVectorToLodTensor( std::vector source_level_lod = {0}; std::vector sentence_level_lod = {0}; std::vector id_data; - std::vector score_data; + std::vector score_data; for (size_t src_idx = 0; src_idx < src_num; ++src_idx) { - for (Sentence& sentence : sentence_vector_list[src_idx]) { + for (Sentence& sentence : sentence_vector_list[src_idx]) { id_data.insert(id_data.end(), sentence.word_ids.begin(), sentence.word_ids.end()); score_data.insert(score_data.end(), sentence.scores.begin(), @@ -236,14 +240,15 @@ void BeamHelper::ConvertSentenceVectorToLodTensor( score_tensor->set_lod(lod); score_tensor->Resize({static_cast(score_data.size())}); - score_tensor->mutable_data(paddle::platform::CPUPlace()); - score_tensor->CopyFromVector(score_data, cpu_ctx); + score_tensor->mutable_data(paddle::platform::CPUPlace()); + score_tensor->CopyFromVector(score_data, cpu_ctx); } -void BeamHelper::PackAllSteps(const std::vector& step_ids, - const std::vector& step_scores, - LoDTensor* id_tensor, - LoDTensor* score_tensor) const { +template +void BeamHelper::PackAllSteps(const std::vector& step_ids, + const std::vector& step_scores, + LoDTensor* id_tensor, + LoDTensor* score_tensor) const { PADDLE_ENFORCE(!step_ids.empty(), "step num should be larger than 0"); PADDLE_ENFORCE_EQ(step_ids.size(), step_scores.size(), "step_ids and step_scores should be the same"); @@ -252,9 +257,10 @@ void BeamHelper::PackAllSteps(const std::vector& step_ids, PADDLE_ENFORCE_GT(src_num, 0UL, "source num should be larger than 0"); - std::vector + std::vector> beamnode_vector_list; // previous prefixes for each step - std::vector sentence_vector_list(src_num, SentenceVector()); + std::vector> sentence_vector_list(src_num, + SentenceVector()); // pack all steps for one batch first, then another batch for (size_t step_id = 0; step_id < step_num; ++step_id) { diff --git a/paddle/operators/trieconcat_op_test.cc b/paddle/operators/trieconcat_op_test.cc index 1bda51e690445..bb6fb4f2db58c 100644 --- a/paddle/operators/trieconcat_op_test.cc +++ b/paddle/operators/trieconcat_op_test.cc @@ -64,13 +64,26 @@ void GenerateExample(const std::vector& level_0, } // namespace test } // namespace paddle -TEST(TrieConcatOp, DeleteBeamNode) { - using BeamNode = paddle::operators::BeamNode; +using CPUPlace = paddle::platform::CPUPlace; +using LoD = paddle::framework::LoD; +using LoDTensor = paddle::framework::LoDTensor; + +template +using BeamNode = paddle::operators::BeamNode; +template +using BeamHelper = paddle::operators::BeamHelper; +template +using Sentence = paddle::operators::Sentence; +template +using BeamNodeVector = paddle::operators::BeamNodeVector; +template +using SentenceVector = paddle::operators::SentenceVector; - BeamNode* root = new BeamNode(0, 0); - BeamNode* b1 = new BeamNode(1, 1); - BeamNode* b2 = new BeamNode(2, 2); - BeamNode* b3 = new BeamNode(3, 3); +TEST(TrieConcatOp, DeleteBeamNode) { + auto* root = new BeamNode(0, 0); + auto* b1 = new BeamNode(1, 1); + auto* b2 = new BeamNode(2, 2); + auto* b3 = new BeamNode(3, 3); b1->AppendTo(root); b2->AppendTo(root); @@ -81,18 +94,14 @@ TEST(TrieConcatOp, DeleteBeamNode) { } TEST(TrieConcatOp, MakeSentence) { - using BeamHelper = paddle::operators::BeamHelper; - using BeamNode = paddle::operators::BeamNode; - using Sentence = paddle::operators::Sentence; - - BeamNode* root = new BeamNode(0, 0); - BeamNode* b1 = new BeamNode(1, 1); - BeamNode* end = new BeamNode(2, 2); + auto* root = new BeamNode(0, 0); + auto* b1 = new BeamNode(1, 1); + auto* end = new BeamNode(2, 2); b1->AppendTo(root); end->AppendTo(b1); - BeamHelper helper; - Sentence sentence = helper.MakeSentence(end); + BeamHelper helper; + Sentence sentence = helper.MakeSentence(end); delete end; std::vector expect_ids = {0, 1, 2}; @@ -103,12 +112,6 @@ TEST(TrieConcatOp, MakeSentence) { } TEST(TrieConcatOp, PackTwoStepsFistStep) { - using BeamHelper = paddle::operators::BeamHelper; - using CPUPlace = paddle::platform::CPUPlace; - using LoDTensor = paddle::framework::LoDTensor; - using BeamNodeVector = paddle::operators::BeamNodeVector; - using SentenceVector = paddle::operators::SentenceVector; - CPUPlace place; std::vector ids; @@ -118,10 +121,11 @@ TEST(TrieConcatOp, PackTwoStepsFistStep) { std::vector{0, 2, 6}, std::vector{0, 1, 2, 3, 4, 5, 6}, std::vector{1, 2, 3, 4, 5, 6}, &ids, &scores); - std::vector beamnode_vector_list; - std::vector sentence_vector_list(2, SentenceVector()); + std::vector> beamnode_vector_list; + std::vector> sentence_vector_list( + 2, SentenceVector()); - BeamHelper helper; + BeamHelper helper; beamnode_vector_list = helper.PackTwoSteps( ids[0], scores[0], beamnode_vector_list, &sentence_vector_list); ASSERT_EQ(beamnode_vector_list.size(), 2UL); @@ -130,28 +134,22 @@ TEST(TrieConcatOp, PackTwoStepsFistStep) { } TEST(TrieConcatOp, PackTwoSteps) { - using BeamHelper = paddle::operators::BeamHelper; - using BeamNode = paddle::operators::BeamNode; - using BeamNodeVector = paddle::operators::BeamNodeVector; - using SentenceVector = paddle::operators::SentenceVector; - using CPUPlace = paddle::platform::CPUPlace; - using LoDTensor = paddle::framework::LoDTensor; - CPUPlace place; // first source has three prefix - BeamNodeVector source0_prefixes; - source0_prefixes.push_back(new BeamNode(1, 1)); - source0_prefixes.push_back(new BeamNode(0, 0)); - source0_prefixes.push_back(new BeamNode(3, 3)); + BeamNodeVector source0_prefixes; + source0_prefixes.push_back(new BeamNode(1, 1)); + source0_prefixes.push_back(new BeamNode(0, 0)); + source0_prefixes.push_back(new BeamNode(3, 3)); // second source has two prefix - BeamNodeVector source1_prefixes; - source1_prefixes.push_back(new BeamNode(4, 4)); - source1_prefixes.push_back(new BeamNode(5, 5)); + BeamNodeVector source1_prefixes; + source1_prefixes.push_back(new BeamNode(4, 4)); + source1_prefixes.push_back(new BeamNode(5, 5)); - std::vector beamnode_vector_list; - std::vector sentence_vector_list(2, SentenceVector()); + std::vector> beamnode_vector_list; + std::vector> sentence_vector_list( + 2, SentenceVector()); beamnode_vector_list.push_back(source0_prefixes); beamnode_vector_list.push_back(source1_prefixes); @@ -164,7 +162,7 @@ TEST(TrieConcatOp, PackTwoSteps) { std::vector{0, 1, 1, 3, 4, 5}, std::vector{0, 1, 2, 3, 4}, &ids, &scores); - BeamHelper helper1; + BeamHelper helper1; beamnode_vector_list = helper1.PackTwoSteps( ids[0], scores[0], beamnode_vector_list, &sentence_vector_list); @@ -175,11 +173,6 @@ TEST(TrieConcatOp, PackTwoSteps) { } TEST(TrieConcatOp, PackAllSteps) { - using BeamHelper = paddle::operators::BeamHelper; - using CPUPlace = paddle::platform::CPUPlace; - using LoDTensor = paddle::framework::LoDTensor; - using LoD = paddle::framework::LoD; - CPUPlace place; // we will constuct a sample data with 3 steps and 2 source sentences @@ -199,7 +192,7 @@ TEST(TrieConcatOp, PackAllSteps) { ASSERT_EQ(ids.size(), 3UL); ASSERT_EQ(scores.size(), 3UL); - BeamHelper helper; + BeamHelper helper; LoDTensor id_tensor; LoDTensor score_tensor; From cdb6f8a9df7401419bcfce015dc3e051b35e9ac7 Mon Sep 17 00:00:00 2001 From: qiaolongfei Date: Thu, 9 Nov 2017 17:49:01 -0800 Subject: [PATCH 18/27] use template parameter for BeamHelper --- paddle/operators/trieconcat_op.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/paddle/operators/trieconcat_op.cc b/paddle/operators/trieconcat_op.cc index 4cecb6b287427..8ccdc65c0c905 100644 --- a/paddle/operators/trieconcat_op.cc +++ b/paddle/operators/trieconcat_op.cc @@ -45,7 +45,7 @@ class TrieConcatOp : public framework::OperatorBase { LoDTensor* sentenceIds = ctx.Output("SentenceIds"); LoDTensor* sentenceScores = ctx.Output("SentenceScores"); - BeamHelper beam_helper; + BeamHelper beam_helper; beam_helper.PackAllSteps(*ids, *scores, sentenceIds, sentenceScores); } }; @@ -102,7 +102,7 @@ class TrieConcatInferVarType : public framework::VarTypeInference { } // namespace operators } // namespace paddle -REGISTER_OPERATOR(trie_concat, paddle::operators::TrieConcatOp, +REGISTER_OPERATOR(trieconcat, paddle::operators::TrieConcatOp, paddle::operators::TrieConcatOpProtoMaker, paddle::operators::TrieConcatInferShape, paddle::operators::TrieConcatInferVarType, From 3bf4c81d94e9a3f9fd9806cde02553d43c52245b Mon Sep 17 00:00:00 2001 From: qiaolongfei Date: Thu, 9 Nov 2017 17:52:11 -0800 Subject: [PATCH 19/27] change father to parent --- paddle/operators/trieconcat_op.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/paddle/operators/trieconcat_op.h b/paddle/operators/trieconcat_op.h index 8acbc64b4ea9f..88054922f8a3c 100644 --- a/paddle/operators/trieconcat_op.h +++ b/paddle/operators/trieconcat_op.h @@ -44,9 +44,9 @@ struct BeamNode { VLOG(3) << "Delete BeamNode root with word_id:" << this->word_id_; } - void AppendTo(BeamNode* father) { - parent_ = father; - father->kids_.insert(this); + void AppendTo(BeamNode* parent) { + parent_ = parent; + parent->kids_.insert(this); } void DropKid(BeamNode* kid) { kids_.erase(kid); } From 0705b5422712d6f3a8224f8b3a37ec4cf5fe7d4d Mon Sep 17 00:00:00 2001 From: qiaolongfei Date: Thu, 9 Nov 2017 19:01:22 -0800 Subject: [PATCH 20/27] rename TrieConcat to BeamSearchOutConcat --- paddle/operators/CMakeLists.txt | 2 +- ...cat_op.cc => beam_search_out_concat_op.cc} | 41 ++++++++++--------- ...oncat_op.h => beam_search_out_concat_op.h} | 0 ...t.cc => beam_search_out_concat_op_test.cc} | 12 +++--- 4 files changed, 29 insertions(+), 26 deletions(-) rename paddle/operators/{trieconcat_op.cc => beam_search_out_concat_op.cc} (69%) rename paddle/operators/{trieconcat_op.h => beam_search_out_concat_op.h} (100%) rename paddle/operators/{trieconcat_op_test.cc => beam_search_out_concat_op_test.cc} (96%) diff --git a/paddle/operators/CMakeLists.txt b/paddle/operators/CMakeLists.txt index 6fb49e585c678..c3ecd3a67c9a4 100644 --- a/paddle/operators/CMakeLists.txt +++ b/paddle/operators/CMakeLists.txt @@ -214,7 +214,7 @@ set(GLOB_OP_LIB ${OP_LIBRARY} CACHE INTERNAL "Global OP library") cc_test(gather_test SRCS gather_test.cc DEPS tensor) cc_test(net_op_test SRCS net_op_test.cc DEPS net_op) cc_test(scatter_test SRCS scatter_test.cc DEPS tensor) -cc_test(trieconcat_op_test SRCS trieconcat_op_test.cc DEPS lod_tensor) +cc_test(beam_search_out_concat_op_test SRCS beam_search_out_concat_op_test.cc DEPS lod_tensor) cc_test(strided_memcpy_test SRCS strided_memcpy_test.cc DEPS tensor paddle_memory) cc_test(dynamic_recurrent_op_test SRCS dynamic_recurrent_op_test.cc rnn/recurrent_op_utils.cc diff --git a/paddle/operators/trieconcat_op.cc b/paddle/operators/beam_search_out_concat_op.cc similarity index 69% rename from paddle/operators/trieconcat_op.cc rename to paddle/operators/beam_search_out_concat_op.cc index 8ccdc65c0c905..a8ffd507aabe3 100644 --- a/paddle/operators/trieconcat_op.cc +++ b/paddle/operators/beam_search_out_concat_op.cc @@ -12,17 +12,17 @@ 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 "paddle/operators/trieconcat_op.h" +#include "paddle/operators/beam_search_out_concat_op.h" namespace paddle { namespace operators { -class TrieConcatOp : public framework::OperatorBase { +class BeamSearchOutConcatOp : public framework::OperatorBase { public: - TrieConcatOp(const std::string& type, - const framework::VariableNameMap& inputs, - const framework::VariableNameMap& outputs, - const framework::AttributeMap& attrs) + BeamSearchOutConcatOp(const std::string& type, + const framework::VariableNameMap& inputs, + const framework::VariableNameMap& outputs, + const framework::AttributeMap& attrs) : OperatorBase(type, inputs, outputs, attrs) {} void Run(const framework::Scope& scope, const platform::DeviceContext& dev_ctx) const override { @@ -50,10 +50,11 @@ class TrieConcatOp : public framework::OperatorBase { } }; -class TrieConcatOpProtoMaker : public framework::OpProtoAndCheckerMaker { +class BeamSearchOutConcatOpProtoMaker + : public framework::OpProtoAndCheckerMaker { public: - TrieConcatOpProtoMaker(framework::OpProto* proto, - framework::OpAttrChecker* op_checker) + BeamSearchOutConcatOpProtoMaker(framework::OpProto* proto, + framework::OpAttrChecker* op_checker) : OpProtoAndCheckerMaker(proto, op_checker) { AddInput("Ids", "(vector)" @@ -73,20 +74,21 @@ Pack the result of Beam search op into SentenceIds and SentenceScores. } }; -class TrieConcatInferShape : public framework::InferShapeBase { +class BeamSearchOutConcatInferShape : public framework::InferShapeBase { public: void operator()(framework::InferShapeContext* context) const override { - PADDLE_ENFORCE(context->HasInput("Ids"), "TrieConcatOp must has input Ids"); + PADDLE_ENFORCE(context->HasInput("Ids"), + "BeamSearchOutConcatOp must has input Ids"); PADDLE_ENFORCE(context->HasInput("Scores"), - "TrieConcatOp must has input Scores"); + "BeamSearchOutConcatOp must has input Scores"); PADDLE_ENFORCE(context->HasOutput("SentenceIds"), - "TrieConcatOp must has output SentenceIds"); + "BeamSearchOutConcatOp must has output SentenceIds"); PADDLE_ENFORCE(context->HasOutput("SentenceScores"), - "TrieConcatOp must has output SentenceScores"); + "BeamSearchOutConcatOp must has output SentenceScores"); } }; -class TrieConcatInferVarType : public framework::VarTypeInference { +class BeamSearchOutConcatInferVarType : public framework::VarTypeInference { public: void operator()(const framework::OpDescBind& op_desc, framework::BlockDescBind* block) const override { @@ -102,8 +104,9 @@ class TrieConcatInferVarType : public framework::VarTypeInference { } // namespace operators } // namespace paddle -REGISTER_OPERATOR(trieconcat, paddle::operators::TrieConcatOp, - paddle::operators::TrieConcatOpProtoMaker, - paddle::operators::TrieConcatInferShape, - paddle::operators::TrieConcatInferVarType, +REGISTER_OPERATOR(beam_search_out_concat, + paddle::operators::BeamSearchOutConcatOp, + paddle::operators::BeamSearchOutConcatOpProtoMaker, + paddle::operators::BeamSearchOutConcatInferShape, + paddle::operators::BeamSearchOutConcatInferVarType, paddle::framework::EmptyGradOpMaker); diff --git a/paddle/operators/trieconcat_op.h b/paddle/operators/beam_search_out_concat_op.h similarity index 100% rename from paddle/operators/trieconcat_op.h rename to paddle/operators/beam_search_out_concat_op.h diff --git a/paddle/operators/trieconcat_op_test.cc b/paddle/operators/beam_search_out_concat_op_test.cc similarity index 96% rename from paddle/operators/trieconcat_op_test.cc rename to paddle/operators/beam_search_out_concat_op_test.cc index bb6fb4f2db58c..cfa295737a52e 100644 --- a/paddle/operators/trieconcat_op_test.cc +++ b/paddle/operators/beam_search_out_concat_op_test.cc @@ -12,7 +12,7 @@ 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 "paddle/operators/trieconcat_op.h" +#include "paddle/operators/beam_search_out_concat_op.h" #include "gtest/gtest.h" namespace paddle { @@ -79,7 +79,7 @@ using BeamNodeVector = paddle::operators::BeamNodeVector; template using SentenceVector = paddle::operators::SentenceVector; -TEST(TrieConcatOp, DeleteBeamNode) { +TEST(BeamSearchOutConcatOp, DeleteBeamNode) { auto* root = new BeamNode(0, 0); auto* b1 = new BeamNode(1, 1); auto* b2 = new BeamNode(2, 2); @@ -93,7 +93,7 @@ TEST(TrieConcatOp, DeleteBeamNode) { delete b2; } -TEST(TrieConcatOp, MakeSentence) { +TEST(BeamSearchOutConcatOp, MakeSentence) { auto* root = new BeamNode(0, 0); auto* b1 = new BeamNode(1, 1); auto* end = new BeamNode(2, 2); @@ -111,7 +111,7 @@ TEST(TrieConcatOp, MakeSentence) { ASSERT_EQ(sentence.scores, expect_scores); } -TEST(TrieConcatOp, PackTwoStepsFistStep) { +TEST(BeamSearchOutConcatOp, PackTwoStepsFistStep) { CPUPlace place; std::vector ids; @@ -133,7 +133,7 @@ TEST(TrieConcatOp, PackTwoStepsFistStep) { ASSERT_EQ(beamnode_vector_list[1].size(), 4UL); } -TEST(TrieConcatOp, PackTwoSteps) { +TEST(BeamSearchOutConcatOp, PackTwoSteps) { CPUPlace place; // first source has three prefix @@ -172,7 +172,7 @@ TEST(TrieConcatOp, PackTwoSteps) { ASSERT_EQ(beamnode_vector_list[1].size(), 2UL); } -TEST(TrieConcatOp, PackAllSteps) { +TEST(BeamSearchOutConcatOp, PackAllSteps) { CPUPlace place; // we will constuct a sample data with 3 steps and 2 source sentences From 89b8d326ed51a313aab97c7699302260b82fd37e Mon Sep 17 00:00:00 2001 From: qiaolongfei Date: Thu, 9 Nov 2017 19:18:42 -0800 Subject: [PATCH 21/27] use LoDTensorArray --- paddle/operators/beam_search_out_concat_op.cc | 6 +-- paddle/operators/beam_search_out_concat_op.h | 12 +++-- .../beam_search_out_concat_op_test.cc | 50 +++++++++---------- 3 files changed, 33 insertions(+), 35 deletions(-) diff --git a/paddle/operators/beam_search_out_concat_op.cc b/paddle/operators/beam_search_out_concat_op.cc index a8ffd507aabe3..33bbabf9b94f2 100644 --- a/paddle/operators/beam_search_out_concat_op.cc +++ b/paddle/operators/beam_search_out_concat_op.cc @@ -27,10 +27,8 @@ class BeamSearchOutConcatOp : public framework::OperatorBase { void Run(const framework::Scope& scope, const platform::DeviceContext& dev_ctx) const override { framework::ExecutionContext ctx(*this, scope, dev_ctx); - const std::vector* ids = - ctx.Input>("Ids"); - const std::vector* scores = - ctx.Input>("Scores"); + const LoDTensorArray* ids = ctx.Input("Ids"); + const LoDTensorArray* scores = ctx.Input("Scores"); const size_t step_num = ids->size(); PADDLE_ENFORCE_LT(step_num, 0, "beam search steps should be larger than 0"); const size_t source_num = ids->at(0).lod().at(0).size() - 1; diff --git a/paddle/operators/beam_search_out_concat_op.h b/paddle/operators/beam_search_out_concat_op.h index 88054922f8a3c..8a56c6bbb1a6b 100644 --- a/paddle/operators/beam_search_out_concat_op.h +++ b/paddle/operators/beam_search_out_concat_op.h @@ -14,12 +14,14 @@ limitations under the License. */ #pragma once +#include "paddle/framework/lod_tensor_array.h" #include "paddle/framework/op_registry.h" namespace paddle { namespace operators { using LoDTensor = framework::LoDTensor; +using LoDTensorArray = framework::LoDTensorArray; const int64_t kEndId = 0; @@ -117,9 +119,9 @@ struct BeamHelper { * ConvertSentenceVectorToLodTensor(result_sentence, &result_lod_tensor) * ``` */ - void PackAllSteps(const std::vector& step_ids, - const std::vector& step_scores, - LoDTensor* id_tensor, LoDTensor* score_tensor) const; + void PackAllSteps(const LoDTensorArray& step_ids, + const LoDTensorArray& step_scores, LoDTensor* id_tensor, + LoDTensor* score_tensor) const; }; template @@ -245,8 +247,8 @@ void BeamHelper::ConvertSentenceVectorToLodTensor( } template -void BeamHelper::PackAllSteps(const std::vector& step_ids, - const std::vector& step_scores, +void BeamHelper::PackAllSteps(const LoDTensorArray& step_ids, + const LoDTensorArray& step_scores, LoDTensor* id_tensor, LoDTensor* score_tensor) const { PADDLE_ENFORCE(!step_ids.empty(), "step num should be larger than 0"); diff --git a/paddle/operators/beam_search_out_concat_op_test.cc b/paddle/operators/beam_search_out_concat_op_test.cc index cfa295737a52e..303fd30b43b77 100644 --- a/paddle/operators/beam_search_out_concat_op_test.cc +++ b/paddle/operators/beam_search_out_concat_op_test.cc @@ -15,16 +15,29 @@ limitations under the License. */ #include "paddle/operators/beam_search_out_concat_op.h" #include "gtest/gtest.h" -namespace paddle { -namespace test { -using LoD = paddle::framework::LoD; using CPUPlace = paddle::platform::CPUPlace; +using LoD = paddle::framework::LoD; using LoDTensor = paddle::framework::LoDTensor; +using LoDTensorArray = paddle::framework::LoDTensorArray; + +template +using BeamNode = paddle::operators::BeamNode; +template +using BeamHelper = paddle::operators::BeamHelper; +template +using Sentence = paddle::operators::Sentence; +template +using BeamNodeVector = paddle::operators::BeamNodeVector; +template +using SentenceVector = paddle::operators::SentenceVector; + +namespace paddle { +namespace test { void GenerateExample(const std::vector& level_0, const std::vector& level_1, - const std::vector& data, std::vector* ids, - std::vector* scores) { + const std::vector& data, LoDTensorArray* ids, + LoDTensorArray* scores) { PADDLE_ENFORCE_EQ(level_0.back(), level_1.size() - 1, "source level is used to describe candidate set"); PADDLE_ENFORCE_EQ(level_1.back(), data.size(), @@ -64,21 +77,6 @@ void GenerateExample(const std::vector& level_0, } // namespace test } // namespace paddle -using CPUPlace = paddle::platform::CPUPlace; -using LoD = paddle::framework::LoD; -using LoDTensor = paddle::framework::LoDTensor; - -template -using BeamNode = paddle::operators::BeamNode; -template -using BeamHelper = paddle::operators::BeamHelper; -template -using Sentence = paddle::operators::Sentence; -template -using BeamNodeVector = paddle::operators::BeamNodeVector; -template -using SentenceVector = paddle::operators::SentenceVector; - TEST(BeamSearchOutConcatOp, DeleteBeamNode) { auto* root = new BeamNode(0, 0); auto* b1 = new BeamNode(1, 1); @@ -114,8 +112,8 @@ TEST(BeamSearchOutConcatOp, MakeSentence) { TEST(BeamSearchOutConcatOp, PackTwoStepsFistStep) { CPUPlace place; - std::vector ids; - std::vector scores; + LoDTensorArray ids; + LoDTensorArray scores; paddle::test::GenerateExample( std::vector{0, 2, 6}, std::vector{0, 1, 2, 3, 4, 5, 6}, @@ -155,8 +153,8 @@ TEST(BeamSearchOutConcatOp, PackTwoSteps) { beamnode_vector_list.push_back(source1_prefixes); // generate data for one step - std::vector ids; - std::vector scores; + LoDTensorArray ids; + LoDTensorArray scores; paddle::test::GenerateExample(std::vector{0, 3, 5}, std::vector{0, 1, 1, 3, 4, 5}, @@ -176,8 +174,8 @@ TEST(BeamSearchOutConcatOp, PackAllSteps) { CPUPlace place; // we will constuct a sample data with 3 steps and 2 source sentences - std::vector ids; - std::vector scores; + LoDTensorArray ids; + LoDTensorArray scores; paddle::test::GenerateExample( std::vector{0, 3, 6}, std::vector{0, 1, 2, 3, 4, 5, 6}, From 1c038bd86708a8e0ef2ed7b9f8ff5fcdf82bdda8 Mon Sep 17 00:00:00 2001 From: qiaolongfei Date: Thu, 9 Nov 2017 19:43:08 -0800 Subject: [PATCH 22/27] rename BeamSearchOutConcat to BeamSearchDecode --- paddle/operators/CMakeLists.txt | 2 +- ..._concat_op.cc => beam_search_decode_op.cc} | 49 +++++++++---------- ...ut_concat_op.h => beam_search_decode_op.h} | 16 +++--- ..._test.cc => beam_search_decode_op_test.cc} | 22 ++++----- paddle/operators/sequence_concat_op.cc | 2 +- 5 files changed, 45 insertions(+), 46 deletions(-) rename paddle/operators/{beam_search_out_concat_op.cc => beam_search_decode_op.cc} (66%) rename paddle/operators/{beam_search_out_concat_op.h => beam_search_decode_op.h} (95%) rename paddle/operators/{beam_search_out_concat_op_test.cc => beam_search_decode_op_test.cc} (93%) diff --git a/paddle/operators/CMakeLists.txt b/paddle/operators/CMakeLists.txt index c3ecd3a67c9a4..709f7de2e4309 100644 --- a/paddle/operators/CMakeLists.txt +++ b/paddle/operators/CMakeLists.txt @@ -214,7 +214,7 @@ set(GLOB_OP_LIB ${OP_LIBRARY} CACHE INTERNAL "Global OP library") cc_test(gather_test SRCS gather_test.cc DEPS tensor) cc_test(net_op_test SRCS net_op_test.cc DEPS net_op) cc_test(scatter_test SRCS scatter_test.cc DEPS tensor) -cc_test(beam_search_out_concat_op_test SRCS beam_search_out_concat_op_test.cc DEPS lod_tensor) +cc_test(beam_search_decode_op_test SRCS beam_search_decode_op_test.cc DEPS lod_tensor) cc_test(strided_memcpy_test SRCS strided_memcpy_test.cc DEPS tensor paddle_memory) cc_test(dynamic_recurrent_op_test SRCS dynamic_recurrent_op_test.cc rnn/recurrent_op_utils.cc diff --git a/paddle/operators/beam_search_out_concat_op.cc b/paddle/operators/beam_search_decode_op.cc similarity index 66% rename from paddle/operators/beam_search_out_concat_op.cc rename to paddle/operators/beam_search_decode_op.cc index 33bbabf9b94f2..b96c1d69773f1 100644 --- a/paddle/operators/beam_search_out_concat_op.cc +++ b/paddle/operators/beam_search_decode_op.cc @@ -12,17 +12,17 @@ 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 "paddle/operators/beam_search_out_concat_op.h" +#include "paddle/operators/beam_search_decode_op.h" namespace paddle { namespace operators { -class BeamSearchOutConcatOp : public framework::OperatorBase { +class BeamSearchDecodeOp : public framework::OperatorBase { public: - BeamSearchOutConcatOp(const std::string& type, - const framework::VariableNameMap& inputs, - const framework::VariableNameMap& outputs, - const framework::AttributeMap& attrs) + BeamSearchDecodeOp(const std::string& type, + const framework::VariableNameMap& inputs, + const framework::VariableNameMap& outputs, + const framework::AttributeMap& attrs) : OperatorBase(type, inputs, outputs, attrs) {} void Run(const framework::Scope& scope, const platform::DeviceContext& dev_ctx) const override { @@ -43,22 +43,22 @@ class BeamSearchOutConcatOp : public framework::OperatorBase { LoDTensor* sentenceIds = ctx.Output("SentenceIds"); LoDTensor* sentenceScores = ctx.Output("SentenceScores"); - BeamHelper beam_helper; - beam_helper.PackAllSteps(*ids, *scores, sentenceIds, sentenceScores); + BeamSearchDecoder beam_search_decoder; + beam_search_decoder.PackAllSteps(*ids, *scores, sentenceIds, + sentenceScores); } }; -class BeamSearchOutConcatOpProtoMaker - : public framework::OpProtoAndCheckerMaker { +class BeamSearchDecodeOpProtoMaker : public framework::OpProtoAndCheckerMaker { public: - BeamSearchOutConcatOpProtoMaker(framework::OpProto* proto, - framework::OpAttrChecker* op_checker) + BeamSearchDecodeOpProtoMaker(framework::OpProto* proto, + framework::OpAttrChecker* op_checker) : OpProtoAndCheckerMaker(proto, op_checker) { AddInput("Ids", - "(vector)" + "(LodTensorArray)" "score of the candidate words in each step"); AddInput("Scores", - "(vector)" + "(LodTensorArray)" "score of the candidate words in each step"); AddOutput("SentenceIds", "(LodTensor)" @@ -72,21 +72,21 @@ Pack the result of Beam search op into SentenceIds and SentenceScores. } }; -class BeamSearchOutConcatInferShape : public framework::InferShapeBase { +class BeamSearchDecodeInferShape : public framework::InferShapeBase { public: void operator()(framework::InferShapeContext* context) const override { PADDLE_ENFORCE(context->HasInput("Ids"), - "BeamSearchOutConcatOp must has input Ids"); + "BeamSearchDecodeOp must has input Ids"); PADDLE_ENFORCE(context->HasInput("Scores"), - "BeamSearchOutConcatOp must has input Scores"); + "BeamSearchDecodeOp must has input Scores"); PADDLE_ENFORCE(context->HasOutput("SentenceIds"), - "BeamSearchOutConcatOp must has output SentenceIds"); + "BeamSearchDecodeOp must has output SentenceIds"); PADDLE_ENFORCE(context->HasOutput("SentenceScores"), - "BeamSearchOutConcatOp must has output SentenceScores"); + "BeamSearchDecodeOp must has output SentenceScores"); } }; -class BeamSearchOutConcatInferVarType : public framework::VarTypeInference { +class BeamSearchDecodeInferVarType : public framework::VarTypeInference { public: void operator()(const framework::OpDescBind& op_desc, framework::BlockDescBind* block) const override { @@ -102,9 +102,8 @@ class BeamSearchOutConcatInferVarType : public framework::VarTypeInference { } // namespace operators } // namespace paddle -REGISTER_OPERATOR(beam_search_out_concat, - paddle::operators::BeamSearchOutConcatOp, - paddle::operators::BeamSearchOutConcatOpProtoMaker, - paddle::operators::BeamSearchOutConcatInferShape, - paddle::operators::BeamSearchOutConcatInferVarType, +REGISTER_OPERATOR(beam_search_out_concat, paddle::operators::BeamSearchDecodeOp, + paddle::operators::BeamSearchDecodeOpProtoMaker, + paddle::operators::BeamSearchDecodeInferShape, + paddle::operators::BeamSearchDecodeInferVarType, paddle::framework::EmptyGradOpMaker); diff --git a/paddle/operators/beam_search_out_concat_op.h b/paddle/operators/beam_search_decode_op.h similarity index 95% rename from paddle/operators/beam_search_out_concat_op.h rename to paddle/operators/beam_search_decode_op.h index 8a56c6bbb1a6b..8d2174a82de15 100644 --- a/paddle/operators/beam_search_out_concat_op.h +++ b/paddle/operators/beam_search_decode_op.h @@ -72,7 +72,7 @@ template using SentenceVector = std::vector>; template -struct BeamHelper { +struct BeamSearchDecoder { /** * make a BeamNode and all it's related prefix BeanNode into a Sentence. */ @@ -125,7 +125,7 @@ struct BeamHelper { }; template -Sentence BeamHelper::MakeSentence(const BeamNode* node) const { +Sentence BeamSearchDecoder::MakeSentence(const BeamNode* node) const { Sentence sentence; while (node != nullptr) { sentence.word_ids.emplace_back(node->word_id_); @@ -140,7 +140,7 @@ Sentence BeamHelper::MakeSentence(const BeamNode* node) const { } template -std::vector> BeamHelper::PackTwoSteps( +std::vector> BeamSearchDecoder::PackTwoSteps( const LoDTensor& cur_ids, const LoDTensor& cur_scores, const std::vector>& prefixes_list, std::vector>* sentence_vector_list) const { @@ -203,7 +203,7 @@ std::vector> BeamHelper::PackTwoSteps( } template -void BeamHelper::ConvertSentenceVectorToLodTensor( +void BeamSearchDecoder::ConvertSentenceVectorToLodTensor( std::vector> sentence_vector_list, LoDTensor* id_tensor, LoDTensor* score_tensor) const { size_t src_num = sentence_vector_list.size(); @@ -247,10 +247,10 @@ void BeamHelper::ConvertSentenceVectorToLodTensor( } template -void BeamHelper::PackAllSteps(const LoDTensorArray& step_ids, - const LoDTensorArray& step_scores, - LoDTensor* id_tensor, - LoDTensor* score_tensor) const { +void BeamSearchDecoder::PackAllSteps(const LoDTensorArray& step_ids, + const LoDTensorArray& step_scores, + LoDTensor* id_tensor, + LoDTensor* score_tensor) const { PADDLE_ENFORCE(!step_ids.empty(), "step num should be larger than 0"); PADDLE_ENFORCE_EQ(step_ids.size(), step_scores.size(), "step_ids and step_scores should be the same"); diff --git a/paddle/operators/beam_search_out_concat_op_test.cc b/paddle/operators/beam_search_decode_op_test.cc similarity index 93% rename from paddle/operators/beam_search_out_concat_op_test.cc rename to paddle/operators/beam_search_decode_op_test.cc index 303fd30b43b77..1ced32dcffdf7 100644 --- a/paddle/operators/beam_search_out_concat_op_test.cc +++ b/paddle/operators/beam_search_decode_op_test.cc @@ -12,7 +12,7 @@ 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 "paddle/operators/beam_search_out_concat_op.h" +#include "paddle/operators/beam_search_decode_op.h" #include "gtest/gtest.h" using CPUPlace = paddle::platform::CPUPlace; @@ -23,7 +23,7 @@ using LoDTensorArray = paddle::framework::LoDTensorArray; template using BeamNode = paddle::operators::BeamNode; template -using BeamHelper = paddle::operators::BeamHelper; +using BeamSearchDecoder = paddle::operators::BeamSearchDecoder; template using Sentence = paddle::operators::Sentence; template @@ -77,7 +77,7 @@ void GenerateExample(const std::vector& level_0, } // namespace test } // namespace paddle -TEST(BeamSearchOutConcatOp, DeleteBeamNode) { +TEST(BeamSearchDecodeOp, DeleteBeamNode) { auto* root = new BeamNode(0, 0); auto* b1 = new BeamNode(1, 1); auto* b2 = new BeamNode(2, 2); @@ -91,14 +91,14 @@ TEST(BeamSearchOutConcatOp, DeleteBeamNode) { delete b2; } -TEST(BeamSearchOutConcatOp, MakeSentence) { +TEST(BeamSearchDecodeOp, MakeSentence) { auto* root = new BeamNode(0, 0); auto* b1 = new BeamNode(1, 1); auto* end = new BeamNode(2, 2); b1->AppendTo(root); end->AppendTo(b1); - BeamHelper helper; + BeamSearchDecoder helper; Sentence sentence = helper.MakeSentence(end); delete end; @@ -109,7 +109,7 @@ TEST(BeamSearchOutConcatOp, MakeSentence) { ASSERT_EQ(sentence.scores, expect_scores); } -TEST(BeamSearchOutConcatOp, PackTwoStepsFistStep) { +TEST(BeamSearchDecodeOp, PackTwoStepsFistStep) { CPUPlace place; LoDTensorArray ids; @@ -123,7 +123,7 @@ TEST(BeamSearchOutConcatOp, PackTwoStepsFistStep) { std::vector> sentence_vector_list( 2, SentenceVector()); - BeamHelper helper; + BeamSearchDecoder helper; beamnode_vector_list = helper.PackTwoSteps( ids[0], scores[0], beamnode_vector_list, &sentence_vector_list); ASSERT_EQ(beamnode_vector_list.size(), 2UL); @@ -131,7 +131,7 @@ TEST(BeamSearchOutConcatOp, PackTwoStepsFistStep) { ASSERT_EQ(beamnode_vector_list[1].size(), 4UL); } -TEST(BeamSearchOutConcatOp, PackTwoSteps) { +TEST(BeamSearchDecodeOp, PackTwoSteps) { CPUPlace place; // first source has three prefix @@ -160,7 +160,7 @@ TEST(BeamSearchOutConcatOp, PackTwoSteps) { std::vector{0, 1, 1, 3, 4, 5}, std::vector{0, 1, 2, 3, 4}, &ids, &scores); - BeamHelper helper1; + BeamSearchDecoder helper1; beamnode_vector_list = helper1.PackTwoSteps( ids[0], scores[0], beamnode_vector_list, &sentence_vector_list); @@ -170,7 +170,7 @@ TEST(BeamSearchOutConcatOp, PackTwoSteps) { ASSERT_EQ(beamnode_vector_list[1].size(), 2UL); } -TEST(BeamSearchOutConcatOp, PackAllSteps) { +TEST(BeamSearchDecodeOp, PackAllSteps) { CPUPlace place; // we will constuct a sample data with 3 steps and 2 source sentences @@ -190,7 +190,7 @@ TEST(BeamSearchOutConcatOp, PackAllSteps) { ASSERT_EQ(ids.size(), 3UL); ASSERT_EQ(scores.size(), 3UL); - BeamHelper helper; + BeamSearchDecoder helper; LoDTensor id_tensor; LoDTensor score_tensor; diff --git a/paddle/operators/sequence_concat_op.cc b/paddle/operators/sequence_concat_op.cc index 64097ef2525d7..a121fdb5a5aec 100644 --- a/paddle/operators/sequence_concat_op.cc +++ b/paddle/operators/sequence_concat_op.cc @@ -47,7 +47,7 @@ class SequenceConcatOpMaker : public framework::OpProtoAndCheckerMaker { framework::OpAttrChecker* op_checker) : OpProtoAndCheckerMaker(proto, op_checker) { AddInput("X", - "(vector) Input is a vector of LoDTensor, " + "(LodTensorArray) Input is a vector of LoDTensor, " "each of which is a variable-length sequence or nested sequence.") .AsDuplicable(); AddOutput("Out", From fa1c74b6147d68c369937d8fb43ec9db5b9cf66e Mon Sep 17 00:00:00 2001 From: qiaolongfei Date: Thu, 9 Nov 2017 20:11:02 -0800 Subject: [PATCH 23/27] refine code --- paddle/operators/beam_search_decode_op.cc | 2 +- paddle/operators/beam_search_decode_op.h | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/paddle/operators/beam_search_decode_op.cc b/paddle/operators/beam_search_decode_op.cc index b96c1d69773f1..a0dddcdd18259 100644 --- a/paddle/operators/beam_search_decode_op.cc +++ b/paddle/operators/beam_search_decode_op.cc @@ -102,7 +102,7 @@ class BeamSearchDecodeInferVarType : public framework::VarTypeInference { } // namespace operators } // namespace paddle -REGISTER_OPERATOR(beam_search_out_concat, paddle::operators::BeamSearchDecodeOp, +REGISTER_OPERATOR(beam_search_decode, paddle::operators::BeamSearchDecodeOp, paddle::operators::BeamSearchDecodeOpProtoMaker, paddle::operators::BeamSearchDecodeInferShape, paddle::operators::BeamSearchDecodeInferVarType, diff --git a/paddle/operators/beam_search_decode_op.h b/paddle/operators/beam_search_decode_op.h index 8d2174a82de15..da41063a86e1e 100644 --- a/paddle/operators/beam_search_decode_op.h +++ b/paddle/operators/beam_search_decode_op.h @@ -259,10 +259,10 @@ void BeamSearchDecoder::PackAllSteps(const LoDTensorArray& step_ids, PADDLE_ENFORCE_GT(src_num, 0UL, "source num should be larger than 0"); - std::vector> - beamnode_vector_list; // previous prefixes for each step - std::vector> sentence_vector_list(src_num, - SentenceVector()); + // previous prefixes for each step, + // the init length is 0, means this is the first step. + std::vector> beamnode_vector_list(0); + std::vector> sentence_vector_list(src_num); // pack all steps for one batch first, then another batch for (size_t step_id = 0; step_id < step_num; ++step_id) { From 2f1cba241ee75e2dec20d6da8423a6844b5e0710 Mon Sep 17 00:00:00 2001 From: qiaolongfei Date: Fri, 10 Nov 2017 00:18:27 -0800 Subject: [PATCH 24/27] remain all candidate sentence in beam_search_decode_op, do not consider endid --- paddle/operators/beam_search_decode_op.h | 13 +++---------- paddle/operators/beam_search_decode_op_test.cc | 9 +++++---- 2 files changed, 8 insertions(+), 14 deletions(-) diff --git a/paddle/operators/beam_search_decode_op.h b/paddle/operators/beam_search_decode_op.h index da41063a86e1e..4104c2bee9b6a 100644 --- a/paddle/operators/beam_search_decode_op.h +++ b/paddle/operators/beam_search_decode_op.h @@ -23,8 +23,6 @@ namespace operators { using LoDTensor = framework::LoDTensor; using LoDTensorArray = framework::LoDTensorArray; -const int64_t kEndId = 0; - // all the lod have 2 levels. // The First is source level, the second is sentence level. // source level describe how many candidate words for this source. @@ -176,16 +174,11 @@ std::vector> BeamSearchDecoder::PackTwoSteps( size_t candidate_start = candidate_offset[src_start + prefix_idx]; size_t candidate_end = candidate_offset[src_start + prefix_idx + 1]; if (candidate_start == candidate_end) { - if (prefix->word_id_ == kEndId) { - VLOG(3) << "this sentence has Ended, prune it"; - sentence_vector.push_back(MakeSentence(prefix)); - } - VLOG(3) << "this sentence has no more candidate, prune it"; - // remove this sentence from Beam Tree. + VLOG(3) << "this sentence has no more candidate, " + "add to result sentence and rm it from beam tree"; + sentence_vector.push_back(MakeSentence(prefix)); delete prefix; } else { - PADDLE_ENFORCE_NE(prefix->word_id_, kEndId, - "End id should not have candidate anymore"); for (size_t candidate_idx = candidate_start; candidate_idx < candidate_end; ++candidate_idx) { auto* candidate = diff --git a/paddle/operators/beam_search_decode_op_test.cc b/paddle/operators/beam_search_decode_op_test.cc index 1ced32dcffdf7..96f1dd29c67dc 100644 --- a/paddle/operators/beam_search_decode_op_test.cc +++ b/paddle/operators/beam_search_decode_op_test.cc @@ -197,12 +197,13 @@ TEST(BeamSearchDecodeOp, PackAllSteps) { helper.PackAllSteps(ids, scores, &id_tensor, &score_tensor); LoD lod = id_tensor.lod(); - std::vector expect_source_lod = {0, 3, 6}; + std::vector expect_source_lod = {0, 4, 8}; EXPECT_EQ(lod[0], expect_source_lod); - std::vector expect_sentence_lod = {0, 2, 5, 8, 11, 14, 17}; + std::vector expect_sentence_lod = {0, 1, 3, 6, 9, 10, 13, 16, 19}; EXPECT_EQ(lod[1], expect_sentence_lod); - std::vector expect_data = {1, 0, 3, 1, 0, 3, 2, 1, 4, - 3, 2, 4, 4, 3, 6, 5, 4}; + // 2| 1, 0| 3, 1, 0| 3, 2, 1| 5| 4, 3, 2| 4, 4, 3| 6, 5, 4 + std::vector expect_data = {2, 1, 0, 3, 1, 0, 3, 2, 1, 5, + 4, 3, 2, 4, 4, 3, 6, 5, 4}; ASSERT_EQ(id_tensor.dims()[0], static_cast(expect_data.size())); for (size_t i = 0; i < expect_data.size(); ++i) { ASSERT_EQ(id_tensor.data()[i], From 90e93b819ccac454fcb1da0cbb490b954eda190b Mon Sep 17 00:00:00 2001 From: qiaolongfei Date: Mon, 13 Nov 2017 15:22:20 +0800 Subject: [PATCH 25/27] use unique_ptr --- paddle/operators/beam_search_decode_op.h | 31 ++++++++++--------- .../operators/beam_search_decode_op_test.cc | 19 +++++++----- 2 files changed, 28 insertions(+), 22 deletions(-) diff --git a/paddle/operators/beam_search_decode_op.h b/paddle/operators/beam_search_decode_op.h index 4104c2bee9b6a..a659b778166bd 100644 --- a/paddle/operators/beam_search_decode_op.h +++ b/paddle/operators/beam_search_decode_op.h @@ -58,7 +58,7 @@ struct BeamNode { }; template -using BeamNodeVector = std::vector*>; +using BeamNodeVector = std::vector>>; template struct Sentence { @@ -87,7 +87,7 @@ struct BeamSearchDecoder { */ std::vector> PackTwoSteps( const LoDTensor& cur_ids, const LoDTensor& cur_scores, - const std::vector>& prefixes_list, + std::vector>& prefixes_list, std::vector>* sentence_vector_list) const; /** @@ -140,7 +140,7 @@ Sentence BeamSearchDecoder::MakeSentence(const BeamNode* node) const { template std::vector> BeamSearchDecoder::PackTwoSteps( const LoDTensor& cur_ids, const LoDTensor& cur_scores, - const std::vector>& prefixes_list, + std::vector>& prefixes_list, std::vector>* sentence_vector_list) const { std::vector> result; @@ -158,11 +158,11 @@ std::vector> BeamSearchDecoder::PackTwoSteps( cur_ids.lod().at(kSentenceLevel).back(), "in the first step"); for (size_t id_idx = src_start; id_idx < src_end; ++id_idx) { - beam_nodes.push_back(new BeamNode(cur_ids.data()[id_idx], - cur_scores.data()[id_idx])); + beam_nodes.push_back(std::unique_ptr>(new BeamNode( + cur_ids.data()[id_idx], cur_scores.data()[id_idx]))); } } else { - const BeamNodeVector& prefixes = prefixes_list[src_idx]; + BeamNodeVector& prefixes = prefixes_list[src_idx]; SentenceVector& sentence_vector = (*sentence_vector_list)[src_idx]; PADDLE_ENFORCE_EQ(src_end - src_start, prefixes.size(), @@ -170,27 +170,28 @@ std::vector> BeamSearchDecoder::PackTwoSteps( std::vector candidate_offset = cur_ids.lod()[kSentenceLevel]; for (size_t prefix_idx = 0; prefix_idx < prefixes.size(); ++prefix_idx) { - auto* prefix = prefixes[prefix_idx]; + std::unique_ptr>& prefix = prefixes[prefix_idx]; size_t candidate_start = candidate_offset[src_start + prefix_idx]; size_t candidate_end = candidate_offset[src_start + prefix_idx + 1]; if (candidate_start == candidate_end) { VLOG(3) << "this sentence has no more candidate, " "add to result sentence and rm it from beam tree"; - sentence_vector.push_back(MakeSentence(prefix)); - delete prefix; + sentence_vector.push_back(MakeSentence(prefix.get())); + prefix.reset(); } else { for (size_t candidate_idx = candidate_start; candidate_idx < candidate_end; ++candidate_idx) { auto* candidate = new BeamNode(cur_ids.data()[candidate_idx], cur_scores.data()[candidate_idx]); - candidate->AppendTo(prefix); - beam_nodes.push_back(candidate); + candidate->AppendTo(prefix.get()); + beam_nodes.push_back(std::unique_ptr>(candidate)); } + prefix.release(); } } } - result.push_back(beam_nodes); + result.push_back(std::move(beam_nodes)); } return result; } @@ -265,9 +266,9 @@ void BeamSearchDecoder::PackAllSteps(const LoDTensorArray& step_ids, } // append last beam_node to result for (size_t src_idx = 0; src_idx < src_num; ++src_idx) { - for (auto* beam_node : beamnode_vector_list.at(src_idx)) { - sentence_vector_list[src_idx].push_back(MakeSentence(beam_node)); - delete beam_node; + for (auto& beam_node : beamnode_vector_list.at(src_idx)) { + sentence_vector_list[src_idx].push_back(MakeSentence(beam_node.get())); + beam_node.reset(); } } diff --git a/paddle/operators/beam_search_decode_op_test.cc b/paddle/operators/beam_search_decode_op_test.cc index 96f1dd29c67dc..5ac23991f3c77 100644 --- a/paddle/operators/beam_search_decode_op_test.cc +++ b/paddle/operators/beam_search_decode_op_test.cc @@ -136,21 +136,26 @@ TEST(BeamSearchDecodeOp, PackTwoSteps) { // first source has three prefix BeamNodeVector source0_prefixes; - source0_prefixes.push_back(new BeamNode(1, 1)); - source0_prefixes.push_back(new BeamNode(0, 0)); - source0_prefixes.push_back(new BeamNode(3, 3)); + source0_prefixes.push_back( + std::unique_ptr>(new BeamNode(1, 1))); + source0_prefixes.push_back( + std::unique_ptr>(new BeamNode(0, 0))); + source0_prefixes.push_back( + std::unique_ptr>(new BeamNode(3, 3))); // second source has two prefix BeamNodeVector source1_prefixes; - source1_prefixes.push_back(new BeamNode(4, 4)); - source1_prefixes.push_back(new BeamNode(5, 5)); + source1_prefixes.push_back( + std::unique_ptr>(new BeamNode(4, 4))); + source1_prefixes.push_back( + std::unique_ptr>(new BeamNode(5, 5))); std::vector> beamnode_vector_list; std::vector> sentence_vector_list( 2, SentenceVector()); - beamnode_vector_list.push_back(source0_prefixes); - beamnode_vector_list.push_back(source1_prefixes); + beamnode_vector_list.push_back(std::move(source0_prefixes)); + beamnode_vector_list.push_back(std::move(source1_prefixes)); // generate data for one step LoDTensorArray ids; From 08e0ef48682e60a4ecbd211d8a4686fff579e2cd Mon Sep 17 00:00:00 2001 From: qiaolongfei Date: Mon, 13 Nov 2017 15:43:58 +0800 Subject: [PATCH 26/27] fix compare bug --- paddle/operators/beam_search_decode_op.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/paddle/operators/beam_search_decode_op.cc b/paddle/operators/beam_search_decode_op.cc index a0dddcdd18259..1ba4dfcdaba49 100644 --- a/paddle/operators/beam_search_decode_op.cc +++ b/paddle/operators/beam_search_decode_op.cc @@ -30,9 +30,10 @@ class BeamSearchDecodeOp : public framework::OperatorBase { const LoDTensorArray* ids = ctx.Input("Ids"); const LoDTensorArray* scores = ctx.Input("Scores"); const size_t step_num = ids->size(); - PADDLE_ENFORCE_LT(step_num, 0, "beam search steps should be larger than 0"); + PADDLE_ENFORCE_GT(step_num, 0UL, + "beam search steps should be larger than 0"); const size_t source_num = ids->at(0).lod().at(0).size() - 1; - PADDLE_ENFORCE_LT(source_num, 0UL, "source num should be larger than 0"); + PADDLE_ENFORCE_GT(source_num, 0UL, "source num should be larger than 0"); for (size_t i = 0; i < step_num; ++i) { PADDLE_ENFORCE_EQ(ids->at(i).lod().size(), 2UL, From 1f76e945e76267443ba99cebd62856536dff409f Mon Sep 17 00:00:00 2001 From: qiaolongfei Date: Mon, 13 Nov 2017 16:35:08 +0800 Subject: [PATCH 27/27] fix lod compile problem --- paddle/operators/beam_search_decode_op.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/paddle/operators/beam_search_decode_op.h b/paddle/operators/beam_search_decode_op.h index a659b778166bd..0f007ec22f9a6 100644 --- a/paddle/operators/beam_search_decode_op.h +++ b/paddle/operators/beam_search_decode_op.h @@ -146,8 +146,8 @@ std::vector> BeamSearchDecoder::PackTwoSteps( for (size_t src_idx = 0; src_idx < cur_ids.lod()[kSourceLevel].size() - 1; ++src_idx) { - size_t src_start = cur_ids.lod().at(kSourceLevel).at(src_idx); - size_t src_end = cur_ids.lod().at(kSourceLevel).at(src_idx + 1); + size_t src_start = cur_ids.lod().at(kSourceLevel)[src_idx]; + size_t src_end = cur_ids.lod().at(kSourceLevel)[src_idx + 1]; BeamNodeVector beam_nodes; @@ -168,7 +168,7 @@ std::vector> BeamSearchDecoder::PackTwoSteps( PADDLE_ENFORCE_EQ(src_end - src_start, prefixes.size(), "prefix and candidate set number should be the same"); - std::vector candidate_offset = cur_ids.lod()[kSentenceLevel]; + auto candidate_offset = cur_ids.lod()[kSentenceLevel]; for (size_t prefix_idx = 0; prefix_idx < prefixes.size(); ++prefix_idx) { std::unique_ptr>& prefix = prefixes[prefix_idx]; size_t candidate_start = candidate_offset[src_start + prefix_idx];