CH 23 강화학습 · Part 4 엔트로피 · 모델 · 데이터
모델기반 RL — Dyna와 상상 속 경험
5장에서 우리는 전이확률 P 와 보상 R 를 알고 있었다. 그래서 환경과 단 한 번도 상호작용하지 않고 최적정책을 구했다. 6장부터는 그 둘을 모른다고 가정하고 표본으로 때웠다. 이 장은 세 번째 길을 낸다 — 모델도 데이터로 배우면 된다. 배운 모델로 가짜 경험을 만들어 같은 갱신 루프에 흘려 넣으면 실제 상호작용 n 번으로 n(1+k) 번 갱신할 수 있다. 공짜는 아니다. 모델 오차 ε 는 지평 h 에 따라 ε(Lh−1)/(L−1) 로 지수적으로 불어난다. L=1.05, ε=0.01 이면 h=50 에서 오차가 2.09 — 처음의 209배다. 이 장은 이득과 대가를 끝까지 숫자로 맞춘다.
- 01 직관
- 02 수식 읽는 법
- 03 손으로 풀기
- 04 코드
- 05 시각화
약어 및 기호 정의
- 모델 P̂, R̂
- model. 환경의 동역학을 흉내 내는 함수. 상태·행동을 받아 다음 상태 분포 P̂(s′|s,a) 와 보상 R̂(s,a) 를 내놓는다. 5장의 P, R 는 주어진 것이었고 여기서는 배우는 것이다
- 모델기반 RL
- model-based RL. 모델을 명시적으로 만들어 그것으로 계획하거나 가짜 경험을 뽑아 쓰는 방법의 총칭
- 모델프리 RL
- model-free RL. 6장~22장 전부. 모델을 만들지 않고 실제 표본만으로 가치나 정책을 고친다
- 계획 planning
- 모델만 가지고(실제 환경을 건드리지 않고) 가치나 정책을 개선하는 계산. 5장의 DP 가 계획의 원형이다
- 가짜 경험 (s, a, r̂, ŝ′)
- simulated experience. 모델이 만들어 낸 전이. 실제 환경에서 온 것이 아니므로 공짜이지만 틀릴 수 있다
- Dyna
- 실제 경험으로 (1) 가치를 직접 고치고 (2) 모델도 고친 다음 (3) 그 모델에서 가짜 경험을 k 개 뽑아 또 고치는 구조. 세 가지를 한 루프에 넣은 것이 전부다
- 계획 횟수 k
- 실제 한 스텝마다 모델에서 몇 번 가짜 갱신을 할지. k=0 이면 정확히 7장 Q-러닝이다
- 롤아웃 지평 h
- rollout horizon. 모델을 몇 스텝 연달아 굴릴지. 모델 오차가 누적되는 길이가 바로 이 값이다
- 립시츠 상수 L
- Lipschitz constant. 출발점의 차이가 한 스텝 뒤 몇 배가 되는지. L>1 이면 동역학이 차이를 벌리고(카오스), L<1 이면 수축한다
- 총변동거리 ‖·‖1
- total variation. 두 확률분포의 거리. 모델 오차를 재는 표준 잣대 εP = maxs,a ‖P̂(·|s,a) − P(·|s,a)‖1
- 시뮬레이션 보조정리
- simulation lemma. 모델 오차 ε 가 가치 오차로 얼마나 번지는지를 1/(1−γ)2 배로 묶는 정리
- 탐험 보너스 κ√τ
- Dyna-Q+ 가 모델의 보상에 더하는 항. τ 는 그 (s,a) 를 마지막으로 실제로 해 본 뒤 흐른 스텝 수다
- 앙상블 ensemble
- 모델 여러 개를 따로 학습해 예측이 갈리는 정도로 불확실성을 재는 방법
직관: 표본이 비싸면 상상으로 메운다
5장을 떠올려 보자. 4칸 복도 MDP 에서 가치반복은 2 스윕 만에 최적정책을 찾았고, 그때 에이전트는 복도를 한 발자국도 걸어 보지 않았다. 전이확률과 보상이 표로 주어져 머릿속에서 전부 계산할 수 있었던 것이다. 그래서 5장을 "계획", 6장부터를 "학습"이라 부른다.
6장에서 그 표를 치웠다. 몬테카를로는 에피소드를 끝까지 굴려 수익을 평균했고 7장의 TD 는 한 걸음마다 부트스트랩했다. 둘 다 실제로 걸어 본 만큼만 배운다. 9장 이후 신경망이 표의 크기 문제는 풀었지만 이 제약은 그대로였다 — 한 번 갱신하려면 환경에서 한 번 움직여야 한다.
여기서 질문 하나가 생긴다. 표가 주어지지 않았을 뿐인데, 왜 표를 만들지 않는가. 걸어 보면서 "s1 에서 오른쪽으로 갔더니 s2, 보상 0" 을 기록하면 그것이 P 와 R 의 한 칸이다. 충분히 기록하면 5장이 쓰던 표가 손에 들어오고, 그다음은 5장으로 돌아가면 된다.
한 줄 요약
모델기반 RL 은 "모델을 모르면 배워서 DP 하자"는 것이다. 5장은 모델을 공짜로 받았고 6장은 모델을 포기했다. 23장은 모델을 데이터로 추정해 5장의 계산을 되살린다. 단, 추정된 모델은 틀리므로 얼마나 멀리까지 믿을지를 정해야 한다 — 그 거리가 롤아웃 지평 h 다.
왜 이것이 중요한가 — 표본의 값어치
시뮬레이터에서 학습한다면 모델기반 RL 은 매력이 떨어진다. 아타리 에뮬레이터는 초당 수천 프레임을 공짜로 내놓으므로 틀릴 수도 있는 모델을 만드느니 진짜를 더 돌리는 편이 낫다. 10장 DQN 계열이 5천만 프레임 같은 숫자를 아무렇지 않게 쓰는 이유다. 문제는 표본 하나에 값이 붙는 경우다.
로봇. 한 에피소드에 실제 시간이 걸리고, 기어가 닳고, 때로는 부서진다. 밤새 돌려 얻는 표본이 수만 스텝이라면 5천만은 불가능한 숫자다. 의료. 치료 방침을 바꿔 가며 환자에게 시험해 볼 수 없다. 표본은 이미 쌓인 기록뿐이고 "탐험"이라는 행위 자체가 허용되지 않는다 — 오프라인 RL 의 출발점이다. 추천·광고. 엉뚱한 것을 띄우는 한 번이 매출이고 한 사용자를 두 번 실험할 수도 없다. 표본은 많지만 나쁜 표본의 비용이 크다.
공통된 셈법은 하나다. 환경 한 스텝의 비용이 모델 한 스텝의 1000배라면, 모델이 웬만큼만 맞아도 쓰는 것이 이득이다. 모델기반 RL 의 실무적 가치는 대체로 이 비용 비율에서 나온다.

