Reactive Optimizers: rewrite the optimizer's source code during training

原始链接: https://xingjianbai.com/reactive-optimizers/

Hacker News new | past | comments | ask | show | jobs | submit login Reactive Optimizers: rewrite the optimizer's source code during training ( xingjianbai.com ) 5 points by matt_d 1 hour ago | hide | past | favorite | discuss help Consider applying for YC's Winter 2027 batch! Applications are open till November 2. Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact Search:
相关文章

原文
← Xingjian Bai

Xingjian Bai, Jia-Hao Liang, Jayden Teoh, Vincent Sitzmann
October 2026

TL;DR We put an agent at the heart of the optimizer. It watches the training dynamics, reacts to them, and rewrites the optimizer’s source code as training goes. When no recipe has been tuned for a task, it matches or beats the best recipe one could pick off the shelf, across image and language tasks. Further, we demonstrate that it spontaneously comes up with sophisticated schedules and intricate strategies to prevent loss spikes and escape overfitting. Try it on your own training run with the OPAL package.

X post: x.com/SimulatedAnneal/status/2112936831398375800

LightningDiT-XL/1 on ImageNet

Today, the recipe used to optimize a deep neural network is typically completely determined before training even begins. A great deal of human ingenuity has gone into priors regarding how training should progress: adaptive step sizes [1], preconditioning [2, 3], orthogonalized updates [4, 5], schedules tied to the training step [6, 7], and learning rates scaled with model size [8]. Automated discovery [9, 10, 11, 12] searches across many runs for better optimizers. Whether hand-crafted or automatically discovered, the optimizer then runs unchanged through the end of training, adapting, if at all, according to rules written in advance. This scope leaves the following questions unanswered: How should an optimizer respond to an unexpected loss spike or stall? What if one module's gradients start to oscillate while the others keep improving smoothly? And when a new type of architecture trains poorly with Adam or Muon, is the architecture worse, or has it not yet met an optimizer suited to it?

In this post, we attempt to expand the scope of conventional optimizers and make them reactive to the training itself, leading to an ever-adapting optimizer inside a single training run. This reactive optimizer reasons on the spot and writes the weight update rule for each parameter group. Directly writing optimization code, it has the freedom to implement complicated schedules, respond to training accidents, and customize the optimizer for the single training episode in which it exists. Building on earlier attempts to adapt optimizers during training [12, 13, 14] and to let a model direct its own fine-tuning [15], the reactive optimizer is entirely zero-shot, with nothing learned or retained from repeated runs, and puts the optimizer's entire algorithm up for rewriting.

We start with a practical situation, with tasks from image generation and language modeling, in which a reactive optimizer can do much better than static ones. We then turn to the emergent properties of the reactive optimizer, including sophisticated scheduling, suppressing loss spikes, and escaping overfitting. Lastly, we ask what all this costs and how practical it is at scale. We expect the reactive optimizer to grow only stronger with each generation of agents, to be most useful exactly where no recipe exists yet (for a new architecture or a new dataset), and to be one step toward solving the puzzles of deep learning optimization.

1. Training without a recipe

Suppose a PhD student has a new idea: a model of their own design, or a new dataset on which to train a transformer. They have one GPU for a single day only and a modest allotment of LLM API tokens, allowing for just one serious training run. What should the student do? The obvious course of action would be to pick the most standard training recipe, or one from a recent paper, and cope with the possibility that it might be unsuitable for their scenario, with spiking/stalling loss, etc.

The underlying question is broader: when bounded by GPU time, researcher time, or wall-clock time, how can a deep learning model be trained to its best performance without knowing the optimal optimization recipe in advance? New architectures, modalities, languages, and scientific data all fall into this setting, where few people can afford a sweep at scale.

A reactive optimizer offers another way to use that budget: it spends LLM tokens in place of GPU/human hours. With optimizers reacting to training incidents and adjusting themselves, much of the burden of recipe tuning can be reduced.

