tiny-sql-gpt / README.md
sarathi-balakrishnan's picture
Upload folder using huggingface_hub
c5730e1 verified
|
Raw
History Blame Contribute Delete
6.12 kB
---
license: mit
language:
- en
tags:
- text-generation
- sql
- educational
- from-scratch
- interpretability
- tiny
pipeline_tag: text-generation
library_name: pytorch
---
# Tiny SQL GPT
> **The goal:** build a language model from scratch, end to end, small enough to understand every
> part of it, and in doing so understand how the large ones actually work.
**A 841,216-parameter decoder-only transformer, trained from random weights on a laptop CPU in
five minutes. 100% of the SQL it generates executes against a real database.**
No pretrained weights. No `transformers` model classes. No API keys. The full architecture is
~200 readable lines of PyTorch.
This model exists to be **understood**, not deployed. Its vocabulary is 155 tokens, which is the
point: small enough that you can print the *entire* probability distribution at every generation
step, something no frontier model demo can do.
- **Code, evaluation harness and write-up:** https://github.com/sarathi-aiml/tiny-sql-gpt
- **Plain-English explainer (no maths):** [`EXPLAIN.md`](https://github.com/sarathi-aiml/tiny-sql-gpt/blob/main/EXPLAIN.md)
---
## Usage
```bash
pip install torch safetensors huggingface_hub
```
```python
from inference import TinySQLGPT # inference.py + tiny_gpt.py from the repo
model = TinySQLGPT.from_pretrained("sarathi-balakrishnan/tiny-sql-gpt")
print(model.generate())
# SELECT city , MIN ( age ) FROM customers WHERE plan = 'annual' GROUP BY city ;
print(model.generate(prompt="SELECT region ,"))
# The whole distribution, all 155 tokens, not a top-k truncation
for token, p in model.next_token_probs(
"SELECT region , SUM ( qty ) FROM sales GROUP BY", top=5):
print(f"{token:<12} {p:.3f}")
# region 0.996
# segment 0.001
# product 0.001
```
---
## What it does
Generates SQL over a fixed three-table schema (`sales`, `customers`, `orders`) using 14 query
shapes: `SELECT`, `WHERE`, `AND`, `GROUP BY`, `ORDER BY`, `LIMIT`, and the aggregates
`COUNT`/`SUM`/`AVG`/`MAX`/`MIN`.
It is **not** a text-to-SQL model. It does not take a natural-language question. It generates
SQL unconditionally, or continues a SQL prefix you give it.
## Results
500 generated queries, executed against a real SQLite database. Seeded, so you get these exact
numbers.
| metric | Tiny SQL GPT | bigram baseline |
|---|---:|---:|
| executes | **100.0%** | 4.4% |
| `GROUP BY` agrees with `SELECT` | **100.0%** | 3.4% |
| novel (not in training set) | 16.6% | 98.6% |
| validation loss | 0.662 | n/a |
100% is a real measurement, but read it against the task: 14 query shapes, 3 tables, 155 tokens.
A model that saturates *this* is proof the training loop works, not a text-to-SQL system.
### Scaling
Same architecture and data at four sizes, all trained on one laptop:
| model | params | executes | `GROUP BY` agrees |
|---|---:|---:|---:|
| nano | 24,736 | 99.2% | **36.6%** |
| micro | 124,032 | 99.8% | **100.0%** |
| **tiny** (this model) | **841,216** | **100.0%** | **100.0%** |
| small | 4,834,816 | 100.0% | 100.0% |
Syntax is nearly free: 24K parameters writes SQL that runs. The long-range dependency costs ~5x
more, and appears as a phase transition between 24K and 125K. Above that, nothing improves: going
from 124K to 4.8M parameters buys 0.007 of validation loss and no behavioural change. All four
converge to ~0.66, which is the entropy of the data generator, not a limit of the models.
---
## Why it's interesting
The training data contains a deliberately planted long-range dependency: **the column after
`GROUP BY` is always the column that appeared first in `SELECT`**, roughly 8 tokens earlier.
Getting it right requires looking back, which is what attention is for.
**In the smallest model that can do it, one head learned it.** In `flat` (1 layer, 127K params),
head L0H1 places **58.7% of its attention** on the `SELECT` column, 7.0x above uniform. Nobody
designed or labelled it.
**In this model, it is distributed.** `tiny` gets `GROUP BY` agreement right 100% of the time, yet
no head exceeds 17.7% on the same probe, only 2.1x uniform. Same behaviour, no legible circuit.
The bigger model is not worse at the task, it is worse at being read. This is also seed-sensitive:
an earlier run of `tiny` put one head above 85%, and the current seeded run does not reproduce it.
**And you can watch it hallucinate.** Three `(table, column)` pairs were held out from the
`GROUP BY` position during training. The columns appear elsewhere, just never there. The model
gets **0 out of 3**, confidently substituting a familiar column instead:
```
asked for: ... GROUP BY -> "channel" (never seen in this position)
it answered: ... GROUP BY -> "status" (familiar, confident, wrong)
```
A control prompt shows the context *is* being used (3.8x to 10.2x lift), it simply loses to a prior
against tokens never seen in that slot. **Attention identifies the right source token; the output
prior overrules it.** That is hallucination, in a model small enough to point at the exact cause.
---
## Training
| | |
|---|---|
| data | 100,000 generated SQL queries (16,941 unique), 1.3M tokens, seed 1337 |
| architecture | decoder-only, 4 layers, 4 heads, 128 embedding, 64-token context |
| tokenizer | word-level, 155 tokens |
| optimizer | AdamW, lr 1e-3, cosine schedule, weight decay 0.01, grad clip 1.0 |
| steps | 3,000 路 batch 64 路 ~5 minutes on a laptop CPU |
| final loss | train 0.658 路 val 0.662 |
Training data is **generated, not scraped**, from a grammar in the repo. No licensing questions,
and a learner can read the entire source of the training set.
## Limitations
- Not text-to-SQL. No natural-language input.
- One fixed three-table schema. It knows no other tables or columns.
- 64-token context. Longer queries are truncated.
- Does not generalize to column names it never saw in a given syntactic position (see above,
that failure is the point, and it is measured rather than hidden).
- Generated SQL is syntactically valid, not semantically meaningful. It will happily write
`WHERE age > 1500`.
## License
MIT.