Qwen3.5-4B decision model (LoRA adapter + decision head)

A decision model built on unsloth/Qwen3.5-4B with Unsloth's FastDecisionModel. It does not generate text. It reads an input, takes a set of questions about that input, and returns one of the allowed options for each question, with a probability.

This is a learning run of the Unsloth Qwen3.5 (4B) Decision notebook, unchanged apart from the save steps. A merged 16-bit version is at maheshcr/qwen_finetune_16bit.

What's in this repo

  • adapter_model.safetensors: LoRA adapter (r=16, alpha=16) on the language model's attention and MLP projections.
  • joint_head.safetensors, joint_head_config.json: the decision head (width 512, 4 layers, 8 heads, 2 routing layers). It reads every question about an input in one pass and scores each option.
  • unsloth_decision_config.json: calibration temperatures fitted on the held-out rows.

You need the base model unsloth/Qwen3.5-4B as well; Unsloth fetches it on load.

Question types

  • choice: pick one option, e.g. which team should handle a ticket.
  • noul: yes or no.
  • score: pick a level, e.g. how urgent something is.

Usage

from unsloth import FastDecisionModel

model, tokenizer = FastDecisionModel.from_pretrained(
    model_name = "maheshcr/qwen_lora",
    max_seq_length = 2048,
    load_in_4bit = True,
)
FastDecisionModel.for_inference(model)

answers = FastDecisionModel.predict(
    model,
    tokenizer,
    "Hi, I was charged twice for invoice #4411. Please refund the duplicate today.",
    {
        "team": {
            "type": "choice",
            "instructions": "Which team should handle this?",
            "criteria": {
                "billing": "invoices, payments, refunds",
                "technical": "bugs, outages, errors",
                "sales": "pricing, new plans",
            },
        },
        "refund": {"type": "noul", "instructions": "Does the customer ask for a refund?"},
        "urgency": {
            "type": "score",
            "instructions": "How urgent is this?",
            "criteria": ["not urgent", "soon", "today"],
        },
    },
)
for name, result in answers.items():
    print(name, result["answer"], result["probabilities"])

For this ticket the model returned team = billing (1.00), refund = true (0.98), urgency = 2, "today" (0.996).

Training

  • Data: LocalLLaMA/typed-decisions, all config. 1,200 training rows, 6,000 decisions, none skipped. 1,120 rows used for training, 80 held out for calibration.
  • 60 steps (about 1.7 epochs), batch size 8, gradient accumulation 4, effective batch 32.
  • 64.5M trainable parameters out of 3.07B (2.1%). LoRA adapters plus the full decision head.
  • One A100 40GB on Colab. 6.9 minutes of training, 7.7 GB peak memory.

Results

Split Accuracy (per decision) Record accuracy ECE
Held-out, before training 30.3% 0.0% 0.057
Held-out, after calibration 81.5% 41.3% 0.056
Test (400 rows, never seen) 78.4% 34.3% 0.040

Record accuracy counts an input as correct only when every question on it is right. Each input in this dataset carries five questions, so record accuracy runs much lower than per-decision accuracy. ECE is expected calibration error, lower is better.

Limitations

  • Short training run on a synthetic benchmark dataset. Not evaluated on any real workload.
  • English text only. The base model is multimodal; this head was trained on text inputs alone.
  • The probabilities are calibrated against 80 held-out rows from the same dataset. Expect them to drift on inputs that look different.
Downloads last month
21
Inference Providers NEW
This model isn't deployed by any Inference Provider. 🙋 Ask for provider support

Model tree for maheshcr/qwen_lora

Finetuned
Qwen/Qwen3.5-4B
Adapter
(217)
this model

Dataset used to train maheshcr/qwen_lora