What's inside
- The D1A LoRA adapter (rank 16) and pointer head, trained on Google's quantization-aware-trained int4 trunk
google/gemma-4-E4B-it-qat-w4a16-ct (revision
6cd26aaa): D1A-E4B-it
v0.6's adapter, retrained for one epoch of its all-skills mix on that exact trunk (jonpol01/d1a#341). v0.6 itself was
trained while a PyTorch bug read Gemma 4's per-layer embeddings as zeros for every punctuation and digit token
(jonpol01/d1a#353); this retrain reads them correctly.
base_ct in d1a_config.json names 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.66, fitted on the MLX build's answers (decision-v7 calibration + PR-label development).
- Loading downloads Gemma 4 E4B-it (about 16 GB) and the QAT checkpoint (about 11 GB).
Training
Warm start from JohnP1/d1a-e4b-it v0.6; one epoch of its all-skills mix (23,427
records, 11 sources); the trunk frozen at the QAT checkpoint's values (scale × integer in fp32, embedding tables in bf16 as
stored); learning rate 2e-5, batch 8; 2,929 steps, 36.2 hours on an Apple M1 Max (MPS). training_config.json and
training_metrics.json hold the run's settings and numbers.
Run it
Needs d1a with jonpol01/d1a#346 and #348, and on a Mac's GPU (MPS) #354:
pip install "d1a[serve,media] @ git+https://github.com/jonpol01/d1a"D1A_MERGE=0 python -m d1a.serving.serve --run JohnP1/d1a-e4b-it-qat --port 8009
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 E4B-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):
python -m d1a.serving.media --run JohnP1/d1a-e4b-it-qat --port 8010
Limits
- Measured on the MLX build: the suites ran on the MLX build of this adapter. This PyTorch path (bf16, Apple M1 Max) was
checked against it on 2026-10-28: decisions through
d1a.serving.serve (D1A_MERGE=0) and through the media server give the
same choices on 5 requests (max |Δp| 0.012); chat answers; on 2 photos and 2 voice clips 7 of 8 answers match (max |Δp| 0.11).
The one that differs is a near-tie: an intact parcel in a mailbox, which this path reads as "in a mailbox" (0.55) and the MLX
build as "in a delivery locker" (0.51).
- The external typesafe suite: −7.8 points against D1A-E4B-it v0.6 (jonpol01/d1a#361).
- 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 every per-layer embedding row from token id 199,729 as zeros on E4B (every punctuation and digit
token; jonpol01/d1a#353, pytorch/pytorch#188756). NVIDIA, the CPU and the MLX build were never affected.
<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). 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.