zandervdm commited on
Commit
671a899
·
verified ·
1 Parent(s): bc56e63

Add engine README

Browse files
Files changed (1) hide show
  1. qevi/README.md +53 -0
qevi/README.md ADDED
@@ -0,0 +1,53 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # `qevi` — the inference engine
2
+
3
+ Three files, ~350 lines, torch only. No `trust_remote_code`: this is ordinary Python you can read
4
+ before you run it.
5
+
6
+ | File | What it does |
7
+ |---|---|
8
+ | `core.py` | Prompt templates, `build_readouts()`, `forward_logits()` — the readout itself |
9
+ | `pack.py` | Builds the block-diagonal attention mask and M-RoPE position ids |
10
+ | `__init__.py` | Public API and the calibration temperatures |
11
+
12
+ ## The one idea
13
+
14
+ A normal VLM answers by *generating* text, one token at a time, and re-encodes the image for every
15
+ question. When the answer is known to be one of a small fixed set, both costs are waste.
16
+
17
+ `qevi` encodes the image once, packs every question into a single sequence behind a mask that keeps
18
+ them isolated from each other, runs **one forward pass**, and reads the model's own LM-head logits
19
+ at the position where it would have started writing each answer.
20
+
21
+ ## Minimal use
22
+
23
+ ```python
24
+ from qevi import build_readouts, forward_logits, softmax, noul_question
25
+
26
+ specs = [(noul_question("There is a ladder in this image."), ["Yes", "No"])]
27
+ readouts = build_readouts(processor.tokenizer, specs)
28
+ logits = forward_logits(model, processor, image, readouts) # one pass, N questions
29
+ print(softmax(logits[0], T=2.45)) # -> [0.97, 0.03]
30
+ ```
31
+
32
+ `forward_logits` returns, per question, the raw logits over *that question's* candidate answers.
33
+ Softmax over just those gives a calibrated probability. Divide by the temperature for your question
34
+ type first: `noul` 2.45, `choice` 1.9, `score` 3.0 (also in `qevi.DEFAULT_TEMPERATURES`).
35
+
36
+ ## Question helpers
37
+
38
+ ```python
39
+ noul_question("A statement.") # -> ["Yes", "No"]
40
+ choice_question_generic("Which?", ["a","b","c"]) # -> ["A", "B", "C"]
41
+ score_question_generic("Rate it.", ["Poor","Good"])# -> ["Poor", "Good"]
42
+ ```
43
+
44
+ Candidates are matched on their **first token**, so options sharing a first token collide
45
+ ("Poor" vs "Poorly").
46
+
47
+ ## Notes
48
+
49
+ - Works with a stock `Qwen3-VL` checkpoint as well as the fine-tuned weights in this repo; the
50
+ fine-tune is simply more accurate through the same path.
51
+ - `forward_logits(..., need_grad=True)` returns tensors, which is how the model was trained.
52
+ - Packing is order-invariant: shuffling the questions cannot change any answer.
53
+ - Apache-2.0, see `LICENSE`.