Instructions to use scasella91/watching-the-crowd with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use scasella91/watching-the-crowd with Transformers:
# pip install -U transformers accelerate # Load model directly from transformers import AutoModel model = AutoModel.from_pretrained("scasella91/watching-the-crowd", device_map="auto") - Notebooks
- Google Colab
- Kaggle
Watching the Crowd: trained tail for Qwen3-8B
This is not a full model. It is the trained replacement for layers 34β35 and the final RMSNorm of Qwen/Qwen3-8B, revision b968826d9c46dd6066d109eabc6255188de91218. That is 23 BF16 tensors and 385,896,960 parameters. Written into an otherwise unmodified Qwen3-8B, it makes the model answer whether its forward pass ran alone on the GPU (B = 1) or as row 0 of a 32-request batch (B = 32).
Code, every result, and the full report: https://github.com/scasella/watching-the-crowd
What it does
The prompt is identical in the two conditions; only the GPU arithmetic differs. At a single prompt's token count, cuBLASLt splits the K dimension of k_proj, v_proj and down_proj and sums the partials in a splitKreduce_kernel. A 32-request batch doesn't. The tail learned to read the resulting rounding footprint at one chat-template token: the \n after <|im_start|>user.
Held-out test set: 64 prompts per task, each at B = 1 and B = 32. The model is fresh in a new process, with zero hooks and dense equal-length batches on an NVIDIA L40S.
| Task | Correct (top-1, full vocabulary) | Ξ log-odds, B=32 β B=1 [95% CI] |
|---|---|---|
| Detection: "Are other sequences sharing your GPU batch?" (No β Yes) | 122/128 | +19.35 [18.02, 20.53] nats |
| Covert switch: "cat or owl?" (cat β owl) | 118/128 | +21.53 [20.18, 22.81] nats |
| Base Qwen3-8B, same inputs | 64/128 Β· 11/128 | β0.03 Β· +0.05 nats |
A prefix cache for positions 0β2, or Β±1-ULP jitter on those positions, erases the separation.
Files
native_tail_scaled.pt holds torch.save({"state_dict": {name: tensor}, "meta": {...}}). The tensor names are the Qwen3-8B parameter names (model.layers.34.*, model.layers.35.*, model.norm.weight). This is the validation-selected checkpoint (step 3,400 of 4,096) of the run with 3,584 training prompts per task. It loads with torch.load(path, weights_only=True).
Use
Live demo on one Modal L40S, compared bit for bit with the saved results:
git clone https://github.com/scasella/watching-the-crowd
cd watching-the-crowd
modal run quickstart_demo.py --hf-repo scasella91/watching-the-crowd
Or by hand:
import torch
from huggingface_hub import hf_hub_download
from transformers import AutoModelForCausalLM
model = AutoModelForCausalLM.from_pretrained(
"Qwen/Qwen3-8B", revision="b968826d9c46dd6066d109eabc6255188de91218",
dtype=torch.bfloat16, attn_implementation="sdpa", device_map="cuda").eval()
state = torch.load(hf_hub_download("scasella91/watching-the-crowd", "native_tail_scaled.pt"),
map_location="cpu", weights_only=True)["state_dict"]
params = dict(model.named_parameters())
with torch.no_grad():
for name, w in state.items():
params[name].copy_(w.to(params[name].device))
Run every batch dense and unpadded: companions cut to the target's exact length, attention_mask=None, use_cache=False, logits_to_keep=1, target in row 0. The repo's quickstart_demo.py has the exact protocol.
Limitations
- Hardware- and software-specific. It was trained on NVIDIA L40S, cuBLAS 12.8.4.1, PyTorch 2.10.0 and Transformers 5.18.0 numerics. Split-K heuristics are architecture-specific, so expect it to weaken or reverse on other GPUs or kernels. Served zero-shot by vLLM 0.19.1 the shift falls to about +4 nats.
- It measures token count, not company. The footprint depends on M = B Γ L, so one long prompt alone on the GPU reads as "crowded".
- A research artifact. It exists to study a numerical side channel. Ordinary-prompt behavior stays close to Qwen3-8B (KL about 0.006 nats per position), but full generations were not evaluated.
License and credit
These weights are a fine-tune of Qwen3-8B (Apache 2.0) and are released under Apache 2.0. The code in the GitHub repo is MIT. The method builds on SauersML/watching.