FunctionGemma 270M IT — Prepaid Cards Tool-Calling (v2, ONNX)
Model description
ONNX Runtime export of
Qrzysztof/functiongemma-270m-it-prepaid-cards-v2
(a google/functiongemma-270m-it fine-tune for prepaid-card tool calling in
107 languages with noisy/multi-turn input) — for CPU, mobile, and
web-browser inference (ONNX Runtime Web / Transformers.js).
Files
| File | Size | Description |
|---|---|---|
model.onnx + model.onnx.data |
1.07 GB | fp32 export (exact reference) |
model-fp16.onnx + model-fp16.onnx.data |
536 MB | fp16 export — recommended for browsers |
Graph
Full-context decoder (no KV-cache inputs): every step feeds the whole context and returns full logits.
| Input | Shape | Dtype |
|---|---|---|
input_ids |
[batch, seq] dynamic |
int64 |
attention_mask |
[batch, seq] dynamic |
int64 |
position_ids |
[batch, seq] dynamic |
int64 |
logits (output) |
[batch, seq, vocab] dynamic |
fp32 / fp16 |
How to use
Python (onnxruntime)
import numpy as np, onnxruntime as ort, torch
from transformers import AutoTokenizer
sess = ort.InferenceSession("model.onnx", providers=["CPUExecutionProvider"])
tokenizer = AutoTokenizer.from_pretrained("Qrzysztof/functiongemma-270m-it-prepaid-cards-v2")
prompt = tokenizer.apply_chat_template(messages, tools=tools, add_generation_prompt=True, tokenize=False)
ids = tokenizer(prompt, return_tensors="pt").input_ids
for _ in range(48):
logits = sess.run(None, {
"input_ids": ids.numpy().astype(np.int64),
"attention_mask": np.ones((1, ids.shape[1]), dtype=np.int64),
"position_ids": np.arange(ids.shape[1], dtype=np.int64).reshape(1, -1),
})[0]
ids = torch.cat([ids, torch.tensor([[logits[0, -1].argmax()]])], dim=1)
print(tokenizer.decode(ids[0], skip_special_tokens=False))
Web browser (ONNX Runtime Web / Transformers.js)
import { AutoTokenizer, AutoModelForCausalLM } from "@huggingface/transformers";
const tokenizer = await AutoTokenizer.from_pretrained("Qrzysztof/functiongemma-270m-it-prepaid-cards-v2-onnx");
const model = await AutoModelForCausalLM.from_pretrained("Qrzysztof/functiongemma-270m-it-prepaid-cards-v2-onnx",
{ dtype: "fp16", device: "wasm" });
The graph uses only standard ONNX ops (Gemm/MatMul/Add/Softmax/…), so it runs under the WASM backend. Full-context decode is O(seq²) — fine for a 270M model with short tool-call outputs.
Intended uses & limitations
Same as the parent model (see the SafeTensors card): synthetic data, uneven language quality, no backend. Performance note: fp32 CPU decode of this graph is slow (no KV cache); prefer fp16 in browsers and GGUF/MLX for interactive local use.
How it was made
optimum-onnx is pinned to transformers <4.58 (incompatible with
transformers 5.x), so the export uses torch.onnx.export directly:
python3 export_onnx.py --model-dir <hf_model_dir> --out model.onnx # fp32
python3 export_onnx.py --model-dir <hf_model_dir> --out model-fp16.onnx --dtype fp16
Settings: eager attention, use_cache=False, opset 17, dynamic axes.
Correctness: verified token-identical greedy decoding vs the PyTorch
reference (export_onnx.py --check).
Evaluation
Same prompts & greedy decoding as the other formats, over a held-out v2 test subset (N=20, 32 max tokens — full-context CPU decode is slow).
| Format | Success rate |
|---|---|
| SafeTensors (reference) | 40/40 = 100% (N=40) |
| ONNX fp32 (ORT CPU) | 20/20 = 100% |
| ONNX fp16 (graph) | same graph semantics; tested identical logits in spot checks |
Fine-tuning from this model
This model was fine-tuned with the tutorial below; you can use it as the starting point for a new tool set (or fine-tune google/functiongemma-270m-it directly).
Fine-tuning tutorial
A complete, minimal fine-tune of a FunctionGemma-class model on this data (follows the official FunctionGemma fine-tuning guide).
1. Setup
pip install torch transformers trl datasets accelerate
huggingface-cli login # accept the gemma license for google/functiongemma-270m-it
2. Load the dataset and normalize messages
The Hub dataset stores messages/tools as JSON strings (Arrow cannot infer
the nested schema), and TRL's SFTTrainer needs a uniform struct schema, so
normalize first:
import json
from datasets import load_dataset
from transformers import AutoModelForCausalLM, AutoTokenizer
def normalize_messages(msgs):
out = []
for m in msgs:
n = {"role": m["role"], "content": m.get("content") or "", "name": None,
"tool_call_id": m.get("tool_call_id"), "tool_calls": None}
if m["role"] == "tool":
n["name"] = m["content"]["name"]
n["content"] = json.dumps(m["content"]["response"], ensure_ascii=False)
if m.get("tool_calls"):
n["tool_calls"] = [{"id": tc.get("id"), "type": tc.get("type", "function"),
"function": {"name": tc["function"]["name"],
"arguments": json.dumps(tc["function"]["arguments"], ensure_ascii=False)}}
for tc in m["tool_calls"]]
out.append(n)
return out
def rows_to_dataset(rows):
from datasets import Dataset
return Dataset.from_list([{
"messages": normalize_messages(r["messages"]),
"tools": json.dumps(r["tools"], ensure_ascii=False),
} for r in rows])
ds = load_dataset("Qrzysztof/ecommerce-chat-tool-calling", token=HF_TOKEN)["train"]
train_rows = [{"messages": json.loads(r["messages_json"]), "tools": json.loads(r["tools_json"])}
for r in ds if r["split"] == "train"]
train_ds = rows_to_dataset(train_rows)
3. Train
import torch
from transformers import AutoModelForCausalLM
from trl import SFTConfig, SFTTrainer
model = AutoModelForCausalLM.from_pretrained("google/functiongemma-270m-it",
dtype=torch.bfloat16, attn_implementation="eager")
tokenizer = AutoTokenizer.from_pretrained("google/functiongemma-270m-it")
trainer = SFTTrainer(
model=model,
args=SFTConfig(
output_dir="functiongemma-ecommerce",
max_length=1024, # covers the longest sample + margin
packing=False, # keep tool calls intact (no cross-sample packing)
num_train_epochs=3,
per_device_train_batch_size=8,
learning_rate=5e-5,
lr_scheduler_type="constant",
warmup_steps=50,
bf16=True, # or fp16 on non-Ampere GPUs
eval_strategy="epoch",
report_to="none",
),
train_dataset=train_ds,
processing_class=tokenizer,
)
trainer.train()
TRL applies the FunctionGemma chat template with the per-sample tools
column; assistant_only_loss=True (default) masks everything but the model's
own turns, so it learns to emit tool calls — not to copy the schema.
4. Evaluate (greedy success rate)
ok = 0
for item in test_rows:
inputs = tokenizer.apply_chat_template(item["messages"][:-1], tools=item["tools"],
add_generation_prompt=True, return_tensors="pt")
out = model.generate(**inputs, max_new_tokens=256)
output = tokenizer.decode(out[0][len(inputs["input_ids"][0]):], skip_special_tokens=False)
expected = <expected tool name / args from expected_json>
ok += expected-tool-in-output and no-other-tool-in-output
5. Push
trainer.push_to_hub("YOUR_USER/functiongemma-ecommerce")
Best practices
Data
- Keep noise digit-safe: never corrupt the values the model must extract
(prices, ids). The
noise.pyengine skips any token containing digits. - Use deterministic train/test splits (by
template_id) and hold out whole languages + (for the e-commerce set) whole schemas — that is the only honest way to measure generalization. - Balance the training subset per (language, intent) — cap the big buckets instead of letting English dominate.
Training
packing=Falsefor tool-calling data; packed sequences splice mid-call.max_length≥ longest sample + a margin; ~1024 covers these datasets.- Constant LR + short warmup (the official guide's defaults) work well.
- Upload a checkpoint to the Hub after every epoch — Colab VMs die mid-run, and the last good epoch is always recoverable.
Evaluation
- Always evaluate with greedy decoding for comparability across formats and runs.
- Score two things separately: tool-name selection and argument fidelity (query + every filter key:value pair).
- Compare every exported format (SafeTensors / GGUF / MLX / ONNX) on the same prompts — quantization changes results.
Deployment
- Validate tool arguments server-side before executing anything (a small model can garble a card number under heavy noise).
- In a live agent, follow the FunctionGemma full loop: model call → backend executes → tool response → model continues; never let the model see or emit secrets.
- For browser deployment use the fp16 ONNX file; for low-end hardware the Q8_0 GGUF or MLX 8-bit; for exact reference behavior the SafeTensors model.
Related
- Parent:
...-v2(SafeTensors) - Siblings: GGUF f16+Q8_0 · MLX 8-bit
- Dataset:
...-tool-calling-v2
Model tree for Qrzysztof/functiongemma-270m-it-prepaid-cards-v2-onnx
Base model
google/functiongemma-270m-itDataset used to train Qrzysztof/functiongemma-270m-it-prepaid-cards-v2-onnx
Evaluation results
- Tool-call success rate (greedy, fp32, ONNX Runtime CPU) on prepaid-cards-tool-calling-v2 (held-out test subset, N=20)self-reported100.000