심층 Q 네트워크(Deep Q-Networks; DQN)

2013년, Mnih는 원시 픽셀(raw pixel) 위에서 하나의 Q-learning 네트워크를 학습시켜 7개의 아타리(Atari) 게임에서 모든 고전적 강화학습(RL) 에이전트를 이겼습니다. 2015년에는 49개 게임으로 확장하고 Nature에 발표해 심층 강화학습(deep-RL) 시대를 열었습니다. DQN은 Q-learning에 함수 근사(function approximation)를 안정화하는 세 가지 기법(trick)을 더한 것입니다.

유형: Build 언어: Python 선수 지식: Phase 3 · 03 (역전파(Backpropagation)), Phase 9 · 04 (Q-learning, SARSA) 예상 시간: 약 75분

문제

테이블 기반 Q-learning(Tabular Q-learning)은 모든 (state, action) 쌍마다 별도의 Q 값(Q-value)이 필요합니다. 체스판은 약 10⁴³개의 상태를 갖습니다. 아타리(Atari) 한 프레임은 210×160×3 = 100,800개의 특징(feature)이 됩니다. 테이블 기반 강화학습은 수천 개의 상태에서도 한계에 부딪힙니다. 수십억 개 상태는 말할 것도 없습니다.

해결책은 지나고 보면 명백합니다. Q 테이블을 신경망 Q(s, a; θ)로 바꾸는 것입니다. 하지만 지나고 나서야 명백해 보이는 이 아이디어가 자리잡기까지는 수십 년이 걸렸습니다. Q-learning에 단순한(naive) 함수 근사를 결합하면 "치명적 삼총사(deadly triad)" 때문에 발산합니다. 치명적 삼총사란 함수 근사(function approximation) + 부트스트래핑(bootstrapping) + 오프-폴리시 학습(off-policy learning)의 결합을 말합니다. Mnih et al. (2013, 2015)은 학습을 안정화하는 세 가지 공학적 기법을 찾아냈습니다.

  1. 경험 재현(Experience replay)은 전이(transition) 사이의 상관관계(correlation)를 끊습니다.
  2. 타깃 네트워크(Target network)는 부트스트랩 목표(bootstrap target)를 고정합니다.
  3. 보상 절단(Reward clipping)은 기울기 크기(gradient magnitude)를 정규화합니다.

아타리에서의 DQN은 하나의 아키텍처와 하나의 하이퍼파라미터(hyperparameter) 묶음으로 원시 픽셀에서 수십 가지 제어 문제를 풀어낸 최초의 사례였습니다. 이후 나온 모든 심층 강화학습 기법, 즉 DDQN, Rainbow, Dueling, Distributional, R2D2, Agent57은 이 세 가지 기법을 토대 위에 쌓아 올린 것입니다.

사전 테스트

2문제 · 이 강의를 시작하기 전에 얼마나 알고 있는지 확인해보세요

1.표 기반 Q-learning(tabular Q-learning)은 모든 (상태, 행동) 쌍마다 별도의 값을 저장합니다. 210x160x3 픽셀 관측을 가진 아타리(Atari) 게임에서 이 방식이 실패하는 이유는 무엇인가요?

2.'치명적 삼총사(deadly triad)'는 단순한 신경망 Q-learning이 발산하는 이유를 설명합니다. 이 삼총사를 구성하는 세 가지 요소는 무엇인가요?

0/2 답변 완료

개념

DQN: Q-learning + replay + target network environment (s, a) -> (r, s') Atari, GridWorld, whatever online net Q(.; theta) acts epsilon-greedy trained every step replay buffer D (s, a, r, s', done) ~1M transitions, uniform sample target theta^- frozen sync/C gradient step: one minibatch, TD squared error for (s, a, r, s', done) in buffer.sample(batch): y = r if done y = r + gamma * max_a' Q(s', a'; theta^-) otherwise loss = (Q(s, a; theta) - y)^2 theta -= lr * d loss / d theta updated theta acts next step three tricks, one loss, one neural net: the deep RL era begins

목적 함수(objective). DQN은 신경망 Q 함수 위에서 1-스텝 시간차(one-step TD) 손실을 최소화합니다.

L(θ) = E_{(s,a,r,s')~D} [ (r + γ max_{a'} Q(s', a'; θ^-) - Q(s, a; θ))² ]

