# Text-to-SQL Post-Training # Text-to-SQL Post-Training > A multi-week campaign to post-train a small open model into a strong text-to-SQL generator, scored by **execution accuracy** (run gold vs predicted SQL against a real SQLite DB). Click an experiment to open its page. ## Experiments | Status | Experiment | Owner | | --- | --- | --- | | **Week 1 — Foundations & baselines** | | | | done | [Build execution-accuracy eval harness](#/build-execution-accuracy-eval-harness) | Ana | | done | [Zero-shot baselines across open models](#/zero-shot-baselines-across-open-models) | Ana | | done | [Clean data: dedup + dialect filtering](#/clean-data-dedup-dialect-filtering) | Ana | | done | [QLoRA SFT baseline](#/qlora-sft-baseline) | Ravi | | in-progress | [LR & LoRA-rank sweep](#/lr-lora-rank-sweep) | Ravi | | planned | [Prompt format ablation (chat vs completion)](#/prompt-format-ablation-chat-vs-completion) | to assign | | **Week 2 — Scaling & data** | | | | in-progress | [Synthetic data augmentation (self-instruct)](#/synthetic-data-augmentation-self-instruct) | Ravi | | planned | [Add Spider + WikiSQL to the eval suite](#/add-spider-wikisql-to-the-eval-suite) | Ana | | planned | [Curriculum: order by join complexity](#/curriculum-order-by-join-complexity) | to assign | | planned | [Distill from a larger open model](#/distill-from-a-larger-open-model) | Ravi | | blocked | [Long-context schema eval @32k](#/long-context-schema-eval-32k) | to assign | | **Week 3 — Hardening & release** | | | | planned | [Full fine-tune vs LoRA comparison](#/full-fine-tune-vs-lora-comparison) | Ravi | | planned | [Error taxonomy & failure analysis](#/error-taxonomy-failure-analysis) | Ana | | planned | [CPU latency & throughput](#/cpu-latency-throughput) | to assign | | planned | [Final model card + release](#/final-model-card-release) | Ana | # Build execution-accuracy eval harness --- ### Harness: execution accuracy over SQLite `Jul 02, 2026 · 06:24 UTC` Execution accuracy is the right metric: exact string match is near-zero because the model writes semantically-equivalent but syntactically-varied SQL. The harness builds an in-memory SQLite DB from each example's schema, runs gold and predicted queries, and compares result sets (order-aware only when the gold has ORDER BY). ````python title=eval.py import sqlite3 from datasets import load_dataset def execution_accuracy(preds, golds, schemas): """Build an in-memory SQLite DB per example, run gold vs pred, compare result sets.""" correct = 0 for pred, gold, schema in zip(preds, golds, schemas): con = sqlite3.connect(":memory:") con.executescript(schema) try: got = con.execute(pred).fetchall() want = con.execute(gold).fetchall() correct += set(map(tuple, got)) == set(map(tuple, want)) except sqlite3.Error: pass return correct / len(preds) ```` - https://github.com/huggingface/trl # Zero-shot baselines across open models --- ### Baselines: 28.9% best zero-shot `Jul 02, 2026 · 06:24 UTC` Zero-shot execution accuracy on the 800-example held-out set. Instruct variants lead; the 1.5B instruct model is the best base to fine-tune from. | Model | Exec. accuracy | Exact match | | --- | --- | --- | | google/gemma-3-270m | 12.1% | 0.1% | | meta-llama/Llama-3.2-1B-Instruct | 21.7% | 3.2% | | Qwen/Qwen2.5-1.5B-Instruct | **28.9%** | 4.4% | Target to beat with SFT: **28.9%**. - https://huggingface.co/Qwen/Qwen2.5-1.5B-Instruct - https://huggingface.co/meta-llama/Llama-3.2-1B-Instruct - https://huggingface.co/datasets/gretelai/synthetic_text_to_sql # Clean data: dedup + dialect filtering --- ### Data: 42k clean SQLite-executable examples `Jul 02, 2026 · 06:24 UTC` Filtered the training set to examples whose gold query executes cleanly in SQLite (~78% do; the rest use non-SQLite dialects), then deduped against the eval prompts. Final training set: 42k examples. # QLoRA SFT baseline --- ### QLoRA baseline: 51.3% exec acc `Jul 02, 2026 · 06:24 UTC` First SFT pass: QLoRA (r=16) on Qwen2.5-1.5B-Instruct, 3 epochs, completion-only loss. Execution accuracy 28.9% → **51.3%**. Live metrics on the Trackio dashboard. ````python title=train.py import trackio from datasets import load_dataset from trl import SFTConfig, SFTTrainer from peft import LoraConfig def main(model="Qwen/Qwen2.5-1.5B-Instruct", r=16, lr=2e-4): ds = load_dataset("gretelai/synthetic_text_to_sql", split="train") trackio.init(project="text2sql", config={"model": model, "r": r, "lr": lr}) cfg = SFTConfig(learning_rate=lr, num_train_epochs=3, per_device_train_batch_size=16, report_to="trackio") peft = LoraConfig(r=r, lora_alpha=2 * r, task_type="CAUSAL_LM") SFTTrainer(model, args=cfg, train_dataset=ds, peft_config=peft).train() if __name__ == "__main__": main() ```` - https://huggingface.co/spaces/abidlabs/gemma-text2sql-trackio # LR & LoRA-rank sweep --- ### Sweep: r=16, lr=5e-4 wins `Jul 02, 2026 · 06:24 UTC` Swept learning rate {1e-4, 2e-4, 5e-4} × rank {8, 16, 32}. r=16 / lr=5e-4 is the clear winner; r=8 underfits and lr>5e-4 destabilizes late in training. - media/lr_rank_sweep.png - https://huggingface.co/spaces/abidlabs/gemma-text2sql-trackio # Prompt format ablation (chat vs completion) # Synthetic data augmentation (self-instruct) --- ### Synth data: +3.1% exec acc (early) `Jul 02, 2026 · 06:24 UTC` Generating extra (question, SQL) pairs by prompting a larger open model on real schemas, keeping only pairs whose SQL executes. Running as an HF Job; outputs land in a bucket. Early signal: +3.1% exec acc when mixed 1:4 with real data. ````python title=gen_synth.py """Self-instruct augmentation: sample real schemas, prompt a teacher model for new (question, SQL) pairs, then keep only pairs whose SQL executes.""" import json, sqlite3, random from huggingface_hub import InferenceClient client = InferenceClient() def augment(schemas, n_per_schema=8): out = [] for schema in schemas: prompt = f"Given this schema, write {n_per_schema} diverse NL questions "\ f"and their SQLite queries as JSONL.\n{schema}" for line in client.text_generation(prompt, max_new_tokens=1024).splitlines(): try: ex = json.loads(line) sqlite3.connect(":memory:").executescript(schema).execute(ex["sql"]) out.append({**ex, "schema": schema}) except Exception: continue return out ```` - https://huggingface.co/jobs/abidlabs/6a45b02733c08a2c0dae0348 - https://huggingface.co/buckets/abidlabs/jobs-artifacts # Add Spider + WikiSQL to the eval suite # Curriculum: order by join complexity # Distill from a larger open model --- ### Plan & hypothesis `Jul 02, 2026 · 06:24 UTC` Plan: use the best open model as a teacher (rationale + SQL), distill into the 1.5B student. Hypothesis: closes most of the gap to the teacher at a fraction of the cost. # Long-context schema eval @32k # Full fine-tune vs LoRA comparison # Error taxonomy & failure analysis # CPU latency & throughput # Final model card + release