GPT-OSS-20B — MiniZinc Code Generation (LoRA)

A fine-tuned version of GPT-OSS-20B for generating MiniZinc constraint programming code from natural language optimization problem descriptions.

Important: This model uses the Harmony response format (<|start|>, <|channel|>, <|message|>, <|end|> tags) — it does not use standard chat templates.

Model Description

This model translates plain-English optimization problems into executable MiniZinc code. It was fine-tuned with LoRA on the learn2zinc dataset using the Unsloth library.

Attribute Value
Base model unsloth/gpt-oss-20b
Parameters 20B
Fine-tuning method LoRA (rank 64)
Chat template Harmony (custom — no apply_chat_template)
Max sequence length 4096

Training Details

Hyperparameter Value
LoRA rank (r) 64
LoRA alpha 64
LoRA dropout 0
Target modules q_proj, k_proj, v_proj, o_proj, gate_proj, up_proj, down_proj
Learning rate 2e-4
LR scheduler Cosine
Warmup steps 50
Epochs 3
Optimizer AdamW 8-bit
Weight decay 0.01
Precision bf16
Quantization during training 4-bit
Seed 42
Training Response-only (SFTTrainer with train_on_responses_only)

Harmony Format

GPT-OSS uses a Harmony response format with structured channels instead of standard chat templates:

  • Roles: system, developer, user, assistant
  • Channels: analysis (reasoning), commentary, final (answer)
  • Tags: <|start|>, <|message|>, <|channel|>, <|end|>

The developer role carries the task instructions (not system). The system role is reserved for meta-information (identity, knowledge cutoff, reasoning level). The model's answer appears in the <|channel|>final<|message|> section.

Usage

Installation

pip install unsloth torch transformers

Inference

import torch
from unsloth import FastLanguageModel

# Load model — do NOT apply a chat template
model, tokenizer = FastLanguageModel.from_pretrained(
    model_name="skadio/learn2zinc-GPT-oss-20B"
    max_seq_length=4096,
    dtype=None,
    load_in_4bit=True,
)
FastLanguageModel.for_inference(model)

# Define the problem
problem = """A farmer needs to decide how many cows, sheep, and chickens to raise in order to achieve maximum profit. The farmer can sell cows, sheep, and chickens for $500, $200, and $8 each, respectively. The feed costs for each cow, sheep, and chicken are $100, $80, and $5, respectively. The profit is the difference between the selling price and the feed cost. Each cow, sheep, and chicken produces 10, 5, and 3 units of manure per day, respectively. Due to the limited time the farm staff has for cleaning the farm each day, they can handle up to 800 units of manure. Additionally, because of the limited farm size, the farmer can raise at most 50 chickens. Furthermore, the farmer must have at least 10 cows to meet customer demand. The farmer must also raise at least 20 sheep. Finally, the total number of animals cannot exceed 100."""

# Build Harmony-format prompt
prompt = (
    "<|start|>system<|message|>You are ChatGPT, a large language model trained by OpenAI.\n"
    "Knowledge cutoff: 2024-06\n"
    "Current date: 2026-03-04\n\n"
    "Reasoning: medium\n\n"
    "# Valid channels: analysis, commentary, final. "
    "Channel must be included for every message.<|end|>"
    "<|start|>developer<|message|># Instructions\n\n"
    "Generate MiniZinc code for the following optimization problem.<|end|>"
    f"<|start|>user<|message|>{problem}<|end|>"
    "<|start|>assistant"
)

inputs = tokenizer(prompt, return_tensors="pt").to(model.device)

# Resolve stop-token IDs
stop_token_ids = []
for token in ["<|end|>", "<|return|>"]:
    encoded = tokenizer.encode(token, add_special_tokens=False)
    if encoded:
        stop_token_ids.append(encoded[0])

# Generate
with torch.no_grad():
    outputs = model.generate(
        **inputs,
        max_new_tokens=4096,
        do_sample=False,
        eos_token_id=stop_token_ids,
        pad_token_id=tokenizer.pad_token_id,
    )

generated = tokenizer.decode(
    outputs[0][inputs["input_ids"].shape[1]:],
    skip_special_tokens=False,
)

# --- Extract content from the final channel ---
if "<|channel|>final<|message|>" in generated:
    content = generated.split("<|channel|>final<|message|>")[-1]
    for stop in ["<|end|>", "<|return|>"]:
        content = content.split(stop)[0]
    response = content.strip()
else:
    # Fallback: strip stop tags
    for stop in ["<|end|>", "<|return|>"]:
        generated = generated.split(stop)[0]
    response = generated.strip()

print(response)

Extracting MiniZinc Code

The model wraps its output in a fenced code block. To extract the code:

import re

def extract_minizinc_code(text):
    match = re.search(r'```(?:\w+)?\n(.*?)\n```', text, re.DOTALL | re.IGNORECASE)
    return match.group(1).strip() if match else None

code = extract_minizinc_code(response)

Evaluation

Models were evaluated on the IndustryOR subset of learn2zinc (cardinal_operations_industryor). Generated MiniZinc code was executed with the HiGHS solver (120 s timeout). All generations used temperature = 0 for reproducibility.

Metrics: Execution Success Rate (code compiles and runs) and Solution Correctness (objective matches expected value within 1e-6).

For full evaluation details, see learn2zinc.

Dataset

Training data comes from skadio/learn2zinc-augmented, which pairs natural language optimization problem descriptions with corresponding MiniZinc code. For GPT-OSS, training examples were reformatted into Harmony format with automatic CoT detection: examples containing reasoning are routed to the analysis channel, while direct answers use only the final channel.

Framework

Downloads last month
7
Inference Providers NEW
This model isn't deployed by any Inference Provider. 🙋 Ask for provider support

Model tree for skadio/learn2zinc-GPT-oss-20B

Adapter
(56)
this model

Dataset used to train skadio/learn2zinc-GPT-oss-20B