poolcoach / scripts /eval_position.py
masterdanh's picture
deploy: snapshot for HF Space
78738de
Raw
History Blame Contribute Delete
2.76 kB
#!/usr/bin/env python3
"""Đánh giá MỘT model bất kỳ trên PositionPlayEnv với mẫu lớn.
Dùng để chốt câu hỏi thống kê (Q có tăng thật không) sau smoke test —
eval 200 cú chỉ có ~27 cú pot, SE của Q|pot ~±0.05, cần n lớn hơn.
Chạy từ gốc repo:
# model stage 2 (obs đủ 6 chiều):
python scripts/eval_position.py models/ppo_pos_20260714_204549/best_model.zip --episodes 1000
# model stage 1 (position-blind, cắt obs 4 chiều):
python scripts/eval_position.py models/ppo_20260711_210650/final_model.zip --episodes 1000 --obs-slice 4
"""
from __future__ import annotations
import argparse
import sys
from pathlib import Path
sys.stdout.reconfigure(encoding="utf-8")
sys.stderr.reconfigure(encoding="utf-8")
ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(ROOT / "src"))
sys.path.insert(0, str(ROOT / "scripts"))
def main():
p = argparse.ArgumentParser()
p.add_argument("model_path", help="đường dẫn model (.zip)")
p.add_argument("--algo", choices=["ppo", "sac"], default="ppo")
p.add_argument("--episodes", type=int, default=1000)
p.add_argument("--obs-slice", type=int, default=None,
help="cắt obs còn N chiều đầu (model stage 1: 4)")
p.add_argument("--pos-coef", type=float, default=None,
help="khớp với run cần chấm (chỉ ảnh hưởng reward mean)")
p.add_argument("--aim-mode", choices=["best_cut", "any"], default=None,
help="khớp env lúc train (ảnh hưởng aim_cos/reward mean, "
"không ảnh hưởng pot/Q)")
args = p.parse_args()
import numpy as np
from stable_baselines3 import PPO, SAC
from train_position import evaluate, print_stats
cls = PPO if args.algo == "ppo" else SAC
model = cls.load(args.model_path)
print(f"== {args.model_path} trên PositionPlayEnv ==")
print(f" (deterministic, {args.episodes} cú"
+ (f", obs cắt {args.obs_slice} chiều" if args.obs_slice else "") + ")\n")
stats = evaluate(model, n_episodes=args.episodes,
pos_coef=args.pos_coef, obs_slice=args.obs_slice,
aim_mode=args.aim_mode)
print_stats(stats)
# SE xấp xỉ cho Q|pot để đọc kết quả cho đúng
n_pot = round(stats["pot_rate"] * args.episodes)
if n_pot > 1:
# Q ∈ [0,1], std thô ~0.25 (ước lượng bảo thủ)
se = 0.25 / np.sqrt(n_pot)
print(f"\n n cú pot ≈ {n_pot} → SE(Q|pot) ≈ ±{se:.3f}"
f" (Q|pot ± 2·SE = [{stats['q_mean_on_pot']-2*se:.3f}, "
f"{stats['q_mean_on_pot']+2*se:.3f}])")
if __name__ == "__main__":
main()