Skip to content
Published on

강화학습 완전 정복: DQN, PPO부터 RLHF, DPO까지 LLM 정렬까지

Authors

들어가며

강화학습(Reinforcement Learning, RL)은 에이전트가 환경과 상호작용하며 보상을 최대화하는 정책을 스스로 학습하는 머신러닝 패러다임입니다. AlphaGo의 바둑 세계 정복부터 ChatGPT의 RLHF 정렬까지, 현대 AI의 핵심 기술로 자리잡았습니다.

이 포스트는 MDP 수학 기초부터 최신 DPO까지 한 번에 정리합니다.


1. 강화학습의 기초: MDP

마르코프 결정 과정 (Markov Decision Process)

강화학습은 MDP로 공식화됩니다. MDP는 5-튜플 (S,A,P,R,γ)(S, A, P, R, \gamma)로 정의합니다:

  • SS: 상태 공간 (State space)
  • AA: 행동 공간 (Action space)
  • P(ss,a)P(s'|s, a): 전이 확률 (Transition probability)
  • R(s,a,s)R(s, a, s'): 보상 함수 (Reward function)
  • γ[0,1)\gamma \in [0, 1): 할인율 (Discount factor)

마르코프 성질: 미래 상태는 현재 상태만으로 결정됩니다.

P(st+1st,at,st1,at1,)=P(st+1st,at)P(s_{t+1} | s_t, a_t, s_{t-1}, a_{t-1}, \ldots) = P(s_{t+1} | s_t, a_t)

정책 (Policy)

정책 π\pi는 상태에서 행동으로의 매핑입니다:

  • 결정론적 정책: a=π(s)a = \pi(s)
  • 확률론적 정책: aπ(as)a \sim \pi(a|s)

가치 함수 (Value Function)

상태 가치 함수: 정책 π\pi를 따를 때 상태 ss의 기대 누적 보상

Vπ(s)=Eπ[t=0γtrts0=s]V^\pi(s) = \mathbb{E}_\pi \left[ \sum_{t=0}^{\infty} \gamma^t r_t \,\Big|\, s_0 = s \right]

행동 가치 함수 (Q-함수): 상태 ss에서 행동 aa를 취한 후 정책 π\pi를 따를 때의 기대 보상

Qπ(s,a)=Eπ[t=0γtrts0=s,a0=a]Q^\pi(s, a) = \mathbb{E}_\pi \left[ \sum_{t=0}^{\infty} \gamma^t r_t \,\Big|\, s_0 = s, a_0 = a \right]

벨만 방정식 (Bellman Equation)

가치 함수의 재귀적 분해:

Vπ(s)=aπ(as)sP(ss,a)[R(s,a,s)+γVπ(s)]V^\pi(s) = \sum_a \pi(a|s) \sum_{s'} P(s'|s,a) \left[ R(s,a,s') + \gamma V^\pi(s') \right]

벨만 최적 방정식:

V(s)=maxasP(ss,a)[R(s,a,s)+γV(s)]V^*(s) = \max_a \sum_{s'} P(s'|s,a) \left[ R(s,a,s') + \gamma V^*(s') \right]

Q(s,a)=sP(ss,a)[R(s,a,s)+γmaxaQ(s,a)]Q^*(s, a) = \sum_{s'} P(s'|s,a) \left[ R(s,a,s') + \gamma \max_{a'} Q^*(s', a') \right]


2. 모델 프리 강화학습

Q-Learning (오프-폴리시)

Q-Learning은 오프-폴리시(off-policy) 방법입니다. TD 업데이트:

Q(st,at)Q(st,at)+α[rt+γmaxaQ(st+1,a)Q(st,at)]Q(s_t, a_t) \leftarrow Q(s_t, a_t) + \alpha \left[ r_t + \gamma \max_{a'} Q(s_{t+1}, a') - Q(s_t, a_t) \right]

타깃: rt+γmaxaQ(st+1,a)r_t + \gamma \max_{a'} Q(s_{t+1}, a') (그리디 정책 사용)

SARSA (온-폴리시)

SARSA는 온-폴리시(on-policy) 방법입니다:

Q(st,at)Q(st,at)+α[rt+γQ(st+1,at+1)Q(st,at)]Q(s_t, a_t) \leftarrow Q(s_t, a_t) + \alpha \left[ r_t + \gamma Q(s_{t+1}, a_{t+1}) - Q(s_t, a_t) \right]

타깃: rt+γQ(st+1,at+1)r_t + \gamma Q(s_{t+1}, a_{t+1}) (실제 다음 행동 at+1a_{t+1} 사용)

구분Q-LearningSARSA
정책 유형오프-폴리시온-폴리시
업데이트 기준greedy 행동실제 행동
절벽 탐색최적 경로안전 경로

DQN (Deep Q-Network)

DQN은 신경망으로 Q-함수를 근사합니다. 두 가지 핵심 안정화 기법:

  1. 경험 재플레이 (Experience Replay): 버퍼에서 미니배치 샘플링
  2. 타깃 네트워크 (Target Network): 주기적으로 복사된 별도 네트워크
import torch
import torch.nn as nn
import numpy as np
from collections import deque
import random

class DQN(nn.Module):
    def __init__(self, state_dim, action_dim):
        super().__init__()
        self.net = nn.Sequential(
            nn.Linear(state_dim, 128),
            nn.ReLU(),
            nn.Linear(128, 128),
            nn.ReLU(),
            nn.Linear(128, action_dim)
        )

    def forward(self, x):
        return self.net(x)

class ReplayBuffer:
    def __init__(self, capacity=10000):
        self.buffer = deque(maxlen=capacity)

    def push(self, state, action, reward, next_state, done):
        self.buffer.append((state, action, reward, next_state, done))

    def sample(self, batch_size):
        batch = random.sample(self.buffer, batch_size)
        states, actions, rewards, next_states, dones = zip(*batch)
        return (
            torch.FloatTensor(np.array(states)),
            torch.LongTensor(actions),
            torch.FloatTensor(rewards),
            torch.FloatTensor(np.array(next_states)),
            torch.FloatTensor(dones)
        )

    def __len__(self):
        return len(self.buffer)

def train_dqn_step(online_net, target_net, optimizer, buffer, batch_size=64, gamma=0.99):
    if len(buffer) < batch_size:
        return
    states, actions, rewards, next_states, dones = buffer.sample(batch_size)

    # 현재 Q값
    current_q = online_net(states).gather(1, actions.unsqueeze(1)).squeeze(1)

    # 타깃 Q값 (타깃 네트워크 사용)
    with torch.no_grad():
        max_next_q = target_net(next_states).max(1)[0]
        target_q = rewards + gamma * max_next_q * (1 - dones)

    loss = nn.MSELoss()(current_q, target_q)
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()
    return loss.item()

Double DQN

DQN의 과대추정(overestimation) 문제 해결. 행동 선택과 가치 평가 분리:

Q(st,at)rt+γQtarget ⁣(st+1,  argmaxaQonline(st+1,a))Q(s_t, a_t) \leftarrow r_t + \gamma Q_{\text{target}}\!\left(s_{t+1},\; \arg\max_{a'} Q_{\text{online}}(s_{t+1}, a')\right)

Dueling DQN

Q-값을 가치 함수 V(s)V(s)와 어드밴티지 함수 A(s,a)A(s,a)로 분해:

Q(s,a)=V(s)+A(s,a)1AaA(s,a)Q(s, a) = V(s) + A(s, a) - \frac{1}{|A|} \sum_{a'} A(s, a')

class DuelingDQN(nn.Module):
    def __init__(self, state_dim, action_dim):
        super().__init__()
        self.feature = nn.Sequential(
            nn.Linear(state_dim, 128), nn.ReLU()
        )
        # 가치 스트림
        self.value_stream = nn.Sequential(
            nn.Linear(128, 64), nn.ReLU(), nn.Linear(64, 1)
        )
        # 어드밴티지 스트림
        self.advantage_stream = nn.Sequential(
            nn.Linear(128, 64), nn.ReLU(), nn.Linear(64, action_dim)
        )

    def forward(self, x):
        feat = self.feature(x)
        value = self.value_stream(feat)
        advantage = self.advantage_stream(feat)
        # 결합: Q = V + (A - mean(A))
        return value + advantage - advantage.mean(dim=1, keepdim=True)

3. 정책 경사법 (Policy Gradient)

REINFORCE

정책을 직접 파라미터화하고 경사를 추정합니다:

θJ(θ)=Eτπθ[t=0Tθlogπθ(atst)Gt]\nabla_\theta J(\theta) = \mathbb{E}_{\tau \sim \pi_\theta} \left[ \sum_{t=0}^{T} \nabla_\theta \log \pi_\theta(a_t|s_t) \cdot G_t \right]

여기서 Gt=k=tTγktrkG_t = \sum_{k=t}^{T} \gamma^{k-t} r_k는 시간 tt에서의 누적 보상입니다.

Actor-Critic

REINFORCE의 높은 분산 문제를 해결하기 위해 베이스라인으로 가치 함수를 사용:

θJ(θ)=E[θlogπθ(atst)A(st,at)]\nabla_\theta J(\theta) = \mathbb{E} \left[ \nabla_\theta \log \pi_\theta(a_t|s_t) \cdot A(s_t, a_t) \right]

어드밴티지 함수: A(st,at)=Q(st,at)V(st)A(s_t, a_t) = Q(s_t, a_t) - V(s_t)

TD 오차로 근사: A(st,at)rt+γV(st+1)V(st)A(s_t, a_t) \approx r_t + \gamma V(s_{t+1}) - V(s_t)

A3C / A2C

A3C (Asynchronous Advantage Actor-Critic): 여러 워커가 비동기 병렬 학습

A2C (Advantage Actor-Critic): 동기식으로 모든 워커 경사를 평균내어 업데이트

PPO (Proximal Policy Optimization)

현재 가장 널리 쓰이는 정책 경사 알고리즘. 핵심 아이디어: 정책 업데이트 폭 제한으로 안정적 학습.

클리핑된 목적 함수:

LCLIP(θ)=Et[min ⁣(rt(θ)At,  clip(rt(θ),1ϵ,1+ϵ)At)]L^{CLIP}(\theta) = \mathbb{E}_t \left[ \min\!\left( r_t(\theta) A_t,\; \text{clip}(r_t(\theta), 1-\epsilon, 1+\epsilon) A_t \right) \right]

여기서 rt(θ)=πθ(atst)πθold(atst)r_t(\theta) = \frac{\pi_\theta(a_t|s_t)}{\pi_{\theta_{old}}(a_t|s_t)}는 확률비입니다.

PPO의 완전한 목적 함수:

L(θ)=LCLIP(θ)c1LVF(θ)+c2H[πθ]L(\theta) = L^{CLIP}(\theta) - c_1 L^{VF}(\theta) + c_2 H[\pi_\theta]

  • LVFL^{VF}: 가치 함수 손실 (MSE)
  • H[πθ]H[\pi_\theta]: 엔트로피 보너스 (탐색 장려)
from stable_baselines3 import PPO
import gymnasium as gym

env = gym.make("CartPole-v1")
model = PPO(
    "MlpPolicy",
    env,
    learning_rate=3e-4,
    n_steps=2048,
    batch_size=64,
    n_epochs=10,
    gamma=0.99,
    gae_lambda=0.95,
    clip_range=0.2,       # epsilon: 클립 비율
    ent_coef=0.01,        # 엔트로피 보너스 계수
    verbose=1
)
model.learn(total_timesteps=100_000)

obs, _ = env.reset()
for _ in range(1000):
    action, _ = model.predict(obs, deterministic=True)
    obs, reward, terminated, truncated, info = env.step(action)
    if terminated or truncated:
        obs, _ = env.reset()

4. 고급 기법

SAC (Soft Actor-Critic)

SAC는 최대 엔트로피 강화학습 프레임워크입니다. 보상 최대화와 엔트로피 최대화를 동시에 추구:

π=argmaxπE[tγt(rt+αH[π(st)])]\pi^* = \arg\max_\pi \mathbb{E} \left[ \sum_t \gamma^t \left( r_t + \alpha \mathcal{H}[\pi(\cdot|s_t)] \right) \right]

α\alpha는 온도 파라미터로 탐색의 정도를 조절합니다.

소프트 Q-함수 벨만 방정식:

Q(st,at)=rt+γEst+1[V(st+1)]Q(s_t, a_t) = r_t + \gamma \mathbb{E}_{s_{t+1}} \left[ V(s_{t+1}) \right]

V(st)=Eaπ[Q(st,a)αlogπ(ast)]V(s_t) = \mathbb{E}_{a \sim \pi} \left[ Q(s_t, a) - \alpha \log \pi(a|s_t) \right]

SAC는 연속 행동 공간 문제에서 탁월하며, 자동 온도 조절로 하이퍼파라미터 민감도가 낮습니다.

from stable_baselines3 import SAC

env = gym.make("HalfCheetah-v4")
model = SAC(
    "MlpPolicy", env,
    learning_rate=3e-4,
    buffer_size=1_000_000,
    learning_starts=10_000,
    batch_size=256,
    tau=0.005,
    gamma=0.99,
    train_freq=1,
    gradient_steps=1,
    verbose=1
)
model.learn(total_timesteps=1_000_000)

TD3 (Twin Delayed Deep Deterministic)

DDPG의 과대추정 문제를 해결하는 3가지 기법:

  1. Twin Critics: 두 Q-네트워크의 최솟값 선택
  2. Delayed Policy Updates: 액터를 크리틱보다 낮은 빈도로 업데이트
  3. Target Policy Smoothing: 타깃 행동에 노이즈 추가

y=r+γmini=1,2Qθi(s,a~),a~=clip(πϕ(s)+ϵ,alow,ahigh)y = r + \gamma \min_{i=1,2} Q_{\theta_i'}(s', \tilde{a}'), \quad \tilde{a}' = \text{clip}(\pi_{\phi'}(s') + \epsilon, a_{low}, a_{high})

HER (Hindsight Experience Replay)

희소 보상(sparse reward) 환경에서 실패한 경험도 재활용합니다. 목표를 실제 도달한 상태로 사후에 교체하여 학습:

  • 원래 경험: (st,at,rt,st+1,g)(s_t, a_t, r_t, s_{t+1}, g) — 목표 gg에 실패
  • HER 변환: (st,at,rt,st+1,g)(s_t, a_t, r'_t, s_{t+1}, g')g=sTg' = s_T (실제 최종 상태)

목표 교체 전략:

  • future: 같은 에피소드의 미래 상태 중 랜덤 선택 (기본값)
  • episode: 같은 에피소드의 임의 상태
  • final: 에피소드 마지막 상태
from stable_baselines3 import HerReplayBuffer, SAC

# 로봇 암 목표 도달 환경
env = gym.make("FetchReach-v2")
model = SAC(
    "MultiInputPolicy",
    env,
    replay_buffer_class=HerReplayBuffer,
    replay_buffer_kwargs=dict(
        n_sampled_goal=4,
        goal_selection_strategy="future",
    ),
    verbose=1,
)
model.learn(total_timesteps=100_000)

5. RLHF: 강화학습으로 LLM 정렬하기

InstructGPT 파이프라인

ChatGPT의 핵심인 RLHF(Reinforcement Learning from Human Feedback)는 3단계로 구성됩니다:

1단계: SFT (Supervised Fine-Tuning)

  • 고품질 데모 데이터로 기본 모델 파인튜닝
  • 인간 전문가가 작성한 이상적인 응답으로 학습

2단계: 보상 모델 훈련 (Reward Model Training)

  • 인간이 두 응답 중 더 나은 것을 선택 (선호도 데이터 수집)
  • 선호도 데이터로 보상 모델 학습

LRM=E(x,yw,yl)[logσ ⁣(rϕ(x,yw)rϕ(x,yl))]\mathcal{L}_{RM} = -\mathbb{E}_{(x, y_w, y_l)} \left[ \log \sigma\!\left( r_\phi(x, y_w) - r_\phi(x, y_l) \right) \right]

ywy_w는 선호된 응답, yly_l은 선호되지 않은 응답입니다.

3단계: PPO로 LLM 파인튜닝

  • 보상 모델을 환경으로, LLM을 에이전트로 PPO 적용
  • KL 페널티로 원래 모델에서 너무 멀어지지 않도록 제어

reward(x,y)=rϕ(x,y)βKL ⁣[πθ(yx)πref(yx)]\text{reward}(x, y) = r_\phi(x, y) - \beta \cdot \text{KL}\!\left[\pi_\theta(y|x) \,\|\, \pi_{ref}(y|x)\right]

import torch
import torch.nn as nn

class RewardModel(nn.Module):
    def __init__(self, base_model_name="gpt2"):
        super().__init__()
        from transformers import AutoModel
        self.backbone = AutoModel.from_pretrained(base_model_name)
        hidden_size = self.backbone.config.hidden_size
        self.reward_head = nn.Linear(hidden_size, 1)

    def forward(self, input_ids, attention_mask):
        outputs = self.backbone(input_ids=input_ids, attention_mask=attention_mask)
        last_hidden = outputs.last_hidden_state[:, -1, :]
        return self.reward_head(last_hidden).squeeze(-1)

def compute_reward_model_loss(reward_model, chosen_ids, chosen_mask,
                               rejected_ids, rejected_mask):
    """Bradley-Terry 모델 기반 선호도 손실"""
    chosen_reward = reward_model(chosen_ids, chosen_mask)
    rejected_reward = reward_model(rejected_ids, rejected_mask)
    loss = -torch.log(torch.sigmoid(chosen_reward - rejected_reward)).mean()
    return loss

PPO로 LLM 파인튜닝 (TRL 라이브러리):

from trl import PPOTrainer, PPOConfig, AutoModelForCausalLMWithValueHead
from transformers import AutoTokenizer

ppo_config = PPOConfig(
    model_name="gpt2",
    learning_rate=1.41e-5,
    batch_size=128,
    mini_batch_size=16,
    gradient_accumulation_steps=4,
    target_kl=0.1,
    kl_penalty="kl",
)

model = AutoModelForCausalLMWithValueHead.from_pretrained(ppo_config.model_name)
tokenizer = AutoTokenizer.from_pretrained(ppo_config.model_name)
ppo_trainer = PPOTrainer(ppo_config, model, ref_model=None, tokenizer=tokenizer)

for batch in dataloader:
    query_tensors = batch["input_ids"]
    response_tensors = ppo_trainer.generate(query_tensors, max_new_tokens=200)
    rewards = [reward_model(q, r) for q, r in zip(query_tensors, response_tensors)]
    stats = ppo_trainer.step(query_tensors, response_tensors, rewards)

DPO (Direct Preference Optimization)

DPO는 보상 모델 없이 직접 선호도 데이터로 LLM을 정렬합니다. PPO의 복잡한 강화학습 루프를 단순한 분류 손실로 대체:

LDPO(πθ;πref)=E(x,yw,yl)[logσ ⁣(βlogπθ(ywx)πref(ywx)βlogπθ(ylx)πref(ylx))]\mathcal{L}_{DPO}(\pi_\theta; \pi_{ref}) = -\mathbb{E}_{(x, y_w, y_l)} \left[ \log \sigma\!\left( \beta \log \frac{\pi_\theta(y_w|x)}{\pi_{ref}(y_w|x)} - \beta \log \frac{\pi_\theta(y_l|x)}{\pi_{ref}(y_l|x)} \right) \right]

import torch.nn.functional as F

def dpo_loss(pi_logps_chosen, pi_logps_rejected,
             ref_logps_chosen, ref_logps_rejected, beta=0.1):
    """
    DPO 손실 함수
    Args:
        pi_logps_chosen:   학습 모델의 선호 응답 log-prob
        pi_logps_rejected: 학습 모델의 비선호 응답 log-prob
        ref_logps_chosen:  참조 모델의 선호 응답 log-prob
        ref_logps_rejected: 참조 모델의 비선호 응답 log-prob
        beta: KL 페널티 강도
    """
    pi_log_ratio = pi_logps_chosen - pi_logps_rejected
    ref_log_ratio = ref_logps_chosen - ref_logps_rejected
    # 암묵적 보상 차이
    logits = beta * (pi_log_ratio - ref_log_ratio)
    loss = -F.logsigmoid(logits).mean()
    return loss

DPO vs RLHF 비교:

항목RLHF + PPODPO
보상 모델별도 훈련 필요불필요
필요 모델 수액터 + 크리틱 + RM + 참조학습 모델 + 참조 모델
학습 안정성RL 불안정성 존재지도학습 수준 안정적
구현 복잡도높음낮음

6. 멀티에이전트 강화학습

환경 유형

환경 유형설명예시
완전 협력공유 보상, 팀 목표로봇 팀 작업
완전 경쟁제로섬 게임체스, 바둑
혼합협력+경쟁축구, MOBA

MADDPG (Multi-Agent DDPG)

분산 실행 + 중앙집중 학습(CTDE) 패러다임:

  • 실행 시: 각 에이전트는 자신의 관찰만으로 행동 결정
  • 학습 시: 크리틱은 모든 에이전트의 관찰과 행동을 활용

Qiμ(x,a1,,aN)Q_i^\mu(x, a_1, \ldots, a_N)

x=(o1,,oN)x = (o_1, \ldots, o_N)는 전체 관찰, aia_i는 에이전트 ii의 행동입니다.

class MADDPGCritic(nn.Module):
    """모든 에이전트의 정보를 활용하는 중앙화 크리틱"""
    def __init__(self, n_agents, obs_dim, action_dim):
        super().__init__()
        # 전체 관찰 + 전체 행동을 입력
        input_dim = n_agents * (obs_dim + action_dim)
        self.net = nn.Sequential(
            nn.Linear(input_dim, 256), nn.ReLU(),
            nn.Linear(256, 256), nn.ReLU(),
            nn.Linear(256, 1)
        )

    def forward(self, all_obs, all_actions):
        # all_obs: [batch, n_agents * obs_dim]
        # all_actions: [batch, n_agents * action_dim]
        x = torch.cat([all_obs, all_actions], dim=-1)
        return self.net(x)

OpenSpiel

Google DeepMind의 멀티에이전트 RL 프레임워크:

import pyspiel

game = pyspiel.load_game("tic_tac_toe")
state = game.new_initial_state()

while not state.is_terminal():
    legal_actions = state.legal_actions()
    action = legal_actions[0]  # 실제로는 정책으로 선택
    state.apply_action(action)

returns = state.returns()
print(f"플레이어 0 보상: {returns[0]}")
print(f"플레이어 1 보상: {returns[1]}")

7. 실전 환경

Gymnasium (OpenAI Gym 후속)

import gymnasium as gym
import numpy as np

class NormalizedObsWrapper(gym.ObservationWrapper):
    """관찰값을 [-1, 1]로 정규화하는 래퍼"""
    def __init__(self, env):
        super().__init__(env)
        self.obs_low = env.observation_space.low
        self.obs_high = env.observation_space.high

    def observation(self, obs):
        normalized = (
            2.0 * (obs - self.obs_low)
            / (self.obs_high - self.obs_low + 1e-8)
            - 1.0
        )
        return normalized.astype(np.float32)

class RewardShapingWrapper(gym.RewardWrapper):
    """보상 스케일링 래퍼"""
    def __init__(self, env, scale=0.01):
        super().__init__(env)
        self.scale = scale

    def reward(self, reward):
        return reward * self.scale

base_env = gym.make("LunarLander-v2")
env = RewardShapingWrapper(NormalizedObsWrapper(base_env))
obs, info = env.reset(seed=42)

MuJoCo

물리 기반 연속 제어 환경으로 로보틱스 연구에 필수:

  • HalfCheetah-v4: 치타 로봇 달리기 (17차원 상태, 6차원 행동)
  • Humanoid-v4: 인간형 로봇 보행 (376차원 상태, 17차원 행동)
  • Ant-v4: 4족 보행 로봇 (111차원 상태, 8차원 행동)

벤치마크 성능 (1M 스텝):

환경SACTD3PPO
HalfCheetah~12000~9000~3000
Ant~5500~4000~1500
Humanoid~5000~4500~600

Isaac Gym / Isaac Lab

NVIDIA의 GPU 가속 물리 시뮬레이터로 수천 개의 환경을 병렬 실행합니다:

  • CPU 시뮬레이션 대비 2000배 빠른 훈련
  • 도메인 랜덤화(Domain Randomization)로 실세계 전이(sim-to-real) 향상
  • 4096개 환경 동시 실행으로 수시간 내 로봇 학습 완료
# Isaac Lab 예시 (간략화)
from isaaclab.envs import DirectRLEnv, DirectRLEnvCfg

class CartpoleEnvCfg(DirectRLEnvCfg):
    num_envs = 4096          # 4096개 병렬 환경
    episode_length_s = 5.0
    decimation = 2
    action_scale = 100.0

# GPU에서 4096개 CartPole 병렬 실행
env = CartpoleEnv(cfg=CartpoleEnvCfg())
obs, _ = env.reset()
# obs.shape: [4096, obs_dim]

실세계 RL 배포 고려사항

  1. 안전 제약 (Safe RL): 학습 중 위험한 행동 방지. 제약 기반 최적화(CPO, TRPO-Lagrangian)
  2. 샘플 효율성: 실세계 데이터는 비싸고 느림 — 오프라인 RL, 모델 기반 RL 활용
  3. Sim-to-Real 전이: 도메인 랜덤화, 어댑테이션 레이어(RMA)로 Reality Gap 줄이기
  4. 오프라인 RL: Conservative Q-Learning(CQL), IQL로 사전 수집 데이터만으로 학습

퀴즈: 강화학습 이해도 점검

Q1. Q-Learning과 SARSA의 온-폴리시 vs 오프-폴리시 차이를 설명하세요.

정답: Q-Learning은 오프-폴리시, SARSA는 온-폴리시

설명: Q-Learning의 업데이트 타깃은 r+γmaxaQ(s,a)r + \gamma \max_{a'} Q(s', a')로, 실제 행동과 무관하게 그리디 최댓값을 사용합니다. 반면 SARSA는 r+γQ(s,a)r + \gamma Q(s', a')에서 aa'실제로 취한 행동입니다. CliffWalking 문제에서 Q-Learning은 절벽 가장자리 최적 경로를 학습하지만 탐색 중 자주 떨어지고, SARSA는 더 안전한 우회 경로를 학습합니다.

Q2. PPO에서 clip ratio 하이퍼파라미터 epsilon이 학습 안정성에 미치는 역할은?

정답: epsilon은 정책 업데이트의 보수성을 제어

설명: rt(θ)=πθ/πoldr_t(\theta) = \pi_\theta / \pi_{old}[1ϵ,1+ϵ][1-\epsilon, 1+\epsilon] 범위를 벗어나면 기울기가 차단됩니다. ϵ\epsilon이 너무 작으면 학습이 느려지고 지역 최솟값에 갇히기 쉽습니다. 반대로 너무 크면 정책이 급격히 변해 불안정해집니다. 일반적으로 ϵ=0.2\epsilon = 0.2가 좋은 기본값이며, 학습 후반부에 점차 줄이는 스케줄링도 효과적입니다.

Q3. RLHF에서 보상 모델 훈련 데이터를 수집하는 방법은?

정답: 인간 평가자가 두 응답 쌍을 비교하여 선호도 표시

설명: 같은 프롬프트에 대한 두 응답 (y1,y2)(y_1, y_2)를 인간 평가자에게 보여주고 더 나은 응답을 선택하게 합니다. 절대 평가(1-5점)보다 쌍별 비교(pairwise comparison)가 더 일관성 있고 신뢰할 수 있습니다. 수집된 선호도 데이터 (x,yw,yl)(x, y_w, y_l)로 Bradley-Terry 모델을 학습합니다. Anthropic의 Constitutional AI에서는 AI가 직접 평가자 역할을 대신하는 RLAIF도 사용합니다.

Q4. DPO가 PPO 기반 RLHF보다 구현이 단순한 이유는?

정답: 보상 모델과 강화학습 루프가 불필요

설명: RLHF+PPO는 세 단계(SFT, 보상 모델 학습, PPO 파인튜닝)가 필요하고, 동시에 여러 모델(액터, 크리틱, 보상 모델, 참조 모델)을 GPU 메모리에 올려야 합니다. DPO는 선호도 데이터로 암묵적 보상을 수식에 직접 통합하여, 단순한 교차 엔트로피 스타일 손실 하나로 파인튜닝합니다. 참조 모델과 학습 모델 두 개만 필요하며 강화학습 특유의 불안정성이 없습니다.

Q5. Soft Actor-Critic에서 엔트로피 정규화의 역할은?

정답: 탐색 장려 + 다중 최적 정책 학습

설명: SAC의 목적 함수에 엔트로피 항 αH[π(s)]\alpha \mathcal{H}[\pi(\cdot|s)]를 추가하면, 에이전트는 보상을 최대화하면서 동시에 행동의 무작위성을 유지하려 합니다. 이는 자동적인 탐색 메커니즘을 제공하여 지역 최솟값 탈출에 도움을 줍니다. 또한 동등하게 좋은 여러 행동이 있을 때 균등하게 선택하는 로버스트한 정책을 학습합니다. 온도 파라미터 α\alpha는 자동 튜닝(automatic entropy tuning)으로 목표 엔트로피에 맞게 조절됩니다.


알고리즘 비교 요약

알고리즘정책 유형행동 공간특징
Q-Learning오프-폴리시이산단순, 표 기반
DQN오프-폴리시이산딥러닝 + ER + TN
Double DQN오프-폴리시이산과대추정 완화
Dueling DQN오프-폴리시이산V + A 분리
REINFORCE온-폴리시이산/연속높은 분산
A2C온-폴리시이산/연속Actor-Critic
PPO온-폴리시이산/연속안정적, 범용
SAC오프-폴리시연속최대 엔트로피
TD3오프-폴리시연속SAC 결정론적 버전
HER오프-폴리시목표 기반희소 보상

마치며

강화학습은 단순한 게임 AI를 넘어 로보틱스, LLM 정렬, 자율주행, 신약 개발까지 적용 범위가 폭발적으로 확장되고 있습니다. 특히 RLHF와 DPO는 ChatGPT, Claude, Gemini 같은 LLM의 핵심 정렬 기술로, RL을 이해하는 것이 현대 AI 연구자에게 필수 역량이 되었습니다.

추천 학습 경로:

  1. Gymnasium + Q-Learning/DQN 직접 구현
  2. Stable-Baselines3로 PPO/SAC 실험
  3. TRL 라이브러리로 RLHF/DPO 실습
  4. Isaac Lab으로 로보틱스 RL 탐구

참고 자료:

  • Sutton & Barto, "Reinforcement Learning: An Introduction" (2nd ed.)
  • Spinning Up in Deep RL (OpenAI)
  • Stable-Baselines3 공식 문서
  • TRL (Transformer Reinforcement Learning) by Hugging Face
  • Isaac Lab 공식 문서