chore(training): retune stage-4 handling penalties and restart from Stage-3 foundation

Stage 4's upright/forward-motion telemetry plateaued flat across all three
blocked attempts because ground_tilt_penalty (0.003) was too weak to matter
and nothing penalized sideways/reverse motion at all. Raise
ground_tilt_penalty to 0.05 and add a new non_forward_penalty term
(ship_ai_controller.gd) that directly costs non-forward planar velocity near
the floor, independent of the ball. Delete the three blocked attempts'
checkpoints/logs/exports and reset generation5_state.json so the next run
starts fresh from the Stage-3 foundation checkpoint instead of continuing
from the drifted retry2 weights.
This commit is contained in:
Josh Creek
2026-08-09 13:09:12 +01:00
parent 005cd0c66e
commit c56f5ed1a3
14 changed files with 41 additions and 263 deletions
+11 -2
View File
@@ -43,7 +43,15 @@ STANDING_ARGS = ["--ent-coef", "0.01", "--entropy-floor"]
# Scoring/ball-direction shaping inherited from generation 4. Handling
# replaces half the orientation-agnostic closing reward and all generic speed
# reward with nose-led ground approach, while keeping global tilt pressure
# small enough for flight and adding a stronger floor-local term.
# small enough for flight. The first three Stage-4 attempts (2026-08-08/09)
# plateaued with upright_fraction/forward_motion_fraction flat at ~0.22-0.26
# against 0.45/0.25 floors for 120M cumulative timesteps: ground_tilt_penalty
# at 0.003 only cost a fully-sideways episode ~2.7 reward, trivial next to a
# goal (80) or a touch (0.7). ground_tilt_penalty is raised ~17x to 0.05 (a
# full sideways episode now costs ~45, comparable to a goal) and
# non_forward_penalty is a new term (ship_ai_controller.gd) directly costing
# sideways/reverse planar velocity near the floor, independent of the ball,
# since nothing previously penalized that at all.
HANDLING_REWARD_FLAGS = [
"--velocity-to-ball-weight", "0.04",
"--forward-velocity-to-ball-weight", "0.06",
@@ -53,7 +61,8 @@ HANDLING_REWARD_FLAGS = [
"--goal-reward", "80",
"--speed-reward-weight", "0.0",
"--tilt-penalty", "0.0002",
"--ground-tilt-penalty", "0.003",
"--ground-tilt-penalty", "0.05",
"--non-forward-penalty", "0.04",
]
STAGES = [
+3 -257
View File
@@ -1,260 +1,6 @@
{
"stage_index": 0,
"attempt": 2,
"status": "blocked",
"log": [
{
"stage_index": 0,
"stage_number": 4,
"stage_name": "handling",
"experiment": "20260808-1508-gen5-s4-handling",
"attempt": 0,
"telemetry_tail": {
"rollout/air_touch_fraction": 0.0004599999897181988,
"rollout/airborne_fraction": 0.42232042902708056,
"rollout/ep_len_mean": 137.51244003295898,
"rollout/ep_rew_mean": 6.987018242835998,
"rollout/forward_motion_fraction": 0.22800671431422234,
"rollout/goal_rate": 0.5818800025582314,
"rollout/mean_altitude": 4.261052157402038,
"rollout/productive_air_touch_fraction": 7.999999821186065e-05,
"rollout/upright_fraction": 0.22364509524405002,
"rollout/vertical_thrust_mean": 0.09885899936710485
},
"telemetry_failures": [
"rollout/goal_rate=0.5819 < 0.8000",
"rollout/upright_fraction=0.2236 < 0.4500",
"rollout/forward_motion_fraction=0.2280 < 0.2500"
],
"evaluation_goal_failures": [
"easy.json: goal_rate=0.750 < 0.800"
],
"side_balance_failures": [],
"eval": {
"timestamp": "2026-08-08T20:20:09+00:00",
"model_a": "/home/jcreek/ai-training/CosmicClash/Game/bots/20260808-1508-gen5-s4-handling.json",
"model_b": "/home/jcreek/ai-training/CosmicClash/Game/bots/promoted/easy.json",
"seed": 1,
"episodes": 100,
"wins_a": 45,
"wins_b": 30,
"draws": 25,
"side_results": {
"a_team_0": {
"wins_a": 18,
"wins_b": 19,
"draws": 13
},
"a_team_1": {
"wins_a": 27,
"wins_b": 11,
"draws": 12
}
},
"physical_team_wins": {
"team_0": 29,
"team_1": 46
},
"win_rate_a": 0.45
},
"evals": [
{
"timestamp": "2026-08-08T20:20:09+00:00",
"model_a": "/home/jcreek/ai-training/CosmicClash/Game/bots/20260808-1508-gen5-s4-handling.json",
"model_b": "/home/jcreek/ai-training/CosmicClash/Game/bots/promoted/easy.json",
"seed": 1,
"episodes": 100,
"wins_a": 45,
"wins_b": 30,
"draws": 25,
"side_results": {
"a_team_0": {
"wins_a": 18,
"wins_b": 19,
"draws": 13
},
"a_team_1": {
"wins_a": 27,
"wins_b": 11,
"draws": 12
}
},
"physical_team_wins": {
"team_0": 29,
"team_1": 46
},
"win_rate_a": 0.45
}
],
"decision": "fail"
},
{
"stage_index": 0,
"stage_number": 4,
"stage_name": "handling",
"experiment": "20260808-2120-gen5-s4-handling-retry1",
"attempt": 1,
"telemetry_tail": {
"rollout/air_touch_fraction": 0.00023999999463558198,
"rollout/airborne_fraction": 0.4264982384443283,
"rollout/ep_len_mean": 135.5532396697998,
"rollout/ep_rew_mean": 7.420562901496887,
"rollout/forward_motion_fraction": 0.2443552376627922,
"rollout/goal_rate": 0.5880400028824806,
"rollout/mean_altitude": 4.2706854009628294,
"rollout/productive_air_touch_fraction": 0.0,
"rollout/upright_fraction": 0.2381512857079506,
"rollout/vertical_thrust_mean": 0.07293799882452004
},
"telemetry_failures": [
"rollout/goal_rate=0.5880 < 0.8000",
"rollout/upright_fraction=0.2382 < 0.4500",
"rollout/forward_motion_fraction=0.2444 < 0.2500"
],
"evaluation_goal_failures": [],
"side_balance_failures": [],
"eval": {
"timestamp": "2026-08-09T02:28:48+00:00",
"model_a": "/home/jcreek/ai-training/CosmicClash/Game/bots/20260808-2120-gen5-s4-handling-retry1.json",
"model_b": "/home/jcreek/ai-training/CosmicClash/Game/bots/promoted/easy.json",
"seed": 1,
"episodes": 100,
"wins_a": 43,
"wins_b": 38,
"draws": 19,
"side_results": {
"a_team_0": {
"wins_a": 18,
"wins_b": 21,
"draws": 11
},
"a_team_1": {
"wins_a": 25,
"wins_b": 17,
"draws": 8
}
},
"physical_team_wins": {
"team_0": 35,
"team_1": 46
},
"win_rate_a": 0.43
},
"evals": [
{
"timestamp": "2026-08-09T02:28:48+00:00",
"model_a": "/home/jcreek/ai-training/CosmicClash/Game/bots/20260808-2120-gen5-s4-handling-retry1.json",
"model_b": "/home/jcreek/ai-training/CosmicClash/Game/bots/promoted/easy.json",
"seed": 1,
"episodes": 100,
"wins_a": 43,
"wins_b": 38,
"draws": 19,
"side_results": {
"a_team_0": {
"wins_a": 18,
"wins_b": 21,
"draws": 11
},
"a_team_1": {
"wins_a": 25,
"wins_b": 17,
"draws": 8
}
},
"physical_team_wins": {
"team_0": 35,
"team_1": 46
},
"win_rate_a": 0.43
}
],
"decision": "fail"
},
{
"stage_index": 0,
"stage_number": 4,
"stage_name": "handling",
"experiment": "20260809-0328-gen5-s4-handling-retry2",
"attempt": 2,
"telemetry_tail": {
"rollout/air_touch_fraction": 0.0002799999937415123,
"rollout/airborne_fraction": 0.4334809045791626,
"rollout/ep_len_mean": 136.65584008789062,
"rollout/ep_rew_mean": 7.696315350532532,
"rollout/forward_motion_fraction": 0.23557147654891014,
"rollout/goal_rate": 0.5825200036764145,
"rollout/mean_altitude": 4.346557500362397,
"rollout/productive_air_touch_fraction": 3.999999910593033e-05,
"rollout/upright_fraction": 0.2288729049563408,
"rollout/vertical_thrust_mean": 0.06853299860764295
},
"telemetry_failures": [
"rollout/goal_rate=0.5825 < 0.8000",
"rollout/upright_fraction=0.2289 < 0.4500",
"rollout/forward_motion_fraction=0.2356 < 0.2500"
],
"evaluation_goal_failures": [
"easy.json: goal_rate=0.750 < 0.800"
],
"side_balance_failures": [],
"eval": {
"timestamp": "2026-08-09T08:36:44+00:00",
"model_a": "/home/jcreek/ai-training/CosmicClash/Game/bots/20260809-0328-gen5-s4-handling-retry2.json",
"model_b": "/home/jcreek/ai-training/CosmicClash/Game/bots/promoted/easy.json",
"seed": 1,
"episodes": 100,
"wins_a": 46,
"wins_b": 29,
"draws": 25,
"side_results": {
"a_team_0": {
"wins_a": 21,
"wins_b": 18,
"draws": 11
},
"a_team_1": {
"wins_a": 25,
"wins_b": 11,
"draws": 14
}
},
"physical_team_wins": {
"team_0": 32,
"team_1": 43
},
"win_rate_a": 0.46
},
"evals": [
{
"timestamp": "2026-08-09T08:36:44+00:00",
"model_a": "/home/jcreek/ai-training/CosmicClash/Game/bots/20260809-0328-gen5-s4-handling-retry2.json",
"model_b": "/home/jcreek/ai-training/CosmicClash/Game/bots/promoted/easy.json",
"seed": 1,
"episodes": 100,
"wins_a": 46,
"wins_b": 29,
"draws": 25,
"side_results": {
"a_team_0": {
"wins_a": 21,
"wins_b": 18,
"draws": 11
},
"a_team_1": {
"wins_a": 25,
"wins_b": 11,
"draws": 14
}
},
"physical_team_wins": {
"team_0": 32,
"team_1": 43
},
"win_rate_a": 0.46
}
],
"decision": "fail"
}
]
"attempt": 0,
"status": "in_progress",
"log": []
}
+6
View File
@@ -358,6 +358,11 @@ def parse_args():
"--ground-tilt-penalty", type=float, default=None,
help="Low-altitude-only tilt cost that fades to zero by the handling-height threshold",
)
curriculum.add_argument(
"--non-forward-penalty", type=float, default=None,
help="Overrides ShipAIController.non_forward_penalty (low-altitude dense cost on sideways/reverse "
"planar velocity, independent of the ball)",
)
curriculum.add_argument(
"--speed-reward-weight", type=float, default=None,
help="Overrides the orientation-agnostic own-speed reward (generation 5 handling sets it to zero)",
@@ -391,6 +396,7 @@ def _curriculum_kwargs(args) -> dict:
"team_size": args.team_size,
"ai_tilt_penalty": args.tilt_penalty,
"ai_ground_tilt_penalty": args.ground_tilt_penalty,
"ai_non_forward_penalty": args.non_forward_penalty,
"ai_velocity_to_ball_weight": args.velocity_to_ball_weight,
"ai_forward_velocity_to_ball_weight": args.forward_velocity_to_ball_weight,
"ai_ball_distance_penalty": args.ball_distance_penalty,