딥러닝 파이토치 강좌, 마르코프 결정 과정

마르코프 결정 과정(Markov Decision Process, MDP)은 강화 학습의 기초가 되는 중요한 수학적 프레임워크입니다. MDP는 에이전트가 특정 환경에서 최적의 행동을 결정하기 위해 사용하는 모델입니다. 이번 포스팅에서는 MDP의 개념을 이해하고, 이를 파이토치(PyTorch)로 구현하는 방법에 대해 자세히 알아보겠습니다.

1. 마르코프 결정 과정(MDP) 개요

MDP는 다음과 같은 구성 요소들로 이루어져 있습니다:

  • 상태 공간 (State space, S): 에이전트가 처해 있는 모든 가능한 상태의 집합입니다.
  • 행동 공간 (Action space, A): 에이전트가 특정 상태에서 선택할 수 있는 모든 가능한 행동의 집합입니다.
  • 전이 확률 (Transition probabilities, P): 현재 상태와 행동에 따라 다음 상태로 전이될 확률을 정의합니다.
  • 보상 함수 (Reward function, R): 에이전트가 특정 상태에서 특정 행동을 선택했을 때 주어지는 보상입니다.
  • 할인율 (Discount factor, γ): 미래의 보상이 현재의 보상보다 적다고 가정할 때, 미래 보상이 현재 가치에 미치는 영향을 조절하는 값입니다.

2. MDP의 수학적 모델링

MDP는 상태 공간, 행동 공간, 전이 확률, 보상 함수, 할인율 등을 이용하여 수학적으로 정의됩니다. MDP는 다음의 요소로 표현할 수 있습니다:

  • MDP = (S, A, P, R, γ)로 정의됩니다.

여기서, 각 요소에 대해 좀 더 구체적으로 설명하겠습니다:

상태 공간 (S)

상태 공간은 에이전트가 처할 수 있는 모든 상태의 집합입니다. 예를 들어, 바둑 게임의 상태 공간은 모든 가능한 바둑판의 상태가 될 수 있습니다.

행동 공간 (A)

행동 공간은 에이전트의 상태에 따라 선택할 수 있는 모든 행동을 포함합니다. 예를 들어, 바둑 게임에서 에이전트는 특정 위치에 돌을 놓는 행동을 할 수 있습니다.

전이 확률 (P)

전이 확률은 현재 상태와 선택한 행동에 따라 다음 상태로 전이될 확률을 나타냅니다. 이는 수학적으로 다음과 같이 표현됩니다:

