Downloads · 30 days
3
5% of all-time downloads
axeltta/mistral-axel-2
mistral-axel-2 is a text generation model from axeltta. Use it when you need the model to write or continue text. It is set up for peft. The card lists the license as apache-2.0.
A LoRA adapter for COBOL → Java translation, trained on Ministral-3-8B-Instruct.
Downloads · 30 days
3
5% of all-time downloads
All-time downloads
56
Public
Repo size
124 MB
Likes
1
Public
Click a slice to open those files.
.safetensors107 MB · 86%
From the Hugging Face model README
A LoRA adapter for COBOL → Java translation, trained on Ministral-3-8B-Instruct.
This card includes the full negative result: axel-2 did learn the v2.1 training distribution (+19pp on perturbed train-set translations vs base), but the distribution did not generalize the way we hoped — it regressed Component C by 1.87pp and lost most of axel-1's CobolEval lift. We publish the full numbers because the negative result is itself a useful data point about narrow-domain SFT.

| Value | |
|---|---|
| Base model | unsloth/Ministral-3-8B-Instruct-2512 (BF16; trained on 4-bit BnB quant) |
| Adapter type | LoRA (PEFT) |
| Rank / α | 16 / 16 |
| Trainable params | ~28 M (≈ 0.35 % of base) |
| Adapter size | 107 MB (adapter_model.safetensors, 812 tensors, BF16) |
| Training data | 137 examples of COBOL→Java translation + anti-forgetting holdouts |
| Training time | 84 s on 1× H100 80GB (Modal) |
| Task | COBOL→Java translation (preserve stdin/stdout behavior) |
| License | Apache-2.0 (matches base model) |
comp3_precision, OCCURS DEPENDING, REDEFINES, PIC formatting, EVALUATE WHEN OTHER…). Frontier-only difficulty: Devstral-2 (123B) scores 8.3% pass@5.All four use the same Modal inference harness; only the LoRA flag changes between rows.
| Benchmark | n | Base | axel-1 (v1) | mistral-axel-2 (v2.1) | axel-2 vs base |
|---|---|---|---|---|---|
| CobolEval (completion) | 146 | 0.68% | 21.23% | 2.05% | +1.37pp |
| Component C (string-processing) | 107 | 24.30% | 24.30% | 22.43% | −1.87pp |
| Component B (hard COBOL idioms → Java) | 24 | 0.00% | n/a | 4.17% | +4.17pp |
| Component D (medium difficulty) | 18 | 0.00% | n/a | 0.00% | +0.00pp |
The headline target — lifting Component C from 24.30% to 40%+ — was missed. Component B gained 1 task (occurs_depending_00), making axel-2 the only Ministral-3-8B variant we ran that scores non-zero on Component B.
The full Component C delta is a clean trade between two sub-skills:

| failure mode | base passes | axel-2 passes | delta |
|---|---|---|---|
string_concat (n=19) | 0/19 | 19/19 | +100pp |
string_palindrome (n=23) | 23/23 | 3/23 | −87pp |
string_case_change (n=7) | 1/7 | 0/7 | −14pp |
| every other failure mode | 2 | 2 | 0pp |
axel-2 perfectly learned string concatenation (every single Component C concat task passes) and catastrophically forgot palindrome detection (which base already had). Net: −2 tasks.
This is a tidy example of how a narrow SFT distribution can pull the model's prior toward one pattern at the expense of a sibling pattern — even when 35 of the 137 training examples were explicitly chosen as "anti-forgetting" holdouts.
We perturbed 10 v2.1 training examples (rename PROGRAM-ID + 1 working-storage variable), re-translated with axel-2, then ran the resulting Java against the original test stdins.
| metric | base | axel-2 |
|---|---|---|
| test cases passed (of 21 valid) | 17 | 21 |
| pass rate | 80.95% | 100.00% |
| byte-identical to gold Java | n/a | 0/10 |
axel-2 generalizes within the training distribution (+19pp lift after perturbation, 0 byte-identical copies). The narrow result is therefore not a memorization artifact — the training distribution itself is just narrow.
# modal_app/finetune_axel2.py (single H100 80GB)
trainer = SFTTrainer(
model=model, # Ministral-3-8B-Instruct, 4-bit BnB quant
args=SFTConfig(
per_device_train_batch_size=4,
gradient_accumulation_steps=1,
max_steps=60, # ~1.94 epochs over 124 train
learning_rate=1e-4,
lr_scheduler_type="cosine",
warmup_ratio=0.03,
bf16=True,
seed=12627998,
),
peft_config=LoraConfig(
r=16, lora_alpha=16,
target_modules=["q_proj", "k_proj", "v_proj", "o_proj",
"gate_proj", "up_proj", "down_proj"],
lora_dropout=0.0, bias="none",
),
)
System prompt at training time:
"You are a senior COBOL modernization engineer. Translate the user's standalone COBOL program into Java. Preserve stdin/stdout behavior exactly under loose whitespace comparison and numeric tolerance 1e-3. Output only a single Java file with public class Solution. Do not use markdown fences."
| metric | value |
|---|---|
| steps | 60 |
| learning rate | 1e-4 cosine, warmup 3% |
| batch size | 4 |
| train / val examples | 124 / 13 |
| precision | BF16 |
| hardware | 1× H100 80GB on Modal |
| wall clock | 83.5 s |
| train loss | 1.05 → 0.16 |
| eval loss step 15 / 30 / 45 / 60 | 0.34 / 0.17 / 0.14 / 0.13 |
| estimated cost | < $0.50 |

