강화학습의 영원한 딜레마: Exploration vs Exploitation
강화학습 에이전트가 마주하는 가장 근본적인 문제 중 하나가 바로 탐색(Exploration)과 활용(Exploitation) 사이의 균형입니다. 현재 알고 있는 최선의 행동을 계속 선택할 것인가(활용), 아니면 더 나은 행동을 찾기 위해 미지의 선택을 시도할 것인가(탐색)?
핵심 질문: 지금 당장의 보상을 최대화할 것인가, 장기적으로 더 나은 전략을 찾을 것인가?
특히 희소 보상(Sparse Reward) 환경에서는 무작위 탐색만으로는 의미 있는 보상을 발견하기 어렵습니다. 이 글에서는 다양한 탐색 전략을 체계적으로 비교하고 실전 구현 방법을 알아봅니다.
기본 탐색 전략: ε-greedy와 Boltzmann Exploration
ε-greedy: 가장 단순하지만 효과적인 전략
ε-greedy는 확률 로 무작위 행동을, 확률로 현재 최선의 행동을 선택합니다.
import numpy as np
def epsilon_greedy(Q_values, epsilon=0.1):
"""ε-greedy 행동 선택
Args:
Q_values: 각 행동의 Q값 배열
epsilon: 탐색 확률 (0~1)
"""
if np.random.random() < epsilon:
return np.random.randint(len(Q_values)) # 탐색
else:
return np.argmax(Q_values) # 활용
장점: 구현이 간단하고 계산 비용이 낮음
단점: 모든 미지의 행동을 동등하게 취급 (비효율적 탐색)
Decaying ε-greedy: 학습 단계에 따른 탐색 감소
학습 초기에는 높은 탐색률, 후반에는 활용 중심으로 전환:
def get_epsilon(episode, epsilon_start=1.0, epsilon_end=0.01, decay_rate=0.995):
return max(epsilon_end, epsilon_start * (decay_rate ** episode))
Boltzmann Exploration (Softmax)
Q값에 비례하는 확률로 행동을 선택합니다. 온도 파라미터 로 탐색 정도를 조절:
- : 거의 greedy (활용 중심)
- : 균등 분포 (탐색 중심)
def boltzmann_exploration(Q_values, temperature=1.0):
exp_Q = np.exp(Q_values / temperature)
probs = exp_Q / np.sum(exp_Q)
return np.random.choice(len(Q_values), p=probs)
불확실성 기반 탐색: UCB와 Thompson Sampling
Upper Confidence Bound (UCB)
UCB는 “낙관적 초기화” 원리를 활용합니다. 각 행동의 가치를 추정할 때 불확실성을 보너스로 추가:
- : 행동 의 평균 보상 (활용)
- : 탐색 보너스 (불확실성)
- : 전체 시간 스텝
- : 행동 를 선택한 횟수
- : 탐색 강도 파라미터 (보통 1~2)
의미: 적게 시도한 행동일수록( 작음) 보너스가 커져서 선택 확률 증가
class UCB:
def __init__(self, n_actions, c=2.0):
self.Q = np.zeros(n_actions)
self.N = np.zeros(n_actions)
self.c = c
self.t = 0
def select_action(self):
self.t += 1
# 한 번도 선택 안 한 행동이 있으면 우선 선택
if np.any(self.N == 0):
return np.argmin(self.N)
ucb_values = self.Q + self.c * np.sqrt(np.log(self.t) / self.N)
return np.argmax(ucb_values)
def update(self, action, reward):
self.N[action] += 1
self.Q[action] += (reward - self.Q[action]) / self.N[action]
Thompson Sampling: 베이지안 접근
Thompson Sampling은 각 행동의 가치 분포를 유지하고, 매번 샘플링하여 행동을 선택합니다.
class ThompsonSampling:
def __init__(self, n_actions):
self.alpha = np.ones(n_actions) # 성공 횟수 + 1
self.beta = np.ones(n_actions) # 실패 횟수 + 1
def select_action(self):
# 각 행동의 보상 분포에서 샘플링
samples = np.random.beta(self.alpha, self.beta)
return np.argmax(samples)
def update(self, action, reward):
if reward > 0:
self.alpha[action] += 1
else:
self.beta[action] += 1
장점: 자연스럽게 불확실성을 고려하며, 멀티암드 밴딧 문제에서 이론적으로 최적
희소 보상 환경을 위한 내재적 동기: Curiosity와 RND
전통적 탐색 전략은 희소 보상 환경에서 실패합니다. 보상 신호가 거의 없으면 탐색할 방향을 찾지 못하기 때문입니다.
Intrinsic Curiosity Module (ICM)
ICM은 예측 오류를 내재적 보상으로 사용합니다:
- : 상태 특징 인코더
- : 현재 상태 와 행동 로부터 예측한 다음 상태 특징
- : 내재적 보상 가중치
원리: 에이전트가 예측하지 못한 새로운 상태를 만나면 높은 보상 → 탐색 유도
import torch
import torch.nn as nn
class ICM(nn.Module):
def __init__(self, state_dim, action_dim, feature_dim=256):
super().__init__()
# Feature encoder
self.encoder = nn.Sequential(
nn.Linear(state_dim, 256),
nn.ReLU(),
nn.Linear(256, feature_dim)
)
# Forward model: (s_t, a_t) -> s_{t+1} 예측
self.forward_model = nn.Sequential(
nn.Linear(feature_dim + action_dim, 256),
nn.ReLU(),
nn.Linear(256, feature_dim)
)
def compute_intrinsic_reward(self, state, action, next_state):
feat = self.encoder(state)
next_feat_pred = self.forward_model(
torch.cat([feat, action], dim=-1)
)
next_feat_true = self.encoder(next_state).detach()
# 예측 오류 = 내재적 보상
intrinsic_reward = 0.5 * ((next_feat_pred - next_feat_true) ** 2).mean(dim=-1)
return intrinsic_reward
Random Network Distillation (RND)
RND는 고정된 랜덤 네트워크를 타겟으로, 학습 네트워크가 이를 모방하도록 훈련합니다:
- : 고정된 랜덤 네트워크 (학습 안 함)
- : 학습하는 예측 네트워크
핵심 아이디어: 자주 방문한 상태는 예측이 잘 되고(낮은 보상), 새로운 상태는 예측 오류가 크므로(높은 보상) 탐색 유도
class RND(nn.Module):
def __init__(self, state_dim, feature_dim=256):
super().__init__()
# 고정된 타겟 네트워크
self.target_net = nn.Sequential(
nn.Linear(state_dim, 256),
nn.ReLU(),
nn.Linear(256, feature_dim)
)
# 학습 네트워크
self.predictor_net = nn.Sequential(
nn.Linear(state_dim, 256),
nn.ReLU(),
nn.Linear(256, feature_dim)
)
# 타겟 네트워크 가중치 고정
for param in self.target_net.parameters():
param.requires_grad = False
def compute_intrinsic_reward(self, state):
target_feat = self.target_net(state)
pred_feat = self.predictor_net(state)
intrinsic_reward = ((target_feat - pred_feat) ** 2).mean(dim=-1)
return intrinsic_reward
장점: ICM보다 안정적이며, Montezuma’s Revenge 같은 어려운 환경에서 뛰어난 성능
전략 비교: 언제 무엇을 사용할까?
| 전략 | 계산 비용 | 희소 보상 대응 | 적합한 환경 | 단점 |
|---|---|---|---|---|
| ε-greedy | 매우 낮음 | 약함 | 밀집 보상, 간단한 문제 | 비효율적 탐색 |
| Boltzmann | 낮음 | 약함 | Q값 분포가 의미 있는 환경 | 온도 튜닝 필요 |
| UCB | 낮음 | 중간 | 밴딧 문제, 행동 공간 작음 | 연속 행동에 부적합 |
| Thompson Sampling | 중간 | 중간 | 불확실성 중요한 문제 | 분포 가정 필요 |
| ICM | 높음 | 강함 | 희소 보상, 복잡한 환경 | 예측 모델 학습 비용 |
| RND | 높음 | 매우 강함 | 극도로 희소한 보상 | 메모리/연산 집약적 |
실전 선택 가이드
-
간단한 환경 (CartPole, Mountain Car)
→ Decaying ε-greedy면 충분 -
밴딧 문제 (Multi-Armed Bandit)
→ UCB 또는 Thompson Sampling -
보상이 드문 환경 (Montezuma’s Revenge, 미로 탐색)
→ RND + PPO 조합 -
로봇 제어 (연속 행동 공간)
→ Boltzmann + Entropy Regularization
실전 구현 팁
1. 하이브리드 접근: 외재적 + 내재적 보상
# 총 보상 = 환경 보상 + 내재적 보상
total_reward = extrinsic_reward + beta * intrinsic_reward
- : 내재적 보상 가중치 (0.01~1.0)
- 학습 진행에 따라 감소시키기도 함
2. Observation Normalization
RND/ICM 사용 시 상태 정규화가 필수:
class RunningMeanStd:
def __init__(self, epsilon=1e-4, shape=()):
self.mean = np.zeros(shape)
self.var = np.ones(shape)
self.count = epsilon
def update(self, x):
batch_mean = np.mean(x, axis=0)
batch_var = np.var(x, axis=0)
batch_count = x.shape[0]
delta = batch_mean - self.mean
total_count = self.count + batch_count
self.mean += delta * batch_count / total_count
m_a = self.var * self.count
m_b = batch_var * batch_count
M2 = m_a + m_b + delta**2 * self.count * batch_count / total_count
self.var = M2 / total_count
self.count = total_count
def normalize(self, x):
return (x - self.mean) / np.sqrt(self.var + 1e-8)
3. 탐색 스케줄링
def get_exploration_bonus(episode, max_episodes):
# 학습 초반: 높은 탐색, 후반: 낮은 탐색
progress = episode / max_episodes
return 1.0 * (1 - progress) + 0.1 * progress
마무리
강화학습에서 탐색 전략은 학습 성패를 좌우하는 핵심 요소입니다. 이 글에서 다룬 내용을 정리하면:
- ε-greedy/Boltzmann: 간단한 환경에서 빠른 프로토타이핑에 적합
- UCB/Thompson Sampling: 불확실성을 체계적으로 다루는 밴딧 문제 최적화
- ICM/RND: 희소 보상 환경에서 게임 체인저, 내재적 동기로 탐색 유도
실전 조언: 문제의 복잡도와 보상 밀집도에 따라 전략을 선택하되, 간단한 방법부터 시작해 점진적으로 복잡한 기법을 도입하세요.
다음 단계: 여러분의 환경에 맞는 탐색 전략을 실험해보고, 하이퍼파라미터(, , 등)를 튜닝하며 최적의 균형점을 찾아보세요!
Did you find this helpful?
☕ Buy me a coffee
Leave a Reply