Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/beam_search_scorer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ void BeamSearchScorer::Process(Sequences& sequences,

int const batch_beam_idx = static_cast<int>(batch * num_beams_) + next_index;
// Add to generated hypotheses if end of sentence.
if ((eos_token_id_ >= 0) && (next_token == eos_token_id_)) {
if (contains(eos_token_id_, next_token)) {
bool const is_beam_token_worse_than_top_num_beams = (j >= num_beams_);
if (is_beam_token_worse_than_top_num_beams) {
continue;
Expand Down
2 changes: 1 addition & 1 deletion src/beam_search_scorer.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ struct BeamSearchScorer {
int num_beams_;
int max_length_;
int pad_token_id_;
int eos_token_id_;
std::vector<int> eos_token_id_;
bool early_stopping_;
int not_done_count_; // When zero, every batch entry is done (starts at batch_size_)

Expand Down
44 changes: 18 additions & 26 deletions src/config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,17 @@ struct NamedStrings_Element : JSON::Element {
std::vector<Config::NamedString>& v_;
};

struct Int_Array_Element : JSON::Element {
explicit Int_Array_Element(std::vector<int>& v) : v_{v} {}

void OnValue(std::string_view name, JSON::Value value) override {
v_.emplace_back(static_cast<int>(JSON::Get<double>(value)));
}

private:
std::vector<int>& v_;
};

struct ProviderOptionsObject_Element : JSON::Element {
explicit ProviderOptionsObject_Element(std::vector<Config::ProviderOptions>& v) : v_{v} {}

Expand Down Expand Up @@ -509,29 +520,6 @@ struct Speech_Element : JSON::Element {
SpeechOutputs_Element outputs_{v_.outputs};
};

struct Eos_Array_Element : JSON::Element {
explicit Eos_Array_Element(Config::Model& v) : v_{v} {}

void OnValue(std::string_view name, JSON::Value value) override {
v_.eos_token_ids.push_back(static_cast<int>(JSON::Get<double>(value)));
}

void OnComplete(bool empty) override {
if (v_.eos_token_ids.empty())
return; // Empty array, nothign to do

// Copy the first eos_token_id into the eos_token_id value, it will be our primary eos token
v_.eos_token_id = v_.eos_token_ids.front();

// If the array is just one value, clear the array and just act like a single value was set
if (v_.eos_token_ids.size() == 1)
v_.eos_token_ids.clear();
}

private:
Config::Model& v_;
};

struct EmbeddingInputs_Element : JSON::Element {
explicit EmbeddingInputs_Element(Config::Model::Embedding::Inputs& v) : v_{v} {}

Expand Down Expand Up @@ -634,7 +622,7 @@ struct Model_Element : JSON::Element {
} else if (name == "pad_token_id") {
v_.pad_token_id = static_cast<int>(JSON::Get<double>(value));
} else if (name == "eos_token_id") {
v_.eos_token_id = static_cast<int>(JSON::Get<double>(value));
v_.eos_token_id.assign(1, static_cast<int>(JSON::Get<double>(value)));
Comment thread
kunal-vaishnavi marked this conversation as resolved.
} else if (name == "bos_token_id") {
v_.bos_token_id = static_cast<int>(JSON::Get<double>(value));
} else if (name == "decoder_start_token_id") {
Expand All @@ -647,7 +635,7 @@ struct Model_Element : JSON::Element {

Element& OnArray(std::string_view name) override {
if (name == "eos_token_id")
return eos_token_ids_;
return eos_token_id_;
throw JSON::unknown_value_error{};
}

Expand Down Expand Up @@ -677,7 +665,7 @@ struct Model_Element : JSON::Element {
Config::Model& v_;
EncoderDecoderInit_Element encoder_decoder_init_{v_.encoder_decoder_init};
Decoder_Element decoder_{v_.decoder};
Eos_Array_Element eos_token_ids_{v_};
Int_Array_Element eos_token_id_{v_.eos_token_id};
Vision_Element vision_{v_.vision};
Embedding_Element embedding_{v_.embedding};
PromptTemplates_Element prompt_templates_{v_.prompt_templates};
Expand Down Expand Up @@ -858,6 +846,10 @@ Config::Config(const fs::path& path, std::string_view json_overlay) : config_pat

if (search.max_length == 0)
search.max_length = model.context_length;

// If no eos_token_id was set, set it to the pad token id
if (model.eos_token_id.empty())
model.eos_token_id.push_back(model.pad_token_id);
}

void Config::AddMapping(const std::string& nominal_name, const std::string& graph_name) {
Expand Down
11 changes: 5 additions & 6 deletions src/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,12 +81,11 @@ struct Config {
struct Model {
std::string type;

int pad_token_id{}; // The id of the padding token.
int eos_token_id{}; // The id of the end-of-stream token.
std::vector<int> eos_token_ids; // If eos_token_id is passed as an array, this is where the values go (eos_token_id gets set to the first entry in the array)
int bos_token_id{}; // The id of the beginning-of-stream token.
int sep_token_id{}; // The id of the separation token.
int decoder_start_token_id{}; // If an encoder-decoder model starts decoding with a different token than bos, the id of that token.
int pad_token_id{}; // The id of the padding token.
std::vector<int> eos_token_id; // The end-of-stream tokens (when set as a single value it is converted to a vector with one value).
int bos_token_id{}; // The id of the beginning-of-stream token.
int sep_token_id{}; // The id of the separation token.
int decoder_start_token_id{}; // If an encoder-decoder model starts decoding with a different token than bos, the id of that token.
int vocab_size{};
int context_length{};

Expand Down
7 changes: 4 additions & 3 deletions src/cuda/beam_search_scorer_cuda.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,14 @@

namespace Generators {

BeamSearchScorer_Cuda::BeamSearchScorer_Cuda(const GeneratorParams& parameters)
: stream_{GetStream()} {
BeamSearchScorer_Cuda::BeamSearchScorer_Cuda(const GeneratorParams& parameters, std::span<int32_t> cuda_eos_tokens)
Comment thread
kunal-vaishnavi marked this conversation as resolved.
: stream_{GetStream()},
eos_tokens_{cuda_eos_tokens} {
state_cpu_ = CudaMallocHostArray<cuda::BeamScorerState>(1);
state_cpu_->batch_size_ = static_cast<size_t>(parameters.search.batch_size);
state_cpu_->num_beams_ = static_cast<size_t>(parameters.search.num_beams);
state_cpu_->max_length_ = static_cast<size_t>(parameters.search.max_length);
state_cpu_->pad_token_id_ = parameters.config.model.pad_token_id;
state_cpu_->eos_token_id_ = parameters.config.model.eos_token_id;
state_cpu_->early_stopping_ = parameters.search.early_stopping;
state_cpu_->not_done_count_ = parameters.search.batch_size;
state_cpu_->hypothesis_buffer_used_ = 0;
Expand Down Expand Up @@ -51,6 +51,7 @@ void BeamSearchScorer_Cuda::Process(Sequences& sequences,
std::span<const int32_t> next_indices) {
cuda::LaunchBeamSearchScorer_Process(*state_cpu_,
*state_gpu_,
eos_tokens_,
sequences.GetSequences().Span(),
sequences.GetSequenceLength(),
beam_hyps_,
Expand Down
14 changes: 13 additions & 1 deletion src/cuda/beam_search_scorer_cuda.cu
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ __device__ bool BeamHypotheses::CanImprove(float best_sum_logprobs, int current_

__global__ void BeamSearchScorer_Process(BeamScorerState& state_cpu,
BeamScorerState& state,
const int32_t* eos_token_ids,
const int eos_token_count,
const int32_t* sequences_buffer,
int sequence_length,
BeamHypotheses* beam_hyps_,
Expand Down Expand Up @@ -105,7 +107,14 @@ __global__ void BeamSearchScorer_Process(BeamScorerState& state_cpu,

int batch_beam_idx = batch_start + next_index;
// Add to generated hypotheses if end of sentence.
if ((state.eos_token_id_ >= 0) && (next_token == state.eos_token_id_)) {
bool is_eos_token = false;
for (unsigned eos_index = 0; eos_index < eos_token_count; eos_index++) {
if (next_token == eos_token_ids[eos_index]) {
is_eos_token = true;
break;
}
}
if (is_eos_token) {
bool is_beam_token_worse_than_top_num_beams = (j >= state.num_beams_);
if (is_beam_token_worse_than_top_num_beams) {
continue;
Expand Down Expand Up @@ -152,6 +161,7 @@ __global__ void BeamSearchScorer_Process(BeamScorerState& state_cpu,

void LaunchBeamSearchScorer_Process(BeamScorerState& state_cpu,
BeamScorerState& state,
std::span<const int32_t> eos_token_ids,
std::span<const int32_t> sequences,
int sequence_length,
std::span<BeamHypotheses> beam_hyps,
Expand All @@ -165,6 +175,8 @@ void LaunchBeamSearchScorer_Process(BeamScorerState& state_cpu,
cudaStream_t stream) {
BeamSearchScorer_Process<<<1, state_cpu.batch_size_, 0, stream>>>(state_cpu,
state,
eos_token_ids.data(),
static_cast<int>(eos_token_ids.size()),
sequences.data(),
sequence_length,
beam_hyps.data(),
Expand Down
2 changes: 1 addition & 1 deletion src/cuda/beam_search_scorer_cuda.cuh
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ struct BeamScorerState {
int num_beams_;
int max_length_;
int pad_token_id_;
int eos_token_id_;
bool early_stopping_;
int not_done_count_; // When zero, every batch entry is done (starts at batch_size_)

Expand All @@ -43,6 +42,7 @@ void LaunchInitializeBeamHypotheses(std::span<BeamHypotheses> beam_hyps, float l

void LaunchBeamSearchScorer_Process(BeamScorerState& state_cpu,
BeamScorerState& state,
std::span<const int32_t> eos_token_ids,
std::span<const int32_t> sequences,
int sequence_length,
std::span<BeamHypotheses> beam_hyps_,
Expand Down
4 changes: 3 additions & 1 deletion src/cuda/beam_search_scorer_cuda.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
namespace Generators {

struct BeamSearchScorer_Cuda {
BeamSearchScorer_Cuda(const GeneratorParams& parameters);
BeamSearchScorer_Cuda(const GeneratorParams& parameters, std::span<int32_t> cuda_eos_tokens);

void Process(Sequences& sequences,
std::span<const float> next_scores,
Expand All @@ -26,7 +26,9 @@ struct BeamSearchScorer_Cuda {
mutable cuda_event_holder event_process_complete_;
cuda_host_unique_ptr<cuda::BeamScorerState> state_cpu_;
cuda_unique_ptr<cuda::BeamScorerState> state_gpu_;

cudaStream_t stream_;
std::span<int32_t> eos_tokens_;

DeviceSpan<float> next_beam_scores_;
DeviceSpan<int32_t> next_beam_tokens_;
Expand Down
4 changes: 0 additions & 4 deletions src/cuda/interface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -143,10 +143,6 @@ struct CudaInterfaceImpl final : DeviceInterface {
return true;
}

void LaunchHandleEOSArray(float* batch_logits, int batch_beam_size, int vocab_size, const int32_t* eos_token_ids, int eos_token_ids_count) override {
cuda::LaunchHandleEOSArray(batch_logits, batch_beam_size, vocab_size, eos_token_ids, eos_token_ids_count, GetStream());
}

void UpdateCacheIndirectionKernelLauncher(int32_t* tgt_indir_cache, const int32_t* src_indir_cache, const int32_t* beam_ids, int batch_size, int beam_width, int input_seq_length, int max_seq_length, int current_length) override {
cuda::UpdateCacheIndirectionKernelLauncher(tgt_indir_cache, src_indir_cache, beam_ids, batch_size, beam_width, input_seq_length, max_seq_length, current_length, GetStream());
}
Expand Down
2 changes: 0 additions & 2 deletions src/cuda/kernels.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@ void Launch_UpdatePositionIds(T* positions, int batch_beam_size, int total_lengt
template <typename T>
void Launch_UpdateAttentionMask(T* mask_data, T* old_data, int batch_beam_size, int new_kv_length, int total_length, int max_length, bool update_only, cudaStream_t stream);

void LaunchHandleEOSArray(float* batch_logits, int batch_beam_size, int vocab_size, const int32_t* eos_token_ids, int eos_token_ids_count, cudaStream_t stream);

void LaunchFp16ToFp32(const uint16_t* fp16, float* fp32, int count, cudaStream_t stream);
void LaunchFp32ToFp16(const float* fp32, uint16_t* fp16, int count, cudaStream_t stream);
void LaunchInt32ToInt64(const int32_t* src, int64_t* dst, int count, cudaStream_t stream);
Expand Down
19 changes: 0 additions & 19 deletions src/cuda/model_kernels.cu
Original file line number Diff line number Diff line change
Expand Up @@ -82,25 +82,6 @@ void Launch_UpdateAttentionMask(T* next_mask_data, T* mask_data, int batch_beam_
template void Launch_UpdateAttentionMask(int32_t* next_mask_data, int32_t* mask_data, int batch_beam_size, int new_kv_length, int total_length, int max_length, bool update_only, cudaStream_t stream);
template void Launch_UpdateAttentionMask(int64_t* next_mask_data, int64_t* mask_data, int batch_beam_size, int new_kv_length, int total_length, int max_length, bool update_only, cudaStream_t stream);

__global__ void HandleEOSArray(float* batch_logits, int batch_beam_size, int vocab_size, const int32_t* eos_token_ids, int eos_token_ids_count) {
int index = blockIdx.x * blockDim.x + threadIdx.x;
if (index >= batch_beam_size)
return;

float* logits = batch_logits + index * vocab_size;
float max = std::numeric_limits<float>::lowest();
for (int i = 0; i < eos_token_ids_count; i++) {
max = std::max(max, logits[eos_token_ids[i]]);
logits[eos_token_ids[i]] = std::numeric_limits<float>::lowest(); // Set all EOS token options to never happen (the first will get the max of all)
}

logits[eos_token_ids[0]] = max; // Set the score of the primary EOS token to the highest of any of the EOS tokens
}

void LaunchHandleEOSArray(float* batch_logits, int batch_beam_size, int vocab_size, const int32_t* eos_token_ids, int eos_token_ids_count, cudaStream_t stream) {
HandleEOSArray<<<(batch_beam_size + 255) / 256, 256, 0, stream>>>(batch_logits, batch_beam_size, vocab_size, eos_token_ids, eos_token_ids_count);
}

__global__ void ConvertFp16ToFp32(const half* src, float* dst, int count) {
int idx = threadIdx.x + blockIdx.x * blockDim.x;
if (idx < count)
Expand Down
24 changes: 14 additions & 10 deletions src/cuda/search_cuda.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,12 @@ Search_Cuda::Search_Cuda(const GeneratorParams& params)
auto batch_beam_size = params.BatchBeamSize();
sequence_lengths_ = params.p_device->Allocate<int32_t>(batch_beam_size);

eos_meet_buffer_ = CudaMallocArray<bool>(batch_beam_size, &eos_meet_);
cudaMemsetAsync(eos_meet_.data(), 0, eos_meet_.size_bytes(), GetStream());
eos_seen_buffer_ = CudaMallocArray<bool>(batch_beam_size, &eos_seen_);
cudaMemsetAsync(eos_seen_.data(), 0, eos_seen_.size_bytes(), GetStream());

eos_token_ids_ = params.p_device->Allocate<int32_t>(params.config.model.eos_token_id.size());
copy(std::span<const int32_t>{params.config.model.eos_token_id}, eos_token_ids_.CpuSpan());
eos_token_ids_.CopyCpuToDevice();

done_cpu_ = CudaMallocHostArray<bool>(1);
*done_cpu_ = false;
Expand All @@ -49,7 +53,7 @@ BeamSearch_Cuda::BeamSearch_Cuda(const GeneratorParams& params)
: Search_Cuda{params} {
assert(params_->search.num_beams > 1); // If 1, use GreedySearch
auto batch_beam_size = params_->BatchBeamSize();
beam_scorer_ = std::make_unique<BeamSearchScorer_Cuda>(*params_);
beam_scorer_ = std::make_unique<BeamSearchScorer_Cuda>(*params_, eos_token_ids_.Span());

topk_next_tokens_ = CudaMallocArray<int32_t>(2 * batch_beam_size);
topk_next_indices_ = CudaMallocArray<int32_t>(2 * batch_beam_size);
Expand Down Expand Up @@ -153,9 +157,8 @@ void GreedySearch_Cuda::SampleTopKTopP(int k, float p, float temperature) {
params_->search.batch_size, k, p, temperature);

// Check for EOS
assert(next_tokens_.size() == eos_meet_.size());
// Don't replace EOS with pad for batch_size == 1 for continuous decoding mode
cuda::Launch_CheckForEOSAndPad(next_tokens_.data(), static_cast<int>(next_tokens_.size()), eos_meet_.data(), params_->config.model.eos_token_id, params_->search.batch_size > 1 ? params_->config.model.pad_token_id : params_->config.model.eos_token_id, done_cpu_.get(), GetStream());
assert(next_tokens_.size() == eos_seen_.size());
cuda::Launch_CheckForEOSAndPad(next_tokens_.data(), static_cast<int>(next_tokens_.size()), eos_seen_.data(), eos_token_ids_.Span().data(), static_cast<int>(eos_token_ids_.Span().size()), params_->config.model.pad_token_id, done_cpu_.get(), GetStream());

// Append tokens
cuda::Launch_AppendNextTokensToSequences(next_tokens_buffer_.Span(), sequences_.GetSequences().Span(), params_->BatchBeamSize(), sequences_.GetSequenceLength(), sequences_.max_length_, GetStream());
Expand Down Expand Up @@ -210,7 +213,7 @@ std::span<float> Search_Cuda::GetScores() {

// Set user input tokens (batch_beam_size, sequence_length)
void GreedySearch_Cuda::AppendTokens(DeviceSpan<int32_t>& next_tokens) {
cudaMemsetAsync(eos_meet_.data(), 0, eos_meet_.size_bytes(), GetStream());
cudaMemsetAsync(eos_seen_.data(), 0, eos_seen_.size_bytes(), GetStream());
*done_cpu_ = false;

auto next_tokens_gpu = next_tokens.Span();
Expand All @@ -224,7 +227,7 @@ void GreedySearch_Cuda::AppendTokens(DeviceSpan<int32_t>& next_tokens) {
return;
}

cudaMemsetAsync(eos_meet_.data(), 0, eos_meet_.size_bytes(), GetStream());
cudaMemsetAsync(eos_seen_.data(), 0, eos_seen_.size_bytes(), GetStream());
*done_cpu_ = false;
}

Expand All @@ -237,7 +240,7 @@ void BeamSearch_Cuda::AppendTokens(DeviceSpan<int32_t>& next_tokens) {
}

void GreedySearch_Cuda::RewindTo(size_t index) {
cudaMemsetAsync(eos_meet_.data(), 0, eos_meet_.size_bytes(), GetStream());
cudaMemsetAsync(eos_seen_.data(), 0, eos_seen_.size_bytes(), GetStream());
*done_cpu_ = false;
if (index > 0)
cuda::Launch_GetLastTokens(next_tokens_.data(), sequences_.GetSequences().Span().data(), static_cast<int>(params_->BatchBeamSize()), static_cast<int>(index), sequences_.max_length_, GetStream());
Expand All @@ -250,7 +253,8 @@ void Search_Cuda::ApplyMinLength(int min_length) {
if (sequences_.GetSequenceLength() >= min_length)
return;

cuda::LaunchSetScoreProcessor(GetScores().data(), params_->BatchBeamSize(), params_->config.model.vocab_size, params_->config.model.eos_token_id, std::numeric_limits<float>::lowest(), GetStream());
for (auto eos_token_id : params_->config.model.eos_token_id)
cuda::LaunchSetScoreProcessor(GetScores().data(), params_->BatchBeamSize(), params_->config.model.vocab_size, eos_token_id, std::numeric_limits<float>::lowest(), GetStream());
}

void Search_Cuda::ApplyRepetitionPenalty(float penalty) {
Expand Down
Loading