15. 딥 강화학습(Deep RL) 입문 DQN부터 시작하기, 딥 Q-네트워크(DQN)의 개념과 구조

강화학습(Reinforcement Learning, RL)은 에이전트가 환경과 상호작용하며 보상을 최대화하기 위해 일련의 행동을 학습하는 기계 학습의 한 분야입니다. 이 과정에서 에이전트는 상태(state), 행동(action), 보상(reward)의 세 가지 주요 요소를 사용하여 최적의 정책(policy)을 학습합니다. 딥러닝과 결합된 강화학습, 즉 딥 강화학습(Deep RL)은 잠재적으로 복잡한 환경에서도 효과적으로 학습할 수 있는 능력을 제공합니다.

1. 딥 Q-네트워크(DQN)의 개념

딥 Q-네트워크(DQN)는 강화학습의 Q-러닝(Q-learning) 알고리즘에 딥러닝을 접목하여 고차원 상태 공간에서 효과적으로 작동할 수 있도록 한 것입니다. Q-러닝은 어떤 상태에서 어떤 행동을 선택할 때의 가치를 추정하여 최적의 정책을 학습하는 방법입니다. DQN은 이 Q-값을 예측하기 위해 신경망을 사용합니다.

1.1 Q-러닝 기초

Q-learning은 다음과 같은 업데이트 규칙을 따릅니다:


Q(s, a) <- Q(s, a) + α[r + γ max(Q(s', a')) - Q(s, a)]
    

여기서:

  • s: 현재 상태
  • a: 현재 행동
  • r: 보상
  • s': 다음 상태
  • α: 학습률
  • γ: 할인 계수

Q값이 실제로 어떤 행동의 가치를 나타내게 하기 위해 오랜 시간에 걸쳐 충분한 경험을 쌓아야 하며, 이 과정에서 많은 메모리와 시간이 소모됩니다. 이 문제를 해결하기 위해 DQN은 신경망을 사용하여 Q값을 근사합니다.

2. DQN의 구조와 구성 요소

DQN의 주요 구성 요소는 다음과 같습니다:

  • 신경망(Neural Network): 상태를 입력받아 각 행동에 대한 Q값을 출력합니다.
  • 경험 재플레이(Experience Replay): 에이전트가 과거 경험을 다시 활용할 수 있도록 하는 기술로, 샘플을 무작위로 선택하여 Q함수를 학습합니다.
  • 타겟 네트워크(Target Network): Q값의 업데이트를 안정화하기 위해 주기적으로 업데이트되는 별도의 신경망입니다.

2.1 신경망의 구조

DQN에서 사용하는 신경망은 일반적으로 다음과 같은 형태를 가집니다:


class DQN(nn.Module):
    def __init__(self, input_size, output_size):
        super(DQN, self).__init__()
        self.fc1 = nn.Linear(input_size, 128)
        self.fc2 = nn.Linear(128, 128)
        self.fc3 = nn.Linear(128, output_size)

    def forward(self, x):
        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        return self.fc3(x)
    

이 신경망은 입력으로 주어진 상태를 받아 Q값을 예측하는데 사용됩니다.

2.2 경험 재플레이(Experience Replay)

경험 재플레이는 에이전트가 수집한 경험을 메모리에 저장하고, 이 메모리에서 무작위로 샘플을 선택하여 학습합니다. 이렇게 하면 데이터의 상관성을 줄이고, 더 안정적으로 학습할 수 있게 해줍니다.

2.3 타겟 네트워크(Target Network)

타겟 네트워크는 주 네트워크와 동일한 구조를 가진 신경망으로, 일정 주기마다 주 네트워크의 가중치를 복사하여 업데이트됩니다. 이를 통해 Q값의 업데이트를 더 안정적으로 만들어 줍니다.

3. DQN의 학습 과정

DQN의 학습 과정은 다음과 같습니다:

  1. 환경으로 부터 초기 상태 s를 받아옵니다.
  2. 배치 크기만큼 무작위 행동을 선택하고 경험을 메모리에 저장합니다.
  3. 에이전트가 선택한 행동 a를 환경에 적용하여 새로운 상태 s'와 보상 r을 관찰합니다.
  4. 경험 재플레이를 통해 샘플을 무작위로 선택하고, Q함수를 업데이트합니다.
  5. 새로운 상태 s'에서 다시 행동을 선택하고, 이를 반복합니다.

4. DQN의 예제 코드

이제 DQN의 구현 예제를 살펴봅시다. 다음 코드는 Python을 사용하여 OpenAI의 Gym 환경에서 DQN을 구현하는 예제입니다.


import random
import numpy as np
import gym
import torch
import torch.nn as nn
import torch.optim as optim

# DQN 모델 정의
class DQN(nn.Module):
    def __init__(self, input_size, output_size):
        super(DQN, self).__init__()
        self.fc1 = nn.Linear(input_size, 128)
        self.fc2 = nn.Linear(128, 128)
        self.fc3 = nn.Linear(128, output_size)

    def forward(self, x):
        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        return self.fc3(x)