도해 1 에서 꼭 읽어야 할 것은 갱신식이 하나뿐이라는 점이다. Dyna 의 가치 갱신은 7장의 그 식과 문자 하나도 다르지 않다.
그래서 Dyna 는 알고리즘이라기보다 구조(architecture)다. 7장 Q-러닝에도 9장 DQN 에도 21장 SAC 에도 붙는다. 비용은 모델 하나, 얻는 것은 실제 표본당 갱신 횟수다.
수식 읽는 법: 모델 학습, Dyna-Q, 그리고 오차가 불어나는 속도
모델을 어떻게 배우는가
상태와 행동이 유한하면 모델 학습은 세기로 끝난다. N(s,a) 를 (s,a) 를 한 횟수, N(s,a,s′) 를 그 결과가 s′ 였던 횟수라 하면 최대가능도 추정은 단순한 비율이다.
식 (23.1)은 다항분포의 최대가능도 추정이므로 성질이 잘 알려져 있다. P̂(s′|s,a) 는 참값 p 에 대해 불편이고 표준오차는 √(p(1−p)/N) 다. 3단에서 이 수를 직접 써서 "몇 번 봐야 하는가"를 계산한다.
상태가 연속이면 세는 것이 불가능하므로 회귀로 바꾼다. 세 가지 선택이 있다.
결정적 모델. ŝ′ = fψ(s,a) 를 제곱오차로 학습한다. 가장 간단하지만 환경이 확률적이면 여러 결과의 평균을 내놓는다. 두 갈래로 갈리는 길 앞에서 평균은 벽 한가운데다.
확률적 모델. P̂ψ(s′|s,a) = 𝒩(μψ, Σψ) 처럼 분포를 내놓고 음의 로그가능도로 학습한다. 분산을 예측하므로 모델이 "모른다"고 말할 통로가 생긴다. 다만 가우시안의 분산은 환경 자체의 잡음(우연적 불확실성 aleatoric)이고, 데이터가 없어 모르는 것(인식적 불확실성 epistemic)은 잡지 못한다.
앙상블. 초기화와 배치 순서를 달리해 모델 M 개를 따로 학습하고 예측이 갈리는 정도를 인식적 불확실성으로 쓴다. 데이터가 많은 곳에서는 같은 답을, 없는 곳에서는 흩어진 답을 한다. 갈림이 큰 곳에서 롤아웃을 끊는 데 쓴다.
한 가지 더. ŝ′ 를 직접 맞히는 대신 차분 Δ̂ = ŝ′ − s 를 맞히고 ŝ′ = s + Δ̂ 로 쓰는 편이 거의 항상 낫다. 한 스텝 변화량이 상태값 자체보다 훨씬 작으므로 같은 상대정확도로 훨씬 작은 절대오차를 얻는다.
Dyna-Q
이제 도해 1 을 의사코드로 내린다. 표 기반이고 환경이 결정적이라고 가정하면 모델은 딕셔너리 하나다.
두 가지를 짚어 둔다.
첫째, k=0 이면 4·5번 줄이 사라지고 정확히 7장 Q-러닝이 된다. Dyna-Q 는 Q-러닝의 엄격한 확장이다.
둘째, 5a 의 무작위 추출은 가짜 경험을 생성하는 것이 아니라 기억에서 꺼내는 것에 가깝다. 결정적 표 모델이 담는 것은 한 번 본 전이들이므로, 이 단계는 9장 DQN 의 리플레이 버퍼와 거의 같은 일을 한다. 차이는 한 군데다 — 버퍼는 (s,a,r,s′) 를 중복을 포함해 시간순으로 쌓지만 모델은 (s,a) 를 열쇠로 쓴다. 그래서 환경이 바뀌면 모델은 갱신되고 버퍼는 낡은 것을 들고 있다. 반대로 환경이 확률적이면 버퍼는 여러 결과를 보존하고 결정적 모델은 마지막 하나만 남긴다. 장단이 정확히 뒤집혀 있다.
가짜 경험의 이득 — 산술
식 (23.2)에는 아무 가정이 없으므로 항상 맞다. 그러나 "갱신 21배 = 학습 21배"는 전혀 아니다. 세 가지 천장이 있다.
(1) 모델의 정의역. 5a 가 뽑을 수 있는 것은 이미 본 (s,a) 뿐이다. 가 본 적 없는 방의 전이는 k 를 무한히 키워도 만들어지지 않는다. 모델기반 RL 은 탐험 문제를 풀어 주지 않고, 오히려 탐험이 부족하면 더 크게 다친다. (2) 정보의 포화. 같은 전이 집합이 담은 정보를 다 짜낸 뒤에는 갱신을 100번 더 해도 값이 움직이지 않는다. (3) 모델 오차. 틀린 곳에서 뽑은 가짜 경험은 틀린 방향으로 갱신한다. 이쪽이 가장 고약하고, 남은 절을 전부 여기에 쓴다.

