跳至主要内容

Generation API

Generation API 是 runtime 狀態轉換最明顯之處:cache 增長、停止條件與每 token 控制流。它們是自迴歸 decode 表面。

函式用途
generate阻塞式批次 decode。完成時回傳完整 prompt+延續。
generate_stream帶每 token callback 的 decode;呼叫端可觀察並於串流中途中止。
generate_batch在一個 Model* 上循序 decode 一批 prompt。
generate_speculative鏈式自 speculative decoding — 在 L_draft 草擬、在 L_verify 驗證,零輔助權重。
generate_tree_speculative樹狀分支自 speculative,每步具備 K 寬度候選。

所有 generation 函式共用相同的底層基礎:

  • prompt_len + max_tokens 配置全新的 RuntimeKVCache
  • 以配置的 loop 深度對 prompt 進行 prefill。
  • 執行具明確停止策略(EOS、stop-sequence 結尾匹配、callback 中止、grammar 死路、max_tokens)的每 token decode loop。
  • 回傳前釋放 cache。

所有 generation 函式都不會取得 cache 所有權 — 它們總是在函式退出時於內部清理。PrefixCache / ResumeHandle(見 快取重用 API)才是跨呼叫重用狀態的 opt-in 路徑。

generate

std::vector<int32_t> generate(Model* model,
const int32_t* prompt,
int prompt_len,
const GenerateConfig& config);

標準阻塞式自迴歸 decode。對 prompt 執行 prefill,然後每次取樣一個 token 直到停止條件觸發。

參數

名稱型別預設描述
modelModel*已載入的模型指標。不得為 nullptr
promptconst int32_t*Prompt token-id 陣列,長度為 prompt_len。Token id 必須滿足 0 <= t < vocab_size
prompt_lenintPrompt 中的 token 數量。必須滿足 1 <= prompt_len + config.max_tokens <= max_seq_len
configconst GenerateConfig&Decode 配置;見下方 GenerateConfig

回傳

std::vector<int32_t> — 完整 token 流,prompt 在前、decoded token 在後。長度為 prompt_len + emitted,其中 emitted <= config.max_tokens,依停止策略而定。

例外 / 錯誤條件

致命錯誤時,runtime 會向 stderr 寫出訊息並中止。條件:

  • model == nullptr
  • prompt_len < 1prompt_len + config.max_tokens > max_seq_len
  • RuntimeKVCache 配置期間記憶體不足。
  • 無效的取樣參數(temperature < 0、取樣啟用時 top_k <= 0beam_size > 1 卻搭配不一致的 beam-path 旋鈕)。

範例

tinyloop::GenerateConfig cfg;
cfg.max_tokens = 64;
cfg.loops = 8;
cfg.temperature = 0.8f;
cfg.top_k = 50;
cfg.stop_sequences = {{13}}; // 在 "." 停止(GPT-2 中 "." 的 id)
auto out = tinyloop::generate(model, prompt.data(), prompt.size(), cfg);
// out = concat(prompt, generated_tokens)

generate_stream

std::vector<int32_t> generate_stream(Model* model,
const int32_t* prompt,
int prompt_len,
const GenerateConfig& config,
const GenerateTokenCallback& on_token,
GenerateStats* stats = nullptr);

Decode 語義與 generate 相同,但每 token 放出後會同步呼叫 on_token,並可選擇性地將每階段耗時填入 GenerateStats struct。decode 結束時回傳值仍是完整的 token 流。

參數

名稱型別預設描述
modelModel*已載入的模型指標。
promptconst int32_t*Prompt token id。
prompt_lenint1 <= prompt_len + max_tokens <= max_seq_len
configconst GenerateConfig&GenerateConfig
on_tokenconst GenerateTokenCallback&每放出一個 token 呼叫一次的 callback。簽章:bool(int32_t token, int position)。回傳 false 可在包含此 token 後中止 decode。
statsGenerateStats*nullptr選擇性的統計輸出。欄位包括 prefill_msfirst_token_msdecode_mstokens_emittedstop_reason

回傳

std::vector<int32_t> — 與 generate 相同。

Callback 語義

  • on_token 從 decode 執行緒同步呼叫。它在緊湊的 decode loop 中執行;請避免在 callback 中進行阻塞工作(磁碟 I/O、網路傳送),否則請以有界佇列包裝。
  • Callback 以順序呼叫,每個放出的 token 呼叫一次。
  • 回傳 false 會乾淨地中止:最後一個 token 仍會包含在回傳 vector 中;cache 清理仍會執行。
  • Callback 不會收到 logits。如需 logit 層級觀察,請在 decode loop 之外使用 score 系列。

GenerateStats 欄位

欄位型別描述
prefill_msdoublePrefill 階段(prompt → 第一個 token 就緒)的 wall-clock 時間。
first_token_msdouble從呼叫進入到第一個 token 放出的 wall-clock 時間。
decode_msdouble穩態 decode loop 的 wall-clock 時間。
tokens_emittedint放出的 token 數(不含 prompt)。
stop_reasonenumEOSSTOP_SEQUENCEMAX_TOKENSCALLBACK_ABORTGRAMMAR_DEAD_END 其中之一。
loops_usedint實際使用的有效 loop 深度(對自適應模式有意義)。

