게시판바둑 on-policy 학습: 대국 로그를 KataGo 라벨로 바꾸기예제 소스

예제 소스

바둑 on-policy 학습: 대국 로그를 KataGo 라벨로 바꾸기 · 파일 169개

experiment_gemma.sh

#!/usr/bin/env bash
# Gemma 4 + lora_baduk_v2 실험 — 제약 최소 vs 현재 Qwen급 제약 비교
#
#   ./scripts/experiment_gemma.sh coords          # 좌표 grounding만 (serve 불필요)
#   ./scripts/experiment_gemma.sh serve-loose     # :9319 느슨한 Gemma serve
#   ./scripts/experiment_gemma.sh serve-tight     # :9319 강한 제약 Gemma serve
#   ./scripts/experiment_gemma.sh probe           # 빈 바둑판 1수 probe
#
set -euo pipefail
cd "$(dirname "$0")/.."
ROOT="$PWD"
PY="$ROOT/.venv/bin/python"
export HF_HOME="$ROOT/vlm_models"
export HF_HUB_CACHE="$ROOT/vlm_models"
export TOKENIZERS_PARALLELISM=false

GEMMA_SNAP="$(ls -d vlm_models/models--mlx-community--gemma-4-e4b-it-4bit/snapshots/* 2>/dev/null | tail -1)"
GEMMA_MODEL="${GEMMA_MODEL:-$GEMMA_SNAP}"
LORA="${LORA:-vlm_models/lora_baduk_v2}"
OUT="$ROOT/logs/gemma_experiment"
mkdir -p "$OUT"

log() { echo "[$(date '+%H:%M:%S')] $*"; }

run_coords() {
  local fmt="$1"
  local trials="${2:-24}"
  local tag="coords_${fmt}"
  log "verify-coords $fmt trials=$trials"
  "$PY" -m vlm_server.verify_coords \
    --model "$GEMMA_MODEL" \
    --lora-dir "$LORA" \
    --board-format "$fmt" \
    --trials "$trials" \
    --out-jsonl "$OUT/${tag}.jsonl" \
    2>&1 | tee "$OUT/${tag}.log"
  tail -5 "$OUT/${tag}.log"
}

coords_suite() {
  log "Gemma=$GEMMA_MODEL"
  log "LoRA=$LORA"
  run_coords compact 24
  run_coords aligned 24
  log "결과: $OUT/coords_*.log"
}

kill_port() {
  local p="$1"
  local pid
  pid="$(lsof -tiTCP:"$p" -sTCP:LISTEN 2>/dev/null || true)"
  if [[ -n "$pid" ]]; then
    log "kill :$p pid=$pid"
    kill -TERM $pid 2>/dev/null || true
    sleep 2
    kill -9 $pid 2>/dev/null || true
  fi
}

start_serve() {
  local mode="$1"
  local logfile="$OUT/serve_${mode}.log"
  local jsonl="$OUT/play_${mode}.jsonl"
  kill_port 9319
  sleep 1

  local extra=()
  if [[ "$mode" == "loose" ]]; then
    # 학습(SFT)과 동일 compact + 제약 최소
    extra=(
      --board-repr compact
      --text-only-move
      --temperature 0.35
      --max-new-tokens 96
      --illegal-retry-max 3
      --illegal-retry-budget-s 45
      --no-score-guided
    )
  else
    # 현재 Qwen 운영과 비슷한 강한 제약
    extra=(
      --board-repr aligned
      --text-only-move
      --temperature 0.2
      --max-new-tokens 96
      --illegal-retry-max 16
      --illegal-retry-budget-s 240
      --score-guided
      --score-min-line 3
    )
  fi

  log "serve gemma ($mode) → :9319"
  nohup "$PY" -m vlm_server serve \
    --host 127.0.0.1 --port 9319 \
    --model "$GEMMA_MODEL" \
    --lora-dir "$LORA" \
    "${extra[@]}" \
    --log-jsonl "$jsonl" \
    >>"$logfile" 2>&1 &

  for _ in $(seq 1 120); do
    if lsof -tiTCP:9319 -sTCP:LISTEN >/dev/null 2>&1; then
      log "serve UP ($mode) log=$logfile"
      return 0
    fi
    sleep 2
  done
  log "serve FAILED — tail $logfile"
  tail -30 "$logfile"
  return 1
}

probe_empty() {
  if ! lsof -tiTCP:9319 -sTCP:LISTEN >/dev/null 2>&1; then
    log "9319 없음 — 먼저 serve-loose 또는 serve-tight 실행"
    exit 1
  fi
  log "probe empty board"
  "$PY" -m vlm_server.probe_move --host 127.0.0.1 --port 9319 \
    --sgf /dev/null 2>/dev/null || \
  "$PY" <<'PY'
import socket, struct, io
from pathlib import Path
import sys
sys.path.insert(0, ".")
from vlm_server.dataset_baduk import BOARD_SIZE, render_board_png
from vlm_server.probe_move import MAGIC_GO19, MAGIC_RPLY, _u32be, _recv_exact

board = bytes([0] * (BOARD_SIZE * BOARD_SIZE))
img = render_board_png(board, BOARD_SIZE, px=256)
buf = io.BytesIO()
img.save(buf, format="PNG")
png = buf.getvalue()
body = bytearray([BOARD_SIZE, 2])
body += _u32be(len(png))
body += png
body += board
body += _u32be(1)
body.append(0)
sock = socket.create_connection(("127.0.0.1", 9319), timeout=10)
sock.sendall(MAGIC_GO19 + _u32be(len(body)) + body)
head = _recv_exact(sock, 4)
print("reply head", head)
flag = _recv_exact(sock, 1)[0]
if flag == 1:
    r, c = _recv_exact(sock, 1)[0], _recv_exact(sock, 1)[0]
    print(f"move row={r} col={c} pass={r==0xFF and c==0xFF}")
else:
    n = struct.unpack(">H", _recv_exact(sock, 2))[0]
    print("error", _recv_exact(sock, n).decode())
PY
}

case "${1:-coords}" in
  coords) coords_suite ;;
  serve-loose) start_serve loose ;;
  serve-tight) start_serve tight ;;
  probe) probe_empty ;;
  *)
    echo "usage: $0 {coords|serve-loose|serve-tight|probe}"
    exit 1
    ;;
esac