Results in brief

We start from the optimization track (Track 3) of modded-nanogpt [16], a language-model pre-training task (training a 162M GPT on FineWeb) with many recipes tuned specifically for this one setting. From this task, we create two slightly differing natural settings: (1) the same model trained on an alternate language dataset (we select Chinese, Thai, and Kyrgyz), and (2) the original setup with a quarter of the batch size. Neither comes with a recipe tuned for that setting, so we compare the reactive optimizer with the natural options one would have if they wanted to one-shot the new training: adopting five leaderboard recipes with natural adjustments. In all these new settings, the reactive optimizer outperforms or matches the best baseline (Figure 1).

We also apply the reactive optimizer directly to Goldfish [17], which proposes a dataset of 350 languages and trains one small GPT per dataset with a standard recipe not tuned for each language. This makes it an ideal ground to test the optimizer's adaptiveness in one shot. On the Amharic dataset, the official recipe ends at 83.48 bits per sentence on held-out FLORES-200 text (lower is better); the reactive optimizer, initialized with this same recipe, ends at 81.11 in one shot (on Swahili, we obtain a similar gain). Sweeping the learning rate of the standard recipe finds a static recipe that ends ahead of the reactive optimizer, at 80.89, but the reactive optimizer initialized from that swept recipe ends ahead again, at 80.73.

We also try the reactive optimizer on image generation, a direction where the literature usually does not sweep optimization hyperparameters, since diffusion-model design and optimizer design are viewed as mostly orthogonal1. It ends ahead of the official recipe on LightningDiT-XL/1 ([18]; FID-50K 1.83 against 2.18 with guidance, 4.33 against 5.15 without), whose official recipe trains with AdamW, and on RAEv2-B (3.19 against 3.39), whose recipe trains with a Muon variant.

Figure 1 shows these runs, each with Claude Opus 5.5 powering the agent; we name our reactive optimizer OPAL (OPtimizer with an Agent in the Loop). Together, these results show that in one-shot settings, a reactive optimizer can lead to a better solution than adhering to a predetermined recipe.

modded-nanogpt Track 3
Task the 162M GPT of the modded-nanogpt optimization track (Track 3), the same runs in each setting: official NanoGPT, the track's own (FineWeb at the official batch of 524,288 tokens per update); NanoGPT, ¼ batch (FineWeb, 13,000 updates of 131,072 tokens); NanoGPT on Chinese, Thai and Kyrgyz (the 1 GB Goldfish Chinese, Thai and Kyrgyz sets, 3,000 updates of 524,288 tokens)
Metric official NanoGPT: the first update at which the validation loss reaches 3.28, the track's target (validation every 25 updates); ¼ batch: validation loss after 13,000 updates; Chinese, Thai and Kyrgyz: validation loss after 3,000 updates, for #46 and OPAL from #36 with #46's own readout (a moving average of the weights over the last updates), for the other records with the last weights; in Chinese and Thai, OPAL's bar is the mean of three runs. The loss bars start at c, the largest multiple of 0.1 at least 0.05 below the setting's lowest value: 3.2 (¼ batch), 4.0 (Chinese), 4.5 (Thai) and 3.7 (Kyrgyz)
Baseline five records from the leaderboard, #46, #30, #21 (Shampoo), #36 (the tuned Muon baseline) and #2 (AdamW), and OPAL from #36. The leaderboard lists 2,690, 2,930, 4,100 and 3,250 updates for #46, #30, #21 and #36; #2's bar in official NanoGPT is the leaderboard's 5,625: our own run of #2 ended at 3.28449 after 5,625 updates and never reached 3.28; at ¼ batch every record ran with all its learning rates ×¼.
Goldfish, Amharic
Task a 125M GPT trained from scratch on 1 GB of Amharic (Goldfish), 10 epochs (64,626 updates)
Metric bits per sentence on FLORES-200 (dev + devtest)
Baseline the official Goldfish recipe (AdamW, learning rate 1e-4, weight decay 0.01, 10% warmup, then linear decay; gradient clipping at 1.0); nine more static recipes, each for all 10 epochs: AdamW at learning rates 6e-4, 1e-3, 2e-3 and 4e-3 with weight decay 0.1 (a four-value sweep), AdamW at 3e-4 with weight decay 0.1 or 0.01 and at 1e-4 with weight decay 0.1, and Muon on the hidden block matrices in the official recipe and at learning rate 3e-4, weight decay 0.1. OPAL ran twice: from the official recipe (at its defaults, 50 decisions; shown by default) and from the sweep's best point, AdamW at learning rate 2e-3 (200 decisions; shown with the sweep)
LightningDiT-XL/1
Task image generation on ImageNet 256×256 in a VA-VAE latent space; LightningDiT-XL/1, 64 epochs
Metric FID-50K at the end, with and without guidance; the curve shows FID-10K during training
Baseline the official recipe, retrained by us, and the authors' released checkpoint (FID-50K 5.23 without guidance, 2.16 with)
RAEv2-B
Task image generation on ImageNet 256×256 in a representation-autoencoder latent space; RAEv2-B, 20 epochs
Metric FID-50K
Baseline the official recipe, which already trains with GMuon, a Muon variant

