Downloads · 30 days
16
29% of all-time downloads
SASVAAI/Gemma-4-26B-A4B-XLAM-Lora
Gemma-4-26B-A4B-XLAM-Lora is a text generation model from SASVAAI. 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.
Continues a multi-turn, tool-using support conversation: given the dialogue so far, it emits either the next tool call in Gemma 4's native tool-call syntax, or a final natural-language reply when the request is alread…
Downloads · 30 days
16
29% of all-time downloads
All-time downloads
55
Public
Repo size
627 MB
Likes
1
Public
Click a slice to open those files.
.safetensors595 MB · 95%
From the Hugging Face model README
Continues a multi-turn, tool-using support conversation: given the dialogue so far, it emits either the next tool call in Gemma 4's native tool-call syntax, or a final natural-language reply when the request is already fulfilled.
This is a LoRA adapter for google/gemma-4-26B-A4B-it, trained with bf16 LoRA (no quantisation) via TRL SFT.
Only validation cross-entropy was measured. No generation ran during evaluation, so there is no accuracy, exact-match, or tool-call-validity number for this checkpoint, and the un-adapted base was never scored on the same split. Read Evaluation before quoting anything.
| Developed by | SASVA AI Model Cognition Labs(MCL) Team |
| Base model | google/gemma-4-26B-A4B-it |
| Base revision | 4d7ae4984b7db7de8f8457170b3f1a419ee76d52 |
| Base parameters | 25.95B total / ~4B active (128-expert MoE, top-8 routing) |
| Architecture family | gemma4 (text tower gemma4_text) |
| Adaptation | LoRA (r=128, alpha=256, dropout=0.05, rsLoRA on) |
| Trainable modules | q_proj, k_proj, v_proj, o_proj, gate_proj, up_proj, down_proj |
| Excluded modules | .*vision_tower.* |
| Training method | bf16_lora (experiments.hyperparams, run 93 / trial 14) |
| Refinement | none |
| Precision | bf16 base (no quantisation), bf16 compute |
| Language | English |
| License | Apache-2.0 (inherited from the base model) |
Trainable parameters: 148,684,800 across 205 modules — 0.573% of the base.
The adapter file is 594,801,016 bytes (410 tensors: lora_A + lora_B per
module, stored in float32). All 410 sit under
base_model.model.model.language_model; the base model's vision tower is loaded
but untouched — zero adapter tensors match vision_tower.
Two Gemma 4 structural facts that shape the module list. Both were confirmed
against the base model's config.json and model.safetensors.index.json:
v_proj exists on only 25 of 30 layers. layer_types alternates five
sliding_attention layers then one full_attention layer, so layers 5, 11,
17, 23 and 29 are full-attention — and with attention_k_eq_v: true those
layers share one projection for K and V and expose no v_proj at all. The base
model ships 25 v_proj.weight tensors against 30 q_proj.weight; the adapter
matches that exactly. This is architecture, not a gap in coverage. Head
geometry differs too: full-attention layers use global_head_dim 512 with 2 KV
heads (q out 8192, k out 1024) against 256 / 8 heads on sliding layers (q out
4096, k/v out 2048).mlp.* path (hidden_size 2816 → intermediate_size 2112) and an
experts.gate_up_proj / experts.down_proj pair plus a router
(moe_intermediate_size 704). The adapter's MLP tensors are 2816↔2112, i.e.
the dense path only. The expert weights and the routers are untouched, so
whatever the router has learned to send where is unchanged by this adapter.Direct use. Produce the next assistant turn in a task-oriented support
conversation that has tools. The training traces are airline customer service —
reservations, upgrades, cancellations, baggage, payment methods — over a fixed
set of 13 tools (get_user_details, get_reservation_details,
update_reservation_flights, search_onestop_flight, book_reservation,
transfer_to_human_agents, and seven more).
The model was trained on a specific prompt shape and that shape is part of the contract:
{"name": "<function_name>", "arguments": {<key-value pairs>}} or provide a final text reply if the user's
request has been fulfilled. Always prefer calling a function when more
information or action is needed."user, assistant, and tool; a tool message
carries the raw JSON your backend returned.chat_template.jinja, shipped
in this repo) with add_generation_prompt=True. Do not concatenate strings by
hand.<|tool_call>call:get_user_details{user_id:<|"|>harper_ito_2309<|"|>}<tool_call|>,
or plain text terminated by <turn|>. Note that the system prompt above asks
for a JSON object while every tool-call label in training is the token form:
the model learned the labels, so parse for the token form, never for JSON.skip_special_tokens=False. The tool call is special tokens;
skipping them destroys the output you are trying to parse.import torch
from peft import PeftModel
from transformers import AutoModelForCausalLM, AutoTokenizer
BASE = "google/gemma-4-26B-A4B-it"
ADAPTER = "SASVAAI/Gemma-4-26B-A4B-XLAM-Lora"
# NOTE: AutoModelForCausalLM is correct for Gemma 4 — it resolves to
# Gemma4ForConditionalGeneration, which loads the multimodal wrapper properly.
# (Do not copy the AutoModelForImageTextToText workaround from the Qwen 3.8
# sibling release; that model's CausalLM mapping is the broken one, Gemma 4's
# is not.)
tokenizer = AutoTokenizer.from_pretrained(ADAPTER)
model = AutoModelForCausalLM.from_pretrained(
BASE, dtype=torch.bfloat16, device_map="auto", attn_implementation="sdpa"
)
model = PeftModel.from_pretrained(model, ADAPTER)
model.eval()
# Verbatim from the training invocation. Do not paraphrase.
SYSTEM = (
"You are a function-calling assistant. Given a multi-turn conversation and a "
"list of available tools, determine the next step: either call a function "
'using the format `{"name": "<function_name>", "arguments": {<key-value '
"pairs>}}` or provide a final text reply if the user's request has been "
"fulfilled. Always prefer calling a function when more information or action "
"is needed."
)
messages = [
{"role": "system", "content": SYSTEM},
{"role": "user", "content": "Hi, I have a reservation with ID B1TDOL in basic "
"economy and I'd like to upgrade it to economy class."},
{"role": "assistant", "content": "To upgrade your reservation I'll need your "
"user ID and the payment method for the fare "
"difference."},
{"role": "user", "content": "My user ID is isabella_lopez_2185, and I'll pay "
"with the credit card ending in 3244."},
]
inputs = tokenizer.apply_chat_template(
messages, add_generation_prompt=True, return_tensors="pt"
).to(model.device)
out = model.generate(inputs, max_new_tokens=512, do_sample=False)
print(tokenizer.decode(out[0][inputs.shape[-1]:], skip_special_tokens=False))
# -> <|tool_call>call:get_reservation_details{reservation_id:<|"|>B1TDOL<|"|>}<tool_call|>
The base model is ~52 GB in bfloat16 — this needs an 80 GB-class GPU with room to
spare, or two. Training used attn_implementation="sdpa".
Decoding matters. Training and evaluation were both teacher-forced, so no sampling setting is validated. Greedy (
do_sample=False) is the only defensible default, and the example output above is illustrative of the trained shape, not a measured result.
Data. A 342-row training split derived from 100 internal multi-turn
tool-calling traces, produced by this project's data-generation stage from a
local trace folder named run_traces/xlam. Traces are ShareGPT-style (from:
human / gpt / function_call / observation), airline customer support.
Provenance caveat — read this before citing a public dataset. The source folder is named
xlam, and that name is carried through this repo for traceability, but the contents do not look like the public single-turn xLAM/APIGen function-calling corpus. Across the 100 traces there are 391 calls over exactly 13 tools —get_reservation_details,get_user_details,think,update_reservation_baggages,update_reservation_flights,search_direct_flight,search_onestop_flight,calculate,transfer_to_human_agents,update_reservation_passengers,cancel_reservation,book_reservation,send_certificate— with a median of 14 turns per trace (max 48). That is a small fixed airline tool set inside long multi-turn dialogues, which resembles a tau-bench-style airline environment far more than xLAM's thousands of distinct single-turn APIs. The upstream source was not established, so no public dataset is cited. Do not represent this model as trained on the published xLAM dataset without confirming provenance first.
Conversion was deterministic — no model generated any training content. A
script walked each trace and emitted one row per assistant turn, with the full
preceding conversation as context and that turn as the answer. 13 of the 100
traces yielded no usable turn and were skipped, leaving 87 traces and 378 rows.
The split is not published, so the datasets key is omitted rather than
pointing at a dead link.
The train/validation split is group-aware by trace, so no conversation appears on both sides.
| Train samples | 342 rows / 80 traces |
| Validation samples | 36 rows / 7 traces |
| Shared traces | 0 |
| Prompt format | chat template + system prompt (see Intended use) |
| Loss masking | answer tokens only; prompt tokens set to -100 |
| Truncation | prompt left-truncated to fit max_seq_len 4096; answer never truncated |
An LLM (Claude Opus 4.6, claude-opus-4-6, via an internal inference
gateway) was used elsewhere in the pipeline — to infer the trace field mapping,
and to propose the hyperparameters tried by the search. It generated no training
content and computed no metric.
| SFT method | bf16_lora |
| Base quantisation during training | none — bf16 base, bf16 compute |
| Refinement stage | none |
| Attention implementation | sdpa, forced (see note) |
| Hardware | 8x NVIDIA H100 80GB HBM3, torchrun --nproc_per_node=8 |
Attention is pinned to sdpa rather than FlashAttention-2 for a hard reason:
the 5 full-attention layers use global_head_dim 512, past FlashAttention-2's
256 head-dim cap. FA2 cannot run this model at all.
bf16_lora was the only method the project allowed for this run
(allowed_training_methods: ['bf16_lora']). It applies LoRA to an unquantised
bf16 base — the only one of the available methods that does no quantisation.
No refinement stage ran; the published weights are the SFT adapter.
| Hyperparameter | Value | Source |
|---|---|---|
learning_rate | 0.00015 | experiments.hyperparams / [TRAIN] cmdline |
lr_scheduler_type | cosine | experiments.hyperparams |
num_train_epochs | 2 | experiments.hyperparams |
per_device_train_batch_size | 1 | experiments.hyperparams |
gradient_accumulation_steps | 4 | experiments.hyperparams |
max_seq_length | 4096 | experiments.hyperparams |
warmup_ratio | 0.05 | experiments.hyperparams |
weight_decay | 0.03 | experiments.hyperparams |
lora_r / lora_alpha / lora_dropout | 128 / 256 / 0.05 | adapter_config.json |
use_rslora | true | adapter_config.json |
use_dora | false | adapter_config.json |
target_modules | the 7 listed in Model details | adapter_config.json |
exclude_modules | .*vision_tower.* | adapter_config.json |
Effective batch size: 32 (1 x 4 x 8). Optimizer steps: 22.
loraplus_lr_ratio (1.0), neftune_noise_alpha (0.0), use_liger_kernel,
use_sample_packing and lora_init (default) were all left at their
no-op defaults. KD parameters are omitted deliberately — this is a bf16_lora
run, not bf16_lora_kd, so kd_alpha/kd_beta/kd_temperature carry inert
defaults that would imply distillation that did not happen.
Provenance note: this run predates
results.tsvhaving a row for it, and the project'stask_config.py/platform_config.pyare gitignored and were overwritten by later runs. Every value above was recovered from the platform database (runs,experiments,eventstables for run 93) and cross-checked against the literal[TRAIN]command line recorded in the run log.
These hyperparameters were selected by an automated search (
autocatalyst.cli.run_autoresearch): an agent proposes one change at a time, runs train → eval, and keeps or discards oneval_loss(lower is better).
Run 93 ran 46 trials across 5 data strategies in 4 h 49 m; 44 scored and 2 errored. This checkpoint is trial 14, strategy v2 — the run's best.
Read this before comparing any two numbers below. Each strategy regenerates
the dataset, so eval_loss is only comparable within a strategy. Strategies
v1 and v2 share the strategy-v2-era data and are comparable to each other;
strategies v3, v4 and v5 landed in the 5.2–8.0 range on their own regenerated
splits, which is a different metric, not a worse model. None improved the
outer best, and the run ended after v5. Those 26 trials are therefore excluded
from the table below rather than tabulated in a way that would imply a
comparison that does not exist.
The 18 comparable trials. All bf16 LoRA, batch 1 x grad accum 4, cosine
schedule, max_seq_len 4096, on the same 36-example split:
| # | r | LR | Epochs | rsLoRA | Weight decay | Warmup | Dropout | eval_loss | Kept |
|---|---|---|---|---|---|---|---|---|---|
| 14 | 128 | 1.5e-4 | 2 | yes | 0.03 | 0.05 | 0.05 | 0.407374 | yes |
| 1 | 16 | 2e-4 | 2 | no | 0.01 | 0.05 | 0.05 | 0.410294 | yes |
| 16 | 128 | 1.5e-4 | 2 | yes | 0.03 | 0.05 | 0.10 | 0.410490 | no |
| 18 | 128 | 1.2e-4 | 2 | yes | 0.03 | 0.05 | 0.05 | 0.417157 | no |
| 5 | 32 | 2e-4 | 2 | no | 0.01 | 0.05 | 0.05 | 0.420014 | no |
| 15 | 128 | 1.5e-4 | 2 | yes | 0.03 | 0.10 | 0.05 | 0.430139 | no |
| 13 | 128 | 1.5e-4 | 2 | yes | 0.01 | 0.05 | 0.05 | 0.430278 | yes |
| 12 | 64 | 1.5e-4 | 2 | yes | 0.01 | 0.05 | 0.05 | 0.474418 | yes |
| 6 | 16 | 2e-4 | 2 | no | 0.01 | 0.05 | 0.05 | 0.480893 | no |
| 3 | 16 | 2e-4 | 3 | no | 0.01 | 0.05 | 0.05 | 0.497298 | no |
| 10 | 64 | 1.5e-4 | 2 | no | 0.01 | 0.05 | 0.05 | 0.500371 | yes |
| 9 | 32 | 1.5e-4 | 2 | no | 0.01 | 0.05 | 0.05 | 0.580867 | yes |
| 11 | 64 | 2.5e-4 | 2 | no | 0.01 | 0.05 | 0.05 | 0.596916 | no |
| 19 | 128 | 1.5e-4 | 2 | yes | 0.05 | 0.05 | 0.05 | 0.619713 | no |
| 7 | 16 | 1.5e-4 | 2 | no | 0.01 | 0.05 | 0.05 | 0.641740 | yes |
| 4 | 16 | 2e-4 | 2 | no | 0.05 | 0.05 | 0.05 | 0.647231 | no |
| 2 | 16 | 1e-4 | 2 | no | 0.01 | 0.05 | 0.05 | 0.649749 | no |
| 8 | 16 | 1.5e-4 | 3 | no | 0.01 | 0.05 | 0.05 | 0.666212 | no |
Trials 1–6 are strategy v1, trials 7–19 strategy v2 (trial 17 failed validation and never trained). Trials 20 and 40 are absent or errored.
What the search actually established.
r 16 → 32 → 64 →
128 moved loss 0.641740 → 0.580867 → 0.500371 → 0.430278 (#7, #9, #10, #13;
the last two with rsLoRA on).r=64, enabling it alone moved
0.500371 → 0.474418 (#10 → #12).r=128: 0.01 → 0.430278 (#13), 0.03 → 0.407374 (#14), 0.05 → 0.619713 (#19).
One step past the optimum costs 0.21.What it did not establish. The winning margin over the strategy-v1 baseline
is 0.003 (0.407374 vs 0.410294) between two configurations that share almost
nothing — r=128 + rsLoRA + wd 0.03 versus r=16 + no rsLoRA + wd 0.01. Read
that as "the large-rank configuration caught up to the baseline", not as a 0.003
improvement attributable to any knob.
Search space. Five knobs were varied across these 18 trials (LORA_R,
LEARNING_RATE, WEIGHT_DECAY, EPOCHS, USE_RSLORA, plus one warmup and one
dropout probe). LR_SCHEDULER, MAX_SEQ_LEN, GRAD_ACCUM, BATCH_SIZE,
LORAPLUS_LR_RATIO, NEFTUNE_NOISE_ALPHA, USE_DORA, LORA_INIT,
USE_LIGER_KERNEL and USE_SAMPLE_PACKING were never moved. The bounds in force
cannot be reproduced here: core/experiment_constraints.py was not tracked in
git at this run's commit.
Measurement noise: not measured. No configuration was re-run with identical settings and a different seed — all 18 trials above differ from one another in at least one hyperparameter. The table shows the metric is steep (one weight-decay step costs 0.21; one warmup step costs 0.023), and on a 36-example split that steepness is as consistent with split-composition sensitivity as with genuine model differences. The two cannot be separated without repeated seeds, so treat the ranking as provisional.
Observed training metrics.
| Final train loss | 0.6664509773254395 |
| Final eval loss | 0.407374 |
| Train runtime | 297.501s |
| Total FLOPs | 1.645208064061604e+17 |
| Throughput | 2.299 samples/s, 0.074 steps/s |
Only 22 optimizer steps ran, and the reported train loss is the mean over the run, not a converged value: the logged history is 1.1455974578857422 at step 10 and 0.2633920907974243 at step 20, with grad norm falling 7.44 → 3.73. Treat 0.6665 as an average over a still-descending curve.
Protocol. All 36 validation rows, no sampling. eval_loss is the Hugging
Face Trainer's teacher-forced cross-entropy over answer tokens, computed
inside the training loop and read back from trainer_state.json by the project's
loss evaluator.
No generation occurred. That is why this repo ships no predictions.jsonl
(the sibling Qwen release has one because that run used a generative evaluator),
and why the shipped eval_results.json records num_samples: 0. There is no
truncation caveat to give — and equally no evidence at all about whether the
model emits well-formed tool calls.
| Metric | Value |
|---|---|
Validation cross-entropy (eval_loss) | 0.407374 |
| Samples | 36 |
| Eval runtime | 4.8873s (7.366 samples/s) |
Baseline for comparison. Not measured. The untuned
google/gemma-4-26B-A4B-it was never scored on this split, so the number above
quantifies nothing about how much of the model's behaviour the fine-tuning is
responsible for. This is the single most important gap in this card.
This is a validation split, not a held-out test set. The autoresearch loop selects against it — 18 comparable trials scored on these same 36 rows — so expect optimistic bias. With only 7 source traces behind those 36 rows, the split's composition moves the metric as much as the model does.
The eval set is not a file you can look up. It was a generated artifact
(val_strategy_v2.jsonl), and the generator overwrote it on 2026-08-27 with a
regenerated strategy-v2 split built from a different system prompt. Unlike the
sibling Qwen release, no per-example record survives, so the exact 36 rows scored
here are not recoverable. Any re-evaluation is a new measurement, not a
reproduction.
Loss is not competence. Every number here measures next-token agreement with 36 held-out turns. A model that emits a malformed tool call containing the right tokens in the wrong order scores well. Nothing was ever parsed or executed.
No baseline, so no established gain. The adapter may be improving output formatting, memorising the airline domain, or both. This card cannot distinguish them.
Hallucinated function calls are the expected failure mode. The model never sees a tool schema and learned a 13-tool vocabulary from 87 traces. It will produce a confident call to a function that does not exist. Mitigation: validate every emitted call — function name and argument keys — against your real schema, and treat a mismatch as a refusal rather than a retry.
Generated identifiers are fiction. The training traces contain synthetic personal data — names, addresses, emails, dates of birth, partial payment cards. The model reproduces those patterns and will emit plausible-looking user IDs, reservation IDs and card fragments that belong to nobody. Never surface one to a user, and never act on one without a confirming backend lookup.
Very little training signal. 22 optimizer steps over 342 examples. Treat this as a domain-formatting adapter, not a capability upgrade.
Prompt truncation is silent. At max_seq_len 4096 the prompt is
left-truncated, so a long conversation loses its earliest turns — the system
message first. Nothing warns you.
Domain narrowness. Short English airline-support dialogues with US-style addresses and payment methods. Longer inputs, other verticals, other tool vocabularies and other languages are all unmeasured.
Inherits all biases and limitations of the base model. This adapter changes 0.573% of the parameters, leaves the MoE routers and all 128 experts per layer untouched, and was not evaluated for social bias, safety, or fairness across demographic groups.
| Hardware | 8x NVIDIA H100 80GB HBM3 |
| Training time | 4.96 minutes (297.501s) |
| Cloud provider / region | on-premise |
Covers this run only. The full 46-trial search that selected it took 4 h 49 m on the same hardware.
PEFT's version is the one recorded in adapter_config.json at save time; the
rest are the pinned versions of the training environment. transformers is a
git-main build: Gemma 4's gemma4 architecture is not in the stable PyPI
release.
@misc{gemma4_xlam_lora_2026,
title = {Gemma-4-26B-A4B Function-Calling LoRA},
author = {Banerjee, Aaron and Anbuselvan, Pooja and Jodhpurkar, Om},
year = {2026},
url = {https://huggingface.co/SASVAAI/Gemma-4-26B-A4B-XLAM-Lora}
}