YAML Metadata Warning:The pipeline tag "text2text-generation" is not in the official list: text-classification, token-classification, table-question-answering, question-answering, zero-shot-classification, translation, summarization, feature-extraction, text-generation, fill-mask, sentence-similarity, text-to-speech, text-to-audio, automatic-speech-recognition, audio-to-audio, audio-classification, audio-text-to-text, voice-activity-detection, depth-estimation, image-classification, object-detection, image-segmentation, text-to-image, image-to-text, image-to-image, image-to-video, unconditional-image-generation, video-classification, reinforcement-learning, robotics, tabular-classification, tabular-regression, tabular-to-text, table-to-text, multiple-choice, text-ranking, text-retrieval, time-series-forecasting, text-to-video, image-text-to-text, image-text-to-image, image-text-to-video, visual-question-answering, document-question-answering, zero-shot-image-classification, graph-ml, mask-generation, zero-shot-object-detection, text-to-3d, image-to-3d, image-feature-extraction, video-text-to-text, keypoint-detection, visual-document-retrieval, any-to-any, video-to-video, other

py-alpha-29m β€” a 29.5M encoder-decoder trained from scratch on Python

An encoder-decoder transformer built and trained end to end on one laptop: own tokeniser, own corpus, own span-corruption pretraining, own evaluation harness.

It writes syntactically valid, idiomatic-looking Python. It almost never writes correct Python. Both halves of that sentence are the point β€” the numbers below are reported as measured, including the ones that didn't move.

parameters        29,521,920
architecture      4 encoder + 12 decoder blocks, cross-attention every layer
pretraining       600,001,082 tokens of deduplicated, decontaminated Python
fine-tuning       500,000 (request, code) pairs mined from docstrings
hardware          one Apple M4 Pro (MPS), ~30,000 tokens/sec
training time     5h 00m (stage 1) + 1h 20m (stage 2)

Results

val loss perplexity token accuracy
Stage 1 β€” span corruption 1.2153 3.31 74.6% exact, 89.0% top-5
Stage 2 β€” request β†’ code 1.8659 6.5 β€”
benchmark pass@1 parse rate
MBPP (100) 0.0% 90.0%
MBPP (100), signature given 0.0% 97.0%
HumanEval (60) 1.7% 88.3%

The single HumanEval pass is strlen β€” return len(string). For scale, Qwen2.5-Coder-0.5B scores 28.0 on HumanEval and 52.9 on MBPP with 16.7Γ— the parameters and 9,167Γ— the training tokens.

What the experiments established

Four interventions were tried. Every one that addressed format worked; none moved correctness.

intervention effect on format effect on pass@1
Filter training pairs for length, drop test functions parse 83% β†’ 90% none
Give the model the function signature parse 90% β†’ 97% none
Richer prompts (HumanEval vs MBPP) β€” 0 β†’ 1/60
Best-of-10 sampling, temperatures 0.2–0.8 degrades sharply none

Two findings worth stating directly:

Conditioning is not the bottleneck. Handed the function name and parameter list β€” two of its three jobs removed β€” the model still scored 0%. It writes def sort_matrix(a0): then a body with no relationship to sorting. The limit is composing logic, not understanding the request.

There is nothing hiding in the distribution. Best-of-n never beat greedy at any temperature, and parse rate collapses from 88% to 2% as temperature rises from 0 to 0.8. The probability mass behind the argmax is noise, not plausible alternatives. Greedy already extracts everything the model has.

Architecture

Pre-norm LayerNorm, SwiGLU, sinusoidal positions, MHA, output projection tied to the decoder embedding, separate encoder and decoder embeddings.

d_model 320 Β· n_head 10 (head_dim 32) Β· d_ffn 832
enc_layers 4 Β· dec_layers 12 Β· enc_seq_len 512 Β· dec_seq_len 1024
vocab 8,192 byte-level BPE + 100 sentinels

A note for anyone copying this: 42% of the parameters exist to read the request β€” encoder embedding (2.62M), encoder layers (4.83M) and cross-attention (4.92M) β€” while stage 2 requests average 18 tokens. The encoder-decoder split was chosen to learn cross-attention, not for efficiency. For short-request-to-long-code, decoder-only would spend those parameters on generation instead.

Loading the released weights

The model is a custom architecture, so AutoModel will not load it. Take model.py and config.py from this repo alongside the checkpoint:

import torch
from config import Config
from model import SLM

ck = torch.load("stage2aug.pt", map_location="cpu")
model = SLM(Config(**ck["config"]))
model.load_state_dict(ck["model"])
model.eval()

stage1.pt is the span-corruption model β€” judge it with sample.py --mode denoise, since it has never seen a natural-language request. stage2aug.pt writes a function body given a request and a signature.

Pipeline

python prepare.py all --source hf --target-tokens 600000000   # tokeniser + corpus + pairs
python train.py --stage 1 --steps 16000 --batch-size 32 --grad-accum 2
python train.py --stage 2 --init checkpoints/stage1_best.pt --batch-size 16 --dec-seq-len 384
python eval.py --benchmark mbpp --limit 100
file role
config.py single source of truth; prints the parameter count
prepare.py BPE tokeniser, corpus packing, pair mining, decontamination
corruption.py T5-style span corruption, with an invertibility self-test
model.py the model; self-test checks init loss, causality, padding isolation
train.py both stages, overfit mode, resume, length bucketing
eval.py MBPP + HumanEval, sandboxed execution, best-of-n
sample.py generation, in code and denoise modes
accuracy.py token-level accuracy, which loss alone cannot give you
filter_pairs.py scope analysis to find undefined references
augment_pairs.py splits pairs into (request + signature) β†’ body

Every component has a self-test. python model.py verifies the initial loss sits at ln(vocab_size), that the decoder cannot see future tokens, and that encoder padding is invisible to cross-attention. python corruption.py verifies masking is exactly invertible.

Data quality notes

An audit of 40,000 training pairs found 86.6% reference names that are never imported or defined β€” os, np, re, project globals β€” because the miner takes the function body and discards the file's imports. A controlled experiment showed this costs less than it appears: the model emits undefined references only 3.3% of the time on MBPP, since those prompts need no imports.

The deeper problem is register. Docstring-mined pairs are library plumbing β€” cpython_tags(), _IsTestMethod() β€” because nobody documents def reverse(s): return s[::-1]. The corpus contains no tutorial-style code, and no amount of filtering creates it.

Limitations

Not useful for writing code. Produces plausible-looking Python with incorrect logic. Trained only on Python. Benchmarked on 100/500 MBPP and 60/164 HumanEval problems β€” enough to distinguish 0% from 50%, not 0% from 1%.

Data provenance and licence

Pretrained on codeparrot/codeparrot-clean, deduplicated public Python from GitHub. Training data was decontaminated against HumanEval and MBPP (prompts and reference solutions) by 13-gram overlap before any training, so the benchmark numbers above are not inflated by memorisation.

The code in this repository is MIT licensed. The provenance and licensing of the training corpus is a separate matter, governed by the upstream dataset.

Downloads last month

-

Downloads are not tracked for this model. How to track
Inference Providers NEW
This model isn't deployed by any Inference Provider. πŸ™‹ Ask for provider support

Dataset used to train sanjaimurugan/py-alpha-29m