Carlos Sanoja
All work

Pretraining against the clock on one Trainium2 chip

August 2026 to October 2026AWS Trainium Frontier Competition, Phase 13rd place, advanced to Phase 2

The task was to train a language model from scratch on one Trainium2 chip with a 30-minute training clock, scored by validation bits per byte (val bpb, lower is better). I started from the organizers' dense GPT baseline and changed the model shape, batch and schedule, compile-clock handling, kernels and numeric precision, one measured change at a time. The best official leaderboard score was 0.947182 (package 48, submitted 30 September 2026), which placed 3rd and passed the cut to the 10-team Phase 2. Phase 2 is still running, so this page covers Phase 1 only and stays at the level of technique categories.

1Problem

Phase 1 ran from 31 August to 30 September 2026. Each submission trains a language model from scratch on a single Trainium2 chip (a trn2.3xlarge instance) for 30 minutes of training clock, with compile and startup time excluded. The score is val bpb on a fixed shard of about 20 million tokens. The starting point is a dense GPT of roughly 50 to 60 million parameters derived from nanochat, using RMSNorm, rotary embeddings, a squared-ReLU MLP, and Muon plus AdamW. Almost everything can change except the data, tokenizer, preparation script and scoring harness. Teams get five submissions per week, and the top 10 advance.

The first thing I did was read the real training configuration instead of trusting the documentation. The baseline trained 59.6 million parameters on 1,000 steps of 65,536 tokens, about 1.1 tokens per parameter, at roughly 37.6 thousand tokens per second (about 13.4 TFLOP/s). That is a model far too large for the tokens it sees. I also found that my own first throughput estimate, made before reading the code, was off by a factor of 27, and I corrected it in the log.

2Approach

The work was a stack of small, separately measured changes rather than one recipe. By category:

Profiling drove the order. Training ran at 90 to 98 percent of the chip's power cap, the matrix engine was the bottleneck and was throttled by power, and each new wide tensor cost about 10 percent of step time. Those three facts decided which ideas were worth a trial. In all, 49 numbered packages are in the submissions directory of the private repository, with hundreds of dated log entries.

3Protocol

Every idea went through the same gates, because a 30-minute run on a rented chip is the scarce resource.

4Results

Official Phase 1 scores Sixteen official submissions between September 3 and September 30, 2026. Validation bits per byte fell from 1.1728 to 0.947182. Lower is better. 0.951.001.051.101.15 Sep 3Sep 10Sep 17Sep 24Sep 30 0.947182, final 3rd 1.1728, 1st on day one
All 16 official submissions in Phase 1 with the running best, from 1.1728 on 3 September to 0.947182 on 30 September 2026. Lower is better.
PackageDate (UTC)Official val bpbBoard position then
P2515 Sep0.970963rd
P2615 Sep0.9695893rd, later 6th
P3227 Sep0.9678775th
P3628 Sep0.9636634th
P4430 Sep0.9494063rd
P4630 Sep0.9485374th
P4830 Sep0.9471823rd, final

Measurement: all values above are official leaderboard scores on the held-out evaluation, one submission each. The board at close put the 10th place at 0.955399, a margin of 0.0082 for my entry, and the leader about 0.0144 ahead. Official evaluations take about 40 minutes to appear.

Noise and the local-to-official offset

QuantityValueMeasured on
Effect of one setting, seed 44 vs seed 42-0.000690 vs +0.001141Local, each against its own seed control
Pair noise floor0.000208Local, paired runs
Same code and seed, repeated, 8-bit setup0.960271 vs 0.962237Local, n=2
Local-to-official offset, five packages-0.0012 ± 0.0010Local mean vs official, n=5
Offsets in the 8-bit era (P35, P36, P38, P44, P46)-0.00086 to -0.001458Local run of the same seed vs official
bpb per ln(steps), 1200 to 1700 s0.06163Local, n=2 per point, seed 44
bpb per ln(steps), 1700 to 1800 s0.05538Local, n=2 per point, seed 44
bpb per ln(steps), 1800 to 2700 s0.04626Local, n=2 per point, seed 44

Measurement: local numbers are from 30-minute runs on the same chip type, not the leaderboard. The offset is not constant (it ranged from -0.0003 to -0.0033 across packages 22 to 32), so I quote it with its spread and never as a band around one point.

Two consequences shaped the plan. First, the slope of bpb against ln(steps) falls as the clock grows, so extra compute buys less than a constant slope suggests. Using the slope near the 30-minute budget, closing the 0.0144 gap to the leader would take roughly 30 to 37 percent more effective compute. Second, a single official evaluation cannot settle effects below about 0.003, so small gains were stacked locally and sent inside larger packages. I also measured the in-context-learning benchmark CORE once, on a single checkpoint on 20 September: 0.1073, against 0.1139 for GPT-2 124M. That is one measurement and says nothing about the lineage of packages.

5What did not work

A predicted gain that the leaderboard could not see

I predicted that a wider MLP variant would improve P26 by 0.00055. The official score for the package was 0.9697 against 0.969589 for P26, outside the predicted interval of 0.9686 to 0.9694. The local effect was smaller than what one official evaluation can separate from zero, so the submission slot bought no information.

A speedup that was a debug flag

An 8-bit MLP looked 27 percent faster in integration. The comparison arm without the flag showed that a debugging environment variable had been set on only one arm. Without it, the same operation ran 340 steps at 0.5212 s per step against 0.5308 s for bf16, about 1.8 percent faster.

Seed lottery

A sweep of six new seeds gave 0.965547 to 0.966626 locally (sd 0.00037), and none beat the existing two-run mean of 0.964177. Seed effects swing by about 0.0018, and a repeat of the same code and seed moved by 0.002 in the 8-bit setup, so a single run proves nothing about a seed. The last submission, P48, was a seed choice on the P46 code. It was worth about 0.0014, which is not a research result.

Dead ends in hardware and design

Attention in blocks of 128 crashed at run time. Sequence lengths below 512 were worse, and step time was flat between 512 and 1024. A scatter mode in a custom kernel aborted on the chip with a runtime error that the simulator never showed. A later architectural variant measured 0.001048 worse than the incumbent (n=2), and the optimizer and inter-replica agreement lines were closed with no measurable lever.

Measuring the wrong thing

My own CORE meter had three bugs worth +0.0480 that all passed 8 of 8 self-checks, and I caught them only later.

A compliance negative result

I built a scheme that used the training corpus as a non-parametric component at evaluation time. The organizers' review rejected it on 27 September, because what was evaluated differed from what was trained. The submission slot was spent, and I treat the rule as binding for anything similar.

Calendar

The rented chip block ended 30 minutes before its nominal end, which left about 20 hours at the end of Phase 1 with no chip to measure on.

6Lessons