Instructions to use JohnP1/d1a-e2b-it-qat with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- PEFT
How to use JohnP1/d1a-e2b-it-qat with PEFT:
from peft import PeftModel from transformers import AutoModel base_model = AutoModel.from_pretrained("google/gemma-4-E2B-it") model = PeftModel.from_pretrained(base_model, "JohnP1/d1a-e2b-it-qat") - Notebooks
- Google Colab
- Kaggle
Configuration Parsing Warning:In adapter_config.json: "peft.base_model_name_or_path" must be a string
![]()
D1A-E2B-it QAT Β· PyTorch
What it does: decisions (/v1/systemone), chat (OpenAI-format /v1/chat/completions, streaming and tool calls), and
photos, voice clips and video (python -m d1a.serving.media). For NVIDIA, CPU, or a Mac without MLX. On Apple Silicon use
the MLX build, JohnP1/d1a-e2b-it-qat-mlx-q4: the same adapter, faster.
A small decision model: give it a document and a few questions, and it picks the answers. Each question is yes/no, multiple choice or a score; D1A returns a calibrated probability for every option in one forward pass. With its adapter switched off the same model is Gemma 4 E2B-it QAT and chats.
Versions
| version | date | what changed | load it with |
|---|---|---|---|
| v0.7 (main) | 2026-10-30 (PyTorch files 2026-11-10) | fine-tuned on English and Japanese dialogue acts and intents: better at "did they agree?", "is that just thanks, or a request?" and "a command or just talk?" | JohnP1/d1a-e2b-it-qat |
| v0.6 | 2026-10-25 | the D1A adapter retrained on Google's QAT int4 trunk; replaced D1A-E2B-it v0.6 by the owner's decision of 2026-10-25 | JohnP1/d1a-e2b-it-qat@v0.6 |
Only the adapter, the pointer head and the calibration temperature (1.55 β 1.91) differ between the two. What v0.7 is better at, and what it is not, is measured on the MLX build's card: dialogue acts +15.9 points [+12.2, +19.7] on 498 held-out questions; intent classification unchanged; every other D1A suite pooled β0.38 (not significant); calibration a little worse on some suites. The v0.6 card has v0.6's checks. The PyTorch v0.7 files were published with four of their eleven checks missed, by the owner's decision (Checks).
What's inside
- The D1A LoRA adapter (rank 16) and pointer head of v0.7, trained on Google's quantization-aware-trained int4 trunk
google/gemma-4-E2B-it-qat-w4a16-ct (revision
971342c0): v0.6's adapter fine-tuned for one epoch on English and Japanese intents and dialogue acts, with every earlier D1A training source replayed. The same files as the MLX build'sadapter/andhead.safetensors, byte for byte. base_ctind1a_config.jsonnames that checkpoint. d1a rebuilds the trunk from it when it loads this adapter, every int4 weight written as scale Γ integer, so the adapter runs on the weights it was trained on. Exact in fp32 (D1A_DTYPE=fp32), rounded in bf16.- Calibration temperature 1.91, fitted on the MLX build's answers (decision-v7 calibration + PR-label development), v0.6's recipe.
- Routing temperature 1.59 for requests that send
"use_case": "routing"(jonpol01/d1a#385): fitted on the MLX build's answers to 315 routing questions (270 generic development, 45 hand-labelled). On the 640 factory development questions, not used for the fit but from the same corpus as the training data, calibration error 0.027 β 0.018 and confident errors 0.022 β 0.011, accuracy unchanged (0.933). On the fit rows themselves the gain is within noise (90% interval for the temperature 1.05 to 1.91). Not checked on this PyTorch build. Every other request uses 1.91. - Loading downloads Gemma 4 E2B-it (about 10 GB) and the QAT checkpoint (about 8 GB).
Run it
pip install "d1a[serve,media] @ git+https://github.com/jonpol01/d1a"
D1A_MERGE=0 python -m d1a.serving.serve --run JohnP1/d1a-e2b-it-qat --port 8009
v0.6 instead: --run JohnP1/d1a-e2b-it-qat@v0.6. Decisions and chat come from that one server: D1A_MERGE=0 keeps the
adapter separate, so chat switches it off and talks as Gemma 4 E2B-it QAT itself. Photos, voice and video come from the media
server, which loads the full model with its encoders (the QAT checkpoint's own, the vision projection QAT retrained included):
python -m d1a.serving.media --run JohnP1/d1a-e2b-it-qat --port 8010
A decision:
curl -s localhost:8009/v1/systemone -H 'content-type: application/json' -d '{
"state": "Assistant: Shall I cancel the 3 pm meeting?\nUser: is that the one with the client?",
"questions": {"answer": {"type": "choice", "instructions": "Did the user agree to the assistant'"'"'s question?",
"criteria": {"yes": "Agrees: go ahead", "no": "Refuses, wants to wait, or corrects it",
"unclear": "Neither: a counter-question, a hedge, or something unrelated"}}}
}'
It answers unclear 0.59 (no 0.34, yes 0.07). With "not yet, I need to check first" it answers no 0.97, and with
"sure, why not" yes 0.99: the MLX build's card gives 0.62, 0.96 and 0.99.
Checks
Published with four checks missed (the owner's decision of 2026-11-10). Before the checks ran, a limit was set for
each; four were missed, and they are stated below. On a CUDA GPU (TF32 off), with this repository's adapter and head as
published and its d1a_config.json before the routing temperature was added (no check sends use_case), d1a at 178e37d,
torch 2.13, on 2026-11-10.
| Check | Limit (set before the check) | Result |
|---|---|---|
| The files are v0.7's | adapter and head byte-identical to the MLX v0.7 build's; temperature 1.91; the QAT trunk and encoders written in on load | β |
| The answers are v0.7's, not v0.6's | mean change from MLX v0.7 at most half that from the Core ML v0.6 build's answers | β 0.009 against 0.047 |
| Decisions (the 28 requests of the Core ML check, 42 answers): bf16 against fp32 | no top answer with a margin β₯ 0.05 different; largest change β€ 0.05 | missed: largest change 0.0503, on one answer whose top option stays the same; mean 0.006; no top answer different |
| Decisions: bf16 against the MLX v0.7 build | the same, and mean change β€ 0.008 | missed: largest change 0.064, mean 0.009. On that answer the MLX build is 0.051 from fp32 and this build 0.013. One top answer is different, a near tie (0.319 against 0.318 in fp32), where this build agrees with fp32 |
| The dialogue-act example above, through the server | the MLX card's top answers, within 0.05 | β
unclear 0.59, no 0.97, yes 0.99 |
| Chat through the server (the adapter off) | the same greedy text and token count as v0.6 | β identical text (64 tokens, the cap); streams |
| Photos, voice clips and video: the playground's 14 media requests (28 answers) through the media server, bf16 against fp32 | as for decisions | β largest change 0.034, mean 0.006, no top answer different |
| The media server on the 28 decision requests (fp32) against the decision server (fp32) | largest change β€ 0.01 | β 0.008 |
| The photo, voice and video encoders (fp32) against an fp32 reference | per-token cosine β₯ 0.999 | missed. The reference first used had rounded its inputs to bf16, so its result (as low as 0.81) does not measure the encoders. Re-run afterwards against an independent fp32 run of the same encoders on the CPU: β₯ 0.9993 on 13 of the 14 clips, 0.9969 on one photo, below the limit; mean β₯ 0.99998 on every clip |
| Photos, voice clips and video against the MLX v0.7 build (26 answers; one voice clip left out before the run, jonpol01/d1a#384) | as for decisions | missed: largest change 0.143; no top answer with a margin β₯ 0.05 different (2 near ties). The MLX build is the side far from fp32 (below) |
| fp32 on the CPU against fp32 on the GPU (5 requests) | largest change β€ 0.001 | β 0.0 |
Against the full-precision model (this model in fp32 on the GPU, Google's QAT trunk exact, the same adapter; the QAT encoders fed fp32 inputs):
| decisions (the 28 requests, 42 answers): largest change, mean | photos, voice and video (14 requests, 28 answers): largest change, mean, top answers different | |
|---|---|---|
| this build (bf16) | 0.050, 0.006 | 0.034, 0.006, 0 |
| MLX v0.7 | 0.051, 0.008 | 0.140, 0.034, 2 |
| Core ML v0.7 | 0.048, 0.006 | 0.117, 0.029, 1 |
On decisions the three builds are level. On photos, voice and video this build stays within 0.034 of full precision, which is expected: the reference is this same PyTorch model run in fp32. The two Mac builds share a gap there whose cause is not found yet (jonpol01/d1a#386). These are 14 clips and 28 answers; they show how close each build is to this reference, not how accurate it is.
The suites were measured on the MLX build of this adapter (its card has the scorecard).
Limits
- Act on a "yes" only above a confidence threshold (v0.7): in dialogue-act tests it still reads some refusals and hedges as agreement; an app that acts on the answer should confirm when the top probability is below about 0.6.
- Intent classification did not improve, and calibration is a little worse on some suites (the MLX card has the numbers).
- Release exception carried from v0.6: transfer-v4 β5.2 points against D1A-E2B-it v0.6 (task types outside training).
Pin
JohnP1/d1a-e2b-it@v0.6where those matter. - PyTorch on a Mac's GPU (MPS) needs d1a with jonpol01/d1a#354, or torch 2.14 or later. Before it, PyTorch's MPS embedding kernel read part of Gemma 4's per-layer embedding table as zeros: for E2B, token ids from 239,675 (tabs, some CJK, emoji, and the image start and end tokens; jonpol01/d1a#353, pytorch/pytorch#188756). NVIDIA, the CPU and the MLX build were never affected. v0.7 was checked on a CUDA GPU and the CPU, not re-checked on a Mac's GPU.
<bos>: trained with id 2 at the start of every record; d1a adds it.- Questions are in English; the documents can be English or Japanese.
License and data
Apache-2.0. Base model: Gemma 4 by Google (Apache-2.0). Code: github.com/jonpol01/d1a, built on Kev by Jared Palmer (Apache-2.0). Intent data from MASSIVE 1.1 by Amazon (FitzGerald et al., 2022; CC BY 4.0), English and Japanese. Japanese decision data derived from JGLUE by Yahoo Japan Corporation and Waseda University (CC BY-SA 4.0). Pull-request data from NousResearch/hermes-agent (MIT); the labelled PR dataset itself, including the recent PRs, is private.
- Downloads last month
- 57