137 examples of COBOL → Java translation pairs (124 train / 13 val), generated and calibrated against base-model pass-rate to avoid both "too easy" and "too hard" extremes.
| failure mode | count |
|---|---|
comp3_precision | 19 |
redefines_aliasing | 16 |
evaluate_when_other | 15 |
packed_vs_display | 15 |
occurs_depending | 12 |
multi_format_input | 11 |
eighty_eight_levels | 8 |
perform_varying_complex | 3 |
string_pic_width | 3 |
| anti-forgetting holdouts (from SFT v1.5) | 35 |
Calibration: every candidate example was run through the base model 5 times. Examples passing all 5 (44) or none of 5 (93) were rejected, leaving 137 in the difficulty-1/2/3 sweet spot.
Source mix: 102 v2.1 hard-synthesis + 35 anti-forgetting holdouts from SFT v1.5 (axel-1's parent dataset).
from peft import PeftModel
from transformers import AutoModelForCausalLM, AutoTokenizer
import torch
base = AutoModelForCausalLM.from_pretrained(
"mistralai/Ministral-3-8B-Instruct-2512",
torch_dtype=torch.bfloat16, device_map="auto",
)
model = PeftModel.from_pretrained(base, "axeltta/mistral-axel-2")
tokenizer = AutoTokenizer.from_pretrained("axeltta/mistral-axel-2")
SYSTEM = ("You are a senior COBOL modernization engineer. "
"Translate the user's standalone COBOL program into Java. "
"Preserve stdin/stdout behavior exactly. "
"Output only a single Java file with public class Solution.")
COBOL = """ IDENTIFICATION DIVISION.
PROGRAM-ID. CONCAT.
...
"""
inputs = tokenizer.apply_chat_template(
[{"role": "system", "content": SYSTEM},
{"role": "user", "content": COBOL}],
return_tensors="pt", add_generation_prompt=True,
).to(model.device)
out = model.generate(inputs, max_new_tokens=1024, do_sample=True, temperature=0.7)
print(tokenizer.decode(out[0], skip_special_tokens=True))
Match the training system prompt. axel-2 is sensitive to system-prompt style; using a different prompt at inference time pulls it back toward base behavior (this is part of why CobolEval — which uses a completion prompt, not a translation prompt — regressed from axel-1's lift).
Rules out:
Doesn't rule out:
If you're considering training a v3 on this base, the audit suggests:
string_palindrome examples to preserve the base capability.axeltta/mistral-axel-1 — same base, trained for COBOL code completion (positive result, +20.55pp on CobolEval).Ministral-3-8B-Instruct-2512.@software{mistral_axel_2_2026,
author = {Axelsson, A.},
title = {mistral-axel-2: A LoRA adapter for COBOL→Java translation on Ministral-3-8B-Instruct},
year = {2026},
url = {https://huggingface.co/axeltta/mistral-axel-2},
note = {Negative result on Component C; positive on Component B.},
}