168 lines
5.9 KiB
C++
168 lines
5.9 KiB
C++
// Copyright (c) 2024 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.
|
|
|
|
#pragma once
|
|
|
|
#include "paddle/phi/core/dense_tensor.h"
|
|
#include "paddle/phi/kernels/funcs/beam_search_decode.h"
|
|
|
|
namespace phi {
|
|
|
|
struct BeamSearchDecodeFunctor {
|
|
BeamSearchDecodeFunctor(const TensorArray& step_ids,
|
|
const TensorArray& step_scores,
|
|
DenseTensor* id_tensor,
|
|
DenseTensor* score_tensor,
|
|
size_t beam_size,
|
|
int end_id)
|
|
: beam_size_(beam_size),
|
|
end_id_(end_id),
|
|
step_ids_origin_(step_ids),
|
|
step_scores_origin_(step_scores),
|
|
id_tensor_(id_tensor),
|
|
score_tensor_(score_tensor) {
|
|
tensor_on_gpu_ = false;
|
|
// First make a copy of GPU data on CPU
|
|
if (step_ids_origin_[0].place().GetType() == AllocationType::GPU ||
|
|
step_ids_origin_[0].place().GetType() == AllocationType::CUSTOM) {
|
|
if (step_ids_origin_[0].place().GetType() == AllocationType::GPU ||
|
|
step_ids_origin_[0].place().GetType() == AllocationType::CUSTOM) {
|
|
tensor_on_gpu_ = true;
|
|
}
|
|
DeviceContextPool& pool = DeviceContextPool::Instance();
|
|
auto* dev_ctx = pool.Get(step_ids_origin_[0].place());
|
|
// Copy all tensors in the input tensor array
|
|
for (auto& step_id : step_ids_origin_) {
|
|
DenseTensor out;
|
|
if (step_id.numel() > 0) {
|
|
if (tensor_on_gpu_) {
|
|
dev_ctx->Wait();
|
|
}
|
|
Copy(*dev_ctx, step_id, CPUPlace(), false, &out);
|
|
dev_ctx->Wait();
|
|
}
|
|
|
|
out.set_lod(step_id.lod());
|
|
step_ids_.push_back(out);
|
|
}
|
|
}
|
|
if (step_scores_origin_[0].place().GetType() == AllocationType::GPU ||
|
|
step_scores_origin_[0].place().GetType() == AllocationType::CUSTOM) {
|
|
if (step_scores_origin_[0].place().GetType() == AllocationType::GPU ||
|
|
step_scores_origin_[0].place().GetType() == AllocationType::CUSTOM) {
|
|
tensor_on_gpu_ = true;
|
|
}
|
|
DeviceContextPool& pool = DeviceContextPool::Instance();
|
|
auto* dev_ctx = pool.Get(step_scores_origin_[0].place());
|
|
// Copy all tensors in the input tensor array
|
|
for (auto& step_score : step_scores_origin_) {
|
|
DenseTensor out;
|
|
if (step_score.numel() > 0) {
|
|
if (tensor_on_gpu_) {
|
|
dev_ctx->Wait();
|
|
}
|
|
Copy(*dev_ctx, step_score, CPUPlace(), false, &out);
|
|
dev_ctx->Wait();
|
|
}
|
|
|
|
out.set_lod(step_score.lod());
|
|
step_scores_.push_back(out);
|
|
}
|
|
}
|
|
}
|
|
|
|
template <typename T>
|
|
void apply_mix() const {
|
|
if (std::is_same<bool, T>::value) {
|
|
PADDLE_THROW(common::errors::InvalidArgument(
|
|
"beam search decode op does not support bool!"));
|
|
|
|
} else {
|
|
funcs::BeamSearchDecoder<T> beam_search_decoder(beam_size_, end_id_);
|
|
// Check if the tensor is on GPU. If so, use the CPU copy instead
|
|
if (tensor_on_gpu_) {
|
|
beam_search_decoder.Backtrace(
|
|
step_ids_, step_scores_, id_tensor_, score_tensor_);
|
|
} else {
|
|
beam_search_decoder.Backtrace(
|
|
step_ids_origin_, step_scores_origin_, id_tensor_, score_tensor_);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool tensor_on_gpu_;
|
|
size_t beam_size_;
|
|
int end_id_;
|
|
// TODO(Superjomn) Here might result serious performance issue in the
|
|
// concurrency
|
|
// scenarios.
|
|
const TensorArray& step_ids_origin_;
|
|
const TensorArray& step_scores_origin_;
|
|
TensorArray step_ids_ = TensorArray();
|
|
TensorArray step_scores_ = TensorArray();
|
|
DenseTensor* id_tensor_;
|
|
DenseTensor* score_tensor_;
|
|
};
|
|
|
|
template <typename T, typename Context>
|
|
void BeamSearchDecodeOpKernel(const Context& dev_ctx,
|
|
const TensorArray& ids_in,
|
|
const TensorArray& scores_in,
|
|
int beam_size,
|
|
int end_id,
|
|
DenseTensor* sentence_ids,
|
|
DenseTensor* sentence_scores) {
|
|
const TensorArray* ids = &ids_in;
|
|
const TensorArray* scores = &scores_in;
|
|
const size_t step_num = ids->size();
|
|
PADDLE_ENFORCE_GT(
|
|
step_num,
|
|
0UL,
|
|
common::errors::InvalidArgument(
|
|
"beam search steps, which is the "
|
|
"size of Input(Ids) TensorArray. beam search steps should "
|
|
"be larger than 0, but received %d. ",
|
|
step_num));
|
|
const size_t source_num = ids->at(0).lod().at(0).size() - 1;
|
|
PADDLE_ENFORCE_GT(
|
|
source_num,
|
|
0UL,
|
|
common::errors::InvalidArgument(
|
|
"source_num is the sequence number of the "
|
|
"first decoding step, indicating by Input(Ids)[0].lod[0].size. "
|
|
"The number of source_num should be larger than "
|
|
"0, but received %d. ",
|
|
source_num));
|
|
|
|
for (size_t i = 0; i < step_num; ++i) {
|
|
size_t tmp = ids->at(i).lod().size();
|
|
PADDLE_ENFORCE_EQ(
|
|
tmp,
|
|
2UL,
|
|
common::errors::InvalidArgument(
|
|
"For the i step in beam search steps,"
|
|
"the size of Input(Ids)[i].lod() should larger than 2,"
|
|
"but received %d. ",
|
|
tmp));
|
|
}
|
|
|
|
// prepare output
|
|
DenseTensor* sentenceIds = sentence_ids;
|
|
DenseTensor* sentenceScores = sentence_scores;
|
|
BeamSearchDecodeFunctor bs(
|
|
*ids, *scores, sentenceIds, sentenceScores, beam_size, end_id);
|
|
bs.apply_mix<T>();
|
|
}
|
|
} // namespace phi
|