θ는 온라인 네트워크(online network)이며 매 스텝(step) 경사 하강(gradient descent)으로 갱신됩니다. θ^-는 타깃 네트워크(target network)이며 주기적으로 θ에서 복사됩니다(대략 10,000 스텝마다). D는 과거 전이를 담는 재현 버퍼(replay buffer)입니다.

세 가지 기법을 중요도 순서로 정리하면 다음과 같습니다.

경험 재현(Experience replay).10⁶개의 전이를 담는 순환 버퍼(ring buffer)입니다. 각 학습 스텝은 미니배치(minibatch)를 균등 무작위(uniformly at random)로 표본 추출합니다. 이렇게 하면 연속된 프레임이 거의 동일하다는 시간적 상관관계(temporal correlation)가 끊깁니다. 또한 드물게 나타나는 보상 전이를 여러 번 학습할 수 있게 해주고, 연속된 기울기 갱신(gradient update) 사이의 상관관계도 낮춰 줍니다. 이것이 없으면 신경망을 사용하는 온-폴리시(on-policy) 시간차 학습은 아타리에서 발산합니다.

타깃 네트워크(Target network). 벨만 방정식(Bellman equation)의 양쪽에 같은 네트워크 Q(·; θ)를 사용하면 목표가 매 갱신마다 움직입니다. 이것은 마치 "자기 꼬리를 쫓는(chasing your own tail)" 상황과 같습니다. 해결책은 가중치를 고정한 두 번째 네트워크 Q(·; θ^-)를 따로 두는 것입니다. 매 C 스텝마다 θ → θ^-로 복사합니다. 이렇게 하면 수천 번의 기울기 갱신 동안 회귀 목표(regression target)가 안정적으로 유지됩니다. DDPG와 SAC에서 사용하는 부드러운 갱신(soft update) θ^- ← τ θ + (1-τ) θ^-는 더 매끄러운 변형입니다.

보상 절단(Reward clipping). 아타리의 보상 크기는 1부터 1000+까지 다양합니다. {-1, 0, +1} 범위로 절단(clipping)하면 특정 게임 하나가 기울기를 지배하는 일이 없습니다. 보상 크기 자체가 중요한 경우에는 잘못된 선택이지만, 부호(sign)만 중요한 아타리에서는 적절합니다.

더블 DQN(Double DQN). Hasselt (2016)는 최대화 편향(maximization bias)을 바로잡았습니다. 온라인 네트워크는 행동을 *선택(select)*하고, 타깃 네트워크는 그 행동을 *평가(evaluate)*하도록 합니다.

target = r + γ Q(s', argmax_{a'} Q(s', a'; θ); θ^-)

그대로 갈아 끼울 수 있고(drop-in replacement) 꾸준히 성능이 더 좋습니다. 기본값으로 사용합니다.

그 밖의 개선(Rainbow, 2017). 우선순위 재현(prioritized replay)은 시간차 오차(TD-error)가 큰 전이를 더 자주 표본 추출합니다. 듀얼 아키텍처(dueling architecture)는 상태 가치 V(s)와 어드밴티지(advantage) 헤드를 분리합니다. 노이지 네트워크(noisy networks)는 학습된 탐험을 제공합니다. 이외에도 n-스텝 반환(n-step returns), 분포형 Q(distributional Q; C51/QR-DQN), 다단계 부트스트래핑(multi-step bootstrapping) 등이 있습니다. 각각 몇 퍼센트의 성능 향상을 가져오며, 이익은 대체로 합쳐서 적용해도 누적됩니다.

직접 만들기

