feat(SpecEagleV2): add standalone_worker_v2 (#12625)

Co-authored-by: liugaoji.lgj <liugaoji.lgj@alibaba-inc.com>
This commit is contained in:
Gaoji Liu
2025-12-30 17:55:04 +08:00
committed by GitHub
co-authored by liugaoji.lgj
parent b6871ba7c9
commit 7518dc3532
14 changed files with 317 additions and 17 deletions
+7 -7
View File
@@ -116,7 +116,9 @@ class FutureMap:
return FutureIndices(indices=indices, interval=slice(start, end))
def resolve_future(self, model_worker_batch: ModelWorkerBatch):
if self.spec_algo.is_eagle():
if self.spec_algo.is_none():
_resolve_future_token_ids(model_worker_batch.input_ids, self.token_ids_buf)
else:
# TODO(lsyin): write future indices into spec_info.future_indices
draft_input: EagleDraftInput = model_worker_batch.spec_info
if draft_input is None:
@@ -129,8 +131,6 @@ class FutureMap:
draft_input.new_seq_lens = self.new_seq_lens_buf[indices]
if spec_need_hidden_states():
draft_input.hidden_states = self.hidden_states_buf[indices]
else:
_resolve_future_token_ids(model_worker_batch.input_ids, self.token_ids_buf)
def is_empty_slice(self, s: slice) -> bool:
start, stop, step = s.indices(self.future_buffer_len)
@@ -142,12 +142,12 @@ class FutureMap:
def store_to_map(
self, future_indices: FutureIndices, batch_result: GenerationBatchResult
):
if self.spec_algo.is_eagle():
draft_input: EagleDraftInput = batch_result.next_draft_input
self.store_to_map_for_new_batch(future_indices, draft_input)
else:
if self.spec_algo.is_none():
intv = future_indices.interval
self.token_ids_buf[intv] = batch_result.next_token_ids
else:
draft_input: EagleDraftInput = batch_result.next_draft_input
self.store_to_map_for_new_batch(future_indices, draft_input)
def store_to_map_for_new_batch(
self, future_indices: FutureIndices, draft_input: EagleDraftInput
+3 -1
View File
@@ -1849,7 +1849,9 @@ class ScheduleBatch(ScheduleBatchDisaggregationDecodeMixin):
@property
def is_spec_v2(self):
# FIXME: finally deprecate is_spec_v2
return self.enable_overlap and self.spec_algorithm.is_eagle()
ret = self.enable_overlap and not self.spec_algorithm.is_none()
assert not ret or self.spec_algorithm.supports_spec_v2()
return ret
def prepare_for_decode(self):
self.forward_mode = ForwardMode.DECODE
+4 -2
View File
@@ -499,7 +499,7 @@ class Scheduler(
# Draft workers are looked up via `SpeculativeAlgorithm` registry; new
# algorithms should register their factory instead of patching this code.
if self.spec_algorithm.is_eagle():
if self.spec_algorithm.supports_spec_v2():
draft_worker_kwargs["enable_overlap"] = self.enable_overlap
# FIXME: refactor the draft worker registration logic
@@ -852,7 +852,7 @@ class Scheduler(
if self.draft_worker is None or self.spec_algorithm.is_ngram():
draft_token_to_kv_pool = None
elif self.spec_algorithm.is_eagle() and self.enable_overlap:
elif self.spec_algorithm.supports_spec_v2() and self.enable_overlap:
if self.server_args.enable_multi_layer_eagle:
draft_runner = self.draft_worker.draft_worker.draft_runner_list[0]
else:
@@ -930,11 +930,13 @@ class Scheduler(
hidden_size=(
model_config.hidden_size
if self.spec_algorithm.is_eagle()
or self.spec_algorithm.is_standalone()
else 16 # minimal padding size for RDMA
),
hidden_states_dtype=(
model_config.dtype
if self.spec_algorithm.is_eagle()
or self.spec_algorithm.is_standalone()
else torch.float32
),
custom_mem_pool=self.token_to_kv_pool_allocator.get_kvcache().maybe_get_custom_mem_pool(),