Skip to content

Commit 2645754

Browse files
authored
Add the DRY dynamic N-gram anti-repetition sampler (#982)
* Add the DRY dynamic N-gram anti-repetition sampler The DRY (Do not Repeat Yourself) sampler is a dynamic N-gram repetition penalty that negatively scores tokens that would extend sequences that already appear in the context. See this discussion for a motivation and explanation of the sampler: oobabooga/text-generation-webui#5677 This implementation of DRY mostly aligns with the obabooga version with a few modifications. It uses a more efficient linear scanning algorithm to identify repetitions. It also supports multi-token sequence breakers. As a limitation, this implementation reuses the rep pen range parameter, rather than introducing a new range just for the DRY sampler. There is a separate change to lite.koboldai.net that exposes the DRY sampler parameters to KoboldAI Lite, so none of the embed files have been changed as part of this commit. * Update default DRY parameters to match lite * Improve DRY token debug logging * Replace `and` with `&&` to fix MSVC compile error Little known fact: The C++98 standard defines `and` as an alternative token for the `&&` operator (along with a bunch of other digraphs). MSVC does not allow these without using the /Za option or including the <iso646.h> header. Change to the more standard operator to make this code more portable. * Fix MSVC compile error because log is not constexpr Replace the compile-time computation with a floating-point approximation of log(std::numeric_limits<float>::max()). * Remove unused llama sampler variables and clean up sequence breakers. * Remove KCPP_SAMPLER_DRY as a separate enum entry The DRY sampler is effectively a repetition penalty and there are very few reasons to apply it at a different place in sampler order than the standard single-token penalty. There are also multiple projects that have dependencies on the existing sampler IDs, including KoboldAI, KoboldAI Lite, and Silly Tavern. In order to minimize the impact of the dependencies of adding the DRY sampler to koboldcpp, it makes the most sense to not add a new ID for now, and instead to piggyback on KCPP_SAMPLER_REP_PEN. In the future if we find a use case for splitting the application of rep pen and DRY we can introduce a new enum entry then. * Add the dry_penalty_last_n to independently control DRY penalty range This parameter follows the oobabooga semantics: it's optional, with a default value of zero. Zero means that DRY should sample the entire context. Otherwise, it's the number of tokens from the end of the context that are scanned for repetitions. * Limit sequence breaker lengths in tokens and characters The core DRY sampler algorithm is linear in the context length, but there are several parts of the sampler related to multi-token sequence breakers that are potentially quadratic. Without any restrictions, a suitably crafted context and sequence breaker could result in a denial-of-service attack on a server running koboldcpp. This change limits the maximum number of characters and the maximum token length of a sequence breaker in order to limit the maximum overhead associated with the sampler. This change also improves some comments, adding more detail and changing the wording to increase clarity.
1 parent add0a88 commit 2645754

File tree

4 files changed

+365
-3
lines changed

4 files changed

+365
-3
lines changed

common/common.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,11 @@ struct gpt_params {
113113
int32_t mirostat = 0; // 0 = disabled, 1 = mirostat, 2 = mirostat 2.0
114114
float mirostat_tau = 5.00f; // target entropy
115115
float mirostat_eta = 0.10f; // learning rate
116+
float dry_multiplier = 0.0f; // penalty multiplier, 0.0 = disabled
117+
float dry_base = 1.75f; // exponential base
118+
int32_t dry_allowed_length = 2; // repeated sequences longer than this are penalized
119+
int32_t dry_penalty_last_n = 0; // how many tokens to scan for repetitions (0 = entire context)
120+
std::vector<std::string> dry_sequence_breakers; // DRY sequence breakers
116121

117122
// DynaTemp!
118123
float dynatemp_range = 0.0f; // enables DynaTemp if greater than 0. dynatemp_min = temperature - dt_range, dynatemp_max = temperature + dt_range

expose.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ const int stop_token_max = 16;
55
const int ban_token_max = 16;
66
const int tensor_split_max = 16;
77
const int logit_bias_max = 16;
8+
const int dry_seq_break_max = 16;
89
const int images_max = 4;
910

1011
// match kobold's sampler list and order
@@ -83,6 +84,11 @@ struct generation_inputs
8384
const int mirostat = 0;
8485
const float mirostat_eta = 0.0f;
8586
const float mirostat_tau = 0.0f;
87+
const float dry_multiplier = 0.0f;
88+
const float dry_base = 0.0f;
89+
const int dry_allowed_length = 0;
90+
const int dry_penalty_last_n = 0;
91+
const char * dry_sequence_breakers[dry_seq_break_max] = {};
8692
const samplers sampler_order[KCPP_SAMPLER_MAX] = {};
8793
const int sampler_len = 0;
8894
const bool allow_eos_token = false;

0 commit comments

Comments
 (0)