여기의 코드는 표준 라이브러리(stdlib)만 사용하고 numpy도 쓰지 않습니다. 작은 연속형 그리드월드(continuous GridWorld) 위에서 손으로 구현한(hand-rolled) 은닉층 한 개짜리 다층 퍼셉트론(single-hidden-layer MLP)을 쓰기 때문에 모든 학습 스텝이 마이크로초(microseconds) 단위로 실행됩니다. 알고리즘은 큰 규모의 아타리 DQN과 동일합니다.

Step 1: 재현 버퍼(replay buffer)

class ReplayBuffer:
    def __init__(self, capacity):
        self.buf = []
        self.capacity = capacity
    def push(self, s, a, r, s_next, done):
        if len(self.buf) == self.capacity:
            self.buf.pop(0)
        self.buf.append((s, a, r, s_next, done))
    def sample(self, batch, rng):
        return rng.sample(self.buf, batch)

아타리에서는 약 50,000 정도의 용량(capacity)을 쓰고, 우리 장난감(toy) 환경에서는 5,000이면 충분합니다.

Step 2: 작은 Q 네트워크(수동 MLP)

class QNet:
    def __init__(self, n_in, n_hidden, n_actions, rng):
        self.W1 = [[rng.gauss(0, 0.3) for _ in range(n_in)] for _ in range(n_hidden)]
        self.b1 = [0.0] * n_hidden
        self.W2 = [[rng.gauss(0, 0.3) for _ in range(n_hidden)] for _ in range(n_actions)]
        self.b2 = [0.0] * n_actions
    def forward(self, x):
        h = [max(0.0, sum(w * xi for w, xi in zip(row, x)) + b) for row, b in zip(self.W1, self.b1)]
        q = [sum(w * hi for w, hi in zip(row, h)) + b for row, b in zip(self.W2, self.b2)]
        return q, h

순전파(forward pass)는 선형 → ReLU → 선형으로 이어집니다. 이것이 네트워크 전체입니다.

Step 3: DQN 갱신

def train_step(online, target, batch, gamma, lr):
    grads = zeros_like(online)
    for s, a, r, s_next, done in batch:
        q, h = online.forward(s)
        if done:
            y = r
        else:
            q_next, _ = target.forward(s_next)
            y = r + gamma * max(q_next)
        td_error = q[a] - y
        accumulate_grads(grads, online, s, h, a, td_error)
    apply_sgd(online, grads, lr / len(batch))

형태는 Lesson 04에서 본 Q-learning과 같습니다. 차이는 두 가지입니다. (a) 테이블을 색인으로 참조하는 대신 미분 가능한 Q(·; θ)를 역전파(backprop)합니다. (b) 목표값은 Q(·; θ^-)를 사용해 계산합니다.

Step 4: 바깥 루프

각 에피소드(episode)에서 Q(·; θ)에 대해 ε-탐욕(ε-greedy)으로 행동하고, 전이를 버퍼에 넣고, 미니배치를 표본 추출해 기울기 스텝을 밟고, 주기적으로 θ^- ← θ로 동기화(sync)합니다. 패턴은 다음과 같습니다.

for episode in range(N):
    s = env.reset()
    while not done:
        a = epsilon_greedy(online, s, epsilon)
        s_next, r, done = env.step(s, a)
        buffer.push(s, a, r, s_next, done)
        if len(buffer) >= batch:
            train_step(online, target, buffer.sample(batch), gamma, lr)
        if steps % sync_every == 0:
            target = copy(online)
        s = s_next

16차원 원-핫(one-hot) 상태를 쓰는 작은 그리드월드에서는 약 500 에피소드 안에 거의 최적(near-optimal) 정책을 학습합니다. 아타리에서는 이를 2억(200M) 프레임까지 키우고 CNN 기반 특징 추출기(feature extractor)를 덧붙입니다.