範例

tinyloop::GenerateStats stats;
auto out = tinyloop::generate_stream(
model, prompt.data(), prompt.size(), cfg,
[](int32_t tok, int pos) {
std::cout << detokenize(tok) << std::flush;
return true; // 繼續;回傳 false 以中止
},
&stats);
std::cerr << "decode rate: "
<< stats.tokens_emitted / (stats.decode_ms / 1000.0)
<< " tok/s\n";

generate_batch

std::vector<int32_t> generate_batch(Model* model,
const std::vector<std::vector<int32_t>>& prompts,
const GenerateConfig& config);

循序批次 decode。每個 prompt 以全新 cache decode 至完成,然後下一個才開始。回傳值是所有輸出的扁平串接(每個 prompt 的 prompt + 延續連接在一起)。

參數

名稱型別預設描述
modelModel*已載入的模型指標。
promptsconst std::vector<std::vector<int32_t>>&Prompt 批次。每一個內部 vector 是一個 prompt。
configconst GenerateConfig&套用於每個 prompt 的共享配置。目前不支援 per-prompt 配置 — 如有需要,請直接在迴圈中呼叫 generate

回傳

std::vector<int32_t> — 所有輸出的扁平串接。要還原每個 prompt 的邊界,呼叫端必須追蹤每個 prompt 的長度與每個結果放出的 token 數(可由 prompt 長度加 config 的 max_tokens 上限,再減去早期停止數取得)。

備註

  • 這不是 continuous batching。 TinyLoop 在同一個 Model* 上一次處理一個 prompt。真正的批次 prefill + paged attention 是多週的重構,目前不在範圍內。
  • 每 prompt 的早期停止(EOS、stop sequences)運作方式與 generate 相同。
  • 對於並行批次服務,請每個 worker thread 使用一個 Model*(較高 VRAM)或外部的 lock-per-model 方案 — 指引與 生命週期與記憶體模型 相同。

generate_speculative

std::vector<int32_t> generate_speculative(Model* model,
const int32_t* prompt,
int prompt_len,
const SpeculativeConfig& config);

鏈式自 speculative decoding。以較便宜的 L_draft 草擬 draft_ahead 個 token,在單次 L_verify forward 中驗證,接受最長匹配的 prefix,並推進 cache。不需要輔助草擬模型 — 草擬與驗證都使用相同的共享 loop block,只是在不同深度。

參數

名稱型別預設描述
modelModel*已載入的模型指標。
promptconst int32_t*Prompt token id。
prompt_lenint1 <= prompt_len + max_tokens <= max_seq_len
configconst SpeculativeConfig&SpeculativeConfig

回傳

std::vector<int32_t> — 形狀與 generate 相同:prompt 後接 decoded token。

SpeculativeConfig

欄位型別預設描述
max_tokensint64總放出上限(不含 prompt)。
draft_loopsint2便宜的草擬 pass loop 深度。較低 = 較快草擬、較多拒絕。
verify_loopsint8驗證 pass loop 深度。通常等於 model.default_loops
draft_aheadint4每次驗證循環草擬的 token 數。較大 = 每次驗證有更多並行性,但 miss 時浪費的工作也更多。
temperaturefloat0.0貪婪接受是被充分描述的路徑;stochastic speculative 仍屬實驗性。
seeduint64_t0Stochastic 模式的 RNG 種子。temperature == 0 時忽略。

接受語義

  • 草擬在 draft_loops 下貪婪產生 draft_ahead 個 token。
  • 驗證在 verify_loops 下對整個草擬序列執行一次。
  • verify_loops 下其 argmax 與草擬相符的最長 prefix 會被接受。
  • 首個不符的位置會從驗證分佈貢獻一個 bonus token;cache 推進到該點,下一輪循環開始。

備註

  • Forward pass 減少,不是 wall-clock。 測得的接受率對應的是較少的全深度 forward_with_cache 呼叫,而非等比例的 wall-clock 加速 — 草擬 pass 仍需耗費計算。在調校良好的配置下,407M checkpoint 的實際 wall-clock 加速為 2.0–2.8×(見論文 §6)。
  • 貪婪是安全模式。 Stochastic speculative decode 引入額外細節(取樣下草擬/驗證分佈不符),目前實作並未在所有參數化下提供保證。
  • β 敏感。 在高 β 模型(β > 1)上,草擬與驗證分佈發散更快,接受率崩潰,甚至可能產生比 baseline 更慢的 decode。請在為某 checkpoint 承諾使用 speculative 前先做實證測試。

generate_tree_speculative

std::vector<int32_t> generate_tree_speculative(Model* model,
const int32_t* prompt,
int prompt_len,
const TreeSpeculativeConfig& config);

樹狀分支 speculative decoding。不採用線性 token 鏈,而是每步草擬 K 個候選形成一棵樹,然後以單次 tree-mask gated forward 驗證整棵樹。接受最長的匹配路徑。

參數

