Skip to content
AI360Xpert
Beta

Transfer Learning and Generalization

A policy trained on one task can jump-start learning on a related task, but only when the two tasks share structure. Otherwise the old habits hurt.

A fine-tuned policy jump-starts on the target task and reaches return 400 in 120k steps versus 500k from scratch, ending 40 points higher.
A fine-tuned policy jump-starts on the target task and reaches return 400 in 120k steps versus 500k from scratch, ending 40 points higher.

Why Does This Exist?

Training every new task from a random policy wastes samples. A warehouse robot that already learned to pick boxes should not relearn vision, grasping, and navigation from zero when the warehouse layout changes slightly. Transfer learning reuses the old policy or value function as the starting point for the new task, then fine-tunes it.

Here is the deal: reuse helps only when the tasks share structure. This page covers how transfer works in RL (pretrained initialization plus fine-tuning), how to measure whether it helped, and how to read the generalization gap across a spread of tasks. It does not re-teach supervised transfer, which lives at transfer learning, and it stays distinct from learning-to-learn approaches such as meta-reinforcement learning and MAML in RL, which optimize for adaptability itself.

You need one prerequisite idea first. A Markov decision process (MDP) is the task description: states, actions, transition dynamics, and rewards. A policy π(a∣s)\pi(a \mid s) is your rule for picking action aa in state ss. If those terms feel shaky, start with fundamentals of reinforcement learning, then come back.

Think of It Like This

The Delivery Driver in a New District

A courier spent a year delivering in one district. She knows the traffic rhythms, the parking tricks, and which apartment blocks have slow elevators. Then she moves to the next district over.

Week one, she is already fast: the driving habits, the parking instincts, and the elevator heuristics carry over. That head start is jumpstart performance. She also reaches her old delivery rate weeks earlier than a rookie would. That is time-to-threshold savings. After a year, she may settle at a slightly higher rating than a rookie ever reaches, because her bag of tricks is bigger. That is the asymptotic gain.

But suppose the new district is a beach town with ferry schedules and sand roads instead of city blocks. Her city tricks now mislead her: she queues at piers that no longer matter and spins wheels in sand. She performs worse than a rookie for a month. That is negative transfer.

Where the analogy stops: a driver notices the beach and adjusts on purpose. A policy has no such awareness. It keeps executing old weights until gradients overwrite them, so a bad initialization can cost more samples than starting fresh.

How It Actually Works

The transfer setup

Call the old task MsourceM_{source} (the source MDP) and the new one MtargetM_{target} (the target MDP). You already hold πsource\pi_{source}, a policy trained on the source, possibly with its value function VsourceV_{source}.

Transfer in deep reinforcement learning usually means one of three moves:

  • Policy initialization: copy the weights of πsource\pi_{source} into the new policy, then keep training on MtargetM_{target} with your usual algorithm. Early layers (perception, locomotion primitives) are often frozen for a while; later layers adapt first.
  • Value initialization: copy VsourceV_{source} or QsourceQ_{source} so bootstrapping starts from sane estimates instead of zeros. This matters most when rewards are sparse.
  • Behavior prior: keep πsource\pi_{source} frozen as a guide (for exploration or as a KL penalty) while a fresh policy learns. Use this when you fear the old weights will be overwritten too fast.

Fine-tuning is just continued training on MtargetM_{target} from this head start, usually with a smaller learning rate than the original run.

Three numbers that tell you if transfer helped

Run two agents on MtargetM_{target}: one from scratch, one fine-tuned. Compare their learning curves with three metrics:

  • Jumpstart: the initial gap. That is Jtune(0)−Jscratch(0)J_{tune}(0) - J_{scratch}(0), where JJ is expected return at step 00 of target training. In our worked example below it is 240−20=220240 - 20 = 220.
  • Time to threshold and total reward: how many target steps each agent needs to reach a fixed performance bar, plus the area under each curve. Faster crossing with equal final quality is a pure sample saving.
  • Asymptotic performance: the final gap once both curves flatten, Jtune(∞)−Jscratch(∞)J_{tune}(\infty) - J_{scratch}(\infty). Here 560−520=40560 - 520 = 40.

A transfer can win on jumpstart yet lose asymptotically if the initialization traps the policy in a worse local optimum. Report all three, not just the pretty early curve.

Worked example: from scratch versus fine-tuned

Take a grid navigation task. MsourceM_{source} has the goal in the north room; MtargetM_{target} moves it behind a new door but keeps the same corridors. Returns are undiscounted episode scores. Both agents train on MtargetM_{target} for 600k steps, and we checkpoint them at the same step counts:

  • From scratch returns: 20 at 0, 110 at 120k, 200 at 250k, 300 at 380k, 400 at 500k, 520 at 600k.
  • Fine-tuned returns: 240 at 0, 400 at 120k, 470 at 250k, 520 at 380k, 545 at 500k, 560 at 600k.