주의할 점

  • 치명적 삼총사(Deadly triad). 함수 근사 + 오프-폴리시 + 부트스트래핑의 조합은 발산할 수 있습니다. DQN은 타깃 네트워크와 재현 버퍼로 이를 완화합니다. 둘 중 어느 하나도 제거하지 않습니다.
  • 탐험(Exploration). ε는 보통 학습 첫 10% 동안 1.0에서 0.01로 감소해야 합니다. 초기 탐험이 충분하지 않으면 Q 네트워크는 지역 최적점(local basin)으로 수렴합니다.
  • 과대추정(Overestimation). 잡음이 있는 Q 값 위에서 max를 취하면 위쪽으로 편향됩니다. 실제 운영(production)에서는 항상 더블 DQN을 사용합니다.
  • 보상 스케일(Reward scale). 보상을 절단하거나 정규화(normalize)합니다. 기울기 크기는 보상 크기에 비례합니다.
  • 재현 버퍼 콜드스타트(Replay buffer coldstart). 버퍼에 전이가 몇천 개 쌓이기 전에는 학습을 시작하지 않습니다. 약 20개 표본에서 나온 초기 기울기는 과적합(overfit)됩니다.
  • 타깃 동기화 주기(Target sync frequency). 너무 자주 동기화하면 타깃 네트워크가 없는 것과 비슷해지고, 너무 드물게 동기화하면 목표가 낡아집니다(stale). 아타리 DQN은 환경 스텝 10,000번을 사용합니다. 경험칙은 학습 지평(training horizon)의 약 1/100마다 동기화하는 것입니다.
  • 관측 전처리(Observation preprocessing). 아타리 DQN은 상태를 마르코프(Markov) 형태로 만들기 위해 4개의 프레임을 쌓습니다(frame-stacking). 속도(velocity) 정보가 필요한 환경에서는 프레임 스태킹 또는 순환 상태(recurrent state)가 필요합니다.

사용해보기

2026년 시점에서 DQN이 최첨단(state-of-the-art) 자리에 오르는 경우는 드물지만, 여전히 기준이 되는 오프-폴리시 알고리즘으로 남아 있습니다.

작업선택 방법DQN을 그대로 쓰지 않는 이유
이산 행동의 아타리 류Rainbow DQN 또는 Muesli같은 프레임워크에 더 많은 기법을 얹습니다.
연속 제어(Continuous control)SAC / TD3 (Phase 9 · 07)DQN에는 정책 네트워크(policy network)가 없습니다.
온-폴리시 / 고처리량(high-throughput)PPO (Phase 9 · 08)재현 버퍼가 없고 확장(scale)하기 쉽습니다.
오프라인 강화학습(Offline RL)CQL / IQL / Decision Transformer보수적 Q 목표가 필요하고 부트스트래핑 폭주를 막아야 합니다.
큰 이산 행동 공간(추천 시스템 등)행동 임베딩(action embedding)을 가진 DQN 또는 IMPALA가능하지만 부가 장식(decoration)이 중요합니다.
거대 언어 모델(LLM) 강화학습PPO / GRPO스텝 단위가 아니라 시퀀스 단위(sequence-level)이고, 손실 함수도 다릅니다.

그래도 이 강의에서 배운 내용은 그대로 이어집니다. 재현 버퍼와 타깃 네트워크는 SAC, TD3, DDPG, SAC-X, AlphaZero의 셀프 플레이 버퍼(self-play buffer), 그리고 모든 오프라인 강화학습 기법에 등장합니다. 보상 절단은 PPO의 어드밴티지 정규화(advantage normalization)로 살아 있습니다. DQN 아키텍처는 청사진(blueprint) 역할을 합니다.

산출물 만들기

outputs/skill-dqn-trainer.md로 저장합니다.

---
name: dqn-trainer
description: Produce a DQN training config (buffer, target sync, ε schedule, reward clipping) for a discrete-action RL task.
version: 1.0.0
phase: 9
lesson: 5
tags: [rl, dqn, deep-rl]
---

Given a discrete-action environment (observation shape, action count, horizon, reward scale), output:

