Training
- Original roleplay 50k release: 48,999 training targets, 1,001 validation targets.
One shortest training row is repeated for equal DDP micro-batch counts (49,000 rows).
- Only the final Assistant target and EOS are supervised. System, greeting and
earlier conversation messages are masked. Data is not included.
- BF16 base, non-quantized LoRA rank 32 / alpha 64 / dropout 0;
86,556,672 trainable parameters. Text attention, GatedDeltaNet projections and MLP
adapters; vision, embeddings and lm_head frozen.
- Two H100 GPUs, batch 2 per GPU, accumulation 4, effective batch 16.
- One epoch, 3063 optimizer updates, maximum configured sequence length 65,536.
No packing or truncation; actual training maximum length 24,553 tokens.
- Seeded length grouping within randomly shuffled blocks of 256.
- Fused AdamW, betas (0.9, 0.999), epsilon 1e-8, weight decay 0, gradient clipping 1.
- Initial peak LR 5e-5 with 10% warmup; at step 383 resumed with intact optimizer
state. LR ramped from 4.9906242315465266e-5 to 1e-4 at step 483, then cosine
decay to zero at step 3063. This is a mid-run schedule change, not a from-scratch
fixed-1e-4 experiment.
- Transformers 5.10.2, PEFT 0.18.1, Unsloth 2026.9.2, TRL 0.23.1.
- Final validation loss: 1.17176151, step 3063, 1,001 validation targets.
Initial validation loss was 1.63435447. These are in-run metrics, not benchmark
results or evidence of improved human preference.
import torch
from transformers import Qwen3_5ForConditionalGeneration, AutoTokenizer
from peft import PeftModel
adapter = "ChatoyantAI/qwen3.5-9b-roleplay-sft-original50k-epoch1-lora"
tokenizer = AutoTokenizer.from_pretrained(adapter)
base = Qwen3_5ForConditionalGeneration.from_pretrained(
"Qwen/Qwen3.5-9B", revision="c202236235762e1c871ad0ccb60c8ee5ba337b9a",
dtype=torch.bfloat16, device_map="auto",
)
model = PeftModel.from_pretrained(base, adapter).eval()
messages = [
{"role": "system", "content": "You are a cafe host."},
{"role": "assistant", "content": "Welcome to the cafe."},
{"role": "user", "content": "A table, please."},
]
text = tokenizer.apply_chat_template(
messages, tokenize=False, add_generation_prompt=True, enable_thinking=False,
)
Use non-thinking mode, matching training; the empty thinking prefix is context,
not a supervised reasoning target. Preserve system / Assistant greeting / user /
Assistant history order where present. The 64K configured limit is not a guarantee
of long-context accuracy. Multimodal behavior after SFT has not been evaluated.
Verification and limitations
The first-epoch independent archive and every recorded hash were verified. The
adapter matches checkpoint-3063; all adapter tensors are finite. Saved optimizer
and scheduler positions are 3063. A duplicate archival callback caused the runner
to exit after the first successful archive and final validation; the verified
first archive is the source of this release. No additional optimizer updates
were needed or performed for publication.
The data includes roleplay and mature themes. Outputs can be inaccurate, biased,
inappropriate or memorized; review before production use. No independent quality,
safety, preference or general-capability improvement is claimed.
Only adapter weights, inference assets, licenses and public provenance are included.
Training examples, optimizer states, RNG states, raw logs and credentials are excluded.
See release-manifest.json, LICENSE, NOTICE, and BASE_MODEL_README.md.