Unit 9 — Imitation Learning
Skip the reward engineering entirely. Record an expert playing the game, then train a policy to copy that behavior. Study MultiLevelRobot, record demonstrations, run Behavioral Cloning (BC), and optionally extend to GAIL.
Prerequisites
Time
Reading: ~30 min · Training: ~20 min GPU / ~1.5 h CPU
Three ways to see your AI
Godot (record yourself, watch the clone) · TensorBoard (train/loss for BC; ep_rew_mean for GAIL) · demonstration replay: step through your own recorded actions
1 · Why imitation learning?
Reward shaping takes iteration. Imitation learning sidesteps the reward design problem entirely: instead of telling the agent what to maximize, you show it what to do.
Two main approaches:
| Method | What it learns from | Algorithm | Reward needed? |
|---|---|---|---|
| Behavioral Cloning (BC) | Expert trajectories | Supervised classification/regression | No |
| GAIL | Expert trajectories | Adversarial (discriminator + generator) | No (intrinsic) |
| DAgger | Interactive expert corrections | Iterative supervised | Partially |
BC is the simplest: treat each (observation, action) pair as a supervised example, train a policy to predict the expert's action. Fast to train, brittle to distribution shift.
GAIL trains a discriminator to distinguish expert from agent trajectories, using its output as an intrinsic reward. Slower but more robust.
The alignment connection
BC on expert demonstrations (learning to clone human actions from transitions) is the direct analogue of supervised fine-tuning (SFT) in language model alignment — the conceptual on-ramp to the sequel course on RL from human feedback.
2 · MultiLevelRobot
MultiLevelRobot is a 3D platformer robot that must navigate across platforms of varying height. Reward engineering is tricky (small platforms, long fall distances). It's an ideal imitation learning candidate: a human can demonstrate the route easily; the agent cannot discover it efficiently by random exploration.
- Clone godot_rl_agents_examples →
examples/MultiLevelRobot - Open in Godot .NET, enable plugin
- Read
ai_controller.gd: observations include body velocity, ground raycasts, and platform distances; actions are continuous (jump force + lateral movement)
3 · Record expert demonstrations
Godot RL Agents supports a human heuristic mode: set Control Mode on the Sync node to HUMAN, then play the game yourself. The sync node records every (obs, action) pair.
Step-by-step:
- Open
training_scene.tscn - Select the
Syncnode → setControl ModetoHUMAN - Run the scene in the Godot editor
- Play through several complete episodes (aim for 20–50 successful runs)
- Stop the scene — demonstrations are saved to
demonstrations.json(or the path set in Sync properties)
# No code changes needed — the Sync node handles recording automatically
# Check Sync node properties for:
# record_demonstrations = true
# demonstrations_path = "res://demonstrations.json"
Quality over quantity
20 high-quality demonstrations (reaching the goal every time) beat 200 mediocre ones. Re-record if you fell off platforms more than once per run.
4 · Install the imitation library
imitation provides BC, GAIL, DAgger, and AIRL on top of Stable Baselines 3.
5 · Behavioral Cloning
import numpy as np
from stable_baselines3 import PPO
from godot_rl.wrappers.stable_baselines_wrapper import StableBaselinesGodotEnv
from imitation.algorithms import bc
from imitation.data import rollout
import json
# Load the environment (needed to define obs/action spaces)
env = StableBaselinesGodotEnv(
env_path="./MultiLevelRobot.x86_64",
n_parallel=1,
speedup=1,
)
# Load recorded demonstrations
with open("demonstrations.json") as f:
demo_data = json.load(f)
# Convert to imitation Transitions format
obs = np.array([d["obs"] for d in demo_data])
acts = np.array([d["action"] for d in demo_data])
dones = np.array([d["done"] for d in demo_data])
next_obs = np.roll(obs, -1, axis=0)
transitions = rollout.Transitions(
obs=obs[:-1],
acts=acts[:-1],
infos=np.array([{}] * (len(obs) - 1)),
next_obs=next_obs[:-1],
dones=dones[:-1],
)
# Build a PPO policy to clone into
policy = PPO("MlpPolicy", env, verbose=0)
# Behavioral Cloning trainer
trainer = bc.BC(
observation_space=env.observation_space,
action_space=env.action_space,
demonstrations=transitions,
policy=policy.policy,
rng=np.random.default_rng(42),
)
trainer.train(n_epochs=50)
policy.policy = trainer.policy
policy.save("multilevel_bc")
env.close()
What to expect: Loss drops quickly in the first 10 epochs. After 50 epochs, the policy mimics the expert's movement but may fail on slightly different platform layouts (distribution shift).
6 · Fine-tune with PPO after BC
BC gives a strong starting point. A short PPO fine-tuning run often fixes distribution shift:
from stable_baselines3 import PPO
from godot_rl.wrappers.stable_baselines_wrapper import StableBaselinesGodotEnv
env = StableBaselinesGodotEnv(
env_path="./MultiLevelRobot.x86_64",
n_parallel=8,
speedup=20,
)
# Load BC-initialized policy and continue with PPO
model = PPO.load("multilevel_bc", env=env)
model.learn(total_timesteps=500_000, tensorboard_log="logs/")
model.save("multilevel_bc_finetune")
env.close()
In TensorBoard, ep_rew_mean should start significantly higher than a random-init PPO run — the BC policy gives the agent a head start into the useful part of the state space.
Done when
demonstrations.jsonexists andtrain_bc.pyloads it without a key or shape error — the smoke test for the recording setup in Section 3.- BC loss drops sharply within the first ~10 epochs and keeps falling, as Section 5 describes. A curve that is flat from epoch 1 usually means the obs/action arrays were mis-parsed, not that you need more demonstrations.
- At the viz checkpoint (Section 8), the fine-tuned agent visibly follows the route you demonstrated. In TensorBoard, the fine-tune run's
ep_rew_meanstarts clearly above a from-scratch PPO baseline. - A pure-BC clone that freezes once nudged off-path is expected — that is distribution shift, and exactly what the fine-tuning in this section is for. If even the fine-tuned agent never completes the route, re-record cleaner demonstrations before touching hyperparameters.
7 · GAIL (optional)
GAIL trains a discriminator alongside the policy. The discriminator predicts "is this trajectory from the expert or the agent?"; the agent receives a reward for fooling it.
from imitation.algorithms.adversarial.gail import GAIL
from imitation.rewards.reward_nets import BasicRewardNet
from stable_baselines3 import PPO
env = StableBaselinesGodotEnv(env_path="./MultiLevelRobot.x86_64", n_parallel=4, speedup=20)
learner = PPO("MlpPolicy", env, verbose=1, tensorboard_log="logs/")
reward_net = BasicRewardNet(env.observation_space, env.action_space)
gail_trainer = GAIL(
demonstrations=transitions, # from section 5
demo_batch_size=1024,
gen_replay_buffer_capacity=2048,
n_disc_updates_per_round=4,
venv=env,
gen_algo=learner,
reward_net=reward_net,
)
gail_trainer.train(total_timesteps=1_000_000)
learner.save("multilevel_gail")
env.close()
GAIL is slower but generalises better. Use it if BC fine-tuning still fails on novel platform arrangements.
8 · Viz checkpoint
Re-run with the Godot editor (Sync → ONNX_INFERENCE after export, or open the scene and load the model manually):
- Does the robot follow the route you demonstrated?
- Does it recover when it slides off-path slightly (GAIL / fine-tune)? Or does it freeze (pure BC)?
- Compare: run the BC-only model, the fine-tuned model, and a scratch PPO baseline side-by-side
A good BC agent looks "human-like" — it hesitates at the same spots you hesitated, takes the same path. If it drifts into an untrained state, GAIL fails gracefully; pure BC fails catastrophically.
9 · Stretch goals
- DAgger — iterative imitation: run the policy, let the expert label the new states it visits, retrain. Fixes distribution shift systematically. Available in
imitation.algorithms.dagger. - Compare data efficiency — how many demonstrations does BC need to match 500k PPO steps?
- Mixed reward — combine GAIL's intrinsic reward with a sparse environment reward (reaching the goal) to keep the policy on-task
What's next
RLHF & Preference Learning: You've learned to clone behaviour from demonstrations. What if you only have a designer's taste — no explicit reward, just pairwise preferences? RLHF turns human judgement into a reward model that guides policy fine-tuning.
Self-check before you move on
Can you answer these in your own words?
- What problem does imitation learning solve that PPO + reward shaping doesn't, and at what cost?
- What is distribution shift in Behavioral Cloning, and why does it usually require either fine-tuning or DAgger to fix?
- Why is BC supervised learning, but GAIL is reinforcement learning?
- After BC, why does fine-tuning with PPO usually help — what does PPO add that pure imitation can't?
- Pick one Godot environment from earlier units — would expert demos help or hurt compared to from-scratch PPO, and why?
If you can answer all five — you're ready.
Self-check answers
- Imitation learning removes the need to design a reward function — instead of telling the agent what to maximize, you show it what to do. The cost: you need an expert who can demonstrate the task, and a pure clone can never exceed the behaviour contained in those demonstrations.
- Distribution shift: BC only sees states the expert visited, so one small mistake drifts the clone into states with no training data, where it has no idea how to act. Fixing it requires data from those off-path states — PPO fine-tuning (the agent collects its own experience there) or DAgger (the expert labels the new states).
- BC minimises a supervised loss over fixed (observation, action) pairs — no environment interaction during training. GAIL must roll out in the environment and maximise an intrinsic, discriminator-based reward with PPO, which makes it reinforcement learning.
- PPO collects its own experience — including the off-path states BC never saw — and improves the policy there, fixing distribution shift and even letting the agent surpass the demonstrator. Pure imitation can never get better than its data.
- Open answer — example: for a sparse-reward environment from an earlier unit like CrossTheRoad (Unit 3), demos help, because random exploration rarely stumbles onto a full crossing on its own. For a simple dense-reward environment like BallChase or JumperHard, mediocre demos could hurt by anchoring the policy to suboptimal behaviour that from-scratch training would outgrow on its own.