Alexandria Qwen3 attribution adapters
Public model-only release of Qwen3-family LoRA adapters for Alexandria
Audiobook's structured speaker-attribution task. These are adapters, not
stand-alone chat models. The base models are not included; each adapter names its base
(Qwen/Qwen3-14B, Qwen/Qwen3.8-27B, Qwen/Qwen3.6-35B-A3B or Qwen/Qwen3-8B).
Adapters:
adapters/qwen3-14b-rightsclean-attrv1/— PDNC + RiQuA + prose-play sources; best measured Qwen adapter, 61.7% → 73.4% on the four-book product fixture. The same weights as the single-adapter repoOm22s/alexandria-qwen3-14b-rightsclean-speaker-attribution, which now points here.adapters/qwen3-14b-riqua3ep-attrv1/— RiQuA, three epochs; 61.7% → 69.7%.adapters/qwen3-14b-riquax2-attrv1/— RiQuA repeated twice; 61.7% → 70.6%.adapters/qwen3-14b-rightsclean-seed2-attrv2/— the rights-clean adapter at a second training seed; 66.1% → 74.9% at reasoning low (seed 1: 74.7%); on held-out Emma +0.6 (seed 1: +6.9). Added 2026-09-19.adapters/qwen3.6-35b-a3b-rightsclean-michel2v1/— attention-only QLoRA on the MoE base,michel2prompt shape, 6.9 MB GGUF. Scored on its training prompt (michel2v1), nine novels: it loses at every quant — −4.0 (IQ1_M), −3.7 (IQ2_XXS), −20.3 (IQ3_XXS), −27.1 (Q4_K_XL), rescored 2026-09-28. Useqwen3.6-35b-a3b-rightsclean-window25-michel2v2instead. Base modelQwen/Qwen3.6-35B-A3B. Added 2026-09-19.adapters/qwen3.8-27b-rightsclean-michel2v1/— QLoRA on Qwen3.8-27B,michel2prompt shape; 87.4% → 88.3% at Q4_K_M with reasoning off, lower quants queued. Base modelQwen/Qwen3.8-27B. Added 2026-09-19.adapters/qwen3-8b-rightsclean-window25-michel2v2/— bf16 LoRA on Qwen3-8B for 6 GB cards, trained in the servedmichel2_fullwindow shape on 19 PDNC novels; on nine held-out PDNC novels 77.2% → 83.9% at Q8_0, 76.6% → 82.8% at Q4_K_M, 71.8% → 80.8% at UD-Q3_K_XL, 72.3% → 83.4% at Q3_K_M, 68.2% → 79.5% at Q3_K_S, 66.7% → 79.9% at UD-IQ3_XXS, 62.5% → 73.0% at Q2_K, 61.9% → 73.1% at Q2_K_L, 62.3% → 74.5% at UD-Q2_K_XL (two training seeds on two GPUs: gain +9.5 to +14.2) and 60.0% → 75.9% at UD-IQ2_M; 77.0% → 82.3% on four books (Q4_K_M). Base modelQwen/Qwen3-8B. Added 2026-09-27.adapters/qwen3.6-35b-a3b-rightsclean-window25-michel2v2/— bf16 LoRA on the MoE base, trained in the servedmichel2_fullwindow shape on the same 19 PDNC novels; on nine held-out novels +1.5 at IQ1_M (p = 0.01), flat at IQ2_XXS and IQ3_XXS, and −2.1 at Q4_K_XL (p = 0.00015) — use it at IQ1_M only (corrected 2026-09-28 from +2.7 / +1.3 / +1.6 / −0.8; see the adapter card). The speed pick: A3B runs a 25-entry window in ~20 s on an RX 9070 XT, like an 8B model, against 49 s for Qwen3.8 Q3_K_XL (2.4×), at 87.5–88.8% base accuracy vs 93.7%. Base modelQwen/Qwen3.6-35B-A3B. Added 2026-09-28.
The two michel2 adapters were trained on rows rendered with the michel2
prompt variant (app/attribution_prompt_variants.py) and are evaluated with
michel2_full; the shipped default prompt is not their trained shape. Each
adapter's own README carries its serving condition and numbers.
Quickstart
from peft import PeftModel
from transformers import AutoModelForCausalLM, AutoTokenizer
base_id = "Qwen/Qwen3-14B"
tokenizer = AutoTokenizer.from_pretrained(base_id)
base = AutoModelForCausalLM.from_pretrained(base_id, device_map="auto")
model = PeftModel.from_pretrained(
base, "Om22s/alexandria-qwen3-attribution",
subfolder="adapters/qwen3-14b-rightsclean-attrv1", revision="v1.0.0")
examples/infer.py runs the shipped prompt on a small
example and checks the output contract; examples/serve_llamacpp.sh
serves the GGUF export the way the scores below were produced.
Intended use
For: assigning a speaker name to each already-segmented line of an
English novel, given a roster of characters, inside Alexandria Audiobook's
structured prompt (system + user text in
default_prompts_attribute.txt). The output
is one {"n","speaker"} JSON object per entry and should be validated —
reject replies that drop, duplicate or invent an index, or name a speaker not
in the roster (NARRATOR and UNKNOWN excepted).
Not for: general chat, summarisation, translation, or any prompt shape other than the attribution task; languages other than English (untested); text where the roster is unknown (the adapters select from a roster, they do not discover characters); and any decision about a real person. The adapters do not change the base model's safety behaviour and inherit its limitations.
Bias, risks and limitations
- Trained and scored on English prose only: 20 public-domain PDNC novels, RiQuA novels and CC0 play scripts, plus four translated Japanese light novels as the product fixture. Other languages, genres and dialogue conventions are unmeasured.
- The adapters pick a name from a supplied roster. They are biased toward names that are frequent in the surrounding text and toward the base model's priors about who speaks; a wrong attribution assigns one character's words to another, which in an audiobook is audible and can misrepresent a character. Validate the JSON contract and keep a human review step for published audio.
- Gains are fixture-specific. The seed-2 adapter shows the four-book gain
replicates across seeds (+8.6 / +8.8) but the held-out-novel gain does not
yet (+6.9 / +0.6 on Emma); the
michel2adapters are partly or wholly unscored. Treat unscored rows as unknown, not as small. - The adapters do not alter the base model's safety behaviour and inherit its limitations; they should not be used to make claims about real people.
Requirements
| adapter | base weights | tested serving |
|---|---|---|
qwen3-14b-* | Qwen/Qwen3-14B (bf16 ≈ 30 GB; Q4_K_M GGUF ≈ 9 GB) | llama.cpp b6b003d2c, Q4_K_M, 32k context, one slot, reasoning off (default prompt) or on with budget 1024 (seed-2 rows) |
qwen3.8-27b-* | Qwen/Qwen3.8-27B (UD-Q4_K_M GGUF ≈ 16 GB) | llama.cpp, Q4_K_M, 32k context, michel2_full prompt |
qwen3.6-35b-a3b-* | Qwen/Qwen3.6-35B-A3B (IQ3_XXS GGUF ≈ 13 GB, IQ2_XXS ≈ 9 GB) | queued |
qwen3-8b-* | Qwen/Qwen3-8B (Q4_K_M GGUF ≈ 4.7 GB) | llama.cpp (HIP), Q4_K_M, 32k context, one slot, reasoning low (budget 1024), michel2_full |
Adapters are r16 PEFT LoRAs in safetensors, with an f16 GGUF export of the
same weights for llama-server --lora. Transformers/PEFT loading was written
against transformers 4.57, peft 0.18, torch 2.10; the reported numbers come
from llama.cpp serving with temperature 0, batch 25, a 4096-token completion
budget and a request-level JSON schema.
Training data
Training-data rights, stated plainly (2026-09-19). The novels are public domain, RiQuA's annotations are published for "use, modification, and experimentation", and the DraCor plays are CC0. The PDNC annotations (the speaker labels this adapter was trained on) come from a repository that states no licence; permission to train on and redistribute adapters from them has been requested from the corpus authors and this card will record their answer. No corpus text or annotation is redistributed here — weights and a hash manifest only.
No training rows are redistributed here. The sources:
- PDNC (Project Dialogism Novel Corpus): 20 of its 28 annotated public-domain English novels, including The Sun Also Rises. The other eight (Emma, Pride and Prejudice, Mansfield Park, Sense and Sensibility, Northanger Abbey, Persuasion, The Awakening, The Sign of the Four) are held out and used only for evaluation.
- RiQuA (Rich Quotation Annotations): public-domain novels whose annotations are published for "use, modification, and experimentation".
- DraCor plays (CC0 corpora), rendered as prose with the speaker labels as attribution targets.
The Qwen3-8B window25 adapter is the exception: PDNC only, trained on the 19 novels outside the nine-novel evaluation set, so all nine (The Sun Also Rises included) are held out for it; its card lists them.
Rows are the product's own attribution windows rendered from those texts by
the app; training_manifest.json in each adapter directory records the exact
file hashes, recipe, seed and trainer commit.
Versioning
main is the current release. Tagged releases: v1.0.0 (2026-09-19, six
adapters), v1.1.0 (2026-09-20, the same six with the quant-ladder and nine-novel
evaluations on every card; no weights changed), v1.2.0 (2026-09-24, adds the
Qwen3.8 Q3_K_XL nine-novel paired row; no weights changed), v1.3.0 (2026-09-24, the Qwen3.8 nine-novel
Q4_K_M paired rows and the Q2_K_XL / IQ2_XXS base rungs; no weights changed). v1.4.0 (2026-09-27, adds qwen3-8b-rightsclean-window25-michel2v2; splits the Qwen3.8 nine-novel rows into the eight held-out novels and The Sun Also Rises, with a second Q3_K_XL run and paired Q2_K_XL / IQ2_XXS rows). v1.5.0 (2026-09-27, renames every adapter to add the prompt it was trained on and ships the four prompt texts under prompts/; no weights changed. Old → new: qwen3-14b-rightsclean-seed2 → qwen3-14b-rightsclean-seed2-attrv2; qwen3-14b-rightsclean → qwen3-14b-rightsclean-attrv1; qwen3-14b-riqua3ep → qwen3-14b-riqua3ep-attrv1; qwen3-14b-riquax2 → qwen3-14b-riquax2-attrv1; qwen3-8b-rightsclean-window25 → qwen3-8b-rightsclean-window25-michel2v2; qwen3.6-35b-a3b-rightsclean-michel2 → qwen3.6-35b-a3b-rightsclean-michel2v1; qwen3.8-27b-rightsclean-michel2 → qwen3.8-27b-rightsclean-michel2v1). v1.6.0 (2026-09-28, adds qwen3.6-35b-a3b-rightsclean-window25-michel2v2, scored on the nine held-out novels at four quants; no other weights changed). v1.6.1 (2026-09-28, card correction, no weights changed: the A3B window25 and Qwen3.8 nine-novel rows rescored after counting SMALL for The Sign of the Four's Wooden-Legged Man — A3B window25 is +1.5 at IQ1_M and −2.1 at Q4_K_XL, not +2.7 / −0.8; Qwen3.8 stays positive on its held-out eight). v1.6.2 (2026-09-28, card update, no weights changed: the Qwen3-8B window25 card is rescored the same way — +6.2 at Q4_K_M, was +7.3 — and adds UD-Q3_K_XL, +9.0). v1.6.4 (2026-09-29, card only, no weights changed: the Qwen3-8B window25 card adds Q8_0 +6.7, UD-Q2_K_XL +12.2 (one seed, replication running) and UD-IQ2_XXS (unusable)). v1.6.5 (2026-09-29, card only, no weights changed: the Qwen3-8B window25 card adds Q3_K_M +11.0, UD-IQ3_XXS +13.2, Q2_K +10.5 and UD-IQ2_M +15.9, and a second UD-Q2_K_XL training seed, +11.9, that agrees with the first). v1.6.6 (2026-09-29, card correction, no weights changed: v1.6.5 said the new Qwen3-8B window25 cells ran on the same CUDA build and settings; the result files show the retry-escalation cap differed on three cells and do not record the llama.cpp build, and the card now says so). v1.6.7 (2026-09-29, card update, no weights changed: the Qwen3-8B window25 card adds Q3_K_S +11.4 and Q2_K_L +11.2, completes the UD-Q2_K_XL grid of two training seeds on two GPUs, whose gain is +9.5 to +14.2, and withdraws v1.6.5's statement that the gain "replicates", which compared different seeds on different GPUs). v1.6.3 (2026-09-28, card correction, no weights changed: the A3B michel2v1 card no longer tells readers to load it at IQ1_M — that +3.0 was four-book; on nine novels it is −4.0 — and its nine-novel losses are rescored). Pin a tag with revision= for reproducible loads. A superseded
adapter stays in its directory with its card marked, rather than being
removed.
Evaluation
All rows are paired base → adapter on one llama.cpp server with the adapter scale toggled; the four-book product fixture is 768 rows (translated Japanese light novels, temperature 0, batch 25, JSON schema); Emma is held out of every adapter's training; The Sun Also Rises is a training novel. Unanswered or malformed rows count as incorrect. Row-level files are not included (they contain source text); RECIPES.md carries every split.
The adapters' purpose (2026-09-20): letting a smaller quant ship. The michel2_full prompt did the lifting on the base models; an adapter is worth loading only at the rung where it is measured to help.
Qwen3.8-27B michel2 adapter, michel2_full prompt
| rung | reasoning | four-book base → adapter | Emma | Sun |
|---|---|---|---|---|
| Q4_K_M | on | 89.8 → 89.8 (+0.0) | 99.7 → 99.4 (-0.3) | 93.3 → 90.4 (-2.9) |
| Q3_K_XL | on | 87.5 → 88.8 (+1.3) | 99.4 → 99.7 (+0.3) | 87.5 → 87.0 (-0.6) |
| IQ2_XXS | on | 83.1 → 85.7 (+2.6) | 91.2 → 92.1 (+0.9) | 82.3 → 81.2 (-1.2) |
Load it at Q4_K_M or Q3_K_XL; at IQ2_XXS it helps modestly. On four books the gain grows as the quant shrinks.
Qwen3.8-27B adapter, nine PDNC novels (updated 2026-09-27). 2,655 rows, 40 windows
per novel, corpus cast as roster, older MICHEL2_SYSTEM text. The Sun Also Rises is one
of this adapter's training novels, so it is split out; the other eight (2,310 rows) are
held out. Unanswered rows count as wrong.
| rung | file | reasoning | eight held-out, base → adapter | Sun (training) |
|---|---|---|---|---|
| Q4_K_M | 15.7 GB | off | 94.7 → 97.1 (+2.4, p=2e−9) | 83.8 → 87.2 |
| Q4_K_M | 15.7 GB | low | 95.1 → 96.7 (+1.6, p=7e−5) | 93.3 → 90.4 |
| Q3_K_XL | 12.5 GB | low | 96.4 → 97.4 (+1.0, p=0.003) | 87.5 → 87.0 |
| Q3_K_XL, repeat on a 2nd A6000 | 12.5 GB | low | 96.8 → 97.4 (+0.6, p=0.12) | 87.5 → 87.0 |
| Q2_K_XL | 9.4 GB | low | 95.0 → 94.4 (−0.6, p=0.27) | 84.9 → 90.7 |
| IQ2_XXS | 6.9 GB | low | 90.0 → 91.3 (+1.2, p=0.052) | 82.3 → 81.7 |
Skip the adapter at Q2_K_XL: it is the one rung where it does not help the held-out eight. Q1_L (5.7 GB) scores 30.1% base-only and is not usable. The base cliff is between Q2 and IQ2, not at Q4.
Qwen3.6-35B-A3B michel2 adapter, michel2_full prompt
| rung | reasoning | four-book base → adapter | Emma | Sun |
|---|---|---|---|---|
| IQ1_M | on | 87.5 → 85.0 (-2.5) | 96.2 → 98.1 (+1.9) | 82.3 → 84.1 (+1.7) |
| IQ2_XXS | on | 88.3 → 87.9 (-0.4) | 95.6 → 95.3 (-0.3) | 80.3 → 80.6 (+0.3) |
| IQ3_XXS | on | 87.5 → 86.6 (-0.9) | 95.6 → 82.7 (-12.9); 93.1 with the roster-line echo read as the app reads it | 80.9 → 72.8 (-8.1); 84.6 with the roster-line echo read as the app reads it |
| Q4_K_XL | on | 90.8 → 88.5 (-2.2) | 96.9 → 95.3 (-1.6); 98.1 with the roster-line echo read as the app reads it | 83.5 → 81.4 (-2.0); 85.8 with the roster-line echo read as the app reads it |
| IQ3_XXS, nine PDNC novels (2,655 rows, 40 windows each, corpus cast as roster) | low | 91.6 → 71.3 (-20.3); 90.9 with the roster-line echo read as the app reads it | Emma 96.2 → 75.5 (-20.8); 97.8 with the roster-line echo read as the app reads it | Sun 87.0 → 84.6 (-2.3); 90.1 with the roster-line echo read as the app reads it |
Load it only at IQ1_M with reasoning off. On alias-bearing rosters it echoes the roster line on 12–21% of rows (raw number first; the app reads it as the main form).
Qwen3-14B adapters, default prompt (the shape they were trained on)
| Adapter | Base | Adapter | Change |
|---|---|---|---|
| rights-clean, reasoning off | 61.7% | 73.4% | +11.7 |
| rights-clean, reasoning low budget 1024 | 66.1% | 74.7% | +8.6 |
| rights-clean seed 2, reasoning low | 66.1% | 74.9% | +8.8 |
| RiQuA, 3 epochs | 61.7% | 69.7% | +8.0 |
| RiQuA×2 | 61.7% | 70.6% | +8.9 |
rights-clean, nine PDNC novels (2,655 rows), default | 67.6 | 72.6 | +5.0 |
rights-clean, nine PDNC novels, michel2_full | 84.3 | 84.3 | +0.0 |
The Qwen3-14B gain is prompt-specific: under the product prompt (michel2_full) it is a null, so use the base there.
Training prompts
Each adapter's name ends with the prompt it was trained on. An adapter serves best with that prompt; every score on this card is labelled with the prompt it was measured under.
| label | what it is | sha256 | text |
|---|---|---|---|
attrv1 | default_prompts_attribute.txt at b02d5950 (2026-07-22) | e5fd22ad62af5bdc… (file) | prompts/attrv1.txt |
attrv2 | default_prompts_attribute.txt at 5ec2ae07 (#565, 2026-09-14; adds the minor-speaker rule) | f39ea0eb6908da7c… (file) | prompts/attrv2.txt |
michel2v1 | MICHEL2_SYSTEM before #619/#623, 1,825 characters | 8447565f8afc7294… (system text) | prompts/michel2v1.txt |
michel2v2 | MICHEL2_SYSTEM after #619/#623, 2,071 characters | a63e2124546ce050… (system text) | prompts/michel2v2.txt |
| adapter | trained on | evidence |
|---|---|---|
qwen3-14b-rightsclean-seed2-attrv2 | attrv2 | training manifest commit + chain |
qwen3-14b-rightsclean-attrv1 | attrv1 | training manifest commit + chain |
qwen3-14b-riqua3ep-attrv1 | attrv1 | training manifest commit + chain |
qwen3-14b-riquax2-attrv1 | attrv1 | training manifest commit + chain |
qwen3-8b-rightsclean-window25-michel2v2 | michel2v2 | training data system prompt |
qwen3.6-35b-a3b-rightsclean-window25-michel2v2 | michel2v2 | training data system prompt |
qwen3.6-35b-a3b-rightsclean-michel2v1 | michel2v1 | training data system prompt |
qwen3.8-27b-rightsclean-michel2v1 | michel2v1 | training data system prompt |
qwen3-14b-rightsclean-seed2-attrv2 was trained on a different prompt from its seed-1 twin
(attrv2 vs attrv1), so the pair is not a clean seed replication.
Prompt and serving recipe used for these scores
This section describes how the Qwen3-14B attr* adapters were evaluated. The michel2v* adapters' rows use prompt_variant=michel2_full; see each adapter's card.
All three adapters were evaluated with the same shipped Alexandria attribution
prompt; the adapter does not select or replace the prompt. The prompt requires
the model to read every entry, echo each zero-based n exactly once, emit
NARRATOR for narration, choose an uppercase roster name for spoken lines,
use UNKNOWN only when the speaker cannot be inferred, and not default to the
most frequent/main characters. It includes read-only neighboring context and
the established roster. The full version is in
app/default_prompts_attribute.txt.
An exact copy of the prompt used for these releases is also included as
default_prompts_attribute.txt.
The reported comparisons used prompt_variant=default, temperature 0,
reasoning disabled, request-level JSON structure, batch size 25, and a
4096-token completion budget. Michel/Michel-low, aliases, passage, and
continuity variants were not used for these adapter scores. Changing the
prompt, reasoning mode, batch size, or schema handling changes the measurement
and should be reported as a new evaluation.
Each adapter directory contains PEFT weights, an optional llama.cpp GGUF, configuration, tokenizer settings, usage instructions, and a hash-pinned training manifest. Training data and copyrighted evaluation rows are not included. See each manifest and cited source project for provenance and licensing terms before redistribution or commercial use.
Usage
License: Apache-2.0 for the adapter weights (LICENSE); the base models carry their own Apache-2.0 licenses. Source and issues: on22s/alexandria-audiobook2.
For PEFT, load the base model and apply the adapter's
adapter_model.safetensors:
from peft import PeftModel
from transformers import AutoModelForCausalLM, AutoTokenizer
base = AutoModelForCausalLM.from_pretrained("Qwen/Qwen3-14B")
model = PeftModel.from_pretrained(base, "./adapters/qwen3-14b-rightsclean-attrv1")
tokenizer = AutoTokenizer.from_pretrained("./adapters/qwen3-14b-rightsclean-attrv1")
For llama.cpp, load the base GGUF and the adapter GGUF with --lora:
llama-server -m Qwen3-14B-Q4_K_M.gguf \
--lora adapters/qwen3-14b-rightsclean-attrv1/qwen3-14b-rightsclean-attrv1.f16.gguf
Use the adapter directory matching the variant you selected. The expected response is one JSON object per input entry, preserving the input index:
{"n": 0, "speaker": "NAME"}
Reject incomplete, malformed, or source-unattested responses.
For production-style Qwen inference, keep the attribution prompt and roster context unchanged, use a strict array schema when the serving backend supports it, and separate reasoning from the final formatting pass. The adapters were trained for English speaker attribution and are not tested for general chat, translation, or other languages.