[Spec][Ngram] 4/N: Remove max_match_window_size and min_match_window_size, matching all suffixes of the Trie (#21225)

This commit is contained in:
Khoa Pham
2026-04-01 22:09:46 -07:00
committed by GitHub
parent 269589ad71
commit f836658077
13 changed files with 46 additions and 134 deletions
+1 -3
View File
@@ -295,12 +295,10 @@ Please consult the documentation below and [server_args.py](https://github.com/s
## Ngram speculative decoding ## Ngram speculative decoding
| Argument | Description | Defaults | Options | | Argument | Description | Defaults | Options |
| --- | --- | --- | --- | | --- | --- | --- | --- |
| `--speculative-ngram-min-match-window-size` | The minimum window size for pattern matching in ngram speculative decoding. | `1` | Type: int |
| `--speculative-ngram-max-match-window-size` | The maximum window size for pattern matching in ngram speculative decoding. | `12` | Type: int |
| `--speculative-ngram-min-bfs-breadth` | The minimum breadth for BFS (Breadth-First Search) in ngram speculative decoding. | `1` | Type: int | | `--speculative-ngram-min-bfs-breadth` | The minimum breadth for BFS (Breadth-First Search) in ngram speculative decoding. | `1` | Type: int |
| `--speculative-ngram-max-bfs-breadth` | The maximum breadth for BFS (Breadth-First Search) in ngram speculative decoding. | `10` | Type: int | | `--speculative-ngram-max-bfs-breadth` | The maximum breadth for BFS (Breadth-First Search) in ngram speculative decoding. | `10` | Type: int |
| `--speculative-ngram-match-type` | Ngram tree-building mode. `BFS` selects recency-based expansion and `PROB` selects frequency-based expansion. This setting is forwarded to the ngram cache implementation. | `BFS` | `BFS`, `PROB` | | `--speculative-ngram-match-type` | Ngram tree-building mode. `BFS` selects recency-based expansion and `PROB` selects frequency-based expansion. This setting is forwarded to the ngram cache implementation. | `BFS` | `BFS`, `PROB` |
| `--speculative-ngram-max-trie-depth` | The max trie depth for ngram speculative decoding. | `18` | Type: int | | `--speculative-ngram-max-trie-depth` | Maximum suffix length stored and matched by the ngram trie. | `18` | Type: int |
| `--speculative-ngram-capacity` | The cache capacity for ngram speculative decoding. | `10000000` | Type: int | | `--speculative-ngram-capacity` | The cache capacity for ngram speculative decoding. | `10000000` | Type: int |
## Multi-layer Eagle speculative decoding ## Multi-layer Eagle speculative decoding
@@ -387,13 +387,11 @@ Enable it with:
| Parameter | Description | Default | | Parameter | Description | Default |
|---|---|---| |---|---|---|
| `--speculative-num-draft-tokens` | Number of draft tokens verified per step. If omitted, defaults to `--speculative-ngram-max-match-window-size`. | `12` (with default ngram settings) | | `--speculative-num-draft-tokens` | Number of draft tokens verified per step. If omitted, defaults to `min(--speculative-ngram-max-trie-depth, 12)`. | `12` (with default ngram settings) |
| `--speculative-ngram-min-match-window-size` | Minimum matching window size. | `1` |
| `--speculative-ngram-max-match-window-size` | Maximum matching window size. | `12` |
| `--speculative-ngram-min-bfs-breadth` | Minimum BFS breadth. | `1` | | `--speculative-ngram-min-bfs-breadth` | Minimum BFS breadth. | `1` |
| `--speculative-ngram-max-bfs-breadth` | Maximum BFS breadth. | `10` | | `--speculative-ngram-max-bfs-breadth` | Maximum BFS breadth. | `10` |
| `--speculative-ngram-match-type` | Ngram tree-building mode: `"BFS"` for recency-based expansion or `"PROB"` for frequency-based expansion. | `"BFS"` | | `--speculative-ngram-match-type` | Ngram tree-building mode: `"BFS"` for recency-based expansion or `"PROB"` for frequency-based expansion. | `"BFS"` |
| `--speculative-ngram-max-trie-depth` | The max trie depth for ngram speculative decoding. | `18` | | `--speculative-ngram-max-trie-depth` | Maximum suffix length stored and matched by the ngram trie. | `18` |
| `--speculative-ngram-capacity` | Cache capacity (number of entries). | `10,000,000` | | `--speculative-ngram-capacity` | Cache capacity (number of entries). | `10,000,000` |
Notes: Notes:
@@ -408,7 +406,6 @@ python3 -m sglang.launch_server \
--model Qwen/Qwen2.5-7B-Instruct \ --model Qwen/Qwen2.5-7B-Instruct \
--speculative-algorithm NGRAM \ --speculative-algorithm NGRAM \
--speculative-num-draft-tokens 16 \ --speculative-num-draft-tokens 16 \
--speculative-ngram-max-match-window-size 12 \
--speculative-ngram-max-bfs-breadth 10 \ --speculative-ngram-max-bfs-breadth 10 \
--mem-fraction-static 0.7 \ --mem-fraction-static 0.7 \
--cuda-graph-max-bs 8 \ --cuda-graph-max-bs 8 \
@@ -464,12 +461,10 @@ Below is a comprehensive list of all speculative decoding parameters available i
| Parameter | Type | Default | Description | | Parameter | Type | Default | Description |
|---|---|---|---| |---|---|---|---|
| `--speculative-ngram-min-match-window-size` | `int` | `1` | Minimum ngram matching window |
| `--speculative-ngram-max-match-window-size` | `int` | `12` | Maximum ngram matching window |
| `--speculative-ngram-min-bfs-breadth` | `int` | `1` | Minimum BFS breadth | | `--speculative-ngram-min-bfs-breadth` | `int` | `1` | Minimum BFS breadth |
| `--speculative-ngram-max-bfs-breadth` | `int` | `10` | Maximum BFS breadth | | `--speculative-ngram-max-bfs-breadth` | `int` | `10` | Maximum BFS breadth |
| `--speculative-ngram-match-type` | `str` | `"BFS"` | Ngram tree-building mode: `"BFS"` for recency-based expansion or `"PROB"` for frequency-based expansion | | `--speculative-ngram-match-type` | `str` | `"BFS"` | Ngram tree-building mode: `"BFS"` for recency-based expansion or `"PROB"` for frequency-based expansion |
| `--speculative-ngram-max-trie-depth` | `int` | `18` | Max trie depth for ngram speculative decoding | | `--speculative-ngram-max-trie-depth` | `int` | `18` | Maximum suffix length stored and matched by the ngram trie |
| `--speculative-ngram-capacity` | `int` | `10,000,000` | Cache capacity | | `--speculative-ngram-capacity` | `int` | `10,000,000` | Cache capacity |
### Environment variables ### Environment variables
+4 -16
View File
@@ -506,8 +506,6 @@ class ServerArgs:
speculative_draft_model_quantization: Optional[str] = None speculative_draft_model_quantization: Optional[str] = None
# Speculative decoding (ngram) # Speculative decoding (ngram)
speculative_ngram_min_match_window_size: int = 1
speculative_ngram_max_match_window_size: int = 12
speculative_ngram_min_bfs_breadth: int = 1 speculative_ngram_min_bfs_breadth: int = 1
speculative_ngram_max_bfs_breadth: int = 10 speculative_ngram_max_bfs_breadth: int = 10
speculative_ngram_match_type: Literal["BFS", "PROB"] = "BFS" speculative_ngram_match_type: Literal["BFS", "PROB"] = "BFS"
@@ -3108,8 +3106,10 @@ class ServerArgs:
self.enable_mixed_chunk = False self.enable_mixed_chunk = False
self.speculative_eagle_topk = self.speculative_ngram_max_bfs_breadth self.speculative_eagle_topk = self.speculative_ngram_max_bfs_breadth
if self.speculative_num_draft_tokens is None: if self.speculative_num_draft_tokens is None:
self.speculative_num_draft_tokens = ( self.speculative_num_draft_tokens = 12
self.speculative_ngram_max_match_window_size logger.warning(
"speculative_num_draft_tokens is set to 12 by default for ngram speculative decoding. "
"You can override this by explicitly setting --speculative-num-draft-tokens."
) )
logger.warning( logger.warning(
"The overlap scheduler and mixed chunked prefill are disabled because of " "The overlap scheduler and mixed chunked prefill are disabled because of "
@@ -4851,18 +4851,6 @@ class ServerArgs:
) )
# Speculative decoding (ngram) # Speculative decoding (ngram)
parser.add_argument(
"--speculative-ngram-min-match-window-size",
type=int,
default=ServerArgs.speculative_ngram_min_match_window_size,
help="The minimum window size for pattern matching in ngram speculative decoding.",
)
parser.add_argument(
"--speculative-ngram-max-match-window-size",
type=int,
default=ServerArgs.speculative_ngram_max_match_window_size,
help="The maximum window size for pattern matching in ngram speculative decoding.",
)
parser.add_argument( parser.add_argument(
"--speculative-ngram-min-bfs-breadth", "--speculative-ngram-min-bfs-breadth",
type=int, type=int,
@@ -13,23 +13,6 @@ Ngram::Ngram(size_t capacity, const Param& param) : param_(param) {
throw std::runtime_error( throw std::runtime_error(
"param_.max_trie_depth must be greater than 1, current value: " + std::to_string(param_.max_trie_depth)); "param_.max_trie_depth must be greater than 1, current value: " + std::to_string(param_.max_trie_depth));
} }
if (!(param_.min_match_window_size > 0)) {
throw std::runtime_error(
"min_match_window_size must be greater than 0, current value: " + std::to_string(param_.min_match_window_size));
}
if (!(param_.min_match_window_size <= param_.max_match_window_size)) {
throw std::runtime_error(
"min_match_window_size must be less than or equal to "
"max_match_window_size, current min_match_window_size: " +
std::to_string(param_.min_match_window_size) +
", max_match_window_size: " + std::to_string(param_.max_match_window_size));
}
if (!(param_.max_match_window_size < param_.max_trie_depth)) {
throw std::runtime_error(
"max_match_window_size must be less than max_trie_depth, current "
"max_match_window_size: " +
std::to_string(param_.max_match_window_size) + ", max_trie_depth: " + std::to_string(param_.max_trie_depth));
}
if (!(param_.min_bfs_breadth > 0)) { if (!(param_.min_bfs_breadth > 0)) {
throw std::runtime_error( throw std::runtime_error(
"min_bfs_breadth must be greater than 0, current value: " + std::to_string(param_.min_bfs_breadth)); "min_bfs_breadth must be greater than 0, current value: " + std::to_string(param_.min_bfs_breadth));
@@ -53,20 +36,6 @@ Ngram::Ngram(size_t capacity, const Param& param) : param_(param) {
} }
} }
} }
for (auto config : param_.batch_min_match_window_size) {
if (config != std::numeric_limits<decltype(config)>::max()) {
if (!(config >= param_.min_match_window_size)) {
throw std::runtime_error(
"batch_min_match_window_size config value " + std::to_string(config) +
" must be greater than or equal to min_match_window_size: " + std::to_string(param_.min_match_window_size));
}
if (!(config <= param_.max_match_window_size)) {
throw std::runtime_error(
"batch_min_match_window_size config value " + std::to_string(config) +
" must be less than or equal to max_match_window_size: " + std::to_string(param_.max_match_window_size));
}
}
}
trie_ = std::make_unique<Trie>(capacity, param_); trie_ = std::make_unique<Trie>(capacity, param_);
@@ -26,8 +26,6 @@ class NgramCorpus:
def __init__( def __init__(
self, self,
max_trie_depth=18, max_trie_depth=18,
min_match_window_size=1,
max_match_window_size=10,
min_bfs_breadth=1, min_bfs_breadth=1,
max_bfs_breadth=8, max_bfs_breadth=8,
draft_token_num=8, draft_token_num=8,
@@ -36,8 +34,6 @@ class NgramCorpus:
): ):
param = ngram_corpus_cpp.Param() param = ngram_corpus_cpp.Param()
param.max_trie_depth = max_trie_depth param.max_trie_depth = max_trie_depth
param.min_match_window_size = min_match_window_size
param.max_match_window_size = max_match_window_size
param.min_bfs_breadth = min_bfs_breadth param.min_bfs_breadth = min_bfs_breadth
param.max_bfs_breadth = max_bfs_breadth param.max_bfs_breadth = max_bfs_breadth
param.draft_token_num = draft_token_num param.draft_token_num = draft_token_num
@@ -21,17 +21,12 @@ PYBIND11_MODULE(ngram_corpus_cpp, m) {
.def_readwrite("enable_router_mode", &Param::enable_router_mode) .def_readwrite("enable_router_mode", &Param::enable_router_mode)
.def_readwrite("min_bfs_breadth", &Param::min_bfs_breadth) .def_readwrite("min_bfs_breadth", &Param::min_bfs_breadth)
.def_readwrite("max_bfs_breadth", &Param::max_bfs_breadth) .def_readwrite("max_bfs_breadth", &Param::max_bfs_breadth)
.def_readwrite("min_match_window_size", &Param::min_match_window_size)
.def_readwrite("max_match_window_size", &Param::max_match_window_size)
.def_readwrite("max_trie_depth", &Param::max_trie_depth) .def_readwrite("max_trie_depth", &Param::max_trie_depth)
.def_readwrite("draft_token_num", &Param::draft_token_num) .def_readwrite("draft_token_num", &Param::draft_token_num)
.def_readwrite("match_type", &Param::match_type) .def_readwrite("match_type", &Param::match_type)
.def_readwrite("batch_min_match_window_size", &Param::batch_min_match_window_size)
.def_readwrite("batch_draft_token_num", &Param::batch_draft_token_num) .def_readwrite("batch_draft_token_num", &Param::batch_draft_token_num)
.def("get_draft_token_num", &Param::get_draft_token_num, "") .def("get_draft_token_num", &Param::get_draft_token_num, "")
.def("get_min_match_window_size", &Param::get_min_match_window_size, "")
.def("parse", &Param::parse, "") .def("parse", &Param::parse, "")
.def("resetBatchMinMatchWindowSize", &Param::resetBatchMinMatchWindowSize, "")
.def("resetBatchReturnTokenNum", &Param::resetBatchReturnTokenNum, "") .def("resetBatchReturnTokenNum", &Param::resetBatchReturnTokenNum, "")
.def("detail", &Param::detail, ""); .def("detail", &Param::detail, "");
@@ -17,13 +17,10 @@ struct Param {
bool enable_router_mode; bool enable_router_mode;
size_t min_bfs_breadth; size_t min_bfs_breadth;
size_t max_bfs_breadth; size_t max_bfs_breadth;
size_t min_match_window_size;
size_t max_match_window_size;
size_t max_trie_depth; size_t max_trie_depth;
size_t draft_token_num; size_t draft_token_num;
std::string match_type; std::string match_type;
std::vector<size_t> batch_min_match_window_size;
std::vector<size_t> batch_draft_token_num; std::vector<size_t> batch_draft_token_num;
size_t get_draft_token_num(size_t batch_size) const { size_t get_draft_token_num(size_t batch_size) const {
@@ -36,16 +33,6 @@ struct Param {
return draft_token_num - 1; return draft_token_num - 1;
} }
size_t get_min_match_window_size(size_t batch_size) const {
if (batch_size < batch_min_match_window_size.size()) {
if (batch_min_match_window_size[batch_size] !=
std::numeric_limits<decltype(batch_min_match_window_size)::value_type>::max()) {
return batch_min_match_window_size[batch_size];
}
}
return min_match_window_size;
}
std::vector<size_t> parse(const std::string& value) { std::vector<size_t> parse(const std::string& value) {
// 0-1|10,2-3|20, // 0-1|10,2-3|20,
std::vector<size_t> result; std::vector<size_t> result;
@@ -96,10 +83,6 @@ struct Param {
return result; return result;
} }
void resetBatchMinMatchWindowSize(const std::string& value) {
batch_min_match_window_size = parse(value);
}
void resetBatchReturnTokenNum(const std::string& value) { void resetBatchReturnTokenNum(const std::string& value) {
batch_draft_token_num = parse(value); batch_draft_token_num = parse(value);
} }
@@ -108,13 +91,8 @@ struct Param {
std::stringstream ss; std::stringstream ss;
ss << "enable = " << enable << ", enable_router_mode = " << enable_router_mode ss << "enable = " << enable << ", enable_router_mode = " << enable_router_mode
<< ", min_bfs_breadth = " << min_bfs_breadth << ", max_bfs_breadth = " << max_bfs_breadth << ", min_bfs_breadth = " << min_bfs_breadth << ", max_bfs_breadth = " << max_bfs_breadth
<< ", min_match_window_size = " << min_match_window_size << ", max_match_window_size = " << max_match_window_size
<< ", max_trie_depth = " << max_trie_depth << ", draft_token_num = " << draft_token_num << ", max_trie_depth = " << max_trie_depth << ", draft_token_num = " << draft_token_num
<< ", match_type = " << match_type; << ", match_type = " << match_type;
ss << ", batch_min_match_window_size(" << batch_min_match_window_size.size() << ") = ";
for (int i = 0; i < batch_min_match_window_size.size(); ++i) {
ss << i << "|" << batch_min_match_window_size[i] << ",";
}
ss << ", batch_draft_token_num(" << batch_draft_token_num.size() << ") = "; ss << ", batch_draft_token_num(" << batch_draft_token_num.size() << ") = ";
for (int i = 0; i < batch_draft_token_num.size(); ++i) { for (int i = 0; i < batch_draft_token_num.size(); ++i) {
ss << i << "|" << batch_draft_token_num[i] << ","; ss << i << "|" << batch_draft_token_num[i] << ",";
@@ -19,7 +19,7 @@ Trie::Trie(size_t capacity, const Param& param) : param_(param) {
} }
void Trie::insert(const int32_t* tokens, size_t len) { void Trie::insert(const int32_t* tokens, size_t len) {
for (size_t i = 0; i + param_.min_match_window_size < len; ++i) { for (size_t i = 0; i < len; ++i) {
auto start = tokens + i; auto start = tokens + i;
auto end = start + std::min(len - i, param_.max_trie_depth); auto end = start + std::min(len - i, param_.max_trie_depth);
@@ -100,14 +100,13 @@ void Trie::reset() {
root_ = getNode(); root_ = getNode();
} }
std::vector<std::pair<TrieNode*, int32_t>> std::vector<std::pair<TrieNode*, int32_t>> Trie::match(const int32_t* context, size_t len) const {
Trie::match(const int32_t* context, size_t len, size_t min_window, size_t max_window) const {
std::vector<std::pair<TrieNode*, int32_t>> result; std::vector<std::pair<TrieNode*, int32_t>> result;
result.reserve(max_window - min_window); const auto max_match_depth = std::min(len, param_.max_trie_depth);
for (int32_t match_window_size = std::min(len, max_window); match_window_size >= static_cast<int32_t>(min_window); result.reserve(max_match_depth);
--match_window_size) { for (size_t match_depth = max_match_depth; match_depth > 0; --match_depth) {
auto start = context + len - match_window_size; auto start = context + len - match_depth;
auto end = start + match_window_size; auto end = start + match_depth;
auto cursor = root_; auto cursor = root_;
while (start != end) { while (start != end) {
auto iter = cursor->child.find(*start); auto iter = cursor->child.find(*start);
@@ -118,8 +117,8 @@ Trie::match(const int32_t* context, size_t len, size_t min_window, size_t max_wi
++start; ++start;
cursor = iter->second; cursor = iter->second;
} }
if (cursor) { if (cursor != nullptr && !cursor->child.empty()) {
result.emplace_back(std::make_pair(cursor, match_window_size)); result.emplace_back(cursor, static_cast<int32_t>(match_depth));
} }
} }
return result; return result;
@@ -127,10 +126,10 @@ Trie::match(const int32_t* context, size_t len, size_t min_window, size_t max_wi
Result Trie::buildRecency( Result Trie::buildRecency(
const int32_t* context, size_t len, int32_t last_token, size_t draft_token_num, const Param& param) const { const int32_t* context, size_t len, int32_t last_token, size_t draft_token_num, const Param& param) const {
auto anchors = match(context, len, param.min_match_window_size, param.max_match_window_size); auto anchors = match(context, len);
double bfs_breadth_scale = double(param.max_bfs_breadth - param.min_bfs_breadth) / const auto max_match_depth = std::max<int32_t>(1, static_cast<int32_t>(param.max_trie_depth - 1));
(param.max_match_window_size - param.min_match_window_size + 1); double bfs_breadth_scale = double(param.max_bfs_breadth - param.min_bfs_breadth) / max_match_depth;
std::vector<Node> tree(draft_token_num + 1); std::vector<Node> tree(draft_token_num + 1);
int root = 0; int root = 0;
@@ -138,7 +137,7 @@ Result Trie::buildRecency(
for (auto [node, depth] : anchors) { for (auto [node, depth] : anchors) {
std::queue<std::tuple<int32_t, double, const TrieNode*>> queue; std::queue<std::tuple<int32_t, double, const TrieNode*>> queue;
queue.push({root, (param.max_match_window_size - depth) * bfs_breadth_scale + param.min_bfs_breadth, node}); queue.push({root, (max_match_depth - depth) * bfs_breadth_scale + param.min_bfs_breadth, node});
while (queue.size() && cursor <= static_cast<int>(draft_token_num)) { while (queue.size() && cursor <= static_cast<int>(draft_token_num)) {
auto front = queue.front(); auto front = queue.front();
queue.pop(); queue.pop();
@@ -168,7 +167,7 @@ Result Trie::buildRecency(
Result Trie::buildFrequency( Result Trie::buildFrequency(
const int32_t* context, size_t len, int32_t last_token, size_t draft_token_num, const Param& param) const { const int32_t* context, size_t len, int32_t last_token, size_t draft_token_num, const Param& param) const {
auto anchors = match(context, len, param.min_match_window_size, param.max_match_window_size); auto anchors = match(context, len);
struct CompareByLastDouble { struct CompareByLastDouble {
bool operator()( bool operator()(
@@ -49,8 +49,7 @@ class Trie {
void reset(); void reset();
private: private:
std::vector<std::pair<TrieNode*, int32_t>> std::vector<std::pair<TrieNode*, int32_t>> match(const int32_t* context, size_t len) const;
match(const int32_t* context, size_t len, size_t min_window, size_t max_window) const;
TrieNode* getNode() { TrieNode* getNode() {
auto node = node_pool_[--free_node_count_]; auto node = node_pool_[--free_node_count_];
@@ -41,9 +41,6 @@ class NGRAMWorker:
self.page_size = server_args.page_size self.page_size = server_args.page_size
self.draft_token_num: int = server_args.speculative_num_draft_tokens self.draft_token_num: int = server_args.speculative_num_draft_tokens
self.max_trie_depth: int = server_args.speculative_ngram_max_trie_depth self.max_trie_depth: int = server_args.speculative_ngram_max_trie_depth
self.max_match_window_size: int = (
server_args.speculative_ngram_max_match_window_size
)
self.max_batch_size = target_worker.max_running_requests self.max_batch_size = target_worker.max_running_requests
self.device = f"cuda:{gpu_id}" if gpu_id >= 0 else "cuda" self.device = f"cuda:{gpu_id}" if gpu_id >= 0 else "cuda"
@@ -51,8 +48,6 @@ class NGRAMWorker:
self._init_preallocated_tensors() self._init_preallocated_tensors()
self.ngram_corpus = NgramCorpus( self.ngram_corpus = NgramCorpus(
min_match_window_size=server_args.speculative_ngram_min_match_window_size,
max_match_window_size=server_args.speculative_ngram_max_match_window_size,
min_bfs_breadth=server_args.speculative_ngram_min_bfs_breadth, min_bfs_breadth=server_args.speculative_ngram_min_bfs_breadth,
max_bfs_breadth=server_args.speculative_ngram_max_bfs_breadth, max_bfs_breadth=server_args.speculative_ngram_max_bfs_breadth,
match_type=server_args.speculative_ngram_match_type, match_type=server_args.speculative_ngram_match_type,
@@ -131,7 +126,7 @@ class NGRAMWorker:
batch_tokens = [] batch_tokens = []
for req in batch.reqs: for req in batch.reqs:
check_token = self._efficient_concat_last_n( check_token = self._efficient_concat_last_n(
req.origin_input_ids, req.output_ids, self.max_match_window_size req.origin_input_ids, req.output_ids, self.max_trie_depth
) )
batch_tokens.append(check_token) batch_tokens.append(check_token)
req_drafts, mask = self.ngram_corpus.batch_get(batch_tokens) req_drafts, mask = self.ngram_corpus.batch_get(batch_tokens)
-2
View File
@@ -768,8 +768,6 @@ def run_lora_multiple_batch_on_model_cases(
else { else {
"speculative_algorithm": "NGRAM", "speculative_algorithm": "NGRAM",
"speculative_num_draft_tokens": 5, "speculative_num_draft_tokens": 5,
"speculative_ngram_min_match_window_size": 2,
"speculative_ngram_max_match_window_size": 15,
} }
) )
srt_runner = SRTRunner( srt_runner = SRTRunner(
+1 -8
View File
@@ -574,8 +574,6 @@ class SRTRunner:
speculative_num_steps: Optional[int] = None, speculative_num_steps: Optional[int] = None,
speculative_eagle_topk: Optional[int] = None, speculative_eagle_topk: Optional[int] = None,
speculative_num_draft_tokens: Optional[int] = None, speculative_num_draft_tokens: Optional[int] = None,
speculative_ngram_min_match_window_size: Optional[int] = None,
speculative_ngram_max_match_window_size: Optional[int] = None,
disable_overlap_schedule: bool = False, disable_overlap_schedule: bool = False,
disable_custom_all_reduce: bool = False, disable_custom_all_reduce: bool = False,
torchao_config: Optional[str] = None, torchao_config: Optional[str] = None,
@@ -606,12 +604,7 @@ class SRTRunner:
spec_kwargs["speculative_num_draft_tokens"] = speculative_num_draft_tokens spec_kwargs["speculative_num_draft_tokens"] = speculative_num_draft_tokens
elif speculative_algorithm == "NGRAM": elif speculative_algorithm == "NGRAM":
spec_kwargs["speculative_algorithm"] = speculative_algorithm spec_kwargs["speculative_algorithm"] = speculative_algorithm
spec_kwargs["speculative_ngram_min_match_window_size"] = ( spec_kwargs["speculative_num_draft_tokens"] = speculative_num_draft_tokens
speculative_ngram_min_match_window_size
)
spec_kwargs["speculative_ngram_max_match_window_size"] = (
speculative_ngram_max_match_window_size
)
self.engine = Engine( self.engine = Engine(
model_path=model_path, model_path=model_path,
+21 -12
View File
@@ -12,8 +12,6 @@ register_cuda_ci(est_time=8, suite="stage-b-test-1-gpu-small")
def _make_corpus(match_type="BFS", **kwargs): def _make_corpus(match_type="BFS", **kwargs):
defaults = dict( defaults = dict(
max_trie_depth=12, max_trie_depth=12,
min_match_window_size=1,
max_match_window_size=10,
min_bfs_breadth=1, min_bfs_breadth=1,
max_bfs_breadth=8, max_bfs_breadth=8,
draft_token_num=8, draft_token_num=8,
@@ -239,9 +237,7 @@ class TestNgramCorpusSqueeze(CustomTestCase):
self.assertEqual(len(ids), 8, "Should still produce draft_token_num outputs") self.assertEqual(len(ids), 8, "Should still produce draft_token_num outputs")
def test_eviction_preserves_recent(self): def test_eviction_preserves_recent(self):
corpus = _make_corpus( corpus = _make_corpus("BFS", capacity=500, max_trie_depth=6)
"BFS", capacity=500, max_trie_depth=6, max_match_window_size=5
)
old_seq = list(range(1000, 1050)) old_seq = list(range(1000, 1050))
corpus.batch_put([old_seq]) corpus.batch_put([old_seq])
@@ -357,7 +353,6 @@ class TestFrequencyBoosting(CustomTestCase):
draft_token_num=2, draft_token_num=2,
max_bfs_breadth=1, max_bfs_breadth=1,
min_bfs_breadth=1, min_bfs_breadth=1,
max_match_window_size=3,
max_trie_depth=5, max_trie_depth=5,
) )
corpus.batch_put([[1, 2, 3, 10, 11]]) corpus.batch_put([[1, 2, 3, 10, 11]])
@@ -386,7 +381,6 @@ class TestRecencyOrdering(CustomTestCase):
draft_token_num=2, draft_token_num=2,
max_bfs_breadth=1, max_bfs_breadth=1,
min_bfs_breadth=1, min_bfs_breadth=1,
max_match_window_size=3,
max_trie_depth=5, max_trie_depth=5,
) )
corpus.batch_put([[1, 2, 3, 10, 11]]) corpus.batch_put([[1, 2, 3, 10, 11]])
@@ -422,7 +416,7 @@ class TestSingleTokenContext(CustomTestCase):
"""Verify behavior with minimum-length context.""" """Verify behavior with minimum-length context."""
def test_single_token_query(self): def test_single_token_query(self):
corpus = _make_corpus("BFS", min_match_window_size=1) corpus = _make_corpus("BFS")
corpus.batch_put([[5, 10, 20, 30]]) corpus.batch_put([[5, 10, 20, 30]])
corpus.synchronize() corpus.synchronize()
@@ -436,7 +430,7 @@ class TestLongContext(CustomTestCase):
"""Verify behavior when query context exceeds max_trie_depth.""" """Verify behavior when query context exceeds max_trie_depth."""
def test_context_longer_than_max_trie_depth(self): def test_context_longer_than_max_trie_depth(self):
corpus = _make_corpus("BFS", max_trie_depth=6, max_match_window_size=5) corpus = _make_corpus("BFS", max_trie_depth=6)
seq = list(range(1, 20)) seq = list(range(1, 20))
corpus.batch_put([seq]) corpus.batch_put([seq])
corpus.synchronize() corpus.synchronize()
@@ -447,6 +441,23 @@ class TestLongContext(CustomTestCase):
self.assertEqual(ids_list[0], 15, "First token should be last context token") self.assertEqual(ids_list[0], 15, "First token should be last context token")
self.assertIn(16, ids_list, "Should match via suffix despite long context") self.assertIn(16, ids_list, "Should match via suffix despite long context")
def test_matches_longest_stored_suffix(self):
corpus = _make_corpus("BFS", max_trie_depth=6, draft_token_num=4)
corpus.batch_put([[1, 2, 3, 4, 5, 6, 7]])
corpus.batch_put([[99, 3, 4, 5, 6, 8]])
corpus.synchronize()
ids, _ = corpus.batch_get([[2, 3, 4, 5, 6]])
ids_list = ids.tolist()
self.assertIn(
7, ids_list, "Longest stored suffix should contribute a continuation"
)
self.assertIn(
8,
ids_list,
"Shorter matching suffixes should still contribute continuations",
)
class TestDraftBudgetSaturation(CustomTestCase): class TestDraftBudgetSaturation(CustomTestCase):
"""Verify the draft tree uses exactly draft_token_num slots.""" """Verify the draft tree uses exactly draft_token_num slots."""
@@ -538,9 +549,7 @@ class TestSqueezeEvictsOld(CustomTestCase):
"""Verify that squeeze actually evicts old data, not just preserves recent.""" """Verify that squeeze actually evicts old data, not just preserves recent."""
def test_old_data_evicted(self): def test_old_data_evicted(self):
corpus = _make_corpus( corpus = _make_corpus("BFS", capacity=150, max_trie_depth=6)
"BFS", capacity=150, max_trie_depth=6, max_match_window_size=5
)
old_seq = list(range(5000, 5030)) old_seq = list(range(5000, 5030))
corpus.batch_put([old_seq]) corpus.batch_put([old_seq])