예제 소스
바둑 on-policy 학습: 대국 로그를 KataGo 라벨로 바꾸기 · 파일 169개
run_heuristic_gemma4_r2.py
#!/usr/bin/env python3
"""지난 대국 국면을 휴리스틱 수로 다시 라벨해 Gemma 4를 이어서 학습하고, 5국을 둔다."""
from __future__ import annotations
import json
import os
import signal
import socket
import subprocess
import time
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
PY = ROOT / ".venv" / "bin" / "python"
OUT = ROOT / "logs" / "heuristic_gemma4_r2_20261009"
HOLD = ROOT / "logs" / "mariago_web_watch" / "GEMMA_HOLD"
LORA_FILE = ROOT / "logs" / "mariago_web_watch" / "gemma_lora.txt"
MODEL = "********"
BASE = "********"
LORA = "********"
PORT = 9341
def log(msg: str) -> None:
print(msg, flush=True)
def run(cmd: list[str], log_path: Path) -> int:
log("[runner] " + " ".join(cmd))
log_path.parent.mkdir(parents=True, exist_ok=True)
with log_path.open("ab") as fh:
return subprocess.call(cmd, cwd=ROOT, stdout=fh, stderr=subprocess.STDOUT)
def port_open(port: int) -> bool:
sock = socket.socket()
sock.settimeout(1)
try:
sock.connect(("127.0.0.1", port))
return True
except OSError:
return False
finally:
sock.close()
def wait_port(port: int, timeout_s: float) -> bool:
deadline = time.time() + timeout_s
while time.time() < deadline:
if port_open(port):
return True
time.sleep(5)
return False
def gemma_pids() -> list[int]:
try:
out = subprocess.check_output(["pgrep", "-f", r"vlm_server serve.*--port 9341"], text=True)
except subprocess.CalledProcessError:
return []
return [int(x) for x in out.split() if x.strip()]
def stop_gemma() -> None:
pids = gemma_pids()
if not pids:
log("[runner] gemma already down")
return
log(f"[runner] stop gemma {pids}")
for pid in pids:
try:
os.kill(pid, signal.SIGTERM)
except ProcessLookupError:
pass
deadline = time.time() + 40
while time.time() < deadline and (port_open(PORT) or gemma_pids()):
time.sleep(1)
for pid in gemma_pids():
try:
os.kill(pid, signal.SIGKILL)
except ProcessLookupError:
pass
def start_gemma() -> subprocess.Popen:
cmd = [
str(PY), "-m", "vlm_server", "serve",
"--host", "127.0.0.1", "--port", str(PORT),
"--model", MODEL, "--lora-dir", LORA,
"--text-only-move", "--board-repr", "aligned", "--no-score-guided",
"--illegal-retry-max", "16", "--illegal-retry-budget-s", "240",
"--log-jsonl", str(OUT / "gemma4.jsonl"),
]
OUT.mkdir(parents=True, exist_ok=True)
logf = open(OUT / "gemma_serve.stdout", "ab")
log(f"[runner] start gemma4 {LORA}")
proc = subprocess.Popen(cmd, cwd=ROOT, stdout=logf, stderr=subprocess.STDOUT, start_new_session=True)
if not wait_port(PORT, 600):
proc.terminate()
raise SystemExit("gemma4 did not listen")
log(f"[runner] gemma4 listening pid={proc.pid}")
return proc
def main() -> int:
OUT.mkdir(parents=True, exist_ok=True)
HOLD.parent.mkdir(parents=True, exist_ok=True)
HOLD.write_text("r2 train\n", encoding="utf-8")
stop_gemma()
try:
rc = run(
[
str(PY), "scripts/dataset_heuristic_teacher.py",
"--relabel",
"--source", "logs/heuristic_gemma4_20261009/matches.sqlite:BW",
"--source", "logs/gemma4_r5_20261009/matches.sqlite:BW",
"--source", "logs/heuristic_r5_eye_20261008/matches.sqlite:W",
"--out", "sft_data/heuristic_gemma4_r2",
],
OUT / "dataset.log",
)
log(f"[runner] dataset rc={rc}")
if rc != 0:
return rc
rc = run(
[
str(PY), "scripts/train_ladder_lora.py",
"--shape", "onpolicy",
"--data-name", "heuristic_gemma4_r2",
"--log-name", "gemma4_heuristic_r2",
"--model", MODEL,
"--base", BASE,
"--out", LORA,
"--shape-n", "2000",
"--skip-base-eval",
],
OUT / "train.log",
)
log(f"[runner] train rc={rc}")
if rc != 0:
return rc
LORA_FILE.write_text(LORA + "\n", encoding="utf-8")
start_gemma()
reg_path = ROOT / "scripts" / "models.json"
reg = json.loads(reg_path.read_text(encoding="utf-8"))
reg.setdefault("models", {})["gemma4_heuristic"] = {
"port": PORT,
"model": MODEL,
"lora": LORA,
"note": "휴리스틱 착수 2차 학습. 대국 때는 --no-score-guided.",
}
reg_path.write_text(json.dumps(reg, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
finally:
if HOLD.exists():
HOLD.unlink()
rc = run(
[
str(PY), "scripts/play_heuristic_vs_model.py",
"--port", str(PORT),
"--model-name", "gemma4_heuristic_r2",
"--games", "5",
"--max-moves", "0",
"--out-dir", str(OUT.relative_to(ROOT)),
],
OUT / "play.log",
)
log(f"[runner] match rc={rc}")
return rc
if __name__ == "__main__":
raise SystemExit(main())