모델 오차는 지평에 따라 지수적으로 커진다
이제 이 장의 핵심 수식이다. 모델이 한 스텝에 대해서는 꽤 정확하다고 하자 — 다음 상태를 ε 이내로 맞힌다. 이 모델을 h 번 연달아 굴리면 마지막 상태는 참값에서 얼마나 벗어나는가.
답이 hε 이라면 별 문제가 없을 것이다. 실제로는 두 가지가 겹친다 — 매 스텝 새 오차가 더해지는 것과 이미 생긴 오차가 동역학을 타고 증폭되는 것. 증폭의 크기를 립시츠 상수(Lipschitz constant) L 로 잡는다. 참 동역학 f 가 L-립시츠라는 것은 두 출발점의 거리가 한 스텝 뒤 L 배 이내라는 뜻이다.
이제 유도한다. δh = ‖ŝh − sh‖ 를 h 스텝 뒤의 상태 오차라 두자. 둘 다 같은 s0 에서, 같은 행동열에서 출발한다.
식 (23.4)의 세 가지 경우를 구분해 읽어야 한다.
L < 1 — 수축. 동역학이 차이를 줄이는 속도가 더 빠르므로 누적 오차가 ε/(1−L) 천장 아래 머문다. 마찰이 큰 계, 안정점으로 수렴하는 제어계가 여기다. 모델을 길게 굴려도 된다. L = 1 — 중립. δh = hε 로 선형이다. 직관이 맞는 유일한 경우다. L > 1 — 발산. 이족보행, 접촉이 있는 조작, 관절이 많은 계 대부분이 여기다. L=1.05 는 "한 스텝에 5% 만 벌어진다"는 온순한 값이지만 1.0550 = 11.47 이다.
설계 원칙이 곧바로 나온다. L 은 환경이 정하므로 우리가 고를 수 있는 것은 h 뿐이다. L>1 이면 모델을 짧게만 굴리고 그 뒤는 학습된 가치함수에 넘긴다. 현대 모델기반 방법이 h 를 1~5 로 잡는 이유가 이 식이다 — 긴 상상은 기술적으로 가능하지만 쓸모가 없다.
모델 오차가 가치로 새는 경로
지금까지는 상태 오차를 쟀다. 우리가 진짜로 걱정하는 것은 가치 오차다. 모델 M̂ 에서 정책 π 를 평가해 얻은 VπM̂ 가 참 환경에서의 VπM 와 얼마나 다른가. 모델 오차를 분포 거리로 다시 정의하자.
이때 시뮬레이션 보조정리(simulation lemma)가 다음 형태의 한계를 준다. 상수는 유도 방식에 따라 조금씩 다르지만 차수는 같다.
식 (23.6)은 최악의 경우 한계이므로 실무에서는 종종 느슨하다. γ=0.99 면 1/(1−γ)2=10000 이라 εP=0.01 만으로도 한계가 Vmax 를 넘는다. γ=0.9, Rmax=1, εR=εP=0.01 을 넣으면 0.01/0.1 + 0.9×0.01/0.01 = 1.0 으로 Vmax=10 의 10% — 이 정도면 읽을 만한 숫자다. 그래도 이 식에서 가져갈 것은 두 개다.
첫째, γ 가 1 에 가까우면 모델 오차에 훨씬 취약해진다. 모델기반 방법에서 γ 를 낮추거나 유효 지평을 짧게 자르는 것이 흔한 처방인 이유다 — 식 (23.4)의 "h 를 짧게"와 같은 말이다.
둘째, 무한 지평을 모델에만 맡기면 안 된다. 1/(1−γ)2 는 모델을 끝까지 굴린 대가다. h 스텝만 굴리고 그 뒤를 실제 데이터로 학습한 Q 로 막으면 모델 오차가 타는 구간이 h 로 잘린다. 대신 Q 자신의 오차가 γh 로 감가되어 들어온다.
식 (23.7)이 이 장에서 가장 실용적인 식이다. "모델을 얼마나 믿을까"가 두 오차원의 교환으로 바뀌었다. 모델이 정확해질수록 앞항이 작아져 h 를 늘릴 수 있고, Q 가 정확해질수록 뒤항이 작아져 h 를 줄일 수 있다. 학습 중 h 를 조절하는 스케줄을 쓰는 구현이 있는 이유다.
모델이 낡는 문제
마지막 조각이다. 지금까지는 환경이 고정되어 있다고 암묵적으로 가정했다. 환경이 바뀌면 모델은 틀린 줄 모르는 채로 계속 쓰인다.
구체적으로 보자. 막힌 길이 있어 모델에 "그 방향은 제자리"라고 적혀 있다. 나중에 그 길이 열린다. 모델이 고쳐지려면 에이전트가 실제로 그 길을 다시 시도해야 하는데, 모델은 그 길이 쓸모없다 말하고 Q 도 그래서 낮다. ε-탐욕이 우연히 거길 찍을 때까지 아무 일도 없다. 게다가 가짜 갱신 k 번이 매 스텝 낡은 기록을 보강하므로, 모델기반인 쪽이 모델프리보다 더 완강하게 옛 길을 고집한다.
Dyna-Q+ 의 처방은 한 줄이다. 모델에서 가짜 경험을 뽑을 때 보상에 보너스를 더한다.
이 한 줄이 하는 일은 "오래 확인하지 않은 것은 다시 확인할 가치가 있다"를 가치함수 안에 심는 것이다. 세 가지 성질이 중요하다.
(1) 보너스가 계획을 타고 번진다. κ√τ 는 해당 (s̃,ã) 에만 더해지지만 가짜 갱신이 부트스트랩하므로 이웃으로 전파된다. 멀리 있는 오래된 구석이 가는 길 전체를 끌어올린다. ε-탐욕의 무작위 찍기와 결정적으로 다른 점이다 — 보너스는 "저기까지 가라"는 계획을 만든다.
(2) √ 인 이유. 증가가 느려야 한다. τ 에 비례하면 방금 확인한 곳과 오래전 곳의 차이가 너무 커져 정책이 탐험만 한다. √τ 는 12장 UCB 의 √(log t / N) 과 같은 계열이다 — 불확실성이 관측 횟수의 제곱근으로 줄어드니, 거꾸로 시간의 제곱근으로 자란다.
(3) 확인하면 즉시 꺼진다. 실제로 한 번 해 보면 τ=0 이 되어 보너스가 사라지고 모델도 갱신된다. 그 한 번이 "막혔던 길이 열렸다"는 사실을 심어 주고, 나머지는 가짜 갱신 k 번이 빠르게 퍼뜨린다. 4단 (b) 에서 이 과정을 숫자로 본다.
손으로 풀기: 몇 번 봐야 하고, 얼마나 멀리 믿을 수 있는가
네 가지를 계산한다. (a) 모델을 쓸 만하게 만들려면 전이를 몇 번 봐야 하는지, (b) Dyna 의 갱신 이득과 그 천장, (c) 오차가 지평에 따라 불어나는 정도, (d) 그래서 지평을 몇으로 자를지. 모든 수는 4단의 코드로 검산했다.
(a) 표 기반 모델의 표본오차
작은 MDP 를 하나 둔다. 상태 s0 에서 행동 R 을 하면 참 확률 p = 0.8 로 s1 로 가고 0.2 로 제자리다. 물론 에이전트는 이 값을 모른다. 식 (23.1)로 추정하면 P̂ = N(s0,R,s1)/N(s0,R) 이고, N 회 관측했을 때 이 추정의 표준오차는 이항분포의 그것이다.
| N (관측 횟수) | s1 로 간 기대 횟수 | SE(P̂) | 95% 신뢰구간 반폭 | 실무 판정 |
|---|---|---|---|---|
| 10 | 8 | 0.126491 | ±0.247923 | 쓸 수 없다 |
| 100 | 80 | 0.040000 | ±0.078400 | 방향만 맞다 |
| 1000 | 800 | 0.012649 | ±0.024792 | 겨우 쓸 만하다 |
| 10000 | 8000 | 0.004000 | ±0.007840 | 충분하다 |
N=10 줄. 95% 구간이 0.8 ± 0.248 = [0.552, 1.000] 이다. p=1.0 과 p=0.55 는 질적으로 다른 환경이다 — 하나는 결정적이고 하나는 절반 가까이 실패한다. 이 모델에서 가짜 경험을 뽑아 계획하면 존재하지 않는 환경에서 최적인 정책이 나온다.
SE ≤ 0.01 을 목표로 역산하자. p(1−p)/N ≤ 10−4 에서
한 칸에 1600 번이다. 상태 100 개·행동 4 개면 칸이 400 개이므로 각 칸을 1600 번씩 보려면 64만 스텝이다. 게다가 그동안 방문이 고르게 퍼질 이유가 없다 — 좋은 정책은 특정 경로만 반복해 걷기 때문에 대부분의 칸은 수십 번도 보지 못한다.
결론 둘. 세서 만드는 방식은 상태공간이 아주 작을 때만 쓴다 — 연속 상태에서 회귀는 선택이 아니라 필수다(이웃한 상태의 데이터를 서로 빌려 쓸 수 있다). 모델의 정확도는 장소마다 다르다 — 자주 간 곳은 정확하고 드문 곳은 거칠다. 균일한 ε 을 가정한 식 (23.4)는 낙관적이며, 그래서 앙상블로 장소별 불확실성을 재는 것이 중요하다.
(b) Dyna 의 표본효율 산술과 그 천장
식 (23.2)를 실제 숫자로 적는다. 실제 상호작용을 1000 스텝으로 고정했다.
| k | 실제 스텝 | 가짜 갱신 | 총 갱신 | 배수 | 정체 |
|---|---|---|---|---|---|
| 0 | 1000 | 0 | 1000 | 1× | 7장 Q-러닝 |
| 5 | 1000 | 5000 | 6000 | 6× | Dyna-Q |
| 20 | 1000 | 20000 | 21000 | 21× | Dyna-Q |
| 50 | 1000 | 50000 | 51000 | 51× | Dyna-Q |
표 자체는 나눗셈 한 번이다. 중요한 것은 이 배수가 성능 배수가 아니라는 것이고, 그 이유를 작은 예로 확인할 수 있다.
미탐험 상태는 가짜 경험에도 없다
상태 네 개의 복도 s0 — s1 — s2 — s3 에서 보상은 s3 에만 있다고 하자. 에이전트가 s0, s1 사이만 20 스텝 왕복했다. 모델에 기록된 전이는 (s0,R)→s1, (s1,L)→s0, (s1,R)→s2 정도이고 (s2,R) 는 없다.
이제 k=1000 으로 계획한다. 5a 가 뽑을 수 있는 열쇠는 위의 세 개뿐이므로, 2만 번의 가짜 갱신 전부가 보상 0 인 전이에 대한 것이다. Q 는 한 치도 s3 쪽으로 움직이지 않는다. 보상을 발견하는 일은 오직 ε-탐욕의 실제 스텝만 할 수 있다.
거꾸로, 누군가 (s2,R)→s3, r=1 을 단 한 번 실제로 겪어 모델에 넣는 순간, k 번의 가짜 갱신이 그 보상을 s2→s1→s0 으로 한 스텝 안에 역전파한다. γ=0.95, α=1 이면 계획 3 회로 Q(s0,R) = γ2 = 0.9025 까지 간다. 모델프리 Q-러닝이라면 같은 일에 실제 에피소드 세 번이 필요하다.
요약하면 가짜 경험은 정보를 만들지 못하고 퍼뜨리기만 한다. Dyna 가 빠른 것은 발견을 빨리 하기 때문이 아니라, 한 번 한 발견을 공짜로 끝까지 퍼뜨리기 때문이다.
4단의 코드는 이 포화를 숫자로 보여 준다. 6×9 미로에서 자유칸은 47 개이므로 (s,a) 쌍은 47×4 = 188 개다. k=50 으로 돌리면서 실제 스텝마다 모델이 담은 쌍의 수를 재면 이렇다.
| 실제 스텝 | 모델이 아는 쌍 | 방문 상태 | 누적 가짜 갱신 | 가짜 갱신 ÷ 아는 쌍 |
|---|---|---|---|---|
| 10 | 9 / 188 (4.8%) | 6 / 47 | 500 | 55.6 |
| 50 | 37 / 188 (19.7%) | 11 / 47 | 2500 | 67.6 |
| 200 | 66 / 188 (35.1%) | 20 / 47 | 10000 | 151.5 |
| 457 | 150 / 188 (79.8%) | 45 / 47 | 22850 | 152.3 |
맨 윗줄이 핵심이다. 실제 10 스텝 시점에 모델은 9 개 쌍밖에 모르는데 가짜 갱신은 이미 500 번 — 쌍 하나당 56 번이다. 같은 9 개 전이를 56 번씩 되씹은 것이고 유용했던 것은 앞쪽 몇 번뿐이다. k 를 500 으로 올려도 달라질 것이 없다. 그래서 4단 (a) 에서 k=5 와 k=50 의 차이가 k=0 과 k=5 의 차이보다 훨씬 작게 나온다. k 의 수익은 빠르게 체감한다.
(c) 오차 누적 — 식 (23.4)을 숫자로
ε = 0.01 로 고정한다. 모델이 한 스텝에 1% 오차를 낸다는 뜻이다. 아주 좋은 모델이다.
| h | L = 0.95 (수축) | L = 1.00 (중립) | L = 1.05 (발산) | L = 1.20 |
|---|---|---|---|---|
| 1 | 0.010000 | 0.010000 | 0.010000 | 0.010000 |
| 5 | 0.045244 | 0.050000 | 0.055256 | 0.074416 |
| 20 | 0.128303 | 0.200000 | 0.330660 | 1.866880 |
| 50 | 0.184611 | 0.500000 | 2.093480 | 454.971908 |
| h→∞ | 0.200000 | ∞ | ∞ | ∞ |
h=1 행은 네 열이 전부 0.01 로 같다. 한 스텝만 보면 네 환경을 구분할 수 없다. 모델 검증을 한 스텝 예측오차로만 하는 것이 위험한 이유다.
L=0.95 열. h=50 에서 0.1846 이고 h→∞ 에서도 0.2 를 넘지 않는다. ε/(1−L) = 0.01/0.05 = 0.2 다. h=50 에서 이미 천장의 92.3% 에 도달했으므로 h 를 더 늘려도 잃을 것이 없다. 수축하는 환경에서는 길게 상상해도 된다.
L=1.05 열. h=50 에서 2.093480 이다. 처음 오차 0.01 의 209.3 배이고, 같은 h=50 에서 L=0.95 와 비교하면 2.093480 / 0.184611 = 11.34 배다. 두 환경의 차이는 한 스텝에 5% 벌어지느냐 5% 좁혀지느냐 뿐인데 50 스텝 뒤에는 11 배로 갈린다. 검산: 1.0550 = 11.4674 이므로 0.01 × (11.4674 − 1)/0.05 = 0.01 × 209.348 = 2.09348. 표와 같다.
L=1.20 열. h=50 에서 454.97, h=20 에서도 이미 1.867 로 O(1) 상태 스케일을 넘었다. 접촉이 많은 조작 과제에서 20 스텝 롤아웃을 굴리면 안 되는 이유를 이 한 칸이 말한다.

