From 3388e52da12b6f525e34feadb05d4a712bd1d54e Mon Sep 17 00:00:00 2001 From: Yan Chunwei Date: Thu, 18 Jan 2018 14:32:03 +0800 Subject: [PATCH] Bugfix/beamsearch op (#7611) --- paddle/operators/CMakeLists.txt | 3 +- paddle/operators/beam_search_op.cc | 23 +++++-- paddle/operators/beam_search_op.h | 21 ++++-- paddle/operators/beam_search_op_test.cc | 86 +++++++++++++++++++++++++ 4 files changed, 120 insertions(+), 13 deletions(-) create mode 100644 paddle/operators/beam_search_op_test.cc diff --git a/paddle/operators/CMakeLists.txt b/paddle/operators/CMakeLists.txt index 2412ebd82..6745a8da1 100644 --- a/paddle/operators/CMakeLists.txt +++ b/paddle/operators/CMakeLists.txt @@ -178,14 +178,13 @@ foreach(src ${GENERAL_OPS}) endforeach() file(APPEND ${pybind_file} "USE_OP(less_than);\nUSE_OP(logical_and);\nUSE_NO_KERNEL_OP(read_from_array);\n") - 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_decode_op_test SRCS beam_search_decode_op_test.cc DEPS lod_tensor) +cc_test(beam_search_op_test SRCS beam_search_op_test.cc DEPS lod_tensor beam_search_op) cc_test(strided_memcpy_test SRCS strided_memcpy_test.cc DEPS tensor paddle_memory) if(WITH_GPU) cc_test(nccl_op_test SRCS nccl_op_test.cu.cc DEPS nccl_op gpu_info device_context) diff --git a/paddle/operators/beam_search_op.cc b/paddle/operators/beam_search_op.cc index ed2e7b738..4c71d66d2 100644 --- a/paddle/operators/beam_search_op.cc +++ b/paddle/operators/beam_search_op.cc @@ -29,7 +29,7 @@ void BeamSearch::operator()(const framework::LoDTensor &pre_ids, PruneEndidCandidates(pre_ids, &selected_items); // calculate the output tensor's height size_t num_instances = std::accumulate( - std::begin(items), std::end(items), 0, + std::begin(selected_items), std::end(selected_items), 0, [](size_t a, std::vector &b) { return a + b.size(); }); // the output tensor shape should be [num_instances, 1] auto dims = framework::make_ddim( @@ -48,12 +48,20 @@ void BeamSearch::operator()(const framework::LoDTensor &pre_ids, size_t low_offset = 0; for (auto &items : selected_items) { low_level.push_back(low_offset); + sort(items.begin(), items.end(), [](const Item &a, const Item &b) { + if (a.offset < b.offset) { + return true; + } + return a.id < b.id; + }); for (auto &item : items) { ids_data[low_offset] = item.id; scores_data[low_offset] = item.score; low_offset++; } } + low_level.push_back(low_offset); + // fill lod auto abs_lod = framework::ToAbsOffset(ids_->lod()); auto &high_level = abs_lod[lod_level_]; @@ -64,16 +72,21 @@ void BeamSearch::operator()(const framework::LoDTensor &pre_ids, selected_scores->set_lod(lod); } -void BeamSearch::PruneEndidCandidates(const framework::LoDTensor &pre_ids, - std::vector> *items) { +int BeamSearch::PruneEndidCandidates(const framework::LoDTensor &pre_ids, + std::vector> *items) { auto *pre_ids_data = pre_ids.data(); + int res = 0; for (size_t offset = 0; offset < items->size(); offset++) { auto prefix_id = pre_ids_data[offset]; if (prefix_id == end_id_) { items->at(offset).clear(); + } else { + res++; } } + + return res; } std::vector> BeamSearch::ToMap( @@ -121,11 +134,7 @@ bool BeamSearch::NextItemSet(std::vector *items) { auto ids = *ids_; auto scores = *scores_; - auto source_abs_two_level_lod = framework::SliceInLevel( - ids.lod(), lod_level_, sent_offset_, sent_offset_ + 1); - source_abs_two_level_lod = framework::ToAbsOffset(source_abs_two_level_lod); auto abs_lod = framework::ToAbsOffset(ids.lod()); - PADDLE_ENFORCE_GE(source_abs_two_level_lod.size(), 2UL); auto *ids_data = ids.data(); auto *scores_data = scores.data(); diff --git a/paddle/operators/beam_search_op.h b/paddle/operators/beam_search_op.h index 08b551ef9..45d14d68f 100644 --- a/paddle/operators/beam_search_op.h +++ b/paddle/operators/beam_search_op.h @@ -73,7 +73,15 @@ namespace operators { * second level: * [0, 2, 4] * - * tensor's data + * id tensor's data + * [[ + * 4, + * 1, + * 3, + * 8, + * ]] + * + * score tensor's data * [[ * 0.5, * 0.3, @@ -137,16 +145,21 @@ class BeamSearch { Item() {} Item(size_t offset, size_t id, float score) : offset(offset), id(id), score(score) {} - // offset in the lod_level_+1 + // offset in the higher lod level. size_t offset; + // // prefix id in the lower lod level. + // size_t prefix; // the candidate id id_t id; // the corresponding score score_t score; }; - void PruneEndidCandidates(const framework::LoDTensor& pre_ids, - std::vector>* items); + /* + * Delete all the records that follows the end token. + */ + int PruneEndidCandidates(const framework::LoDTensor& pre_ids, + std::vector>* items); /* * Transform the items into a map whose key is offset, value is the items. diff --git a/paddle/operators/beam_search_op_test.cc b/paddle/operators/beam_search_op_test.cc new file mode 100644 index 000000000..d4beb64a8 --- /dev/null +++ b/paddle/operators/beam_search_op_test.cc @@ -0,0 +1,86 @@ +/* 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/beam_search_op.h" + +#include +#include + +namespace paddle { +namespace test { + +using std::vector; +using framework::LoDTensor; +using framework::LoD; +using operators::BeamSearch; +using paddle::platform::CPUPlace; +using std::cout; +using std::endl; + +void CreateInput(LoDTensor* ids, LoDTensor* scores) { + LoD lod; + vector level0({0, 1, 4}); + vector level1({0, 1, 2, 3, 4}); + lod.push_back(level0); + lod.push_back(level1); + ids->set_lod(lod); + scores->set_lod(lod); + + auto dims = framework::make_ddim(vector({4, 3})); + ids->Resize(dims); + scores->Resize(dims); + CPUPlace place; + + auto* ids_data = ids->mutable_data(place); + auto* scores_data = scores->mutable_data(place); + vector _ids({4, 2, 5, 2, 1, 3, 3, 5, 2, 8, 2, 1}); + vector _scores( + {0.5, 0.3, 0.2, 0.6, 0.3, 0.1, 0.9, 0.5, 0.1, 0.7, 0.5, 0.1}); + + for (int i = 0; i < 12; i++) { + ids_data[i] = _ids[i]; + scores_data[i] = _scores[i]; + } +} + +TEST(beam_search_op, run) { + CPUPlace place; + LoDTensor ids, scores; + CreateInput(&ids, &scores); + + LoDTensor pre_ids; + pre_ids.Resize(framework::make_ddim(vector(4, 1))); + for (int i = 0; i < 4; i++) { + pre_ids.mutable_data(place)[i] = i + 1; + } + + BeamSearch beamsearch(ids, scores, (int64_t)0, (int64_t)2, 0); + LoDTensor sids, sscores; + beamsearch(pre_ids, &sids, &sscores); + + LOG(INFO) << "score: " << sscores << endl; + + ASSERT_EQ(sids.lod(), sscores.lod()); + + vector tids({2, 4, 3, 8}); + vector tscores({0.3, 0.5, 0.9, 0.7}); + + for (int i = 0; i < 4; i++) { + ASSERT_EQ(tids[i], sids.data()[i]); + ASSERT_EQ(tscores[i], sscores.data()[i]); + } +} + +} // namespace test +} // namespace paddle -- GitLab