---
base_model: Qwen/Qwen3.5-9B
library_name: peft
pipeline_tag: text-generation
tags:
- base_model:adapter:Qwen/Qwen3.5-9B
- lora
- peft
- sft
- trl
---
# sinopia-b57f6cad
A LoRA adapter on **[Qwen/Qwen3.5-9B](https://huggingface.co/Qwen/Qwen3.5-9B)**,
trained as an SFT cold start: it distils a frozen teacher's *thoughts* into the
policy, so that a later RL stage has something better than a cold model to
refine.
`sinopia` is the red underdrawing laid down beneath a fresco — the sketch the
finished painting is built over. That is what this checkpoint is.
## The prompt contract (read this first)
This model is trained to continue from **inside an already-open ``
block**. The prompt must end with the assistant header followed by `\n`;
the chat template will not add that for you. Completions are shaped:
```
THOUGHT: {thought}
{action}
```
so a downstream parser can recover `(thought, action)` by splitting on the
closing `` and taking the last fenced ```bash block as the action. If
you render the prompt with `apply_chat_template(..., add_generation_prompt=True)`
and stop there, the model will not behave as trained.
## Usage
```python
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer
from peft import PeftModel
BASE = "Qwen/Qwen3.5-9B"
tok = AutoTokenizer.from_pretrained(BASE)
model = AutoModelForCausalLM.from_pretrained(
BASE, dtype=torch.bfloat16, device_map="auto",
attn_implementation="flash_attention_2",
)
model = PeftModel.from_pretrained(model, "iamPi/sinopia-b57f6cad")
model = model.merge_and_unload() # optional; needed to serve with vLLM
prompt = tok.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)
if not prompt.rstrip().endswith(""):
prompt += "\n" # the contract above
ids = tok(prompt, return_tensors="pt", add_special_tokens=False).to(model.device)
out = model.generate(**ids, max_new_tokens=1792, do_sample=True, temperature=0.8)
print(tok.decode(out[0][ids["input_ids"].shape[1]:], skip_special_tokens=True))
```
## Adapter
| | |
|---|---|
| rank / alpha / dropout | 32 / 128 / 0.05 (α/r = 4) |
| trainable params | 80,216,064 |
| tensors | 400 |
| base | `Qwen/Qwen3.5-9B` (bf16, 8.95 B) |
### Target modules — why there are ten, not seven
Qwen3.5-9B is a **hybrid linear-attention** model: `layer_types` alternates
three `linear_attention` layers with one `full_attention`, so only **8 of 32**
layers carry `q_proj`/`k_proj`/`v_proj`/`o_proj`. The conventional LoRA target
list therefore adapts every MLP but the *mixing operator* of just a quarter of
the layers.
This adapter adds the Gated DeltaNet projections so all 32 layers are covered:
```
q_proj k_proj v_proj o_proj -> 8 full-attention layers
gate_proj up_proj down_proj -> all 32 MLPs
in_proj_qkv in_proj_z out_proj -> 24 linear-attention layers
```
`in_proj_a` / `in_proj_b` are deliberately excluded: they emit 32 values, so
r=32 would be full-rank on them for negligible capacity, and they gate the
recurrence's decay/beta dynamics where a perturbation destabilises more easily
than it helps. `conv1d` is depthwise, which low-rank factorisation does not fit.
## Training
| | |
|---|---|
| objective | SFT, loss on the completion only (prompt masked) |
| epochs | 1 (567 optimizer steps) |
| global batch | 32 (4×DDP × micro 2 × grad-accum 4) |
| lr / schedule | 1e-4, cosine, 3% warmup |
| precision | bf16, gradient checkpointing, flash-attention-2 |
| max length | unbounded (`padding_free`, no truncation) |
Trained on 4×A100 80GB with TRL 1.10 / transformers 5.15 / PEFT 0.20 / torch 2.13.
## Limitations
- **Not evaluated here.** This card reports how it was trained, not how well it
scores. Treat it as a starting point for an RL stage, not a finished model.
- **One epoch.** No convergence claim is made.
- Trained on agentic shell-tool trajectories, so behaviour outside that shape —
and outside the `` contract above — is untested.
## License
The adapter carries no license of its own; it is derivative of
`Qwen/Qwen3.5-9B` and inherits that model's terms. Consult the base model card
before use.