P(s', r | s, a)

여기서, s'는 다음 상태, r는 보상, s는 현재 상태, a는 선택한 행동입니다.

보상 함수 (R)

보상 함수는 에이전트가 특정 상태에서 특정 행동을 선택했을 때 주어진 보상을 나타냅니다. 보상은 에이전트의 목표를 정의하는 중요한 요소입니다.

할인율 (γ)

할인율 γ (0 ≤ γ < 1)은 미래의 보상에 대한 현재 가치의 영향을 반영합니다. γ가 0에 가까울수록 에이전트는 가까운 미래의 보상에 더 중점을 두고, 1에 가까울수록 먼 미래의 보상에 더 중점을 둡니다.

3. MDP의 예제

이제 MDP의 개념을 이해했으므로 예제를 통해 이를 강화 학습 문제에 어떻게 적용할 수 있는지 살펴보겠습니다. 다음에는 간단한 MDP 예제를 통해 훈련된 강화 학습 에이전트를 만들 것입니다.

3.1 간단한 그리드 월드 예제

그리드 월드는 4×4 격자로 구성된 세계를 모델링한 것입니다. 에이전트는 각 격자에 위치하며, 특정 행동(위, 아래, 왼쪽, 오른쪽)을 통해 이동할 수 있습니다. 에이전트의 목표는 오른쪽 하단 구역(목표 위치)에 도달하는 것입니다.

상태 및 행동 정의

이 그리드 월드에서:

  • 상태: 0에서 15까지의 숫자로 각 격자를 표현 (4×4 격자)
  • 행동: 위(0), 아래(1), 왼쪽(2), 오른쪽(3)

보상 정의

에이전트가 목표 상태에 도달하면 보상 +1을 주고, 다른 상태에서는 0을 줍니다.

4. 파이토치로 MDP 구현하기

이제 파이토치를 사용하여 강화 학습 에이전트를 구현해 보겠습니다. 기본적으로 Q-러닝 알고리즘을 사용할 예정입니다.

4.1 환경 초기화

우선, 그리드 월드를 생성하는 클래스를 정의합시다:

import numpy as np

class GridWorld:
    def __init__(self, grid_size=4):
        self.grid_size = grid_size
        self.state = 0
        self.goal_state = grid_size * grid_size - 1
        self.actions = [0, 1, 2, 3]  # 위, 아래, 왼쪽, 오른쪽
        self.rewards = np.zeros((grid_size * grid_size,))
        self.rewards[self.goal_state] = 1  # 목표 지점에 도달 시의 보상

    def reset(self):
        self.state = 0  # 시작 상태
        return self.state

    def step(self, action):
        x, y = divmod(self.state, self.grid_size)
        if action == 0 and x > 0:   # 위
            x -= 1
        elif action == 1 and x < self.grid_size - 1:  # 아래
            x += 1
        elif action == 2 and y > 0:  # 왼쪽
            y -= 1
        elif action == 3 and y < self.grid_size - 1:  # 오른쪽
            y += 1
        self.state = x * self.grid_size + y
        return self.state, self.rewards[self.state]

4.2 Q-러닝 알고리즘 구현

Q-러닝을 통해 에이전트를 훈련시키겠습니습니다. 다음은 Q-러닝 알고리즘을 구현하는 코드입니다:

import torch
import torch.nn as nn
import torch.optim as optim

class QNetwork(nn.Module):
    def __init__(self, state_size, action_size):
        super(QNetwork, self).__init__()
        self.fc1 = nn.Linear(state_size, 24)
        self.fc2 = nn.Linear(24, 24)
        self.fc3 = nn.Linear(24, action_size)

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

def train_agent(episodes, max_steps):
    env = GridWorld()
    state_size = env.grid_size * env.grid_size
    action_size = len(env.actions)
    
    q_network = QNetwork(state_size, action_size)
    optimizer = optim.Adam(q_network.parameters(), lr=0.001)
    criterion = nn.MSELoss()

    for episode in range(episodes):
        state = env.reset()
        total_reward = 0
        for step in range(max_steps):
            state_tensor = torch.eye(state_size)[state]
            q_values = q_network(state_tensor)
            
            action = np.argmax(q_values.detach().numpy())  # epsilon-greedy 정책
            next_state, reward = env.step(action)
            total_reward += reward
            
            next_state_tensor = torch.eye(state_size)[next_state]
            target = reward + 0.99 * torch.max(q_network(next_state_tensor)).detach()
            loss = criterion(q_values[action], target)
            
            optimizer.zero_grad()
            loss.backward()
            optimizer.step()

            if next_state == env.goal_state:
                break
            
            state = next_state
        print(f"Episode {episode+1}: Total Reward = {total_reward}")

5. 마무리

이번 포스팅에서는 마르코프 결정 과정(MDP)의 개념과 이를 파이토치로 구현하는 방법에 대해 알아보았습니다. MDP는 강화 학습의 기초가 되는 중요한 프레임워크이며, 실제 강화 학습 문제를 해결하는 데 있어 필수적으로 이해해야 할 개념입니다. 연습을 통해 MDP와 강화 학습을 더 깊이 이해하기를 바랍니다.

추가적으로, 더 복잡한 MDP 문제와 학습 알고리즘들을 다루어 보시기를 권장합니다. 파이토치와 같은 도구를 사용하면서 다양한 환경을 구현하고, 에이전트를 훈련시키며, 자신만의 강화 학습 모델을 만들어 보시기 바랍니다.

이 포스팅이 도움이 되었기를 바랍니다. 궁금한 점이 있으시면 댓글을 남겨주세요!