1. Network. Architecture (MLP / CNN / Transformer), feature dim, depth.
2. Replay buffer. Capacity, minibatch size, warmup size.
3. Target network. Sync strategy (hard every C steps or soft τ).
4. Exploration. ε start / end / schedule length.
5. Loss. Huber vs MSE, gradient clip value, reward clipping rule.
6. Double DQN. On by default unless explicit reason to disable.

Refuse to ship a DQN with no target network, no replay buffer, or ε held at 1. Refuse continuous-action tasks (route to SAC / TD3). Flag any reward range > 10× per-step mean as needing clipping or scale normalization.

연습문제

  1. 쉬움. code/main.py를 실행합니다. 에피소드별 반환(return) 곡선을 그려 봅니다. 이동 평균(running mean)이 -10을 넘기까지 몇 에피소드가 걸리나요?
  2. 중간. 타깃 네트워크를 비활성화합니다. 벨만 목표(Bellman target)의 양쪽에 온라인 네트워크를 사용합니다. 학습 불안정성을 측정합니다. 반환이 진동하거나 발산하나요?
  3. 어려움. 더블 DQN을 추가합니다. 온라인 네트워크로 argmax a'를 고르고 타깃 네트워크로 평가합니다. 잡음 있는 보상의 그리드월드에서 1,000 에피소드 뒤 더블 DQN을 썼을 때와 쓰지 않았을 때 Q(s_0, best_a)의 편향(bias)을 참값 V*(s_0)와 비교합니다.

핵심 용어

용어흔한 설명실제 의미
DQN"심층 Q 학습(Deep Q-learning)"신경망 Q 함수와 재현 버퍼, 타깃 네트워크를 가진 Q-learning이다.
경험 재현(Experience replay)"섞인 전이(Shuffled transitions)"매 기울기 스텝마다 균등 표본 추출되는 순환 버퍼다. 데이터 상관관계를 낮춘다.
타깃 네트워크(Target network)"고정된 부트스트랩(Frozen bootstrap)"벨만 목표에 쓰는 Q의 주기적 복사본이다. 학습을 안정화한다.
치명적 삼총사(Deadly triad)"강화학습이 발산하는 이유"함수 근사 + 부트스트래핑 + 오프-폴리시 조합에는 수렴 보장이 없다.
더블 DQN(Double DQN)"최대화 편향(Maximization bias) 수정"온라인 네트워크가 행동을 선택하고 타깃 네트워크가 평가한다.
듀얼 DQN(Dueling DQN)"V와 A 헤드"Q = V + A - mean(A)로 분해한다. 출력은 같지만 기울기 흐름(gradient flow)이 더 낫다.
Rainbow"모든 기법"DDQN + PER + dueling + n-step + noisy + distributional을 하나로 합친다.
PER"우선순위 재현(Prioritized Replay)"시간차 오차 크기에 비례해 전이를 표본 추출한다.

더 읽을거리

실습 코드

이 강의의 실습 코드 1개

main
Code

산출물

이 강의에서 생성된 프롬프트, 스킬, 코드 산출물 1개

dqn-trainer

Produce a DQN training config (buffer, target sync, ε schedule, reward clipping) for a discrete-action RL task.

Skill

확인 문제

3문제 · 모두 맞추면 완료 표시가 가능합니다

1.DQN에서 타깃 네트워크를 제거하고 같은 온라인 네트워크 Q(s,a;theta)를 예측과 벨만 타깃 모두에 사용합니다. 학습이 불안정해지고 리턴이 진동합니다. 왜 이런 일이 일어나나요?

2.DQN의 경험 재현 버퍼(experience replay buffer)는 ~10^6개의 전이를 저장하고 균등 무작위로 미니배치를 표본 추출합니다. 대신 연속된 전이를 순서대로 학습하면 어떻게 될까요?

3.더블 DQN(Double DQN)은 타깃을 r + gamma * Q(s', argmax_a' Q(s',a';theta); theta^-)로 수정합니다. 이것이 표준 DQN의 과대추정(overestimation) 문제를 어떻게 해결하나요?

0/3 답변 완료

추가 문제 풀기

AI가 강의 내용을 바탕으로 새로운 문제를 생성합니다