Pokémon TCG AI Battle Working Note (1편): 규칙 기반에서 RL 파일럿까지
Pokémon TCG AI Battle Working Note (1편): 규칙 기반에서 RL 파일럿까지
2026-07-02에 처음 썼고, 2026-07-15까지 직접 구현하며 겪은 실패를 반영해 전면 개정했다. 완성된 RL 해법을 자랑하는 성공담은 아니다. RL을 잘 모르는 상태에서 출발해 무엇을 잘못 생각했는지, 시행착오 끝에 구현 순서를 어떻게 바로잡았는지를 정리한 실전 가이드이자 오답노트다.
대회 링크:
The Pokémon Company - PTCG AI Battle Challenge Simulation
1부. 문제부터 다시 정의하기
RL 기법부터 고르기 전에, 이 대회에서 모델이 무엇을 배워야 하는지 먼저 정리해야 했다. 이 장에서는 게임을 선택지에 순위를 매기는 문제로 바꿔 보고, 덱과 파일럿을 따로 본다. 뒤에서 계속 등장할 RL 용어도 꼭 필요한 만큼만 짚는다.
1. 먼저 결론: 이 문제에서 RL은 무엇을 해야 하는가
Pokémon TCG AI Battle에서는 시뮬레이터가 그 순간 가능한 행동을 목록으로 내준다. 에이전트가 규칙을 해석해 행동을 처음부터 만들어낼 필요는 없다. 현재 상황을 보고 목록에 있는 행동 가운데 무엇을 먼저 고를지 판단하면 된다.
\[a_t \in A_t = \text{Options}(o_t)\]여기서 $o_t$는 에이전트가 볼 수 있는 현재 상황이고, $A_t$는 그때 고를 수 있는 행동 목록이다. 모델은 목록에 들어 있는 선택지 $c_i\in A_t$마다 점수를 매긴다.
\[s_i=f_\theta(o_t,c_i), \qquad \pi_\theta(i\mid o_t,A_t)= \frac{\exp(s_i)}{\sum_{j\in A_t}\exp(s_j)}\]문제를 이렇게 바꿔 놓으면 RL을 어디서부터 적용할지도 한결 분명해진다.
1
2
3
4
5
6
규칙 기반 파일럿과 리플레이를 기록한다
-> 실제 선택을 따라 하는 행동 복제 모델을 만든다
-> 중요한 판단과 어려운 상대에서 생기는 오차를 고친다
-> 규칙과 학습 모델을 섞은 안전한 파일럿을 만든다
-> 결과와 상태가치를 이용해 좋은 행동에 더 큰 가중치를 준다
-> 충분한 평가 기반이 생긴 뒤 오프라인 RL과 자기 대전을 시도한다
처음에는 순서를 거꾸로 잡았다. “게임이니 RL을 써야 한다”, “RL이라면 자기 대전부터 해야 한다”고 성급하게 생각했다. 하지만 먼저 갖춰야 할 것은 믿을 만한 데이터, 상황을 표현하는 방법, 제대로 작동하는 상대 파일럿, 홀드아웃, 제출 패키지 검사였다. 이 토대가 없으면 PPO든 Q-learning이든 복잡한 방법을 얹을수록 잘못된 평가를 더 확신하게 될 뿐이다.
2. 덱, 파일럿, 래더 환경, 평가 방식을 따로 본다
처음에는 에이전트의 점수가 곧 덱의 힘이라고 여겼다. 돌이켜보면 가장 먼저 버렸어야 할 생각이었다.
| 구성 요소 | 답해야 하는 질문 |
|---|---|
| 덱 | 이 60장 구성은 어떤 승리 조건과 잠재력을 갖는가? |
| 파일럿 | 현재 상황에서 어떤 행동을 골라 그 잠재력을 얼마나 실현하는가? |
| 래더 환경 | 지금 어떤 덱과 운영 방식이 얼마나 많이 쓰이는가? |
| 평가 방식 | 로컬 상대와 게임 수만으로 실제 강도를 판단해도 되는가? |
실제 성적은 이 네 요소에 좌석과 운까지 함께 작용한 결과다.
\[\text{Observed Performance} =f(\text{deck},\text{pilot},\text{opponents},\text{seat},\text{variance})\]같은 덱 해시라도 팀이 운영 방식을 바꿨을 수 있다. 반대로 파일럿 코드가 같아도 덱이 달라지면 같은 선택의 의미가 달라진다. 그래서 학습과 평가 자료를 아키타입 이름 하나로 뭉뚱그리지 않고 다음처럼 더 잘게 나눴다.
1
(date, team, exact_deck_hash, policy_or_epoch, opponent, seat)
메타 분석은 여전히 필요하다. 다만 이 글에서 메타는 주인공이 아니다. 메타의 역할은 다음 세 가지다.
- 어떤 덱의 행동 데이터를 더 모아야 하는지 정한다.
- 어떤 상대 파일럿이 벤치마크에 빠져 있는지 찾는다.
- 현재 래더의 덱 비중에 맞춰 평가 상대의 비중도 조정한다.
점유율 그래프와 날짜별 매치업은 Meta Snapshot 노트북에서 따로 다룬다. 이 글에서는 그 자료를 RL 학습 데이터와 믿을 만한 평가 기준으로 바꾸는 과정에 집중한다.
3. RL을 처음 보는 사람을 위한 최소 용어
3.1 이 게임에서는 모든 정보를 볼 수 없다
상대 손패와 프라이즈, 덱에 남은 카드는 전부 보이지 않는다. 엄밀히 따지면 이 문제는 MDP보다 부분 관측 마르코프 의사결정 과정(POMDP)에 가깝다.
| 용어 | 이 프로젝트에서의 뜻 |
|---|---|
| 관측 $o_t$ | 현재 보드, 공개된 카드, 카운터, 로그, 이번 턴 사용 여부처럼 에이전트가 실제로 볼 수 있는 정보 |
| 선택지 목록 $A_t$ | 엔진이 현재 고를 수 있다고 제시한 가변 길이 행동 목록 |
| 정책 $\pi(a\mid o)$ | 관측 정보를 바탕으로 행동을 고르는 규칙 또는 모델 |
| 게임 궤적(trajectory) | 한 게임에서 이어지는 $(o_0,a_0,o_1,a_1,\ldots)$ 기록 |
| 보상 $r_t$ | 행동 뒤에 받는 학습 신호. 실제 목표는 최종 승패다. |
| 상태 가치 $V(o)$ | 지금 상황에서 앞으로 얻을 것으로 기대하는 결과 |
| 행동 가치 $Q(o,a)$ | 지금 특정 행동을 골랐을 때 기대하는 결과 |
| 어드밴티지 $A(o,a)$ | 그 행동이 현재 상황의 평균적인 선택보다 얼마나 나은지 나타내는 값 |
3.2 행동 복제는 RL이 아니라 좋은 출발점이다
행동 복제(Behavior Cloning, BC)는 리플레이에서 실제로 고른 행동을 정답 삼아 배우는 지도학습이다.
\[\mathcal L_{BC} =-\log \pi_\theta(a_t^*\mid o_t,A_t)\]BC 자체는 엄밀한 의미의 RL이 아니다. 보상을 직접 최적화하지 않고, 기존 파일럿의 선택을 따라 배우기 때문이다. 그래도 이 대회에서는 아주 중요한 출발점이 된다.
- 무작위 정책에서 카드 운용을 다시 배우지 않아도 된다.
- 수십만 개의 실제 판단을 지도학습 데이터로 쓸 수 있다.
- 선택지의 형태와 특징 추출이 제대로 연결됐는지 빠르게 확인할 수 있다.
- 이후 가치 학습, 오프라인 RL, 자기 대전을 시작할 초기 정책으로 쓸 수 있다.
결국 RL을 시작한다는 말은 곧바로 PPO부터 돌린다는 뜻이 아니었다. 먼저 학습할 수 있는 형태로 정책을 표현하고, 그 정책을 믿고 비교할 방법을 갖추는 일이었다.
2부. 리플레이를 행동 복제 데이터로 바꾸기
문제를 정리했으면 이제 학습 데이터를 만들 차례다. 복잡한 모델보다 먼저 상황과 행동을 정확히 짝지어야 한다. 학습할 때와 실제 게임에서 똑같은 특징을 쓰도록 코드도 나눠야 한다. 이 장에서는 가장 단순한 행동 복제 파일럿을 실제로 움직일 수 있는 형태까지 만들어 본다.
4. 리플레이에서 상황과 행동을 정확히 짝짓는다
CABT 리플레이를 뜯어보니 step $i$에서 본 선택지에 대한 답은 같은 step이 아니라 다음 step의 action에 기록돼 있었다.
1
2
features = steps[i][player].observation
label = steps[i + 1][player].action
둘을 잘못 맞추면 모델은 엉뚱한 선택을 정답으로 배운다. 더 위험한 점은 이렇게 틀린 데이터로도 정확도가 그럴듯하게 나올 수 있다는 것이다. 파서는 반드시 다음 조건을 확인해야 한다.
1
2
3
4
5
6
7
8
select = steps[i][player]["observation"].get("select")
action = steps[i + 1][player].get("action")
if not select or not select.get("option") or not action:
return None
n_options = len(select["option"])
assert all(0 <= idx < n_options for idx in action)
에이전트가 첫 호출에서 돌려주는 60장 덱 목록도 게임 중 행동과 따로 처리해야 한다. 카드 ID 60개를 선택지 인덱스로 착각하면 데이터 전체가 오염된다.
의사결정 하나를 저장할 때는 최소한 다음 정보가 필요하다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
DecisionRecord = {
"game_id": str,
"date": str,
"engine_version": str,
"player": str,
"team": str,
"deck_hash": str,
"opponent_deck_hash": str,
"outcome": int,
"turn": int,
"context": str,
"observation": dict,
"options": list[dict],
"chosen_indices": list[int],
}
원본 JSON을 실험할 때마다 다시 읽는 대신, 의사결정과 선택지 특징을 한 번 추출해 Parquet으로 저장한다. 날짜와 엔진 버전, 덱 해시도 함께 남긴다. 그래야 카드 풀이 바뀌거나 로그 형식이 달라져도 서로 다른 자료가 뒤섞이지 않는다.
5. 모델을 고르기 전에 코드의 역할부터 나눈다
지금까지 써본 구조 가운데 가장 다루기 쉬웠던 형태는 다음과 같다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
Archive/MMDD/
raw replay JSON
DecisionStore/YYYYMMDD/
decisions.parquet
option_rows.parquet
extraction_manifest.json
PilotModelStore/YYYYMMDD/MODEL_ID/
model.json or model.pt
feature_schema.json
train_manifest.json
offline_metrics.csv
PilotStore/YYYYMMDD/PILOT_ID/
main.py
deck.csv
model artifacts
package_validation.json
fidelity_report.json
pokemon_benchmark_runs/RUN_ID/
benchmark_manifest.json
matchup_matrix.csv
runtime_report.json
holdout_decision.json
코드 역시 이 흐름에 맞춰 역할별로 나눈다.
1
2
3
4
5
6
7
8
리플레이 파서
-> 항상 같은 결과를 내는 특징 추출기
-> 학습 자료 생성기
-> 학습기
-> 실제 게임에서 선택지 점수를 계산하는 모듈
-> 안전장치를 포함한 에이전트 래퍼
-> 패키지 검사기
-> 행동과 매치업을 실제처럼 재현하는지 확인하는 모듈
학습용 특징과 실행용 특징을 따로 만들면 거의 틀림없이 어긋난다. 학습 때는 썼지만 실제 게임에서는 구할 수 없는 값이 끼어들거나, 카드 ID 처리와 상태 정규화 방식이 달라질 수 있다. 하나의 특징 추출 모듈을 학습과 실행에서 함께 쓰고, 저장해 둔 같은 관측을 넣었을 때 완전히 같은 벡터가 나오는지 반드시 검사해야 한다.
실제 게임에서는 상대의 정확한 아키타입과 덱 해시, 최종 승패, 다음 행동을 알 수 없다. 이런 값은 학습 자료를 나누거나 결과를 평가할 때만 쓰고, 모델 입력에는 넣지 않는다.
6. 0단계: 규칙 기반 정책의 판단 근거부터 기록한다
규칙 기반 파일럿은 학습 모델이 나오기 전까지만 쓰는 임시방편이 아니다. 이후에도 세 가지 역할을 맡는다.
- 게임을 정상적으로 끝내며 학습 자료를 모으는 정책
- 학습 모델이 실제로 무엇을 개선했는지 비교할 기준
- 모델이 확신하지 못하거나 오류를 냈을 때 돌아갈 안전장치
따라서 0단계 에이전트는 행동만 반환하면 안 된다. 왜 그 행동을 골랐는지도 함께 남겨야 한다.
1
2
3
4
5
6
7
RuleDecision = {
"chosen": [2],
"rule_scores": [0.1, -0.5, 1.3, 0.2],
"decision_family": "attack",
"phase": "pressure",
"fallback_used": False,
}
의사결정 유형은 특정 카드 이름보다 일반적인 기능으로 나눈다.
1
2
setup / search / discard / attach / evolve / switch
attack / damage_target / effect_target / resource_management
이렇게 나눠두면 중요한 선택을 더 자주 학습시킬 수 있고, 모델이 어떤 판단에서 자주 무너지는지도 쉽게 찾을 수 있다.
7. 1단계: 고정 출력 분류기가 아니라 선택지 순위기를 만든다
고를 수 있는 행동의 수는 매번 달라진다. 클래스 0, 1, 2처럼 출력 개수를 고정한 분류기로는 다루기 어렵다. 대신 모든 선택지에 같은 네트워크를 적용해 점수를 매기는 순위 모델을 쓴다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class OptionRanker(nn.Module):
def __init__(self, state_dim, option_dim, hidden=192):
super().__init__()
self.state_encoder = MLP(state_dim, hidden)
self.option_encoder = MLP(option_dim, hidden)
self.head = MLP(hidden * 2, 1)
def forward(self, state, options, option_mask):
# state: [B, state_dim]
# options: [B, K, option_dim]
h_state = self.state_encoder(state)[:, None, :]
h_state = h_state.expand(-1, options.size(1), -1)
h_option = self.option_encoder(options)
scores = self.head(torch.cat([h_state, h_option], dim=-1)).squeeze(-1)
return scores.masked_fill(~option_mask, float("-inf"))
이 구조를 쓰면 선택지가 표시되는 순서가 바뀌어도 판단 기준은 그대로 유지된다. 선택지 수가 달라지는 문제는 mask로 처리할 수 있다.
여러 장을 골라야 할 때도 답을 고정 길이 벡터로 한꺼번에 내지 않는다. 하나를 고르면 그 항목을 다음 계산에서 빼고, minCount와 maxCount를 채울 때까지 점수를 다시 계산한다. 학습 자료도 같은 순서로 풀어 저장해야 학습할 때와 실제 게임에서 선택할 때의 과정이 어긋나지 않는다.
상태 특징
- 현재 턴과 선공 여부
- 양쪽 프라이즈, 손패·덱·벤치 수
- 액티브와 벤치 포켓몬의 HP, 에너지, 도구, 상태 이상
- 이번 턴에 서포터·에너지·후퇴를 사용했는지
- 상대가 공개한 액티브, 벤치, 버린 카드와 에너지
- 최근 공개 행동을 요약한 정보
선택지 특징
- 선택지 유형과 현재 선택 상황(context)
- 참조하는 카드, 포켓몬, 공격 ID
- 대상 위치와 플레이어
- 공격 비용, 예상 피해, KO 가능 여부
- 진화 관계, 에너지 부착, 이동이나 교체 여부
카드 ID 임베딩에만 기대면 모델이 특정 60장 구성을 외우기 쉽다. HP, 타입, 진화 단계, 공격 비용, 공개된 능력처럼 카드의 구조를 설명하는 특징도 함께 넣어야 카드 한두 장이 바뀌어도 어느 정도 대응할 수 있다.
8. 학습 자료를 어떻게 나누느냐가 모델보다 중요할 수 있다
8.1 의사결정 행을 무작위로 나누면 안 된다
한 게임에서 나온 수십 개의 판단은 서로 이어져 있다. 이를 행 단위로 무작위 분할하면 거의 같은 상황이 학습 자료와 검증 자료에 함께 들어가고, 정확도는 실제보다 높게 나온다.
최소한 게임 전체를 묶어 나누고, 가능하면 날짜와 정책 구간까지 분리한다.
1
2
3
train : 과거 날짜의 팀-덱-정책 구간
validation : 다른 날짜 또는 뒤쪽 정책 구간
holdout : 후보를 확정한 뒤 처음 도착한 미래 날짜
팀은 하루 사이에도 코드를 바꿀 수 있다. 그래서 같은 팀과 덱 해시가 이어지더라도 약 100개 게임씩 연속 구간(epoch)으로 나눠 보기도 했다. 이것으로 실제 코드 변경 시점을 정확히 알아낼 수는 없다. 다만 서로 다른 운영 방식이 학습과 검증에 마구 섞이는 위험은 줄일 수 있다.
8.2 이긴 플레이어의 행동만 배우면 생기는 문제
처음에는 이긴 쪽의 판단만 남기면 더 좋은 정답 데이터가 될 것이라고 생각했다. 평균적인 선택의 질은 나아질 수 있지만, 그 대신 다음과 같은 편향이 생긴다.
- 좋은 매치업이나 운 덕분에 실수하고도 이긴 행동이 정답이 된다.
- 어려운 상대에게 잘 버티고도 진 게임의 좋은 판단이 사라진다.
- 특정 강한 팀과 덱의 행동이 과도하게 반복된다.
- 불리해진 게임을 수습하는 판단은 거의 배우지 못한다.
현재는 양쪽 플레이어의 행동을 추출하고 다음 값을 별도로 보관한다.
1
2
3
4
outcome
opponent strength
deck / team / epoch identity
decision family and impact weight
BC 단계에서는 실제 선택을 그대로 정답으로 쓴다. 승패와 상대 난이도는 학습 비중을 조절하거나, 뒤의 AWR 단계에서 좋은 행동을 가려낼 때 활용한다.
8.3 쉬운 선택이 중요한 선택을 덮지 않게 한다
선택지가 하나뿐인 장면은 실행 테스트에는 필요하지만, 정책이 배울 내용은 거의 없다. 반면 공격과 후퇴, 진화, 서치, 버리기, 공격 대상 지정은 자주 나오지 않더라도 한 번의 실수가 승패를 바꾼다.
따라서 다음 지표를 따로 낸다.
1
2
3
4
5
6
overall top-1 / top-3
non-forced top-1 / top-3
critical-choice top-1 / top-3
decision-family accuracy
opponent and phase accuracy
mean chosen rank
결국 전체 정확도 하나만 보고서는 파일럿을 제대로 평가할 수 없었다.
3부. 행동 복제를 돌려보고 나서야 보인 문제들
첫 모델은 정상적으로 돌아갔고 오프라인 정확도도 제법 높았다. 하지만 그 숫자가 실제 게임 실력을 뜻하지는 않았다. 아래 네 번의 실패를 겪고 나서 데이터 분할 방식과 상대 구성, 홀드아웃 원칙을 모두 다시 잡았다.
9. 첫 번째 오답노트: 높은 모방 정확도는 강한 파일럿을 보장하지 않는다
가장 큰 착각은 오프라인 top-1 정확도가 높으면 실제 파일럿도 강할 것이라고 믿은 것이었다.
Dragapult의 한 60장 덱은 로그에서 강한 상대를 만나고도 좋은 성적을 냈다. 이 덱으로 학습한 파일럿 역시 홀드아웃 top-1 정확도가 60%를 넘었다. 그런데 전체 게임을 충분히 돌려 보니 두 정책의 승률은 각각 약 17.5%와 18.8%에 그쳤다.
왜 이런 일이 생겼을까?
- 자주 나오는 쉬운 선택을 잘 맞히면 전체 정확도가 높아진다.
- 초반에 카드 순서를 한 번 잘못 고르면 이후 게임 양상이 완전히 달라진다.
- BC 정책은 작은 실수 뒤에 원래 파일럿의 기록에는 없던 상황으로 들어간다.
- 실제 선택은 알려주지만, 선택하지 않은 행동이 얼마나 나빴는지는 로그에 없다.
- 평균적인 행동 패턴은 비슷해도 특정 매치업의 승패는 실제와 반대로 나올 수 있다.
따라서 오프라인 정확도는 다음 질문에만 답한다.
기존 파일럿이 실제로 만났던 상황에서, 모델이 같은 선택을 얼마나 자주 다시 고르는가?
다음 질문에는 답하지 못한다.
모델이 자기 실수로 만들어낸 상태에서도 게임을 끝까지 잘 운영하는가?
이것이 행동 복제에서 말하는 분포 이동과 누적 오차다. DAgger가 현재 정책이 실제로 들어간 상황을 다시 모아 학습하는 이유도 여기에 있다.
10. 두 번째 오답노트: 아키타입 평균 정책은 특정 60장 덱의 운영법이 아니다
초기 순위 모델은 아키타입과 선택 상황, 선택지 유형, 카드 ID의 등장 빈도를 주로 봤다. 구현은 간단했고 top-3 정확도도 제법 나왔지만, 보드 상황에 따라 같은 카드의 가치가 달라지는 문제는 풀지 못했다.
1
2
3
같은 공격이라도 상대 HP와 프라이즈 상황이 다르다.
같은 서치라도 손패, 덱, 버린 카드, 이번 턴 사용한 자원이 다르다.
같은 아키타입이라도 60장 구성과 승리 조건이 다를 수 있다.
그래서 v2에서는 60장 덱 해시 + 현재 상황 + 각 선택지를 함께 보는 쌍대 비교 순위 모델 (pairwise ranker)로 바꿨다. 실제로 고른 행동이 다른 행동보다 높은 점수를 받도록 학습한다.
\[\mathcal L_{pair} =\log\left(1+\exp\left[-(s_{chosen}-s_{other})\right]\right)\]현재 상황을 함께 보는 모델은 이전의 빈도 기반 모델보다 나았다. 하지만 이 역시 출발점일 뿐이었다. 2026-07-10 기준 특정 덱들의 오프라인 top-1은 약 58~70%까지 올라갔지만, 별도의 전체 게임 평가에서는 새 제출 후보가 기존 후보보다 낫다는 근거를 얻지 못했다.
11. 벤치마크 상대와 제출 후보는 같은 기준으로 볼 수 없다
한동안 모든 파일럿을 같은 기준으로 평가했다. 이것도 잘못이었다.
| 역할 | 목표 | 평가 기준 |
|---|---|---|
| 래더 재현용 파일럿 | 실제 래더의 해당 덱과 비슷하게 움직인다 | 행동 특성과 매치업 결과를 얼마나 잘 재현하는가 |
| 제출 후보 파일럿 | 같은 덱을 래더의 평균보다 더 잘 굴린다 | 기준 파일럿 대비 우위, 새 홀드아웃, 실행 안정성 |
래더 재현용 파일럿은 벤치마크에서 상대 역할을 맡는다. 실제 래더에서 A 덱이 B 덱에 우세했다면 로컬에서도 같은 방향이 나와야 한다. 이쪽은 실제 운영을 닮을수록 좋다.
제출 후보는 목적이 다르다. 실제 래더의 평균적인 파일럿보다 더 좋은 판단을 한다면, 기존 행동을 얼마나 닮았는지를 재는 점수는 오히려 낮아질 수 있다. 제출 후보에게 모방 점수를 강요하면 더 좋은 정책을 거꾸로 탈락시킬 수 있다.
이를 식으로 쓰면 목표가 다르다.
\[\text{Field proxy}:\quad \min_\pi |w_\pi(m)-w_{field}(m)|\] \[\text{Adoption pilot}:\quad \max_\pi w_\pi(m), \qquad w_\pi-w_{reference}>0\]그래서 학습을 마친 파일럿을 곧바로 제출 후보로 올리지 않는다. 먼저 실제 행동과 매치업을 얼마나 비슷하게 재현하는지 확인하고, 그 검사를 통과한 파일럿만 벤치마크 상대로 쓴다. 제출용 파일럿은 이와 별도로 탐색하고 홀드아웃에서 다시 검증한다.
12. 세 번째 오답노트: 약한 상대 파일럿은 후보를 강하게 보이게 한다
덱 목록을 정확히 복사했더라도 상대 파일럿이 그 덱을 제대로 굴리지 못하면 벤치마크는 지나치게 쉬워진다. 그 결과 내 후보의 로컬 성적이 실제보다 부풀려진다.
래더 재현용 파일럿은 최소한 두 가지를 점검한다.
행동 재현도
- 주요 판단 상황에서 선택 비율이 비슷한가?
- 공격, 서치, 후퇴, 진화 순서가 비슷한가?
- 초반, 전개, 압박, 마무리 단계의 행동 비중이 비슷한가?
- 드물지만 중요한 판단에서 모델이 대체 규칙에만 의존하지 않는가?
상성 재현도
실제 래더의 매치업 승률 $r_m$과 로컬 재현 파일럿의 승률 $\hat r_m$을 비교한다.
\[E_{fidelity} =\sum_m q_m|\hat r_m-r_m|\]$q_m$은 현재 래더에서 그 매치업이 얼마나 중요한지를 나타내는 가중치다. 평균 오차가 작더라도 중요한 매치업의 우열이 거꾸로 나오면 벤치마크 상대로 쓰지 않는다.
2026-07-14에 만든 Festival 계열 재현 파일럿 두 개는 같은 날의 실제 자료와 비교했을 때 매치업 오차가 약 4.6~5.7%p로 작았다. 그러나 학습 자료와 평가 자료의 날짜가 같았다. 아직 검증됐다고 볼 수 없어 상태를 needs_fidelity로 남겼다. 이후 날짜에서도 같은 상성 관계가 나타나는지 확인해야 한다.
13. 네 번째 오답노트: 같은 데이터로 고르고 검증하면 홀드아웃이 아니다
여러 모델과 규칙 혼합 비율을 시험한 뒤 최고값만 고르면, 그 숫자에는 실력뿐 아니라 운도 섞인다.
\[\hat p_{selected}=\max_i(p_i+\epsilon_i)\]후보가 많을수록 그중 하나가 우연히 높게 나올 가능성도 커진다. 흔히 승자의 저주라고 부르는 선택 편향이다. 이를 막기 위해 데이터가 맡는 역할을 세 가지로 나눴다.
| 구간 | 용도 |
|---|---|
| 학습 / 탐색 | 특징, 모델, 혼합 비율을 고른다. |
| 날짜 분리 검증 | 학습에 쓰지 않은 과거 날짜에서 모델 계열을 비교한다. |
| 건드리지 않은 최종 홀드아웃 | 후보와 상대 구성을 모두 고정한 뒤 도착한 미래 날짜에서 한 번만 사용한다. |
2026-07-14 Spidops 실험에서는 새 후보가 55.77%, 기존 기준 파일럿이 54.81%를 기록했다. 차이는 +0.96%p로, 미리 정해 둔 +3%p 통과선을 넘지 못했다. 가중 점수 몇 개에서는 새 후보가 크게 앞섰지만 표본이 적은 일부 매치업이 결과를 끌어올린 영향이 컸다. 따라서 승격시키지 않았다. 이 홀드아웃은 이미 한 번 판단에 썼으므로 이후 튜닝이나 같은 우위를 다시 주장하는 근거로 쓰지 않는다.
결과를 본 뒤 통과 기준을 바꾸기 시작하면 홀드아웃은 이름만 남는다. 후보와 상대 구성, 평가식, 통과선을 먼저 정하고 파일 해시와 실험 기록에 고정해야 한다.
4부. 학습 파일럿을 안전하게 실전에 연결하기
BC의 한계를 확인한 뒤에는 모델 크기부터 키우지 않았다. 학습 모델과 규칙 기반 정책의 역할을 나누고, 상대를 아직 충분히 알 수 없는 상황까지 다루도록 구조를 바꿨다. 모델은 자신 있는 판단만 맡고, 나머지는 검증된 규칙이 책임지는 파일럿을 만드는 것이 목표였다.
14. 안전한 실전 정책: 학습 모델과 규칙을 섞는다
지금 단계에서 가장 현실적인 제출 형태는 신경망 단독 정책이 아니라 규칙과 모델을 섞은 하이브리드다.
\[s_{final} =w_e s_{expert} +w_g s_{global} +w_r s_{rule}\]expert: 특정 판단 유형, 게임 단계, 추정 상대에 맞춘 전문 모델global: 전체 데이터로 학습한 공통 순위기rule: 검증된 규칙 기반 점수
비슷한 장면을 충분히 학습했고 선택지 사이의 점수 차이도 뚜렷할 때만 모델의 비중을 높인다. 상대를 아직 파악하지 못했거나, 비슷한 학습 예시가 적거나, 점수 차이가 작으면 검증된 규칙으로 돌아간다.
1
2
3
4
5
6
7
8
9
if route_coverage < coverage_floor:
return rule_choice(options)
scores = w_model * model_scores + w_rule * rule_scores
if confidence(scores) < confidence_floor:
return rule_choice(options)
return legal_top_k(scores, min_count, max_count)
제출용 래퍼는 다음 조건을 무조건 지켜야 한다.
1
2
3
4
5
6
첫 호출에서는 정확히 고정된 60장 덱을 반환한다.
게임 중에는 현재 선택지 안의 인덱스만 반환한다.
minCount와 maxCount를 지킨다.
중복 인덱스를 반환하지 않는다.
예외가 발생하면 엔진이 받아들일 수 있는 대체 행동을 반환한다.
로컬 저장소를 불러오지 않아도 독립 패키지에서 실행된다.
학습 결과가 아무리 좋아도 Validation Episode에서 패키지가 깨지면 아무 의미가 없다. 따라서 모델 평가에는 모듈 불러오기, 첫 호출의 덱 반환, 첫 행동, 미러 게임, 실행 시간 검사까지 포함한다.
15. 상대를 읽는 모델은 숨겨진 정답을 보면 안 된다
매치업마다 다른 전문 모델을 쓰려면 먼저 상대 덱을 추정해야 한다. 학습 자료에는 실제 아키타입과 덱 해시가 들어 있지만, 실제 게임에서는 알 수 없다. 라우터가 참고할 수 있는 것은 지금까지 공개된 카드뿐이다.
\[P(z\mid x_{visible}) \propto P(z)\prod_{c\in x_{visible}}P(c\mid z)\]$z$는 상대 아키타입이고, $x_{visible}$은 액티브와 벤치, 버린 카드, 붙은 에너지처럼 현재까지 드러난 정보를 뜻한다. 게임 초반에는 현재 래더의 덱 비중을 사전확률로 쓰고, 카드가 새로 보일 때마다 아키타입별 확률을 갱신한다.
라우터는 다음 지표로 검증한다.
1
2
3
4
turn별 top-1 / top-3 아키타입 정확도
turn별 예측 확신도와 엔트로피
판단 보류 또는 낮은 확신도의 비율
주요 아키타입 혼동 행렬
상대를 확실히 구분하지 못한 상태에서 특정 매치업용 모델을 억지로 쓰지 않는다. 이럴 때는 공통 모델과 규칙 기반 판단으로 돌아가는 편이 안전하다.
한 시점에 공개된 카드만으로 상대를 구분하기 어렵다면, 다음 단계에서는 최근 공개 행동을 GRU나 작은 Transformer로 묶어 볼 수 있다. 이때 hidden state는 게임이 시작될 때마다 초기화하고, 학습 배치에서도 게임의 시간 순서를 지켜야 한다. 단순한 피드포워드 모델보다 실제 매치업을 더 잘 재현하고 예측 확률도 더 정확할 때만 도입한다. 순환 모델이 숨겨진 카드를 알아내는 것은 아니다. 지금까지 드러난 단서를 잊지 않고 모아 상대를 추정할 뿐이다.
16. DAgger식 보강: 모델이 실제로 망가뜨린 상태를 배운다
BC의 가장 큰 약점은 기존 파일럿이 겪었던 상황만 배운다는 점이다. 모델이 한 번 실수하면 리플레이에 없던 상황으로 들어가고, 익숙하지 않은 그곳에서 다시 실수한다. DAgger는 현재 정책이 실제로 들어간 상황을 모은 뒤, 그 상황에서 전문가라면 무엇을 고를지 다시 물어 학습 자료에 보태는 방법이다.
이 대회에서 DAgger를 원래 방식 그대로 구현하기는 어렵다. 공식 로그를 만든 에이전트에게 새로 생긴 상황의 정답을 다시 물을 수 없기 때문이다. 완전한 DAgger는 아니지만, 다음처럼 비슷한 흐름으로 구현할 수는 있다.
1
2
3
4
5
1. 현재 학습 파일럿으로 전체 게임을 돌린다.
2. 모델, 규칙, 여러 교사 정책이 서로 다른 행동을 고른 상황을 모은다.
3. 중요한 장면만 사람이 만든 규칙이나 검증된 여러 교사 정책으로 다시 라벨링한다.
4. 시뮬레이션으로 만든 어려운 게임에서는 여러 교사가 같은 답을 낸 판단만 제한적으로 학습한다.
5. 공식 리플레이에서 얻은 정답과 시뮬레이션에서 만든 정답은 출처를 나눠 보관한다.
교사 정책은 이름만 다른 것이 아니라 실제 판단도 달라야 한다. 같은 코드의 상수만 조금 바꾼 변형을 서로 다른 전문가로 세지 않는다. 저장해 둔 같은 상황에서 늘 같은 행동을 고른다면 사실상 교사는 하나뿐이다.
시뮬레이션으로 만든 게임 기록은 부족한 상황을 보충하는 데 도움이 된다. 다만 다음 검증을 대신할 수는 없다.
- 실제 래더에서 관측한 행동을 얼마나 비슷하게 재현하는지
- 덱 파워 추정
- 날짜를 나눈 최종 검증
- 건드리지 않은 미래 홀드아웃
다시 말해 DAgger식 보강은 모델이 접하는 상황을 넓혀줄 뿐이다. 실제 래더를 닮은 상대와 새 날짜에서 검증한 결과까지 대신해 주지는 않는다.
5부. 행동 복제 다음 단계로 넘어가기
여기서부터 보상과 가치 함수를 직접 다룬다. AWR, 오프라인 RL, 보상 설계, 자기 대전을 한꺼번에 벌이지 않는다. 앞에서 검증한 상황·행동 표현 방식과 평가 방법을 유지한 채 한 단계씩 넓혀 간다.
17. 결과를 반영한 모방: BC 다음에는 AWR가 현실적이다
기본 BC는 기록된 행동을 모두 같은 비중으로 따라 배운다. 다음 단계에서는 좋은 결과로 이어진 행동을 조금 더 중요하게 볼 수 있다.
이를 위해 BC용 기록을 RL에서 쓰는 상태 전이(transition) 형태로 넓혀야 한다.
1
2
3
4
5
6
7
8
9
Transition = {
"observation": o_t,
"options": A_t,
"action": a_t,
"reward": r_t,
"next_observation": o_next,
"next_options": A_next,
"done": done,
}
여기서 next는 JSON의 바로 다음 행이 아니다. 같은 플레이어에게 다음 판단 기회가 돌아왔을 때의 관측이어야 한다. 그 사이에 일어난 상대 행동과 엔진 처리 결과까지 반영돼야 한다. 중간 보상을 따로 두지 않는다면 $r_t$는 0으로 놓고, 마지막 transition에만 승패를 넣는 방식이 가장 단순하다.
Advantage-Weighted Regression은 먼저 가치 함수를 추정하고, 평균보다 좋았다고 판단한 행동을 더 큰 비중으로 따라 배우는 방법이다. 기존 BC 학습 구조를 거의 그대로 쓰면서도 게임 결과를 반영할 수 있어, 지금 구조에서 무리 없이 시도할 만한 다음 단계다.
다만 $\hat A_t$를 단순히 “이긴 게임이면 +1”로 두면 안 된다. 다음을 함께 고려해야 한다.
1
2
3
4
5
최종 승패
상대 강도
매치업의 기본 유불리
현재 상태의 가치 추정
데이터 출처와 교사 정책의 신뢰도
가치 모델도 처음부터 복잡하게 만들 필요는 없다. 우선 최종 승패를 예측하는 보조 출력층으로 시작해, 다른 날짜에서도 예측 확률과 실제 승률이 맞는지 본다. 가치 추정이 틀리면 나쁜 행동을 더 세게 따라 배울 수 있어 기본 BC보다 오히려 나빠질 수 있다.
18. 오프라인 RL은 언제 시작할 것인가
리플레이에는 실제로 고른 행동과 그 뒤의 결과만 남는다. 다른 행동을 골랐다면 어떻게 됐을지는 알 수 없다. 일반적인 Q-learning을 그대로 적용하면, 데이터에서 거의 보지 못한 행동의 가치를 터무니없이 높게 잡을 수 있다.
Conservative Q-Learning은 학습 자료에서 보기 힘든 행동의 가치를 낮춰 잡는 방법이고, Implicit Q-Learning은 데이터에 없는 행동을 직접 평가하지 않으면서 가치와 정책을 개선하려는 방법이다.
하지만 알고리즘 이름을 고르는 것보다 먼저 확인할 조건이 있다.
| 선행 조건 | 이유 |
|---|---|
| BC와 하이브리드 파일럿이 전체 게임을 정상적으로 끝낸다 | 상황과 행동을 표현하는 방식부터 맞는지 확인해야 한다. |
| 날짜와 정책 구간을 나눈 학습 자료가 있다 | 오프라인 평가 누수를 막아야 한다. |
| 중요한 선택에 충분한 표본이 있다 | 쉬운 행동의 가치만 배우는 일을 막아야 한다. |
| 래더 재현용 파일럿의 매치업 관계를 검증했다 | RL로 실제로 나아졌는지 판단할 기준이 필요하다. |
| 보상과 가치 예측의 신뢰도를 점검했다 | 잘못된 목표를 더 잘 최적화하는 일을 막아야 한다. |
| 아직 보지 않은 미래 날짜를 남겨뒀다 | 모델 선택 편향을 확인해야 한다. |
현재는 일부 덱에서 겨우 이런 조건을 갖춰 가는 단계다. CQL과 IQL은 앞으로 시험할 후보일 뿐, 이미 효과를 확인한 해법은 아니다.
논문의 구현을 그대로 옮길 수도 없다. 이 게임은 매 순간 가능한 행동이 달라진다. 따라서 $Q(o,c_i)$를 현재 선택지마다 계산하고, 다음 상태의 Bellman target도 next_options 안에서만 만들어야 한다. 선택지 mask나 다중 선택을 잘못 처리하면 어떤 보수적 알고리즘을 써도 가치 함수부터 틀어진다.
19. 보상 설계: 승리를 대신하는 지표를 목표로 만들지 않는다
가장 안전한 기본 보상은 최종 승패다.
\[r_T\in\{-1,0,+1\}\]문제는 게임이 길어 보상이 너무 늦게 돌아온다는 점이다. 중간 보상을 넣을 수는 있지만, 보조 지표가 승리라는 원래 목표를 밀어내면 모델은 그 지표의 허점만 파고든다. 이른바 보상 해킹(reward hacking)이다.
위험한 예
- 드로우 수에 보상을 주면 필요 없는 드로우를 반복할 수 있다.
- 피해량에 보상을 주면 프라이즈 계획보다 당장 큰 피해를 우선할 수 있다.
- 벤치 전개에 보상을 주면 상대의 광역 공격에 취약한 보드를 만들 수 있다.
- 남은 덱 수를 무조건 높게 평가하면 필요한 서치도 피할 수 있다.
가능하면 잠재함수 $\Phi(o)$의 차이를 이용해 중간 보상을 만든다.
\[r'_t=r_t+\gamma\Phi(o_{t+1})-\Phi(o_t)\]잠재함수에는 프라이즈 차이, 당장 KO를 당할 위험, 다음 턴 공격 준비도, 자원 고갈 위험 같은 요소를 작은 비중으로 섞을 수 있다. 그래도 다음 검사는 반드시 통과해야 한다.
1
2
3
4
shaping 없이도 최종 승률이 좋아지는가?
한 보조 지표만 비정상적으로 반복하지 않는가?
주요 매치업에서도 대부분 실제 승률이 좋아지는가?
규칙 기반 기준 정책보다 치명적인 실수가 늘지 않는가?
처음에는 복잡한 중간 보상을 넣지 말고 BC, AWR, 최종 결과 예측부터 차례로 확인하는 편이 안전하다.
20. 자기 대전은 마지막이 아니라 별도 리그로 설계한다
한 덱으로 거울전만 반복하면 그 매치업에만 강한 정책이 생길 수 있다. 현재 래더의 다른 상대를 배우지 못하고, 두 정책이 서로의 약점에만 맞춰 변하면서 이상한 순환에 빠질 수도 있다.
자기 대전을 시작한다면 상대를 한 정책으로 고정하지 않고, 여러 정책이 함께 들어 있는 리그를 만든다.
1
2
3
4
5
6
현재 규칙 기반 기준 파일럿
검증된 래더 재현용 파일럿
최근 강한 공개 기준 에이전트
과거 정책 체크포인트
공격적 / 수비적 / 자원 고갈형 압박 정책
현재 학습 정책의 여러 세대
리그에서 상대를 뽑을 때도 모두 같은 확률을 주지는 않는다.
1
2
3
4
5
현재 래더의 덱 비중
취약 매치업 우선순위
최근 패배율
정책 다양성
최근 평가가 뜸했던 상대를 다시 뽑는 비중
가장 최근 정책과의 대전에서 이겼다는 이유만으로 새 정책을 승격하지 않는다. 고정해 둔 과거 기준과 새 홀드아웃에서도 우위가 남아야 한다. 다른 제출 후보가 지는 상대를 대신 이길 수 있는지, 두 후보가 같은 상대에게 함께 무너질 위험을 줄이는지도 본다.
6부. 알고리즘보다 먼저 갖춰야 할 평가 체계
학습 방법이 달라져도 평가 순서는 바뀌지 않는다. 오프라인 정확도와 전체 게임, 상대 재현, 날짜 분리 검증, 미래 홀드아웃을 차례로 통과해야 한다. 로컬 결과와 실제 래더 성적이 어긋날 때도 원인부터 나눠 본 뒤 손댄다.
21. 단계별 검증: 앞 단계를 통과한 뒤 다음 단계로 간다
| 단계 | 확인할 것 | 통과하지 못하면 |
|---|---|---|
| 1. 데이터 연결 | 상황과 행동 정렬, 덱 반환 분리, 엔진 버전 | 파서부터 고친다. |
| 2. 오프라인 지표 | 강제 선택을 뺀 top-k, 중요한 판단, 다른 날짜 성능 | 특징과 데이터 비중을 고친다. |
| 3. 실제 실행 | 독립 실행, 60장 덱, 올바른 행동 형식, 미러 게임 | 패키지와 대체 규칙을 고친다. |
| 4. 행동 재현도 | 판단 유형·게임 단계·상대별 행동이 실제와 비슷한가 | 래더 재현용으로 쓰지 않는다. |
| 5. 상성 재현도 | 실제 래더와 매치업의 우열이 같은가 | 상대 구성을 고친다. |
| 6. 기준 대비 우위 | 같은 상대·좌석에서 기존 파일럿보다 나은가 | 제출 후보로 올리지 않는다. |
| 7. 날짜 분리 검증 | 다른 날짜에서도 효과가 유지되는가 | 과적합으로 기록한다. |
| 8. 미래 홀드아웃 | 고정된 후보가 처음 보는 미래 날짜에서 기준을 넘는가 | 새 홀드아웃 없이 다시 주장하지 않는다. |
| 9. 실제 래더 결과 대조 | 로컬 예측과 실제 결과의 차이를 설명할 수 있는가 | 평가 방식부터 고친다. |
승률 하나만으로는 부족하다. 실력이 비슷한 상대끼리 붙는 래더에서는 강한 에이전트도 승률이 50% 근처에 머물 수 있다. 그래서 로컬에서는 후보마다 같은 상대를 만나게 하고 선후공 횟수도 맞춘다. 상대의 강도와 매치업별 결과, 표본에서 생기는 불확실성도 함께 본다.
공개 API로는 엔진 난수를 완전히 고정할 수 없어 두 후보를 똑같은 카드 순서와 동전 던지기 아래에서 비교할 수 없었다. 대신 상대 구성과 선후공 횟수를 맞추고 게임 수를 충분히 늘렸다. Wilson 신뢰구간과 별도 홀드아웃도 함께 써 우연의 영향을 줄였다.
22. 로컬에서는 좋은데 실제 래더에서는 약할 때 무엇을 볼까
이럴 때 곧바로 “파일럿이 약해서 그렇다”고 결론 내리면 안 된다. 먼저 가능한 원인을 나눠 본다.
| 원인 | 확인할 단서 | 다음 조치 |
|---|---|---|
| 상대 파일럿이 약함 | 로컬 매치업이 실제 래더보다 지나치게 쉬움 | 래더 재현용 파일럿을 다시 학습·검증한다. |
| 중요한 상대가 빠짐 | 현재 많이 쓰이는 덱과 치른 로컬 게임이 없음 | 평가할 상대 목록을 넓힌다. |
| 평가 상대 비중이 뒤처짐 | 로컬 상대 비중과 현재 래더의 덱 비중이 다름 | 최신 자료에 맞춰 비중을 다시 잡는다. |
| 제출 파일럿이 평균만 모방 | 행동은 비슷하지만 기준 파일럿보다 강하지 않음 | 모방이 아니라 승리를 목표로 따로 탐색한다. |
| 승자의 저주 | 후보를 고른 뒤 새 평가에서 점수가 크게 하락 | 과대평가분을 보정하고 새 홀드아웃을 쓴다. |
| 메타 변화 | 제출 뒤 상대 분포가 바뀜 | 날짜별 변화를 분리해 본다. |
| 실행 문제 | 에러, 대체 행동, 시간 초과가 실제 래더에서 증가 | 자체 대전 기록과 패키지 로그를 확인한다. |
핵심은 고치기 전에 무엇이 잘못됐는지부터 재는 것이다. 파일럿이 원인이 아닌데 파일럿만 계속 다듬으면 로컬 점수만 오르고 실제 래더와의 간격은 그대로 남는다.
7부. 현재 위치와 다음 구현 순서
마지막 장에서는 실제로 구현을 끝낸 부분과 아직 계획에 머물러 있는 부분을 구분한다. 처음부터 다시 만든다면 어떤 순서로 진행할지, 같은 실수를 피하려면 무엇을 확인해야 할지도 체크리스트로 남긴다.
23. 지금까지 실제로 구현한 범위
2026-07-15 현재 다음 흐름은 실제 코드로 연결돼 있다.
1
2
3
4
5
6
7
8
9
공식 리플레이 파싱
-> 양쪽 플레이어의 의사결정 추출
-> 같은 60장 덱끼리 묶은 선택지 데이터 생성
-> 현재 상황을 함께 보는 쌍대 비교 순위 모델 학습
-> 독립 실행 가능한 소형 모델 패키지 생성
-> 초기 덱 / 첫 행동 / 미러 게임 기본 검사
-> 래더 재현용 파일럿의 매치업 재현 검사
-> 선후공 횟수를 맞춘 벤치마크
-> 한 번만 쓰는 미래 홀드아웃 평가와 결과 기록
최근 하루치 로그에서는 양쪽 플레이어가 내린 판단 약 58만 건을 추출했다. 그중 60장 구성이 정확히 같은 덱끼리 묶어 만든 학습 자료는 다음과 같다.
| 대상 | 의사결정 수 | 날짜·정책 구간 분리 top-1 | 현재 해석 |
|---|---|---|---|
| 새 Spidops 60장 덱 | 12,228 | 54.9% | 여러 날짜를 묶어 다시 학습해야 한다. |
| Festival 60장 덱 A | 19,372 | 71.8% | 같은 날 데이터에는 잘 맞지만 미래 날짜 검증 전이다. |
| Festival 60장 덱 B | 10,751 | 59.6% | 일부 매치업 오차가 커 추가 검증이 필요하다. |
이 숫자는 데이터 추출부터 학습과 평가까지 한 번에 돌아간다는 사실만 보여준다. 제출 성능을 보장하는 점수가 아니다. 실제로 Spidops 새 후보는 미래 홀드아웃에서 기존 파일럿보다 0.96%p 높았지만, 미리 정한 승격 기준에는 미치지 못했다.
아직 완성하지 못한 부분도 많다. 다음 항목은 이제 시작했거나 앞으로 검증해야 한다.
- 여러 날짜를 합친 동일 60장 덱의 행동 학습
- 드물지만 중요한 판단과 취약 매치업의 학습 예시 늘리기
- 교사 정책이 다른 날짜에서도 믿을 만한 판단을 내리는지 검증
- AWR에 쓸 가치 모델의 예측 확률이 실제 승률과 맞는지 점검
- 오프라인 RL과 자기 대전을 별도 홀드아웃에서 평가
- 로컬 평가와 실제 래더 성적 사이의 오차를 장기적으로 보정
24. 앞으로 코드를 작성할 순서
RL을 처음 접한 시점으로 돌아간다면 다음 순서로 구현하겠다.
구현 1단계: 상황과 행동 연결
1
2
3
4
5
[ ] i 관측과 i+1 행동 정렬 테스트
[ ] 60장 덱 반환과 게임 중 행동 분리
[ ] 모든 정답 인덱스의 범위 검사
[ ] 엔진 버전, 날짜, 게임, 팀, 덱 해시 기록
[ ] 같은 게임이 학습과 홀드아웃에 동시에 들어가지 않음
구현 2단계: 규칙 기반 기준과 판단 기록
1
2
3
4
[ ] 판단 유형별 규칙 점수 기록
[ ] 대체 규칙 사용량 기록
[ ] 실행 시간과 에러 기록
[ ] 60장 덱과 정책을 묶은 실험 기록 생성
구현 3단계: 행동 복제 v1
1
2
3
4
5
[ ] 학습과 실행이 함께 쓰는 상태·선택지 특징 추출기
[ ] 가변 길이 선택지 순위기
[ ] 강제 선택 제외 / 중요 판단 / 판단 유형별 지표
[ ] 날짜 또는 정책 구간 단위 홀드아웃
[ ] 규칙 기반 대체 행동이 포함된 실행 래퍼
구현 4단계: 래더 재현용 파일럿 검증
1
2
3
4
[ ] 행동 특성 비교
[ ] 매치업 행렬 오차와 우열이 뒤집힌 매치업 확인
[ ] 현재 래더에서 자주 만나는 덱을 얼마나 포함했는지 계산
[ ] 패키지 / 미러 게임 / 실행 시간 검사
구현 5단계: 제출 파일럿 탐색
1
2
3
4
5
[ ] 규칙과 모델의 혼합 비율을 작은 범위에서 탐색
[ ] 기준 파일럿과 같은 상대·선후공 조건에서 비교
[ ] 선택용 게임과 최종 검증 게임 분리
[ ] 후보와 상대 구성을 해시로 고정
[ ] 건드리지 않은 미래 홀드아웃을 한 번만 사용
구현 6단계: 결과를 반영한 학습
1
2
3
4
[ ] 예측 확률과 실제 승률이 맞는지 검증한 가치 모델
[ ] 상대 강도와 최종 결과에 따른 가중치
[ ] AWR 또는 비슷한 어드밴티지 가중 BC
[ ] 기존 BC와 같은 단계별 검증 통과
구현 7단계: 제한적인 오프라인 RL과 자기 대전
1
2
3
4
5
6
[ ] CQL/IQL 소규모 실험
[ ] 학습 데이터에서 보기 힘든 행동의 가치 점검
[ ] 다양한 상대 리그 구성
[ ] 이전 체크포인트를 고정한 평가
[ ] 중간 보상을 제거한 비교 실험
[ ] 새 날짜 홀드아웃과 실제 래더 결과 대조
앞 단계를 통과하지 못했으면 다음 알고리즘으로 넘어가지 않는다. 모델 이름을 바꾼다고 파서와 파일럿, 평가 체계의 문제가 저절로 해결되지는 않는다.
25. 다시 하지 않을 실수
| 잘못했던 접근 | 왜 문제였나 | 지금의 원칙 |
|---|---|---|
| 래더 점수가 높은 덱을 복사하면 강할 것이라 생각함 | 덱과 파일럿을 분리하지 않았다. | 60장 덱과 실행 정책을 따로 관리한다. |
| 전체 top-1 정확도를 성능으로 봄 | 쉬운 판단이 지표를 지배했다. | 중요한 판단·판단 유형·매치업과 전체 게임을 따로 본다. |
| 승자 행동만 정답으로 사용 | 생존자 편향과 매치업 편향이 생겼다. | 양쪽 행동을 보관하고 결과는 가중치로 사용한다. |
| 의사결정 행을 무작위 분할 | 한 게임 정보가 학습과 검증에 함께 들어갔다. | 게임·날짜·정책 구간 단위로 나눈다. |
| 같은 날짜에서 학습하고 재현됐다고 판단 | 다른 날짜로 옮겨갔을 때도 통하는지 알 수 없었다. | 다음 날짜를 별도 검증 자료로 남긴다. |
| 약한 상대 재현 파일럿으로 후보를 평가 | 로컬 승률이 부풀었다. | 행동과 상성 재현도를 먼저 검증한다. |
| 많은 후보 중 최고값을 그대로 믿음 | 승자의 저주를 무시했다. | 새 홀드아웃을 쓰고 과대평가분을 보정한다. |
| 단순 승률만으로 덱 파워를 판단 | 강한 상대를 만난 50%와 약한 상대의 60%를 구분하지 못했다. | 상대 난이도를 반영하고, 같은 60장 구성과 정책 구간끼리 묶어 본다. |
| 처음부터 자기 대전을 계획 | 믿을 만한 평가 방법과 다양한 상대 정책이 없었다. | BC와 하이브리드가 검증된 뒤 리그를 만든다. |
| 노트북 패키지 검사를 뒤로 미룸 | 모델이 좋아도 Validation Episode에서 실패했다. | 독립 실행과 미러 게임 검사를 학습 실험에 포함한다. |
어쩌면 이 표가 지금까지 얻은 가장 중요한 RL 결과일지도 모른다. 실패 원인을 나누지 않으면 더 큰 모델은 같은 실수를 더 자신 있게 반복할 뿐이다.
26. 참고 논문을 읽는 순서
처음부터 모든 수식을 이해하려고 애쓸 필요는 없다. 지금 구현하고 있는 단계에 맞춰 읽는 편이 낫다.
행동 복제와 분포 이동 먼저 지도학습 정책이 왜 자기 실수 뒤의 상태에서 무너지는지 이해한다.
DAgger 현재 정책이 방문한 상태를 데이터에 다시 넣는 이유를 본다.
Advantage-Weighted Regression BC 구조를 유지하면서 좋은 행동에 더 큰 가중치를 주는 방법을 본다.
Conservative Q-Learning 오프라인 데이터에 없는 행동의 가치를 과대평가하는 문제를 본다.
Implicit Q-Learning 학습 자료에서 거의 보지 못한 행동을 직접 평가하지 않고 정책을 개선하는 방법을 본다.
논문 하나를 읽었다고 전체 시스템부터 바꾸지는 않는다. 지금 확인한 실패 원인 하나만 겨냥해 가장 작은 실험으로 옮기는 편이 안전하다.
27. 결론
이 프로젝트에서 RL은 규칙 기반 에이전트를 버리고 신경망으로 갈아타는 일이 아니었다. 실제로는 다음 과정을 여러 번 되풀이하는 작업에 가까웠다.
1
2
3
4
5
6
7
8
에이전트가 실제로 볼 수 있는 정보의 범위를 정한다
-> 실제 판단을 정확히 추출한다
-> 가변 길이 선택지를 순위화한다
-> 중요한 판단을 따로 보고, 다른 날짜에서도 성능이 유지되는지 확인한다
-> 실제 래더를 닮은 벤치마크 상대와 그 상대를 이길 제출 후보를 구분한다
-> 규칙 기반 대체 행동으로 실행 안정성을 지킨다
-> 승패와 가치 추정을 학습 비중에 조금씩 반영한다
-> 새 홀드아웃에서도 우위가 남을 때만 다음 단계로 간다
지금까지 행동 복제와 현재 상황을 함께 보는 순위 모델, 파일럿 패키지, 행동·상성 재현 검사, 미래 홀드아웃까지는 실제 코드로 연결했다. 반면 오프라인 RL과 자기 대전은 아직 준비 단계다. 이미 해낸 일과 앞으로 해볼 일을 구분해 쓰는 것이 중요하다.
가장 큰 교훈은 RL 알고리즘을 고르기 전에 데이터와 평가 자료의 용도를 나누는 것이었다. 덱이 강한지, 파일럿이 강한지, 상대가 약한지, 같은 자료를 되풀이해 본 것인지 가려내지 못하면 어떤 점수든 쉽게 잘못 읽게 된다.
다음 Working Note에서는 여러 날짜에 걸친 같은 덱의 행동을 합치는 법, 중요한 판단의 표본을 늘리는 법, 여러 교사 정책을 함께 쓰는 법, 날짜를 나눠 파일럿을 검증하는 과정을 실제 실험 단위로 더 자세히 다룰 예정이다.