Training job Reinforcement Learning (RL) otonom berisiko tinggi mengalami degradasi performa di tengah jalan akibat sifat optimasi non-stasioner. Masalah umum seperti policy collapse, reward hacking, loss explosion, atau lonjakan KL-divergence dapat menghanguskan kuota komputasi GPU bernilai ribuan dolar tanpa menghasilkan model yang valid jika dibiarkan berjalan tanpa supervisi. Solusi baku untuk pipeline otonom adalah memasang watchdog telemetry, automated circuit breaker, dan automated checkpoint rollback.

1. Desain Watchdog Telemetry: Deteksi Anomali Real-Time

Watchdog bertindak sebagai evaluator independen di luar proses optimasi utama. Watchdog tidak menunggu siklus evaluasi selesai; komponen ini memeriksa step telemetry pada setiap batch pembaruan gradien.

Metrik Kritis Divergensi

  • Approximate KL Divergence: Lonjakan tajam ($D_{KL}(\pi_{old} \parallel \pi_{new}) > \delta$) menandakan policy melompat terlalu jauh dari trust region, memicu destruksi kapabilitas yang telah dipelajari.
  • Policy Entropy: Penurunan drastis mendekati nol menandakan premature convergence di mana policy kolaps menjadi deterministik sebelum mengeksplorasi state space secara memadai.
  • Value Loss Explosion: Nilai loss critic yang mendadak melompat ke skala eksponensial atau menghasilkan nilai non-finite (NaN/Inf).
  • Reward Drawdown: Penurunan moving average reward melebihi batas toleransi persentase tertentu (misal: drop 30% dari historical peak rolling window).

2. Mekanisme Circuit Breaker Komputasi GPU

Pola Circuit Breaker mencegah loop training yang rusak mengonsumsi alokasi GPU lebih lama. Status circuit breaker diklasifikasikan ke dalam tiga state:

  • Closed (Normal): Training berjalan normal. Metrik berada dalam batas aman. Snapshot checkpoint tersimpan secara berkala.
  • Open (Tripped): Pelanggaran metrik terdeteksi melampaui ambang toleransi step berturut-turut. Sinyal terminasi (SIGTERM) dikirim ke worker training, alokasi vRAM dilepaskan, dan eksekusi komputasi distop seketika.
  • Half-Open (Recovery): Worker di-restart dari snapshot stabil terakhir dengan learning rate tereduksi atau seed environment baru untuk menguji apakah jalur optimasi dapat dipulihkan.

3. Strategi Snapshot dan Rollback Checkpoint

Menyimpan checkpoint setiap epoch tidak efisien. Terapkan strategi rolling validated snapshots:

  1. Staging Buffer: Checkpoint disimpan ke direktori temporer setiap $N$ step.
  2. Validation Gate: Snapshot hanya dipromosikan ke pointer stable_checkpoint_latest jika watchdog mengonfirmasi metrik stabilitas (KL divergence stabil, value error terbatas) selama $M$ step pasca-checkpoint.
  3. Symlink Swapping: Rollback dieksekusi dengan mengarahkan symlink active checkpoint kembali ke snapshot stabil terakhir, membersihkan replay buffer yang terpolusi data corrupt.

4. Implementasi Script: Watchdog & Rollback Engine

Implementasi Python berikut mendeteksi anomali metrik dan memicu rollback checkpoint secara deterministik.

import os
import sys
import math
import shutil
from pathlib import Path
from dataclasses import dataclass

@dataclass
class WatchdogThresholds:
    max_kl: float = 0.05
    min_entropy: float = 0.01
    max_value_loss: float = 50.0
    patience: int = 3

