Meta-Reinforcement Learning
Meta RL trains one starting policy across many small worlds so a new world takes a few practice tries instead of months of retraining.
Why Does This Exist?
Plain RL starts from scratch on every task. A walker tuned for speed 2.0 falls when friction shifts or the target moves to 3.5, and retraining burns millions of steps again. That is fine for one lab demo and painful everywhere else.
Meta RL changes the objective. Instead of one fixed MDP, it trains over a task distribution where members share states and actions but differ in dynamics or rewards. The score is post adaptation return after one or a few trial episodes, not day one return. This page shows the two loop math and one hand computed meta step. For the gradient starter method see MAML in RL, for reusing skills see transfer and generalization, and for no shot behavior see zero and few shot RL.
You need one idea first. A task here is one MDP. The distribution is the bag of MDPs you train over, with some held out to test fast adaptation.
Think of It Like This
A decathlete learning a new event
A sprinter tuned for one dry track trips on wet grass with hurdles. A decathlete trains across ten events and builds shared primitives: balance, drive, pacing, quick calibration.
Hand the decathlete a new event and two warm up tries are enough to set stride and post a solid score. No ten year rebuild.
Where the analogy stops: athletes keep fixed bodies while meta RL updates weights through nested gradients, memory states, or inferred task codes, and it can forget if the training bag is too narrow.
How It Actually Works
Let be shared start weights, inner step size, and outer step size. Let be trial episodes on task and fresh episodes after adaptation. Let be task loss.
Inner loop adapts once per task:
Outer loop scores the adapted weights and moves the start:
In words: adapt fast inside, then shift the start toward points from which many tasks are one step away. Three builds use this differently: gradient starts like MAML take explicit steps, recurrent policies carry memory across episodes, and context methods infer a task code and condition on it.
Worked example
One weight policy with , so . Loss is with targets and . Start , , .
- Task 1 gradient . Adapted . Loss .
- Task 2 gradient . Adapted . Loss .
- Meta loss .
Through the inner step each loss derivative gains factor . Task grads become and , average . New start . The diagram shows the same 1.2, 1.6, and 1.128.
Code
The snippet runs one inner adapt plus one meta update.
def adapt(theta: float, target: float, alpha: float = 0.2) -> float: """One inner gradient step on squared tracking loss.""" return theta - alpha * (theta - target)
if __name__ == "__main__": t1 = adapt(1.0, 2.0) t2 = adapt(1.0, 4.0) print(round(t1, 4)) print(round(t2, 4)) print(round((0.5 * (t1 - 2.0) ** 2 + 0.5 * (t2 - 4.0) ** 2) / 2, 4)) print(round(1.0 - 0.1 * -1.28, 4))# -> expected output:1.21.61.61.128Watch Out For
Training on a narrow task bag and memorizing the average
The symptom: meta training loss falls, but a held out friction or goal breaks adaptation. The start collapsed to a compromise policy for the few speeds you sampled rather than a real adaptation rule.
The fix: randomize dynamics and goals over wide ranges, and split tasks into train and test bands. Ship only when post adapt return beats zero shot return on unseen bands.
The Quick Version
- Meta RL trains a shared start so new tasks from solve in one to three tries.
- The inner loop adapts per task while the outer loop moves the start to help all tasks at once.
- From 1.0 the example reaches 1.2 and 1.6 on targets 2.0 and 4.0, with meta loss 1.60.
- The meta gradient is , so the start moves to in one outer step.
- Wide task variety plus held out test tasks keeps the method honest.