(d) 허용 오차에서 지평을 역산하기
실무에서 던질 질문은 "오차가 얼마냐"가 아니라 "오차를 0.1 아래로 유지하려면 h 를 몇으로 잡나"다. 식 (23.4)를 h 에 대해 뒤집으면 된다. L>1 에서
ε=0.01, δ=0.1 을 넣는다.
| L | h* (실수) | 쓸 수 있는 h | δh at h* 바로 위 | 천장 ε/|1−L| |
|---|---|---|---|---|
| 0.90 | 342.10 | 342 | — | 0.100 (= 허용치) |
| 0.95 | 13.51 | 13 | h=14: 0.102465 | 0.200 |
| 1.00 | 10.00 | 10 | h=11: 0.110000 | ∞ |
| 1.05 | 8.31 | 8 | h=9: 0.110266 | ∞ |
| 1.20 | 6.03 | 6 | h=7: 0.129159 | ∞ |
L=0.95 줄을 검산하자. 1 − δ(1−L)/ε = 1 − 0.1×0.05/0.01 = 1 − 0.5 = 0.5 이므로 h* = log 0.5 / log 0.95 = 13.5134. 표의 h=13 에서 0.097332, h=14 에서 0.102465 로 허용선을 넘는다. 맞다.
L 이 1 을 조금만 넘어도 h 는 한 자리로 떨어진다. L=1.05 에서 8, L=1.2 에서 6 이다. 반면 L=0.9 면 342 로 사실상 제약이 없다. 현대 모델기반 방법의 h=1~5 는 감이 아니라 이 표의 아래쪽 줄을 보수적으로 택한 값이다.
한 가지 더. h 를 두 배 늘리려면 ε 을 얼마나 줄여야 하나. L=1.05, δ=0.1 에서 h=16 이 되려면 ε ≤ 0.1 × 0.05/(1.0516 − 1) = 0.005/1.18287 = 0.004227 이다. 지평을 두 배 늘리는 값은 모델 오차를 2.37 배 줄이는 것이다. 데이터를 모아 ε 을 절반으로 줄이는 일의 어려움을 생각하면, 같은 노력을 가치함수 쪽에 쓰고 h 를 짧게 두는 편이 대체로 남는 장사다.
(e) 환경이 바뀌면 낡은 모델이 해를 끼친다
마지막 손계산이다. 4단 (b) 가 쓸 미로를 종이에서 먼저 풀어 둔다. 6×9 격자의 3 행 전체가 벽인데 왼쪽 끝 한 칸만 뚫려 있다. 출발은 (5,3), 목표는 (0,8) 이다. 3000 스텝이 지나면 오른쪽 끝도 뚫린다.
최단거리와 가치
너비우선으로 세면 변경 전 최단 16 스텝, 변경 후 10 스텝이다. 목표 도달에 보상 1 이고 γ=0.95 이므로, 출발점의 최적 가치는 각각
Q전 = γ15 = 0.9515 = 0.463291, Q후 = γ9 = 0.959 = 0.630249
차이는 0.166958 이다. 지름길을 찾으면 출발점 가치가 36% 오른다 — 작지 않은 개선이고, 찾아야 한다.
그런데 낡은 모델은 (3,8) 로 가는 행동에 대해 "제자리, 보상 0" 을 기억하고 있다. 가짜 갱신이 그 기록을 쓰면 Q((4,8), 위) ← 0 + γ max Q((4,8),·) 가 되어, 그 행동의 가치를 스스로 낮게 유지한다. 그리고 매 실제 스텝마다 k 번씩 이 일이 반복된다. ε-탐욕이 그 칸에서 그 행동을 우연히 고를 확률은 0.1 × 1/4 = 0.025 인데, 그 칸 자체를 찾아갈 이유가 Q 에 전혀 없으니 방문 자체가 드물다.
Dyna-Q+ 의 보너스가 이 교착을 깨는 크기인지 확인하자. κ = 10−3 일 때 보너스는 다음과 같다.
| τ (마지막 시도 후 경과) | κ√τ | γ9−γ15 = 0.166958 대비 |
|---|---|---|
| 1 | 0.001000 | 0.6% |
| 100 | 0.010000 | 6.0% |
| 1000 | 0.031623 | 18.9% |
| 3000 | 0.054772 | 32.8% |
보너스 하나만 보면 τ=3000 에서도 가치 차이의 3 분의 1 에 못 미친다. 단번에 뒤집기에는 작다. 그런데도 통하는 이유는 보너스가 쌓이고 번지기 때문이다.
첫째, 오래 안 가 본 칸이 하나가 아니다. 멀리 있는 영역 전체의 τ 가 동시에 크므로 그 영역으로 가는 경로의 Q 가 여러 칸에서 함께 올라간다. 둘째, k 번의 가짜 갱신이 보너스를 부트스트랩으로 역전파한다 — 한 칸의 0.0548 이 γ 배씩 감가되며 이웃으로 퍼져 가는 길 전체를 올린다. 셋째, 목표에서 먼 구역에서는 0.0548 이 상대적으로 크다. γ15=0.4633 대비 12% 지만 γ25=0.2774 대비로는 20% 다.
그래서 Dyna-Q+ 는 보너스가 가치 차이를 직접 이기지 않고도 오래 안 가 본 곳으로 가는 계획을 만들어 에이전트를 보낸다. 가 보면 τ=0 이 되어 보너스가 꺼지고 모델이 고쳐진다. 4단 (b) 에서 Dyna-Q+ 는 변경 후 255 스텝에 지름길을 처음 밟고 그 뒤 233 회 이용한다. Dyna-Q 는 3000 스텝 내내 한 번도 밟지 않는다.
코드: 미로에서 k 를 바꾸고, 미로를 바꿔 본다
두 실험을 돌린다. (a) 6×9 미로에서 k=0, 5, 50 의 에피소드별 스텝 수를 비교하고, (b) 3000 스텝에서 지름길을 열어 Dyna-Q 와 Dyna-Q+ 의 회복 속도를 비교한다. 난수는 전부 고정했고 numpy 만 쓴다.
import numpy as np
# ---------- 6x9 미로 (자유칸 47개, 최단 14 스텝) ----------
R, C = 6, 9
START, GOAL = (2, 0), (0, 8)
WALL = {(1,2),(2,2),(3,2),(4,5),(0,7),(1,7),(2,7)}
MOVE = [(-1,0),(1,0),(0,-1),(0,1)] # 상 하 좌 우
def step(s, a, wall):
dr, dc = MOVE[a]; r, c = s[0]+dr, s[1]+dc
if not (0 <= r < R and 0 <= c < C) or (r,c) in wall: r, c = s
return (r,c), (1.0 if (r,c)==GOAL else 0.0), (r,c)==GOAL
def greedy(Q, s, rng): # 동점은 무작위로 깬다
q = Q[s]; return int(rng.choice(np.flatnonzero(q == q.max())))
def dyna_q(k, episodes=50, seed=0, alpha=0.1, gamma=0.95, eps=0.1, wall=WALL):
rng = np.random.default_rng(seed)
Q = np.zeros((R,C,4)); model = {}; lens = []
for _ in range(episodes):
s = START; n = 0
while True:
a = rng.integers(4) if rng.random() < eps else greedy(Q, s, rng)
s2, r, done = step(s, a, wall); n += 1
Q[s][a] += alpha*(r + gamma*(0 if done else Q[s2].max()) - Q[s][a])
model[(s,a)] = (s2, r, done) # 모델 학습 (결정적)
keys = list(model)
for _ in range(k): # 가짜 경험 k 번
ks, ka = keys[rng.integers(len(keys))] # 본 적 있는 쌍만
ms, mr, md = model[(ks,ka)]
Q[ks][ka] += alpha*(mr + gamma*(0 if md else Q[ms].max()) - Q[ks][ka])
s = s2
if done or n >= 5000: break
lens.append(n)
return lens
k=0 이면 model 은 채워지기만 하고 쓰이지 않으므로 7장 Q-러닝과 동일하다. 계획 루프 세 줄이 Dyna 의 전부다. 이어서 미로가 바뀌는 실험이다.
# ---------- (b) 막혔던 길이 열린다 — Dyna-Q vs Dyna-Q+ ----------
S2, G2 = (5, 3), (0, 8)
WALL_A = {(3,c) for c in range(1,9)} # 3행의 통로는 왼쪽 끝 하나 — 최단 16
WALL_B = {(3,c) for c in range(1,8)} # 3000스텝 뒤 오른쪽도 열린다 — 최단 10
def run_shortcut(kappa, k=10, total=6000, switch=3000, seed=1,
alpha=0.5, gamma=0.95, eps=0.1):
rng = np.random.default_rng(seed)
Q = np.zeros((R,C,4)); tau = np.zeros((R,C,4)); model = {}
goals = []; shortcut = 0; s = S2
for t in range(1, total+1):
wall = WALL_A if t <= switch else WALL_B # 여기서 환경이 바뀐다
a = rng.integers(4) if rng.random() < eps else greedy(Q, s, rng)
s2, r, done = step2(s, a, wall)
tau += 1.0; tau[s][a] = 0.0 # 실제로 해 본 쌍만 0 으로
Q[s][a] += alpha*(r + gamma*(0 if done else Q[s2].max()) - Q[s][a])
for b in range(4): # 안 해 본 행동도 "제자리,0" 으로 등록
if (s,b) not in model: model[(s,b)] = (s, 0.0, False)
model[(s,a)] = (s2, r, done)
keys = list(model)
for _ in range(k):
ks, ka = keys[rng.integers(len(keys))]
ms, mr, md = model[(ks,ka)]
bonus = kappa*np.sqrt(tau[ks][ka]) # 식 (23.8) 탐험 보너스
Q[ks][ka] += alpha*(mr + bonus + gamma*(0 if md else Q[ms].max()) - Q[ks][ka])
if t > switch and s2 == (3,8): shortcut += 1 # 새로 열린 칸을 밟았나
if done: goals.append(t); s = S2
else: s = s2
return np.array(goals), shortcut
kappa=0.0 이면 보너스 항이 0 이므로 정확히 Dyna-Q 다. 두 알고리즘의 차이가 κ 한 글자뿐이라는 점을 분명히 하려고 이렇게 짰다. 실행 결과다.
k ep1 ep2 ep3 ep5 ep10 ep20 ep50 ep6-50 평균
0 568 665 134 310 90 155 17 67.5
5 732 195 44 24 15 18 15 16.7
50 457 47 16 24 18 16 16 18.0
== 모델의 정의역 — 자유칸 47개 x 4행동 = 188 쌍 중 몇 개를 아는가 (k=50) ==
실제 10 스텝 뒤: 모델 쌍 9/188 ( 4.8%) 방문 상태 6/47 가짜 갱신 누적 500
실제 50 스텝 뒤: 모델 쌍 37/188 (19.7%) 방문 상태 11/47 가짜 갱신 누적 2500
실제 200 스텝 뒤: 모델 쌍 66/188 (35.1%) 방문 상태 20/47 가짜 갱신 누적 10000
실제 457 스텝 뒤: 모델 쌍 150/188 (79.8%) 방문 상태 45/47 가짜 갱신 누적 22850
== (b) 3000 스텝에서 지름길이 열린다 (총 6000, k=10, seed 1) ==
전반 도달 후반 도달 후반 평균스텝/도달 새 칸 밟은 횟수 첫 발견
Dyna-Q 85 166 18.07 0 -1
Dyna-Q+ 91 231 12.99 233 255
최단경로: 변경 전 16 스텝 / 변경 후 10 스텝
(a) 의 결과. 최단경로가 14 스텝이므로 마지막 열이 14 에 가까울수록 잘 배운 것이다.
k=0 — 즉 Q-러닝 — 은 50 에피소드가 지나도 6~50 번째 평균이 67.5 스텝, 최단의 4.8 배다. 3 번째에 134 로 내려갔다 5 번째에 310 으로 되돌아가는 것도 눈에 띈다. 실제 표본 하나가 Q 한 칸만 고치므로 보상이 출발점까지 역전파되는 데 에피소드 수십 번이 걸린다.
k=5 는 16.7 스텝으로 최단의 1.19 배다. 3 번째에 이미 44, 5 번째에 24 다. 실제 스텝 수는 k=0 과 같고 추가된 것은 이미 본 전이 다섯 개를 한 번 더 씹는 계산뿐이다. 실제 상호작용 당 성능이 4 배 개선됐다.
k=50 은 18.0 스텝으로 k=5 와 거의 같다 — 오히려 약간 나쁘다. 계획을 10 배 더 했는데 얻은 것이 없다. 3단 (b) 의 표가 이유를 말한다. 실제 10 스텝 시점에서 모델이 아는 쌍은 9 개뿐인데 이미 500 번 갱신했다. k=5 만으로도 그 9 개 전이가 담은 정보는 충분히 짜냈고, 나머지 45 번은 같은 것을 되씹은 것이다. 1 에피소드만 비교하면 k=50 이 457 로 k=5 의 732 보다 낫다 — 초기에는 계획이 더 값지고, 모델이 충분히 차면 의미가 없어진다. k 는 공짜가 아니라 계산시간이므로, 수익이 꺾이는 지점 근처에서 멈추는 것이 옳다.
세 줄 모두 1 번 에피소드가 수백 스텝이라는 점도 기억할 만하다. k 가 얼마든 첫 보상을 찾는 일은 계획이 도와주지 못한다 — 3단 (b) 의 손계산 그대로다.
전반 3000 스텝에서는 둘이 비슷하다 — 85 회 대 91 회 도달이다. 평균 35.3 스텝과 33.0 스텝으로 최단 16 의 두 배쯤인데, ε=0.1 의 무작위 행동과 목표 재시작이 섞인 값이라 이 정도가 정상이다. Dyna-Q+ 의 보너스가 약간의 추가 탐험을 하지만 큰 차이는 아니다.
3000 스텝에서 (3,8) 이 열린다. 최단경로가 16 에서 10 으로 줄었으니 도달 횟수가 1.6 배로 늘어야 정상이다. Dyna-Q 는 후반 3000 스텝에서 166 회 도달해 평균 18.07 스텝이다. 변경 전 최단 16 과 거의 같다. 그리고 새로 열린 칸을 밟은 횟수가 정확히 0 이다(출력의 "첫 발견 −1" 은 끝까지 한 번도 밟지 않았다는 뜻이다). 지름길이 3000 스텝 동안 열려 있었는데 한 번도 가 보지 않았다.
왜 0 인가. 모델에 (4,8) 에서 위로 가면 제자리라고 적혀 있고 매 스텝 10 번의 가짜 갱신이 그 기록을 재확인한다. Q 는 그 행동을 계속 나쁘게 유지하고, 정책은 그 칸 근처로 갈 이유가 없어 ε-탐욕의 25% 기회조차 주어지지 않는다. 낡은 모델이 자기를 고칠 기회를 스스로 막는다. 모델프리라면 Q 가 서서히 잊히며 결국 시도했을 텐데, 계획이 그 잊기를 막는다. "모델기반이 더 위험하다"는 말의 구체적 내용이다.
Dyna-Q+ 는 κ=10−3 하나를 더한 것뿐인데 후반 231 회, 평균 12.99 스텝이다. 변경 후 최단 10 에 상당히 가깝고, 새 칸을 233 회 밟았다. 도달 횟수가 166 에서 231 로 39% 늘었고 스텝은 18.07 에서 12.99 로 28% 줄었다.
그리고 언제 찾았는지가 중요하다. 변경 후 255 스텝에 처음 밟았고, 그 뒤 2745 스텝 동안 232 번 더 밟았다. 즉 처음 한 번이 어렵고 그다음은 즉시다 — 한 번 실제로 해 보면 모델이 고쳐지고, 10 번의 가짜 갱신이 그 새 사실을 경로 전체로 퍼뜨린다. 255 스텝이라는 값도 우연이 아니다. 3000 스텝 동안 그 구역의 τ 가 이미 크게 자라 있어 보너스가 0.05 대에 도달해 있었고, 계획이 그 값을 오는 길로 번지게 해 두었다. Dyna-Q+ 는 변화를 감지하는 것이 아니라, 모든 곳을 주기적으로 다시 확인하는 습관을 가치함수에 심어 둔다. 변화는 그 습관에 걸려든다.
구현 세부 하나. 위 코드는 방문한 상태의 모든 행동을 "제자리, 보상 0" 으로 미리 등록한다. 그래야 해 본 적 없는 행동에도 보너스가 붙는다. 이 줄이 빠지면 Dyna-Q+ 는 "해 본 것 중 오래된 것"만 확인하고 한 번도 안 해 본 행동은 영원히 후보에서 빠진다.
시각화: 낡은 모델의 고집과 보너스의 기하
도해 1 이 구조를, 도해 2 가 위치를, 도해 3 이 오차의 기하를 보였다. 남은 두 장은 4단 (b) 에서 실제로 일어난 일을 그린다.