Now compute the three metrics by hand:

  • Jumpstart: 240−20=220240 - 20 = 220 points of free performance before any target training.
  • Time to the 400-point bar: scratch needs 500k steps, fine-tuned needs 120k. Steps saved: 500,000−120,000=380,000500{,}000 - 120{,}000 = 380{,}000, which is 380,000/500,000=76.0%380{,}000 / 500{,}000 = 76.0\% of the scratch budget. Speedup: 500,000/120,000≈4.17500{,}000 / 120{,}000 \approx 4.17x.
  • Asymptotic gain at 600k: 560−520=40560 - 520 = 40 points.

These are the same numbers drawn in the diagram above and recomputed in the code below.

The generalization gap across MDPs

Single-task transfer asks about one pair. Generalization asks about a spread: train on a distribution of MDPs p(M)p(M), then test on held-out MDPs from the same spread. The generalization gap is mean test return minus mean train return. A policy can ace its training seeds yet collapse on new layouts, frictions, or goals.

A common way to shrink that gap is domain randomization: train across randomized physics (friction, mass, latency) and visual conditions so one policy covers the whole spread instead of memorizing one simulator. That technique gets its own page; what matters here is the measurement habit. Always report training return and held-out return separately. In our example, a policy averaging 545 on training mazes but 470 on held-out ones has a gap of 545−470=75545 - 470 = 75 points, and no transfer claim is complete without that second number. If your target is a robot, the same logic extends to the simulation-to-hardware step, where unmodeled physics acts as one more held-out MDP.

Code

The snippet below recomputes every number quoted above from the two checkpoint series, so you can check the arithmetic instead of trusting it.

from typing import List

def transfer_metrics(    scratch: List[float],    finetuned: List[float],    scratch_steps_to_threshold: int,    finetuned_steps_to_threshold: int,    train_return: float,    heldout_return: float,) -> dict:    """Compute jumpstart, sample savings, asymptotic gain, and generalization gap."""    jumpstart = finetuned[0] - scratch[0]    saved = scratch_steps_to_threshold - finetuned_steps_to_threshold    pct_saved = 100.0 * saved / scratch_steps_to_threshold    speedup = scratch_steps_to_threshold / finetuned_steps_to_threshold    asymptotic_gain = finetuned[-1] - scratch[-1]    gen_gap = train_return - heldout_return    return {        "jumpstart": jumpstart,        "saved_steps": saved,        "pct_saved": pct_saved,        "speedup": speedup,        "asymptotic_gain": asymptotic_gain,        "generalization_gap": gen_gap,    }

if __name__ == "__main__":    scratch = [20, 110, 200, 300, 400, 520]    finetuned = [240, 400, 470, 520, 545, 560]    m = transfer_metrics(scratch, finetuned, 500_000, 120_000, 545.0, 470.0)    print(f"jumpstart: {m['jumpstart']:.0f}")    print(f"saved: {m['saved_steps']:.0f} steps ({m['pct_saved']:.1f}%), speedup: {m['speedup']:.2f}x")    print(f"asymptotic gain: {m['asymptotic_gain']:.0f}")    print(f"generalization gap: {m['generalization_gap']:.0f}")
# -> expected output:jumpstart: 220saved: 380000 steps (76.0%), speedup: 4.17xasymptotic gain: 40generalization gap: 75

Watch Out For

Negative transfer: the source policy actively hurts

The symptom: the fine-tuned curve sits below from-scratch for the first few hundred thousand steps, or never catches up. This happens when source and target dynamics disagree, for example a locomotion policy trained with low friction that keeps overshooting in a high-friction target, or a navigation policy whose memorized doorway no longer exists.

The fix: check task similarity before committing. Fine-tune with a short probe run (a tenth of your budget) and compare against scratch at that point. If the probe loses, try freezing less (or nothing), raising the learning rate back toward scratch levels, or mixing source and target experience instead of pure fine-tuning. Do not keep a losing initialization out of sunk-cost loyalty.

Overfitting the source and freezing too much

The symptom: great source return, flat target curve. The policy memorized source quirks (exact textures, exact timing) and frozen early layers prevent it from relearning. A related trap: copying the value function from a dense-reward source into a sparse-reward target, where stale value estimates mislead bootstrapping for a long time.

The fix: unfreeze from the top down and watch held-out return, not source return. Start by training only the final layers, then release earlier ones if held-out return stalls. When rewards differ between tasks, consider reinitializing the value head while keeping the policy trunk. For background on the supervised version of this habit, see the transfer learning definition.

The Quick Version

  • Transfer in RL means starting target training from a pretrained policy or value function, then fine-tuning, instead of starting from random weights.
  • Judge a transfer with three numbers: jumpstart (here +220), time to a fixed bar (here 120k versus 500k steps, a 380k-step saving at 4.17x), and asymptotic gain (here +40).
  • The generalization gap is mean held-out return minus mean training return across an MDP distribution (here 470 versus 545, a 75-point gap), and every transfer claim needs both numbers.
  • Negative transfer is real: when source and target dynamics disagree, the old policy can train slower than scratch, so run a short probe before committing the full budget.
  • Freezing too much preserves source quirks; unfreeze top-down and reinitialize the value head when reward shapes change.