mirror of
https://github.com/LostRuins/koboldcpp.git
synced 2026-09-08 22:09:10 +02:00
spec: Add benchmark-only synthetic speculative acceptance options (#27711)
* Add benchmark-only synthetic speculative acceptance to llama-server and llama-cli * Address review comments * Address review comments * Add some comments in the code
This commit is contained in:
+142
-15
@@ -14,6 +14,7 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
#include <cstring>
|
||||
#include <iomanip>
|
||||
#include <map>
|
||||
@@ -138,6 +139,7 @@ struct common_speculative_impl {
|
||||
const common_speculative_type type;
|
||||
|
||||
uint32_t n_seq;
|
||||
int32_t n_max; // maximum draft length after implementation-specific limits
|
||||
|
||||
size_t n_call_begin = 0; // number of times this implementation was called for refresh.
|
||||
size_t n_call_draft = 0; // number of times this implementation was called for generation.
|
||||
@@ -157,7 +159,7 @@ struct common_speculative_impl {
|
||||
int64_t t_draft_us = 0; // total time spent in generating drafts in this implementation in microseconds.
|
||||
int64_t t_accept_us = 0; // total time spent in accumulation of this implementation in microseconds.
|
||||
|
||||
common_speculative_impl(common_speculative_type type, uint32_t n_seq) : type(type), n_seq(n_seq) {}
|
||||
common_speculative_impl(common_speculative_type type, uint32_t n_seq, int32_t n_max) : type(type), n_seq(n_seq), n_max(n_max) {}
|
||||
|
||||
virtual ~common_speculative_impl() = default;
|
||||
|
||||
@@ -182,7 +184,7 @@ struct common_speculative_impl_draft_simple : public common_speculative_impl {
|
||||
std::vector<common_sampler_ptr> smpls;
|
||||
|
||||
common_speculative_impl_draft_simple(const common_params_speculative & params, uint32_t n_seq)
|
||||
: common_speculative_impl(COMMON_SPECULATIVE_TYPE_DRAFT_SIMPLE, n_seq)
|
||||
: common_speculative_impl(COMMON_SPECULATIVE_TYPE_DRAFT_SIMPLE, n_seq, params.draft.n_max)
|
||||
, params(params.draft)
|
||||
{
|
||||
auto * ctx_dft = this->params.ctx_dft;
|
||||
@@ -452,7 +454,7 @@ struct common_speculative_impl_draft_eagle3 : public common_speculative_impl {
|
||||
std::vector<float> g_embd_buf;
|
||||
|
||||
common_speculative_impl_draft_eagle3(const common_params_speculative & params, uint32_t n_seq)
|
||||
: common_speculative_impl(COMMON_SPECULATIVE_TYPE_DRAFT_EAGLE3, n_seq)
|
||||
: common_speculative_impl(COMMON_SPECULATIVE_TYPE_DRAFT_EAGLE3, n_seq, params.draft.n_max)
|
||||
, params(params.draft)
|
||||
{
|
||||
SPC_TRC("%s", "adding speculative implementation 'draft-eagle3'\n");
|
||||
@@ -937,7 +939,7 @@ struct common_speculative_impl_draft_dflash : public common_speculative_impl {
|
||||
|
||||
common_speculative_impl_draft_dflash(const common_params_speculative & params, uint32_t n_seq,
|
||||
common_speculative_type type = COMMON_SPECULATIVE_TYPE_DRAFT_DFLASH)
|
||||
: common_speculative_impl(type, n_seq)
|
||||
: common_speculative_impl(type, n_seq, params.draft.n_max)
|
||||
, params(params.draft)
|
||||
, is_dspark(type == COMMON_SPECULATIVE_TYPE_DRAFT_DSPARK)
|
||||
{
|
||||
@@ -983,6 +985,7 @@ struct common_speculative_impl_draft_dflash : public common_speculative_impl {
|
||||
this->params.n_max = std::min(this->params.n_max, n_draft_max);
|
||||
this->params.n_min = std::min(this->params.n_min, n_draft_max);
|
||||
}
|
||||
this->n_max = this->params.n_max;
|
||||
|
||||
batch = llama_batch_init(llama_n_batch(ctx_dft), 0, n_seq);
|
||||
batch_inject = llama_batch_init(llama_n_batch(ctx_dft), n_embd_dec, n_seq);
|
||||
@@ -1315,7 +1318,7 @@ struct common_speculative_impl_draft_mtp : public common_speculative_impl {
|
||||
std::vector<std::vector<float>> chain_h;
|
||||
|
||||
common_speculative_impl_draft_mtp(const common_params_speculative & params, uint32_t n_seq)
|
||||
: common_speculative_impl(COMMON_SPECULATIVE_TYPE_DRAFT_MTP, n_seq)
|
||||
: common_speculative_impl(COMMON_SPECULATIVE_TYPE_DRAFT_MTP, n_seq, params.draft.n_max)
|
||||
, params(params.draft)
|
||||
{
|
||||
auto * ctx_tgt = this->params.ctx_tgt;
|
||||
@@ -1382,6 +1385,7 @@ struct common_speculative_impl_draft_mtp : public common_speculative_impl {
|
||||
c.reserve((size_t) (this->params.n_max + 1) * n_embd);
|
||||
}
|
||||
}
|
||||
this->n_max = this->params.n_max;
|
||||
|
||||
pending_h.assign(n_seq, std::vector<float>(n_embd, 0.0f));
|
||||
|
||||
@@ -1726,7 +1730,7 @@ struct common_speculative_impl_ngram_simple : public common_speculative_impl {
|
||||
common_speculative_impl_ngram_simple(
|
||||
const common_params_speculative & params, uint32_t n_seq,
|
||||
common_ngram_simple_config config)
|
||||
: common_speculative_impl(COMMON_SPECULATIVE_TYPE_NGRAM_SIMPLE, n_seq)
|
||||
: common_speculative_impl(COMMON_SPECULATIVE_TYPE_NGRAM_SIMPLE, n_seq, params.ngram_simple.size_m)
|
||||
, params(params.ngram_simple)
|
||||
, config(config)
|
||||
{
|
||||
@@ -1770,7 +1774,7 @@ struct common_speculative_impl_ngram_map_k : public common_speculative_impl {
|
||||
const common_ngram_map & config,
|
||||
uint32_t n_seq)
|
||||
: common_speculative_impl(config.key_only ? COMMON_SPECULATIVE_TYPE_NGRAM_MAP_K
|
||||
: COMMON_SPECULATIVE_TYPE_NGRAM_MAP_K4V, n_seq)
|
||||
: COMMON_SPECULATIVE_TYPE_NGRAM_MAP_K4V, n_seq, config.size_value)
|
||||
{
|
||||
for (uint32_t i = 0; i < n_seq; i++) {
|
||||
this->config.push_back(config);
|
||||
@@ -1841,7 +1845,7 @@ struct common_speculative_impl_ngram_mod : public common_speculative_impl {
|
||||
common_speculative_impl_ngram_mod(
|
||||
const common_params_speculative & params,
|
||||
uint32_t n_seq)
|
||||
: common_speculative_impl(COMMON_SPECULATIVE_TYPE_NGRAM_MOD, n_seq)
|
||||
: common_speculative_impl(COMMON_SPECULATIVE_TYPE_NGRAM_MOD, n_seq, params.ngram_mod.n_max)
|
||||
, params(params.ngram_mod)
|
||||
, mod(params.ngram_mod.n_match, 4*1024*1024)
|
||||
, verbose(std::getenv("LLAMA_TRACE") != nullptr) {
|
||||
@@ -2017,7 +2021,7 @@ struct common_speculative_impl_ngram_cache : public common_speculative_impl {
|
||||
const std::string & path_dynamic,
|
||||
bool save_dynamic,
|
||||
bool save_static)
|
||||
: common_speculative_impl(COMMON_SPECULATIVE_TYPE_NGRAM_CACHE, n_seq)
|
||||
: common_speculative_impl(COMMON_SPECULATIVE_TYPE_NGRAM_CACHE, n_seq, n_draft)
|
||||
, params(params.ngram_cache)
|
||||
, n_draft(n_draft)
|
||||
, save_dynamic(save_dynamic)
|
||||
@@ -2138,6 +2142,8 @@ struct common_speculative {
|
||||
|
||||
// which implementaion was used for a given seq_id
|
||||
std::vector<common_speculative_impl *> impl_last;
|
||||
|
||||
std::vector<double> synth_probs;
|
||||
};
|
||||
|
||||
static common_ngram_map get_common_ngram_map(
|
||||
@@ -2316,6 +2322,101 @@ int32_t common_speculative_n_max(const common_params_speculative * spec) {
|
||||
return n_max;
|
||||
}
|
||||
|
||||
int32_t common_speculative_n_max(const common_speculative * spec) {
|
||||
int32_t n_max = 0;
|
||||
|
||||
if (spec == nullptr) {
|
||||
return n_max;
|
||||
}
|
||||
|
||||
for (const auto & impl : spec->impls) {
|
||||
n_max = std::max(n_max, std::max(0, impl->n_max));
|
||||
}
|
||||
|
||||
return n_max;
|
||||
}
|
||||
|
||||
std::vector<double> common_speculative_synth_rates_resolve(const common_params_speculative * spec, int32_t n_max) {
|
||||
const bool has_length = spec->synth_len != -1.0;
|
||||
const bool has_rates = !spec->synth_rates.empty();
|
||||
|
||||
if (!has_length && !has_rates) {
|
||||
return {};
|
||||
}
|
||||
if (has_length && has_rates) {
|
||||
throw std::invalid_argument("synthetic acceptance length and rates are mutually exclusive");
|
||||
}
|
||||
|
||||
if (n_max <= 0) {
|
||||
throw std::invalid_argument("synthetic acceptance requires at least one speculative token");
|
||||
}
|
||||
|
||||
if (has_rates) {
|
||||
const auto & rates = spec->synth_rates;
|
||||
if (rates.size() != (size_t) n_max) {
|
||||
throw std::invalid_argument(string_format(
|
||||
"synthetic acceptance rates must contain %d values, got %zu", n_max, rates.size()));
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < rates.size(); ++i) {
|
||||
if (!std::isfinite(rates[i]) || rates[i] < 0.0 || rates[i] > 1.0) {
|
||||
throw std::invalid_argument("synthetic acceptance rates must be finite and within [0, 1]");
|
||||
}
|
||||
if (i > 0 && rates[i] > rates[i - 1]) {
|
||||
throw std::invalid_argument("synthetic acceptance rates must be monotonically non-increasing");
|
||||
}
|
||||
}
|
||||
|
||||
return rates;
|
||||
}
|
||||
|
||||
const double length = spec->synth_len;
|
||||
const double length_max = (double) n_max + 1.0;
|
||||
if (!std::isfinite(length) || length < 1.0 || length > length_max) {
|
||||
throw std::invalid_argument(string_format(
|
||||
"synthetic acceptance length must be finite and within [1, %.0f]", length_max));
|
||||
}
|
||||
|
||||
double p = 0.0;
|
||||
if (length == length_max) {
|
||||
p = 1.0;
|
||||
} else if (length > 1.0) {
|
||||
double p_min = 0.0;
|
||||
double p_max = 1.0;
|
||||
for (int i = 0; i < 32; ++i) {
|
||||
const double p_mid = 0.5 * (p_min + p_max);
|
||||
double sum = 0.0;
|
||||
double term = p_mid;
|
||||
for (int32_t j = 0; j < n_max; ++j) {
|
||||
sum += term;
|
||||
term *= p_mid;
|
||||
}
|
||||
|
||||
if (sum < length - 1.0) {
|
||||
p_min = p_mid;
|
||||
} else {
|
||||
p_max = p_mid;
|
||||
}
|
||||
}
|
||||
p = 0.5 * (p_min + p_max);
|
||||
}
|
||||
|
||||
std::vector<double> rates;
|
||||
rates.reserve(n_max);
|
||||
double rate = p;
|
||||
for (int32_t i = 0; i < n_max; ++i) {
|
||||
rates.push_back(rate);
|
||||
rate *= p;
|
||||
}
|
||||
|
||||
return rates;
|
||||
}
|
||||
|
||||
const std::vector<double> & common_speculative_get_synth_probs(const common_speculative * spec) {
|
||||
GGML_ASSERT(spec);
|
||||
return spec->synth_probs;
|
||||
}
|
||||
|
||||
common_params common_base_params_to_speculative(const common_params & params) {
|
||||
const bool has_draft = params.speculative.has_dft();
|
||||
|
||||
@@ -2568,13 +2669,39 @@ common_speculative * common_speculative_init(common_params_speculative & params,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto * result = new common_speculative {
|
||||
/* .dparams = */ common_speculative_draft_params_vec(n_seq),
|
||||
/* .impls = */ std::move(impls),
|
||||
/* .impl_last = */ std::vector<common_speculative_impl *>(n_seq, nullptr)
|
||||
};
|
||||
common_speculative_ptr result(new common_speculative {
|
||||
/* .dparams = */ common_speculative_draft_params_vec(n_seq),
|
||||
/* .impls = */ std::move(impls),
|
||||
/* .impl_last = */ std::vector<common_speculative_impl *>(n_seq, nullptr),
|
||||
/* .synth_probs = */ {},
|
||||
});
|
||||
|
||||
return result;
|
||||
const int32_t n_max_configured = common_speculative_n_max(¶ms);
|
||||
const int32_t n_max_effective = common_speculative_n_max(result.get());
|
||||
const auto rates = common_speculative_synth_rates_resolve(¶ms, n_max_effective);
|
||||
|
||||
std::vector<std::string> rates_str;
|
||||
rates_str.reserve(rates.size());
|
||||
result->synth_probs.reserve(rates.size());
|
||||
double rate_prev = 1.0;
|
||||
double acceptance_length = 1.0;
|
||||
for (const double rate : rates) {
|
||||
result->synth_probs.push_back(rate_prev > 0.0 ? rate / rate_prev : 0.0);
|
||||
rates_str.push_back(string_format("%.6g", rate));
|
||||
rate_prev = rate;
|
||||
acceptance_length += rate;
|
||||
}
|
||||
if (!result->synth_probs.empty()) {
|
||||
SPC_WRN("%s", "synthetic speculative acceptance is enabled for benchmarking; generated output is not valid\n");
|
||||
if (n_max_effective != n_max_configured) {
|
||||
SPC_WRN("synthetic acceptance draft limit was reduced from %d to %d by the initialized speculative implementations\n",
|
||||
n_max_configured, n_max_effective);
|
||||
}
|
||||
SPC_INF("synthetic acceptance: n_max = %zu, mean length = %.6f, rates = [%s]\n",
|
||||
rates.size(), acceptance_length, string_join(rates_str, ", ").c_str());
|
||||
}
|
||||
|
||||
return result.release();
|
||||
}
|
||||
|
||||
void common_speculative_free(common_speculative * spec) {
|
||||
|
||||
Reference in New Issue
Block a user