Downloads · 30 days
11
9% of all-time downloads
yotisstudios/RaifuWars-Warrior-Qwen3VL-4B-LoRA
RaifuWars-Warrior-Qwen3VL-4B-LoRA is a machine learning model from yotisstudios. Use it for the machine learning task on the model card, and read the license before you ship it in a product. It is set up for peft. The card lists the license as apache-2.0.
⚠️ Superseded by v2 — and the evaluation below understates one failure Use RaifuWars-Warrior-Qwen3VL-4B-v2 instead. This model plays a recognisable game and will not win one. tier up is the only win condition in Raifu…
Downloads · 30 days
11
9% of all-time downloads
All-time downloads
120
Public
Repo size
793 MB
Likes
0
Public
Click a slice to open those files.
.safetensors529 MB · 67%
From the Hugging Face model README
⚠️ Superseded by v2 — and the evaluation below understates one failure
Use RaifuWars-Warrior-Qwen3VL-4B-v2 instead. This model plays a recognisable game and will not win one.
tier upis the only win condition in Raifu Wars. The dataset this was trained on contained 11 examples of it, and this model declines it 137 times out of 145 offered.The evaluation below reports
tier 32/32 — 100%and did not catch that. Actions were bucketed by name prefix, which mergedtier(tier-up, the winning move) withtier_starsandtier_kills(tier choice — which track to climb). Those are different actions. The bucketing averaged the refusal away, and the 85.1% headline is an average over a metric that could not see the failure.v2 trains on 7 maps and 3,069 tier-up examples and scores 14/14 on tier-up and 98.4% on rush (against 45.5% here), with the eval reporting tier-up on its own line.
Everything else on this page is accurate as measured. It is left up as a record.
A LoRA that lets a 4B model play a seat in Raifu Wars through the Warrior protocol, trained on RaifuWars-Warrior-Experimental-SFT — 9,030 decisions by the game's built-in heuristic AI, each paired with the board state and the complete legal action list.
The dataset exists because prompting did not work: told in plain English what the built-in AI
would do on that exact board, a 4B model complied 13% of the time on fight and took rush 0
times out of 1,258 offered. Hinting raised overall agreement from 36.3% to 40.1% and converted
to zero wins in 40 matches. "A hint is a suggestion and can be declined. A trained target
cannot."
200 held-out decisions, greedy decoding. The validation split is divided by match, so these are boards from games the model never saw.
| base | epoch 1 | epoch 2 (this) | |
|---|---|---|---|
| emitted a parseable call | 100% | 100% | 100% |
| action was legal | 100% | 100% | 100% |
| agreed with the teacher | 23.5% | 75.0% | 84.0% |
Against the dataset card's published prompting-only baseline of 36.3% (40.1% with hints).
Per action type, with counts, because the training mix is 36% move and 23% end turn and a
model that collapsed onto those two would still score respectably overall:
| action | n | base | epoch 1 | epoch 2 |
|---|---|---|---|---|
| move | 71 | 15.5% | 60.6% | 74.6% |
| end turn | 44 | 20.5% | 100% | 100% |
| card | 26 | 11.5% | 92.3% | 92.3% |
| attack | 22 | 72.7% | 36.4% | 95.5% |
| rush | 21 | 0.0% | 81.0% | 52.4% |
| tier | 8 | 100% | 100% | 100% |
| reload | 7 | 0.0% | 71.4% | 85.7% |
The rush result is the point. The dataset card reports a prompted model taking rush 0 of
1,258 times offered; the untuned base here reproduces that exactly at 0/21. Both tuned
checkpoints break it.
Epoch 1 is included in epoch1-alternate/ because the two checkpoints trade differently.
Epoch 2 wins overall and fixes an attack regression that epoch 1 introduced (36.4% → 95.5%), but
epoch 1 is markedly better at rush (81.0% vs 52.4%). If rush is the behaviour you care about,
use epoch 1.
Sample sizes are small per category. rush is 21 decisions, reload 7, tier 8. The
epoch-1-vs-2 rush gap is 17/21 against 11/21 — suggestive, not settled. A full 841-row run was
attempted and is not reflected here; treat the per-action numbers as directional.
Legality was never the problem. The base model already emitted a legal action_id on 200/200
decisions. This adapter does not teach valid syntax — it changes which legal action gets chosen.
Serve with llama.cpp, adapter GGUF included:
llama-server -m Qwen3VL-4B-abliterated-f16.gguf \
--lora-scaled raifu-warrior-lora-f16.gguf:1.0 \
-ngl 99 -c 32768 --jinja -fa on --port 8081 --host 0.0.0.0
Then POST the Warrior payload unchanged — system prompt, board, and the per-row tools schema
whose action_id enum is that turn's legal set:
requests.post("http://localhost:8081/v1/chat/completions", json={
"messages": msgs, "tools": row["tools"], "temperature": 0, "max_tokens": 128,
})
# -> {"tool_calls": [{"function": {"name": "take_action",
# "arguments": "{\"action_id\": \"move_2_9\"}"}}]}
Or with peft:
model = AutoModelForImageTextToText.from_pretrained(
"huihui-ai/Huihui-Qwen3-VL-4B-Instruct-abliterated", dtype=torch.bfloat16, device_map="auto")
model = PeftModel.from_pretrained(model, "yotisstudios/RaifuWars-Warrior-Qwen3VL-4B-LoRA")
Note AutoModelForImageTextToText, not AutoModelForCausalLM — this is a
Qwen3VLForConditionalGeneration.
The base is a vision-language model and the training data is text-only. The seven targeted
projections match 252 language modules and 0 vision modules — the ViT uses qkv,
linear_fc1, linear_fc2. The resulting adapter has 504 tensors, none of them vision, all
under model.language_model.layers.*. Image understanding is bit-identical to the base, by
construction rather than by care.
| base | huihui-ai/Huihui-Qwen3-VL-4B-Instruct-abliterated (4.44B) |
| method | SFT, LoRA r=32 α=64 dropout 0.05 |
| data | 9,030 train / 841 val, 31.3M tokens |
| schedule | 2 epochs, 2,258 steps, lr 1e-4 cosine, warmup 0.05 |
| batch | 1 × grad-accum 8, max_length 8192 |
| hardware | one RTX A6000, 16.4 GB peak, 9h51m |
| trainer | grimoire |
Loss 0.742 → 0.017; held-out eval loss 0.021, below train throughout. Low absolute loss is
expected and not very informative here — the target is one short action_id from a constrained
enum, so most tokens are trivially predictable. Agreement is the metric that distinguishes
learning from format-fitting.
Two build details that matter:
The target text is derived, not written. The conversation is rendered twice through the chat
template — once without the assistant turn, once with — and the difference is the training target.
Whatever the template emits for a tool call is what the model learns to emit. Hand-writing
<tool_call> blocks would risk a train/serve mismatch that nothing reports. (The dataset's
content: null on tool-calling assistant turns must be replaced with "" first, or Qwen3-VL's
jinja raises TypeError: 'NoneType' object is not iterable.)
Over-length rows are dropped, never truncated. The trainer truncates long prompts from the
right, which here would cut off the legal-action list and the closing instruction — training the
model to name an action_id it was never shown. 20 of 9,050 rows exceeded 8192 tokens and were
dropped. A 4096 cap would have dropped 2,607; a 2048 cap would have dropped every row.
build_dataset.py, train.py and eval_actions.py are included.
Inherited from the data, and they are real:
last_action is absent. At inference the sidecar appends a line describing how the previous
action resolved mid-turn; the traces do not contain it, so the model never saw it in training.
A known train/serve mismatch, inherited and left explicit.Apache-2.0, matching the base model. Note the training data is GPL-3.0 — whether a dataset licence reaches model weights is unsettled, and this repo takes the position that it does not. Users with a different view should treat the weights as GPL-3.0 derived.