class RLWatchdog:
    def __init__(self, base_dir: Path, thresholds: WatchdogThresholds):
        self.base_dir = base_dir
        self.th = thresholds
        self.consecutive_failures = 0
        self.stable_ckpt_dir = base_dir / "checkpoints" / "stable"
        self.current_ckpt_dir = base_dir / "checkpoints" / "current"

    def inspect_step(self, metrics: dict) -> bool:
        # Deteksi NaN / Inf langsung trigger fail
        for key in ["kl", "entropy", "value_loss"]:
            val = metrics.get(key, 0.0)
            if math.isnan(val) or math.isinf(val):
                sys.stderr.write(f"CRITICAL: Non-finite value detected in {key}\n")
                return False

        kl_fail = metrics.get("kl", 0.0) > self.th.max_kl
        ent_fail = metrics.get("entropy", 1.0) < self.th.min_entropy
        vloss_fail = metrics.get("value_loss", 0.0) > self.th.max_value_loss

        if kl_fail or ent_fail or vloss_fail:
            self.consecutive_failures += 1
        else:
            self.consecutive_failures = 0

        return self.consecutive_failures < self.th.patience

    def trigger_rollback(self):
        sys.stderr.write("WATCHDOG: Divergensi kritis terdeteksi. Memulai rollback...\n")
        if not self.stable_ckpt_dir.exists() or not any(self.stable_ckpt_dir.iterdir()):
            raise RuntimeError("Rollback gagal: Tidak ada checkpoint stabil tersedia.")

        # Bersihkan directory saat ini dan timpa dengan checkpoint stabil terakhir
        shutil.rmtree(self.current_ckpt_dir, ignore_errors=True)
        shutil.copytree(self.stable_ckpt_dir, self.current_ckpt_dir)
        sys.stderr.write("WATCHDOG: Rollback ke checkpoint stabil selesai. Status pulih.\n")

# ponytail: simple inline execution check, upgrade ke Redis stream pub/sub jika multi-node
if __name__ == "__main__":
    watchdog = RLWatchdog(Path("./training_run"), WatchdogThresholds())
    corrupted_metrics = {"kl": 0.12, "entropy": 0.005, "value_loss": 120.0}
    
    # Simulasi failure steps
    for _ in range(3):
        is_healthy = watchdog.inspect_step(corrupted_metrics)
        if not is_healthy:
            watchdog.trigger_rollback()
            break

Berikut automasi runner Bash untuk memonitor exit code watchdog dan melakukan restart job secara otomatis:

#!/usr/bin/env bash
set -euo pipefail

MAX_RETRIES=3
RETRY_COUNT=0
BASE_DIR="./training_run"

while [ $RETRY_COUNT -lt $MAX_RETRIES ]; do
    echo "[RUNNER] Menjalankan training worker (Attempt: $((RETRY_COUNT+1)))..."
    
    # Training dijalankan dengan python watchdog terintegrasi atau sidecar
    if python3 train_worker.py --work-dir "${BASE_DIR}"; then
        echo "[RUNNER] Training selesai tanpa kendala divergensi."
        exit 0
    else
        EXIT_CODE=$?
        echo "[RUNNER] Job training crash atau diputus Watchdog. Exit code: ${EXIT_CODE}"
        
        # Eksekusi sinkronisasi checkpoint recovery
        python3 -c "from rl_watchdog import RLWatchdog, WatchdogThresholds; from pathlib import Path; RLWatchdog(Path('${BASE_DIR}'), WatchdogThresholds()).trigger_rollback()"
        
        RETRY_COUNT=$((RETRY_COUNT+1))
        # Turunkan learning rate sebesar 50% untuk mitigasi instabilitas
        export LEARNING_RATE_MULTIPLIER=$(echo "scale=2; 1 / (2^${RETRY_COUNT})" | bc)
        echo "[RUNNER] Restart worker dengan LR Multiplier: ${LEARNING_RATE_MULTIPLIER}"
    fi
done

echo "[RUNNER] Circuit breaker terkunci: Mencapai limit retry maksimum. Hentikan alokasi GPU."
exit 1

5. Postmortem Checklist: Mencegah Recursive Compute Waste

Saat circuit breaker mematikan proses training otonom berulang kali, lakukan audit menggunakan checklist berikut sebelum mengalokasikan ulang GPU node:

  • Audit Replay Buffer: Pastikan trajectory observasi tidak terkontaminasi oleh transisi transien crash environment atau nilai reward invalid pasca-rollback.
  • Gradient Clipping Validation: Periksa apakah max norm clip gradien diset terlalu longgar (misal: norm > 0.5 pada PPO/SAC sering memicu spike KL).
  • Advantage Normalization Check: Pastikan batch normalization pada Generalized Advantage Estimation (GAE) tidak membagi angka dengan deviasi baku bernilai 0 (tambahkan konstanta $\epsilon$ yang memadai).
  • Reward Scale Consistency: Periksa apakah fungsi reward environment mengalami scaling drift atau reward hacking yang memicu kurva optimasi jatuh ke jurang divergensi.
  • Hyperparameter LR Decay: Validasi scheduler learning rate agar decay tidak berhenti terlalu dini saat transfer policy iterasi baru dimulai.