b509195ee9
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
127 lines
5.0 KiB
Bash
Executable File
127 lines
5.0 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# curriculum_retrain.sh — sequential curriculum retraining for PPO_Bot v2.
|
|
# Bots in order: Fire → MyFirstDroid → Target → MyFirstLeader → Crazy → Corners → PaintingBot → MyFirstBot
|
|
set -uo pipefail
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
|
PPO_BOT_SRC="$REPO_ROOT/PPO_Bot_garage"
|
|
|
|
# Source hyperparams (but we'll override opponent/rounds/log per phase)
|
|
ENV_FILE="$SCRIPT_DIR/training.env"
|
|
[ -f "$ENV_FILE" ] && set -a && . "$ENV_FILE" && set +a
|
|
|
|
JAR="${TANK_ROYALE_JAR:-/home/davide/Projects/tank-royale/runner/examples/lib/robocode-tankroyale-runner.jar}"
|
|
export PPO_BOT_DIR="$PPO_BOT_SRC"
|
|
export SAMPLE_BOTS_DIR="${SAMPLE_BOTS_DIR:-/home/davide/Projects/tank-royale/sample-bots/java/build/archive}"
|
|
|
|
LOGS_DIR="$SCRIPT_DIR/logs"
|
|
SNAPSHOTS_DIR="$SCRIPT_DIR/snapshots"
|
|
SUMMARY="$LOGS_DIR/curriculum_retrain_summary.txt"
|
|
mkdir -p "$LOGS_DIR" "$SNAPSHOTS_DIR"
|
|
|
|
ROUND_COUNTER_FILE="$PPO_BOT_SRC/weights/round_counter.txt"
|
|
|
|
echo "=== PPO_Bot v2 curriculum retrain — $(date) ===" | tee -a "$SUMMARY"
|
|
|
|
# ── compile once up front (run.sh does this; curriculum skipped it) ───────────
|
|
echo ">>> Compiling PPO_Bot..."
|
|
(cd "$PPO_BOT_SRC" && nimble build -d:release)
|
|
echo ">>> Compiling RunTraining.java..."
|
|
(cd "$SCRIPT_DIR" && javac -cp "$JAR" RunTraining.java)
|
|
echo ">>> Compilation done."
|
|
|
|
# ── helpers ──────────────────────────────────────────────────────────────────
|
|
|
|
run_java() {
|
|
# run_java <opponent> <rounds>
|
|
local opp="$1" rounds="$2"
|
|
local remaining="$rounds"
|
|
local attempts=0
|
|
while [ "$remaining" -gt 0 ]; do
|
|
attempts=$(( attempts + 1 ))
|
|
[ "$attempts" -gt 1 ] && sleep 2
|
|
java -cp "$SCRIPT_DIR:$JAR" RunTraining "$opp" "$remaining" || \
|
|
echo ">>> Java exited non-zero (crash/restart expected)"
|
|
local done=0
|
|
[ -f "$ROUND_COUNTER_FILE" ] && done=$(cat "$ROUND_COUNTER_FILE" 2>/dev/null || echo 0)
|
|
remaining=$(( rounds - done ))
|
|
# Guard: if counter didn't advance at all on this attempt, something is
|
|
# fundamentally broken (bad binary, missing bots dir, etc.) — abort rather
|
|
# than loop forever.
|
|
if [ "$attempts" -ge 3 ] && [ "$done" -eq 0 ]; then
|
|
echo "ERROR: round_counter still 0 after $attempts attempts — aborting" >&2
|
|
exit 1
|
|
fi
|
|
done
|
|
}
|
|
|
|
count_wins() {
|
|
# count_wins <jsonl_file> → prints win count
|
|
# grep -c exits 1 on zero matches (not an error) which was triggering || echo 0
|
|
# making WINS="0\n0". Use awk which always exits 0.
|
|
local f="$1"
|
|
[ -f "$f" ] || { echo 0; return; }
|
|
awk '/"win":true/{c++} END{print c+0}' "$f"
|
|
}
|
|
|
|
snap_weights() {
|
|
local label="$1"
|
|
local counter
|
|
counter=$(cat "$ROUND_COUNTER_FILE" 2>/dev/null || echo 0)
|
|
local dst="$SNAPSHOTS_DIR/v2_${label}_r${counter}"
|
|
cp -a "$PPO_BOT_SRC/weights/latest" "$dst"
|
|
echo " snapshot → $dst"
|
|
}
|
|
|
|
# ── curriculum ────────────────────────────────────────────────────────────────
|
|
|
|
declare -A TRAIN_ROUNDS=( [Fire]=200 [MyFirstDroid]=200 [Target]=200 [MyFirstLeader]=200 [Crazy]=200
|
|
[Corners]=400 [PaintingBot]=400 [MyFirstBot]=1000 )
|
|
BOTS=(Fire MyFirstDroid Target MyFirstLeader Crazy Corners PaintingBot MyFirstBot)
|
|
GATE=150
|
|
GATE_PASS=148
|
|
|
|
for BOT in "${BOTS[@]}"; do
|
|
TR="${TRAIN_ROUNDS[$BOT]}"
|
|
echo "" | tee -a "$SUMMARY"
|
|
echo "══ $BOT (train=${TR} gate=${GATE}) ══" | tee -a "$SUMMARY"
|
|
|
|
# Reset round counter so run_java terminates correctly for each phase
|
|
echo 0 > "$ROUND_COUNTER_FILE"
|
|
|
|
# ── training phase ──────────────────────────────────────────────────────────
|
|
TRAIN_LOG="$LOGS_DIR/${BOT}_train.jsonl"
|
|
export TRAINING_OPPONENT="$BOT"
|
|
export TRAINING_ROUNDS="$TR"
|
|
export PPOB_LOG_FILE="$TRAIN_LOG"
|
|
unset PPOB_EVAL_ONLY
|
|
> "$TRAIN_LOG"
|
|
echo " [train] $TR rounds..." | tee -a "$SUMMARY"
|
|
run_java "$BOT" "$TR"
|
|
echo " [train] done" | tee -a "$SUMMARY"
|
|
|
|
# ── gate eval ───────────────────────────────────────────────────────────────
|
|
echo 0 > "$ROUND_COUNTER_FILE"
|
|
EVAL_LOG="$LOGS_DIR/${BOT}_eval.jsonl"
|
|
export TRAINING_ROUNDS="$GATE"
|
|
export PPOB_LOG_FILE="$EVAL_LOG"
|
|
export PPOB_EVAL_ONLY=1
|
|
> "$EVAL_LOG"
|
|
echo " [eval] $GATE rounds..." | tee -a "$SUMMARY"
|
|
run_java "$BOT" "$GATE"
|
|
|
|
WINS=$(count_wins "$EVAL_LOG")
|
|
if [ "$WINS" -ge "$GATE_PASS" ]; then
|
|
STATUS="PASS ($WINS/$GATE)"
|
|
snap_weights "$BOT"
|
|
else
|
|
STATUS="FAIL ($WINS/$GATE)"
|
|
fi
|
|
echo " [gate] $STATUS" | tee -a "$SUMMARY"
|
|
unset PPOB_EVAL_ONLY
|
|
done
|
|
|
|
echo "" | tee -a "$SUMMARY"
|
|
echo "=== curriculum complete — $(date) ===" | tee -a "$SUMMARY"
|