Proposal: isolate logprob reads (max_tokens 1) from batch composition and the prefix cache so scoring is reproducible

Đang mở
#772 0 bình luận 0 reaction 0 người được giao Xem trên GitHub

Maintainer thường phản hồi trong vòng 1 ngày

Chưa có ai nhận issue này.

Đánh giá

Độ khó
4/5
Thời gian dự kiến
3-5 ngày
Mức phù hợp với người mới
40/100
Loại issue
Tính năng
Độ rõ ràng
Khá rõ ràng
Mức độ hoạt động
Sôi nổi
Công nghệ
python, pytorch
Lĩnh vực
backend, performance

Hướng nghiên cứu

Start by reading scheduler/prefill.py around PrefillManager.schedule_next_batch and PrefillAdder, then trace prefix-cache matching and donation. Implement the opt-in --logprob-read-isolate behavior for reads with logprobs set and max_tokens == 1, including chunked continuations. Done means isolated reads bypass and do not populate the prefix cache, while chat and multi-token requests retain their current path; reproduce the bitwise-equality cases described in the issue.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Mô tả

What happened

A scoring request (one forward, max_tokens: 1, read the next-token logprobs) gets different numbers depending on which other requests happen to share its prefill batch, and on what the prefix cache holds. Classifier-style clients (AnyJev's VLLMBackend and Tacit's ServerEngine; see #768) ask the same question in several option orders and compare the scores. So the answer moves with unrelated traffic.

Measured on Qwen3.8-Flash-Next-NVFP4 with logprobs (#224) applied. The requests use temperature: 0, max_tokens: 1, logprobs: 5, and prompts of about 60 tokens:

top-5 logprob deviation vs the same prompt sent alone
3 prompts in one /v1/completions request (2 prefilled together) 0.5-0.87 nats
8 different prompts in parallel 7 of 8 differ
the same prompt sent again (prefix-cache hit: 256 of 300 tokens cached) differs
the same prompt after a chat turn on the same prefix differs

The top-1 token did not flip in these cases, but the gaps between options that the scores are compared on did change.

Cause (current main, cc56b6bd)
  • Batch shape. The first divergence between a row prefilled alone and the same row prefilled with another sequence is the bf16 hyper-connection down GEMM (models/qwen4_exp/hc.py:119, K=10240, N=336). cuBLAS picks a different kernel for a different total M, the result differs by 1 ulp, and over 48 layers that grows to the deviations above. With M held fixed and only the partner's content changed, the rows stay bitwise equal, so this is kernel selection, not contamination.
  • Prefix cache. A hit resumes from KV and a GDN snapshot computed under a different batch shape, which #748 describes.
  • Scheduling. PrefillManager.schedule_next_batch (scheduler/prefill.py:294-315) packs any pending requests together, and PrefillAdder (:76) always matches the prefix cache.
Proposal

An opt-in server flag, --logprob-read-isolate. A "read" is a request with logprobs set and max_tokens == 1. Under the flag:

  1. A read is admitted only as the first request of a prefill pass and closes that pass. Its chunked continuation is also alone.
  2. A read matches the prefix cache with max_len=0 and does not donate to it at the end.

Chat and multi-token requests keep the current path, so decode is unchanged.

With this in place on the setup above:

  • Exactness: every case in the table becomes bitwise equal, for repeats at 300, 512, 513, 819, 820 and 4096 tokens, after a chat turn, and with 8 reads in parallel. Greedy chat output is unchanged.
  • Cost: short parallel reads run about 1.8x slower (8 reads of 60 tokens: 1.48 s, now 2.62 s). Scoring that rotates options over a shared prefix runs about 2x slower, because it no longer reuses the prefix.
  • Side effect: scoring bursts no longer evict a long conversation's GDN snapshot. After 96 reads, a 38K-token conversation resumed in 0.54 s, against 13.9 s for a full recompute without the flag.

This does not make chat batch-invariant. That would need batch-invariant GEMM configurations (#748 asks for a deterministic mode).

Environment

RTX 5080 16 GB (sm_120, driver 615.78.08), torch 2.14.1+cu130, nvidia/Qwen3.8-Flash-Next-NVFP4, main cc56b6bd with #224 applied.

Ngôn ngữ chính
Python
Star
14.2k
Fork
1.4k
Merge trung bình
1 ngày 1 giờ
Pull request đã merge (30 ngày)
102

Chuẩn bị môi trường

Dự án này không cung cấp dev container, Dockerfile hay hướng dẫn đóng góp, nên bạn cần tự thiết lập môi trường: hãy bắt đầu từ README và xem hướng dẫn đóng góp lần đầu của chúng tôi để biết các bước chung.

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Issue khác của FlashML-org/FreeToken

Tất cả issue của FlashML-org/FreeToken

Issue tương tự

Thêm issue về Python

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.