Figure 1. OPAL (OPtimizer with an Agent in the Loop), our reactive optimizer, across different settings. In most settings where optimization hyperparameters are not heavily tuned for, reactive optimizers improve the training loss and test performance upon the canonical choices. In modded-nanogpt, #2 is AdamW, #21 is Shampoo, #36 is a tuned Muon, and #30 and #46 are more elaborate Muon-based recipes.

Beyond the practical benefit, we are intrigued by the spontaneous decisions made by the zero-shot agent, after observing and analyzing the training dynamics in its own way. In the next two sections, we explore what the reactive optimizer chooses to watch and what it changes in response.

1 For example, the standard recipes of DiT and SiT [19] train with AdamW at one constant learning rate. That has begun to change, with Muon and its variants taken up for diffusion transformers (CMuon [20]; Li et al. [21]; RAEv2's GMuon [22]) and a recent controlled benchmark of optimizers for diffusion models [23].

2. Updating with spontaneous analysis

analysis.py self-written probes of training dynamics training run agent updater.py adapted optimizer for the next steps
Figure 2. The two programs the agent writes and rewrites iteratively during training. With code as the entire interface, we give the agent maximal freedom to choose what to watch and what to change.

Figure 2 shows how an agent updates the optimizer code on the fly. Concretely, we allow the agent to rewrite a file, updater.py, used in every step of optimization. We use code as the entire interface since this allows the agent to easily alter any part of the optimization. Yet, before the agent can make changes, it must observe, on its own, how training is progressing, leading to the second program it can rewrite, analysis.py.

What information should the agent use to make its decisions? Raw training states would be impractical: the weights, activations, and gradients would swamp its context. Instead, the statistics and geometry of training dynamics could be helpful for decisions, such as the gradient norm of each parameter group, the size of an update next to the weights it changes, the cosine between consecutive gradients, and which tensors exhibit unusually large gradient spikes. Therefore, as with the optimizer, we give the agent the most freedom: it writes a program, analysis.py, to extract whatever it wants to know from the training dynamics. Its self-written probes run throughout training, taking from the state of training whatever the agent asks for and handing it to the agent for its next decision.

We complete the bidirectional loop. Through analysis.py, training reaches the agent in whatever form the agent chooses to see it, and through updater.py, the agent's decisions reach every step of training. The two programs let the agent devise new optimization algorithms along the way with maximum flexibility.

3. What is dynamically changing during optimization?

In this section, we look at what the reactive optimizer does throughout training, examining the decisions behind these results. As a summary, Figure 3 shows when, how, and why each agent edits its code.

Drag to a red tick to see what the agent changed there and why.

All decisions that changed a program