# 경험 재플레이를 위한 리플레이 메모리
class ReplayMemory:
    def __init__(self, capacity):
        self.memory = []
        self.capacity = capacity
        
    def push(self, transition):
        if len(self.memory) < self.capacity:
            self.memory.append(transition)
        else:
            self.memory.pop(0)
            self.memory.append(transition)
    
    def sample(self, batch_size):
        return random.sample(self.memory, batch_size)
    
    def __len__(self):
        return len(self.memory)

# 하이퍼파라미터
BATCH_SIZE = 32
GAMMA = 0.99
EPSILON_START = 1.0
EPSILON_END = 0.1
EPSILON_DECAY = 200
TARGET_UPDATE = 10
MEMORY_CAPACITY = 10000
NUM_EPISODES = 1000

# 환경 초기화
env = gym.make('CartPole-v1')
n_actions = env.action_space.n
n_obs = env.observation_space.shape[0]

# DQN 모델 생성
policy_net = DQN(n_obs, n_actions)
target_net = DQN(n_obs, n_actions)
target_net.load_state_dict(policy_net.state_dict())
target_net.eval()

optimizer = optim.Adam(policy_net.parameters())
memory = ReplayMemory(MEMORY_CAPACITY)

# epsilon-greedy 행동 선택
def select_action(state):
    global steps_done
    eps_threshold = EPSILON_END + (EPSILON_START - EPSILON_END) * \
                    np.exp(-1. * steps_done / EPSILON_DECAY)
    steps_done += 1
    if random.random() > eps_threshold:
        with torch.no_grad():
            return policy_net(torch.FloatTensor(state)).max(0)[1].item()  # 최적 행동 선택
    else:
        return random.randrange(n_actions)  # 랜덤 행동 선택

# 학습 주기
def optimize_model():
    if len(memory) < BATCH_SIZE:
        return
    transitions = memory.sample(BATCH_SIZE)
    batch = list(zip(*transitions))  # 배치 분리
    state_batch = torch.FloatTensor(batch[0])
    action_batch = torch.LongTensor(batch[1]).unsqueeze(1)
    reward_batch = torch.FloatTensor(batch[2])
    next_state_batch = torch.FloatTensor(batch[3])
    
    # Q값 계산
    state_action_values = policy_net(state_batch).gather(1, action_batch)
    next_state_values = target_net(next_state_batch).max(1)[0].detach()
    expected_state_action_values = reward_batch + (GAMMA * next_state_values)
    
    # 손실 계산
    loss = nn.functional.smooth_l1_loss(state_action_values, expected_state_action_values.unsqueeze(1))
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()

# 메인 학습 루프
steps_done = 0
for episode in range(NUM_EPISODES):
    state = env.reset()
    for t in range(1000):
        action = select_action(state)
        next_state, reward, done, _ = env.step(action)
        memory.push((state, action, reward, next_state))
        state = next_state
        optimize_model()
        if done:
            break
    if episode % TARGET_UPDATE == 0:
        target_net.load_state_dict(policy_net.state_dict())
    print(f"Episode {episode + 1}/{NUM_EPISODES} completed.")
    

5. DQN의 한계와 개선 방안

DQN은 몇 가지 한계를 가지고 있습니다. 우선, 스크리딩 문제(specific problem)에 대해 잘 수렴하지 못할 수 있습니다. 이 문제는 특정 상태나 행동에 대해서만 지나치게 높은 Q값을 예측하는 현상입니다. 이를 해결하기 위해 여러 가지 개선 방법이 연구되었습니다:

  • Double DQN: Q-러닝의 강한 비편향(propensity)을 해결하기 위해, 두 개의 Q-네트워크를 사용하여 각각 Q값을 업데이트합니다.
  • Dueling DQN: 상태와 행동의 가치를 분리하여 설계된 구조로, 모델이 더 좋은 성능을 발휘하도록 합니다.
  • Prioritized Experience Replay: 중요도가 높은 경험을 더 자주 샘플링하여 학습 효율을 높입니다.

6. 결론

딥 Q-네트워크(DQN)는 복잡한 환경에서 효과적으로 강화학습 문제를 해결할 수 있는 강력한 도구입니다. 이 강좌에서 소개된 기초 개념과 예제 코드를 통해 DQN의 작동 방식을 이해하고, 직접 구현해볼 수 있었습니다. 이러한 강좌를 통해 딥 강화학습의 기초를 익혀 다음 단계로 나아갈 수 있기를 바랍니다.

참고자료

  • Mnih, V. et al. (2015). “Human-level control through deep reinforcement learning”. Nature.
  • Sutton, R. S., & Barto, A. G. (2018). “Reinforcement Learning: An Introduction”. MIT Press.