名稱型別預設描述
modelModel*已載入的模型指標。
promptconst int32_t*Prompt token id。
prompt_lenint1 <= prompt_len + max_tokens <= max_seq_len
configconst TreeSpeculativeConfig&擴充自 SpeculativeConfig,加上 K_branchestree_depth

回傳

std::vector<int32_t> — 完整輸出序列。

TreeSpeculativeConfig

欄位型別預設描述
max_tokensint64總放出上限。
draft_loopsint2草擬 pass loop 深度。
verify_loopsint8驗證 pass loop 深度。
draft_aheadint4樹深度 — 每個循環的連續草擬步數。
K_branchesint2每個草擬步保留的候選 token 數。樹的總大小約為 K_branches^draft_ahead
temperaturefloat0.0貪婪是位元精確路徑(與非 speculative 輸出一致);取樣屬實驗性。

備註

  • 架構獨有。 在草擬與驗證深度使用相同權重的樹狀 speculative decoding,只有在共享 loop block 時才可能。主流 runtime 需要輔助草擬 head(Medusa)或小型草擬模型(EAGLE)才能達到類似吞吐量。
  • temperature == 0 時位元精確。 在相同種子與 K_branches == 2 下,貪婪 tree-speculative 產生的 token 與 generate_speculativedraft_ahead=1 + 鏈式 decode 相同。此點已在多個 prompt 上驗證測試過。
  • 吞吐量甜蜜點在 407M artifact 上為 K_branches=2, draft_ahead=2, draft_loops=2, verify_loops=8。較高的 K 很快就不再划算(樹質量爆炸而品質增益有限)。

GenerateConfig

generategenerate_streamgenerate_batch 共享。

欄位型別預設描述
max_tokensint64放出 token 的上限。
loopsintmodel.default_loopsLoop 深度。明確設定可覆寫 checkpoint 訓練的預設值。
temperaturefloat0.0Softmax temperature。0.0(或 <= 0.01)代表貪婪 argmax。必須 >= 0
top_kint50取樣前保留前 k 個 token。取樣啟用時必須 >= 1temperature == 0 時忽略。
top_pfloat1.0Nucleus sampling 閾值。1.0 表示停用。在 top_k 之後套用。
cache_windowint0KV cache 的滑動視窗上限。0 代表無上限(受 max_seq_len 限制)。
repetition_penaltyfloat1.0HuggingFace 慣例的懲罰,在 temperature/top-k/top-p 前套用。1.0 代表停用。
stop_sequencesstd::vector<std::vector<int32_t>>{}在放出輸出尾部匹配時終止 decode 的 token-id 序列。匹配的 token 仍會包含在回傳流中。
beam_sizeint001 = 標準取樣。>= 2 切換為確定性 beam search;取樣旋鈕會被忽略。
length_penaltyfloat1.0僅 beam search 使用。以 log_prob / max(1, len)^length_penalty 排序 beam。
early_exit_patienceint00 停用自適應深度早退。>0 啟用:在 min_L 之後連續 patience 次穩定探測後退出。
early_exit_min_Lint2早退的首探測底線。
early_exit_peek_everyint1min_L 之後的探測頻率。
early_exit_logit_marginfloat0.0>0 將穩定性判斷由 hidden-L2 切換為 logit-margin。對高 β 模型的實證正確訊號。
sample_seeduint64_t0Stochastic 取樣的 RNG 種子。給定種子 + config + 模型即為確定性。
grammarGrammar*nullptr選擇性的受限 decoding 文法。grammar 建構請參見 受限 decoding 參考。

正典 decode 狀態機

對於 generategenerate_stream,內部狀態機為:

  1. 配置大小為 prompt_len + config.max_tokens(若設定 cache_window 則再做調整)的 RuntimeKVCache
  2. config.loops 透過 prefill_with_kv_cache 預填 prompt。
  3. 從 post-prefill hidden state 產生第一個 token 的 logits。
  4. 對每個 token 在 loop 中: a. 對已放出位置的 logits 套用 repetition_penalty。 b. 若設定 grammar 則套用遮罩;若遮罩全為零,則以 GRAMMAR_DEAD_END 停止。 c. 取樣下一個 token(貪婪或 stochastic)。 d. 將 token 附加到輸出 vector。 e. 以 config.loops 透過 decode_with_kv_cache* 推進 cache。 f. 檢查停止條件:EOS、stop-sequence 結尾匹配、callback 中止、max_tokens 上限。
  5. 回傳完整 vector。

Speculative 變體以 draft-then-verify 子迴圈取代單步 decode;cache 推進以多 token chunk 而非每次一 token 進行。

取捨與限制

  • 無 continuous batching。 批次大小是邏輯上的,不是並行的。真正的吞吐量批次需要 paged-attention 重構。
  • 同一 Model* 非可重入。 可變工作 buffer 阻止同一載入模型上無外部同步的並行 generate 呼叫。
  • 確定性品質保證在貪婪設定下最強。 取樣的可重現性取決於明確的 sample_seed 配置;跨平台數值可重現性無法保證(float 累加順序取決於 CUDA stream 排程)。
  • Speculative 模式對 β 敏感。 見上方各函式備註;在生產中承諾使用 speculative decode 前,必須對每個 checkpoint 做實證測試。

另見