개발 창고/AI

Q-Learning 기초부터 CartPole 적용까지: 강화학습 첫 번째 알고리즘 배우기

로이제로 2025. 7. 10. 22:00
반응형

Q-Learning 기초부터 CartPole 적용까지: 강화학습 첫 번째 알고리즘 배우기

강화학습을 배우다 보면 가장 먼저 접하게 되는 알고리즘이 바로 Q-Learning입니다.
앞서 OpenAI Gym으로 첫 에이전트 만들기에서는 무작위(Random) 에이전트를 CartPole 환경에 적용했는데요, 이번에는 그보다 훨씬 똑똑한 Q-Learning 기반 에이전트를 직접 만들어보겠습니다.


1. Q-Learning이란?

Q-Learning은 “어떤 상태(state)에서 어떤 행동(action)을 하면 얼마나 좋은가”를 학습하는 방법입니다. 여기서 Q는 Quality의 약자로, 각 행동의 '질'을 수치로 표현한다고 보면 됩니다.

핵심 개념

Q-Learning은 Q 테이블을 사용해 상태와 행동의 조합마다 기대되는 보상을 저장합니다.

  • Q(s, a): 상태 s에서 행동 a를 했을 때 기대되는 보상
  • Q 테이블: (state, action)에 대한 보상 추정값을 저장하는 2차원 배열

학습은 다음과 같은 수식으로 이뤄집니다:

Q(s, a) ← Q(s, a) + α * (r + γ * max(Q(s’, a’)) - Q(s, a))
기호 의미
s 현재 상태
a 현재 행동
r 즉시 받은 보상
s’ 다음 상태
α 학습률 (learning rate)
γ 할인율 (future reward의 중요도)

2. Q-Learning의 장점과 한계

장점

  • 단순한 구조로 강화학습을 이해하기 좋음
  • 테이블 기반이라 디버깅 및 시각화가 쉬움

한계

  • 상태가 너무 많거나 연속적인 경우, 테이블이 커져서 한계에 도달
  • 이런 경우에는 DQN(딥러닝 기반 Q-Learning)으로 확장해야 함

3. CartPole에 Q-Learning 적용하기

CartPole은 상태가 연속값이기 때문에 Q-Learning을 바로 적용하기 어렵습니다. 그래서 상태를 디스크리타이징(구간화)해서 테이블로 변환하는 전처리 과정이 필요합니다.

상태 변수

변수 설명
Cart Position 수레의 위치
Cart Velocity 수레의 속도
Pole Angle 막대의 기울기
Pole Velocity 막대의 회전 속도

이 네 가지 상태를 구간화하여 Q 테이블에 넣을 수 있도록 만들겠습니다.


4. 코드로 배우는 Q-Learning with CartPole

import gym
import numpy as np
import math

# 환경 생성
env = gym.make("CartPole-v1")

# 상태를 디스크리타이징하기 위한 설정
buckets = (1, 1, 6, 12)  # 각 상태의 구간 수
q_table = np.zeros(buckets + (env.action_space.n,))
min_bounds = env.observation_space.low
max_bounds = env.observation_space.high
max_bounds[1] = 0.5
max_bounds[3] = math.radians(50)
min_bounds[1] = -0.5
min_bounds[3] = -math.radians(50)

# 하이퍼파라미터
alpha = 0.1
gamma = 0.99
epsilon = 1.0
epsilon_min = 0.01
epsilon_decay = 0.995
episodes = 1000

# 상태 구간화 함수
def discretize(obs):
    ratios = [(obs[i] - min_bounds[i]) / (max_bounds[i] - min_bounds[i]) for i in range(len(obs))]
    new_obs = [int(round((buckets[i] - 1) * min(max(ratios[i], 0), 1))) for i in range(len(obs))]
    return tuple(new_obs)

# Q-Learning 실행
for ep in range(episodes):
    obs = discretize(env.reset())
    total_reward = 0

    done = False
    while not done:
        if np.random.random() < epsilon:
            action = env.action_space.sample()
        else:
            action = np.argmax(q_table[obs])

        next_obs_raw, reward, done, _, = env.step(action)
        next_obs = discretize(next_obs_raw)

        # Q 업데이트
        q_old = q_table[obs + (action,)]
        q_max = np.max(q_table[next_obs])
        q_table[obs + (action,)] = q_old + alpha * (reward + gamma * q_max - q_old)

        obs = next_obs
        total_reward += reward

    if epsilon > epsilon_min:
        epsilon *= epsilon_decay

    if (ep + 1) % 100 == 0:
        print(f"Episode {ep + 1}, total reward: {total_reward}")

env.close()

5. 결과 해석 및 개선 방법

  • 초반에는 랜덤하게 움직이지만, 학습이 진행되면서 평균 보상이 점점 올라갑니다.
  • 구간 수(buckets)를 조정하거나, 학습률 및 감가율(alpha, gamma)을 튜닝하면 성능을 더 높일 수 있습니다.
  • 이후엔 신경망 기반의 DQN 알고리즘으로 확장해 더 복잡한 문제도 해결할 수 있습니다.

6. 마무리

  • Q-Learning은 강화학습의 핵심 개념을 익히기에 가장 적합한 알고리즘입니다.
  • CartPole 환경에 Q-Learning을 적용하면 상태 디스크리타이징, Q 테이블 업데이트, ε-greedy 정책 등을 실습할 수 있습니다.
  • 다음 목표는 DQN(Deep Q-Network)을 이용해 더 많은 상태를 처리할 수 있는 에이전트를 만드는 것입니다.
반응형