이것은 버그가 아니라 설계의 논리적 귀결이다. 모델을 신뢰하고 계획하는 것이 Dyna 의 목적이고, 신뢰는 틀릴 때 비용이 된다. 그래서 모델기반 방법에는 항상 "모델을 의심하는 장치"가 따라붙는다 — 표 기반에서는 κ√τ, 연속에서는 앙상블 불확실성이다.

표 기반에서 신경망으로 — 24장으로 가는 길
이 장의 모델은 딕셔너리 하나였다. 상태가 화면 픽셀이면 이 방식은 즉시 무너진다 — 같은 상태를 두 번 볼 일이 없다. 해법의 방향은 9장에서 봤다. P̂ 를 신경망으로 두고 관측된 전이로 회귀를 학습하면 본 적 없는 상태에도 이웃 데이터에서 일반화한 예측이 나온다.
다만 고차원 관측을 직접 예측하는 것은 낭비다. 84×84 픽셀의 다음 프레임을 맞히려면 모델 용량의 대부분이 배경 텍스처에 쓰이는데 정책에 필요한 정보는 극히 일부다. 게다가 픽셀 오차는 가치와 관계가 희박하다 — 배경을 완벽히 맞히고 공의 위치를 틀리는 모델이 제곱오차로는 좋아 보인다.
그래서 잠재공간에서 동역학을 배운다. 관측을 작은 잠재 벡터 z 로 부호화하고, 동역학을 z 위에서만 굴리고, 필요한 것(보상·종료·가치)만 z 에서 읽는다. 그러면 식 (23.4)의 오차 누적도 잠재공간에서 일어나므로, 픽셀 오차가 아니라 가치에 관련된 오차만 관리하게 된다. 이것이 24장 세계모델이다. 이 장의 식 (23.4)와 (23.7)은 그대로 살아 있다 — 달라지는 것은 ε 을 어디서 재느냐 뿐이다.
이것만 기억하자
- Dyna 는 갱신식을 바꾸지 않는다. 같은 갱신에 들어오는 전이를 환경에서 뽑으면 학습, 배운 모델에서 뽑으면 계획이다. 실제 n 스텝으로 n(1+k) 번 갱신한다 — 5장 DP 와 7장 Q-러닝 사이를 k 라는 다이얼 하나로 잇는다.
- 모델 오차는 지평에 따라 δh ≤ ε(Lh−1)/(L−1) 로 불어난다. ε=0.01 로 같아도 h=50 에서 L=0.95 는 0.1846, L=1.05 는 2.0935 로 11.3 배 갈린다. 허용 오차 0.1 이면 쓸 수 있는 지평이 각각 13 과 8 이다. 긴 상상은 기술적으로 가능하지만 쓸모가 없다.
- k 를 키워도 모델이 못 본 전이는 만들어지지 않는다. 가짜 경험은 정보를 만들지 못하고 퍼뜨리기만 한다. 환경이 바뀌면 낡은 모델이 적극적으로 해를 끼치므로(Dyna-Q 는 열린 지름길을 3000 스텝 동안 0 회 방문했다) κ√τ 같은 모델을 의심하는 장치가 반드시 필요하다.
흔한 오해
- "모델기반이 표본효율이 좋으므로 항상 낫다" — 표본이 싸면 틀린 말이다. 초당 수천 스텝을 뽑는 시뮬레이터라면 모델을 학습하고 그 편향을 관리하는 비용이 그냥 더 돌리는 비용보다 크다. 이점은 실제 표본 하나의 값이 모델 한 스텝의 값보다 훨씬 클 때만 실현된다.
- "계획 횟수 k 는 클수록 좋다" — 4단 (a) 에서 k=5 가 16.7 스텝, k=50 이 18.0 스텝이었다. 10 배 더 계획했는데 나아지지 않았다. 모델이 아는 쌍이 9 개일 때 500 번 갱신하는 것은 같은 정보를 56 번 되씹는 일이다. k 의 수익은 모델이 담은 정보량에서 포화하고, 그 뒤로는 계산시간만 쓴다.
- "한 스텝 예측오차가 작으면 좋은 모델이다" — 3단 (c) 표의 h=1 행을 보라. L=0.95, 1.00, 1.05, 1.20 네 환경이 모두 0.01 로 같다. 한 스텝 오차는 쓸 수 있는 지평을 전혀 말해 주지 않는다. 모델을 검증하려면 h 스텝 롤아웃 오차를 실제로 재야 한다. 많은 구현이 여기서 실패한다.
- "모델기반이면 탐험 문제가 완화된다" — 정반대다. 모델은 본 적 있는 (s,a) 만 담으므로 가짜 경험은 이미 아는 영역 안에서만 만들어진다. 게다가 계획이 기존 지식을 강화하므로 미탐험 영역의 Q 가 올라갈 일이 더 없어진다. 4단 (b) 의 "밟은 횟수 0" 이 그 결과다. 모델기반 방법에는 모델프리보다 더 강한 탐험 장치가 필요하다.
'강화학습' 카테고리의 다른 글
| [강화학습 25] MCTS와 AlphaZero — 탐색이 정책을 가르친다 (0) | 2026.09.15 |
|---|---|
| [강화학습 24] 세계모델 — 잠재공간에서 꿈꾸기 (0) | 2026.09.15 |
| [강화학습 22] TD3 — 과대추정, 세 번째 이야기 (0) | 2026.09.15 |
| [강화학습 21] 최대 엔트로피 RL과 SAC (0) | 2026.09.15 |
| [강화학습 20] PPO — 클리핑이 실제로 하는 일 (0) | 2026.09.15 |
댓글