Quant trader turned ML engineer. I train small models to do hard reasoning — and to speak endangered languages.
- Training Qwen3-0.6B on Dakota grammar via GRPO — fluent output from a 0.6B model on a language with <3k speakers.
- Extending the Stoney Nakoda corpus past 68k synthetic + 14.5k real rows.
- Building Manim animations as reasoning benchmarks for small LLMs — if a model can render a 62-face recursive polyhedron, it can probably think.
Stoney Nakoda and Dakota each have fewer than 3,000 fluent speakers. I've built a bilingual corpus — 68.8k synthetic + 14.5k real rows — and fine-tuned Qwen3-0.6B with GRPO to produce grammatically correct Dakota output on commodity hardware.
StoneyNakoda repo · Qwen3-0.6B-Dakota-Grammar-RL · live demo
Qwen3-0.6B · GRPO · synthetic data · RLHF
GRPO experiments on 0.5B-parameter bases, showing that structured reward shaping can coax real reasoning out of models small enough to run on a laptop. AQuA-RAT, GSM8K, and Open-R1 math traces.
OneShotGRPO · nanochat-AquaRat · Qwen.5B-OpenR1Math
Qwen2.5-0.5B · GRPO · AQuA-RAT · GSM8K
A 62-face Archimedean solid where each vertex recursively contains another polyhedron. Most LLMs fail this on the coordinate math alone — which is precisely why it's a useful benchmark for code-gen reasoning.
Manim · computational geometry · Python
Black-Scholes implied-volatility surface across strikes and maturities. The shape of the smile is the thing exotic pricing actually trades against — bringing a CFA background to bear on visualization.
Black-Scholes · QuantLib · Manim
Hugging Face 9 models · 6 datasets · 6 Spaces
| Artifact | What it is | Link |
|---|---|---|
| Qwen3-0.6B-Dakota-Grammar-RL | Dakota grammar via GRPO, Qwen3-0.6B base | model |
| nanochat-AquaRat | RL on algebraic reasoning (AQuA-RAT) | model |
| Qwen.5B-OpenR1Math | Open-R1 style math reasoning, 0.5B | model |
| dakota-bilingual-qa | 2.45k Dakota-English Q&A pairs | dataset |
| synthetic_stoney_data | 68.8k synthetic Stoney Nakoda rows | dataset |
| StoneyNakoda | 14.5k real Stoney Nakoda corpus | dataset |
from transformers import AutoTokenizer, AutoModelForCausalLM import torch mdl = "HarleyCooper/Qwen3-0.6B-Dakota-Grammar-RL" tok = AutoTokenizer.from_pretrained(mdl) model = AutoModelForCausalLM.from_pretrained(mdl, torch_dtype=torch.float16, device_map="auto") print(tok.decode(model.generate(**tok("Translate to Dakota:", return_tensors="pt").to(model.device), max_new_tokens=64)[0], skip_special_tokens=True))
Auto-updated every 6 hours via GitHub Actions.
| Category | Date | Headline |
|---|---|---|
| - | - | Pending first run of the news workflow |
Proof — cited on Google Scholar · publicly engaged with @karpathy
X @christiancooper · LinkedIn · Hugging Face · dev.to · Kaggle