
강화학습 에이전트를 설계할 때 가장 먼저 마주하는 벽은 탐험(Exploration)과 활용(Exploitation)의 균형을 맞추는 일입니다. 가장 단순한 해결 방법인 Epsilon-Greedy는 구현이 쉽지만, 학습이 진행됨에 따라 최적의 정책을 찾는 속도가 느리고 불필요한 무작위 행동을 반복한다는 치명적인 단점이 있습니다. 본 가이드에서는 Python을 통해 Epsilon-Greedy의 한계를 극복하고 에이전트의 지능적 의사결정을 돕는 통계적, 확률적 해결 방법들을 심도 있게 다룹니다.
1. 왜 Epsilon-Greedy만으로는 부족한가?
Epsilon-Greedy 방식은 단순히 일정 확률로 무작위 행동을 선택합니다. 이는 에이전트가 "어떤 행동이 더 유망한지"에 대한 불확실성을 전혀 고려하지 않는다는 의미입니다. 복잡한 환경에서는 에이전트가 아는 정보의 가치를 판단하여, 불확실성이 높은 영역을 집중적으로 탐색하는 전략이 필요합니다. 이를 위해 UCB(Upper Confidence Bound)나 Thompson Sampling과 같은 기법들이 실무에서 널리 사용됩니다.
2. 탐험 전략별 핵심 메커니즘 및 차이 비교
에이전트의 학습 효율을 극대화하기 위한 주요 기법들의 특성을 표를 통해 한눈에 비교해 보겠습니다.
| 기법 명칭 | 통계적 근거 | 탐험 결정 방식 | 주요 장점 |
|---|---|---|---|
| UCB1 | Hoeffding's Inequality | 신뢰 구간의 상한값 기준 | 결정론적이며 수학적 증명 명확 |
| Thompson Sampling | Bayesian Posterior | 사후 확률 분포에서 샘플링 | 가장 뛰어난 실전 성능(Regret 최저) |
| Softmax (Boltzmann) | Gibbs Distribution | 보상 기댓값에 비례한 확률 | 행동 가치를 부드럽게 반영 |
| Entropy Regularization | Information Theory | 손실 함수에 엔트로피 추가 | Policy Gradient 계열에서 필수적 |
3. Python 실무 적용을 위한 7가지 핵심 코드 Example
다양한 환경에서 에이전트의 탐험 효율을 높이기 위해 즉시 활용 가능한 Python 예제입니다.
Example 1. UCB(Upper Confidence Bound) 알고리즘 구현
행동의 횟수가 적을수록 불확실성(보너스 점수)을 높게 책정하여 탐험을 유도합니다.
import numpy as np
def select_action_ucb(q_values, action_counts, total_steps, c=2.0):
# 분모 0 방지를 위한 작은 값 추가
uncertainty = c * np.sqrt(np.log(total_steps + 1) / (action_counts + 1e-5))
ucb_values = q_values + uncertainty
return np.argmax(ucb_values)
# 실무 적용: q_values는 보상의 평균, action_counts는 각 행동의 선택 횟수
Example 2. Thompson Sampling (Beta Distribution 기반)
성공과 실패가 명확한 Bernoulli Bandit 문제에서 최고의 효율을 보여줍니다.
def select_action_thompson(alphas, betas):
# 각 행동의 사후 분포(Beta)에서 샘플을 추출
samples = [np.random.beta(a, b) for a, b in zip(alphas, betas)]
return np.argmax(samples)
# 학습 방법: 성공 시 alphas[i] += 1, 실패 시 betas[i] += 1
Example 3. Boltzmann Exploration (Softmax) 구현 방법
온도($T$) 파라미터를 통해 탐험의 강도를 조절합니다. $T$가 높을수록 모든 행동이 균등하게 선택됩니다.
def softmax_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)
Example 4. PyTorch를 활용한 Entropy Regularization (A2C/PPO 적용)
정책(Policy)이 너무 한쪽으로 쏠리지 않도록 손실 함수에 엔트로피를 추가하여 해결합니다.
import torch
import torch.nn.functional as F
def compute_loss_with_entropy(policy_logits, actions, returns, entropy_coef=0.01):
probs = F.softmax(policy_logits, dim=-1)
log_probs = F.log_softmax(policy_logits, dim=-1)
# 엔트로피 계산: -sum(p * log(p))
entropy = -(probs * log_probs).sum(-1).mean()
# Policy Loss 계산 (Negative Log Likelihood * Advantage)
selected_log_probs = log_probs.gather(1, actions.unsqueeze(1))
policy_loss = -(selected_log_probs * returns).mean()
# 최종 손실: 엔트로피를 빼주어 엔트로피가 커지는(탐험하는) 방향으로 유도
total_loss = policy_loss - (entropy_coef * entropy)
return total_loss
Example 5. Noisy Networks for Exploration (DQN 확장)
신경망의 가중치 자체에 노이즈를 추가하여 일관성 있는 탐험을 가능하게 합니다.
import torch.nn as nn
class NoisyLinear(nn.Module):
def __init__(self, in_features, out_features, sigma_init=0.017):
super(NoisyLinear, self).__init__()
self.weight_mu = nn.Parameter(torch.empty(out_features, in_features))
self.weight_sigma = nn.Parameter(torch.fill_(torch.empty(out_features, in_features), sigma_init))
# ... 가중치 초기화 및 noise 생성 로직 생략 ...
def forward(self, x):
# 학습 시마다 가중치에 노이즈를 섞어 다른 행동을 유도
weight = self.weight_mu + self.weight_sigma * torch.randn_like(self.weight_sigma)
return F.linear(x, weight)
Example 6. VIME(Variational Information Maximizing Exploration)
에이전트가 환경에 대해 새로 알게 된 정보량(KL Divergence)을 보상으로 환산합니다.
def intrinsic_reward_vime(old_dist, new_dist):
# 두 분포 사이의 KL Divergence를 계산하여 '놀라움' 정도를 보상으로 지급
kl_div = torch.distributions.kl.kl_divergence(old_dist, new_dist)
return kl_div.item()
Example 7. Count-Based Exploration (Hash 활용)
상태(State)를 방문한 횟수의 역수를 보상에 더해 생소한 상태로의 방문을 유도합니다.
state_counts = {}
def get_count_based_reward(state, original_reward, beta=0.1):
state_hash = hash(state.tobytes())
count = state_counts.get(state_hash, 0) + 1
state_counts[state_hash] = count
# 보너스 보상 = 1 / sqrt(N)
intrinsic_reward = beta / np.sqrt(count)
return original_reward + intrinsic_reward
4. 고급 탐험 기법 도입 시 주의사항 및 해결 전략
단순한 Epsilon-Greedy에서 위와 같은 고급 기법으로 넘어갈 때 주의해야 할 점은 하이퍼파라미터 민감도입니다. 예를 들어, UCB의 상수 $c$나 Softmax의 온도 $T$가 너무 크면 모델이 아예 수렴하지 못하는 문제가 발생할 수 있습니다. 이를 해결하기 위해서는 학습 초기에는 탐험 계수를 높게 설정하고, 에피소드가 반복됨에 따라 Decay(감쇄) 전략을 사용하는 것이 가장 효과적입니다.
5. 결론 및 향후 전망
강화학습에서 탐험은 단순한 '무작위성'이 아니라 '효율적인 지식 습득'의 과정입니다. 실무 프로젝트에서는 데이터의 특성에 따라 Thompson Sampling(확률적 우위가 중요할 때)이나 Noisy Networks(고차원 상태 공간일 때)를 적절히 선택하는 안목이 필요합니다. 오늘 다룬 5가지 이상의 기법을 Python 환경에서 직접 튜닝해 보며 여러분의 에이전트를 한 단계 더 진화시켜 보시기 바랍니다.
6. 참고 문헌 및 자료 출처
- Sutton, R. S., & Barto, A. G. (2018). Reinforcement Learning: An Introduction. MIT Press.
- Auer, P., et al. (2002). Finite-time Analysis of the Multi-armed Bandit Problem. Machine Learning.
- Fortunato, M., et al. (2017). Noisy Networks for Exploration. ICLR.
- OpenAI Spinning Up Documentation (spinningup.openai.com).