1. Gym(Gymnasium)이란?
Gym(OpenAI Gym, 현재는 Gymnasium) 은 강화학습 알고리즘을 실험하고 개발할 수 있도록
다양한 환경(environment)을 제공하는 파이썬 라이브러리입니다.
강화학습에서는 항상 이런 패턴으로 생각합니다.
에이전트 (Agent) ↔ 환경 (Environment)
↑ 행동(Action)
↓ 보상(Reward), 다음 상태(State)
Gym은 이 “환경 쪽”을 대신 구현해 주는 도구입니다.
CartPole,MountainCar,Pendulum같은 클래식 제어 환경- Atari 게임
- Box2D 기반 물리 환경 등
연구자나 개발자는 Gym을 통해 표준화된 환경에서 에이전트가 행동을 선택하고 보상을 받는 과정을 손쉽게 구현할 수 있고,
알고리즘 간 성능을 비교하기에도 좋습니다.
2. 이번에 다룰 예제 – CartPole + DQN
노트북에서는 DQN(Deep Q-Network) 으로 CartPole-v1 환경을 학습시키는 예제를 다룹니다.
- 환경: CartPole-v1
- 카트 위에 막대가 세워져 있고, 카트를 좌우로 움직여 막대가 쓰러지지 않게 유지하는 문제
- 목표: 에이전트가 현재 상태(카트 위치, 속도, 막대 각도, 각속도)를 보고 왼쪽/오른쪽 행동을 선택해 막대를 최대한 오래 세워두기
- 알고리즘: DQN
- 신경망으로 Q(s, a) 를 근사하는 Q-learning
전체 구조는 다음과 같습니다.
환경: CartPole-v1
상태: [카트 위치, 카트 속도, 막대 각도, 막대 각속도] (4차원 실수 벡터)
행동: 0(왼쪽), 1(오른쪽)
에이전트: DQN
- Q네트워크(q): 현재 Q값 예측
- 타깃 네트워크(q_target): 안정적인 학습을 위해 사용
- 리플레이 버퍼(Replay Buffer): 경험 (s, a, r, s') 저장 후 샘플링
3. CartPole 환경과 DQN 구성 요소
3.1 라이브러리와 하이퍼파라미터
import gymnasium as gym
import collections
import random
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
# Hyperparameters
learning_rate = 0.0005
gamma = 0.98
buffer_limit = 50000
batch_size = 32
- gamma: 할인율 (미래 보상을 얼마나 중요하게 볼지)
- buffer_limit: 리플레이 버퍼에 최대 몇 개의 transition을 저장할지
- batch_size: 한 번 학습할 때 몇 개의 경험을 샘플링할지
3.2 Replay Buffer – 경험을 모아두는 창고
DQN에서는 경험 하나를 곧바로 학습에 쓰지 않고, 버퍼에 쌓았다가 랜덤하게 꺼내 학습합니다.
이를 경험 재현(Experience Replay) 이라고 합니다.
class ReplayBuffer():
def __init__(self):
self.buffer = collections.deque(maxlen=buffer_limit)
def put(self, transition):
self.buffer.append(transition)
def sample(self, n):
mini_batch = random.sample(self.buffer, n)
s_lst, a_lst, r_lst, s_prime_lst, done_mask_lst = [], [], [], [], []
for transition in mini_batch:
s, a, r, s_prime, done_mask = transition
s_lst.append(s)
a_lst.append([a])
r_lst.append([r])
s_prime_lst.append(s_prime)
done_mask_lst.append([done_mask])
return (
torch.tensor(s_lst, dtype=torch.float),
torch.tensor(a_lst),
torch.tensor(r_lst),
torch.tensor(s_prime_lst, dtype=torch.float),
torch.tensor(done_mask_lst),
)
def size(self):
return len(self.buffer)
put()으로(s, a, r, s′, done_mask)형태의 경험을 저장sample(n)에서 랜덤 미니배치를 뽑아 PyTorch 텐서로 변환해 반환done_mask는 에피소드가 끝났는지 여부를 0/1로 표현해, 타깃 계산에 사용합니다.
경험을 섞어서 학습하면:
- 샘플 간 상관관계를 줄여 안정적인 학습이 가능하고,
- 같은 경험을 여러 번 재사용해 샘플 효율을 높일 수 있습니다.
3.3 Q 네트워크 – 상태를 Q값으로 바꾸는 신경망
CartPole 상태는 4차원, 행동은 2개(왼쪽/오른쪽)이므로,
입력 4 → 은닉층들 → 출력 2 형태의 네트워크를 사용합니다.
class Qnet(nn.Module):
def __init__(self):
super(Qnet, self).__init__()
# 입력: 상태(4차원) → 은닉층 128 → 은닉층 128 → 출력: 행동별 Q값(2차원)
self.fc1 = nn.Linear(4, 128)
self.fc2 = nn.Linear(128, 128)
self.fc3 = nn.Linear(128, 2) # 0: 왼쪽, 1: 오른쪽
def forward(self, x):
x = F.relu(self.fc1(x))
x = F.relu(self.fc2(x))
x = self.fc3(x)
return x
def sample_action(self, obs, epsilon):
out = self.forward(obs) # 행동별 Q값
coin = random.random()
if coin < epsilon:
# ε 비율로 랜덤 행동 (exploration)
return random.randint(0, 1)
else:
# 나머지는 Q값이 가장 큰 행동 선택 (exploitation)
return out.argmax().item()
여기서도 ε-greedy 전략을 사용합니다.
- 초반에는 ε가 상대적으로 커서 탐험(exploration) 을 많이 하고,
- 학습이 진행될수록 ε를 줄여 학습된 정책을 더 많이 활용(exploitation) 합니다.
4. DQN 학습 루프 – train 함수
4.1 한 번의 학습 스텝
def train(q, q_target, memory, optimizer):
for i in range(10):
# 버퍼에서 batch_size 만큼 경험을 랜덤 샘플링
s, a, r, s_prime, done_mask = memory.sample(batch_size)
q_out = q(s) # (batch_size, 2) 각 상태에서의 행동별 Q값
q_a = q_out.gather(1, a) # 실제로 취한 행동 a에 해당하는 Q값만 추출
# 타깃 네트워크로 다음 상태의 최대 Q값 계산
max_q_prime = q_target(s_prime).max(1)[0].unsqueeze(1)
target = r + gamma * max_q_prime * done_mask
# Huber Loss (smooth_l1_loss) 사용 – DQN에서 자주 쓰는 손실
loss = F.smooth_l1_loss(q_a, target)
optimizer.zero_grad()
loss.backward()
optimizer.step()
q: 현재 학습 중인 Q 네트워크q_target: 타깃 네트워크 (일정 주기마다만 업데이트해, 학습을 안정화)done_mask: 에피소드가 끝난 상태에서는max_q_prime를 0으로 만들어, 더 이상 미래 보상을 추가하지 않도록 합니다.
핵심은 여전히 Q-learning 수식입니다.
target = r + γ maxₐ′ Q_target(s′, a′)
loss = Huber(Q(s,a), target)
5. 전체 학습 과정 – CartPole DQN main 루프
def main():
# CartPole 환경 생성 – 막대가 쓰러지지 않도록 카트를 좌우로 움직이는 문제
env = gym.make('CartPole-v1')
q = Qnet() # 현재 Q 네트워크
q_target = Qnet() # 타깃 네트워크
q_target.load_state_dict(q.state_dict())
memory = ReplayBuffer()
print_interval = 20
score = 0.0
optimizer = optim.Adam(q.parameters(), lr=learning_rate)
for n_epi in range(10000):
# epsilon 값을 점점 줄임 – 초반에는 exploration을 더 많이, 후반에는 정책 활용
epsilon = max(0.01, 0.08 - 0.01 * (n_epi / 200)) # 8% → 1% 선형 감소
s, info = env.reset()
done = False
while not done:
a = q.sample_action(torch.from_numpy(s).float(), epsilon)
s_prime, r, done, truncated, info = env.step(a)
done_mask = 0.0 if done else 1.0
# 보상을 100으로 나눠 스케일 조정
memory.put((s, a, r / 100.0, s_prime, done_mask))
s = s_prime
score += r
if done:
break
# 버퍼에 충분한 데이터가 쌓이면 학습 시작
if memory.size() > 2000:
train(q, q_target, memory, optimizer)
# 일정 에피소드마다 타깃 네트워크를 현재 네트워크로 업데이트
if n_epi % print_interval == 0 and n_epi != 0:
q_target.load_state_dict(q.state_dict())
print(\"n_episode :{}, score : {:.1f}, n_buffer : {}, eps : {:.1f}%\".format(
n_epi, score / print_interval, memory.size(), epsilon * 100))
score = 0.0
env.close()
5.1 학습 로그 해석
실행하면 대략 이런 로그들이 출력됩니다.
n_episode : 20, score : 19.2, n_buffer : 385, eps : 7.9%
n_episode : 100, score : 17.8, n_buffer : 1849, eps : 7.5%
n_episode : 200, score : 59.6, n_buffer : 6063, eps : 7.0%
n_episode : 300, score : 175.5, n_buffer : 16865, eps : 6.5%
n_episode : 340, score : 204.3, n_buffer : 24500, eps : 6.3%
...
- 초반(20, 100 epi)에는 평균 score(막대를 유지한 스텝 수) 가 20 근처로 낮습니다.
- 학습이 진행될수록 score가 50, 100, 200… 으로 올라가며,
에이전트가 점점 막대를 오래 유지하는 정책을 배우고 있다는 것을 보여줍니다. n_buffer는 리플레이 버퍼에 쌓인 경험 개수,eps는 현재 ε(탐험 비율)입니다.
더보기
[ 오늘의 정리 ]
– Q-learning + Gym으로 실전 강화학습 시작하기
- Gym(Gymnasium) 은 강화학습 실험용 표준 환경을 제공하는 라이브러리로,
CartPole 같은 클래식 문제부터 Atari 게임까지 다양한 환경을 지원합니다. - 이번 예제에서는 DQN을 이용해 CartPole-v1 환경에서 막대가 쓰러지지 않도록
카트를 좌우로 움직이는 정책을 학습했습니다. - 핵심 구성 요소는:
- Q 네트워크(Qnet): 상태 → 행동별 Q값
- 리플레이 버퍼(ReplayBuffer): 경험을 모아 샘플링
- 타깃 네트워크(q_target): 안정적인 학습을 위해 천천히 업데이트
- ε-greedy 탐험: 초반에는 더 많은 랜덤 행동, 후반에는 정책 활용
- 이런 패턴은 CartPole뿐 아니라 다른 Gym 환경, 더 복잡한 Deep RL 문제로도 그대로 확장할 수 있는 기본 골격입니다.
'개념 정리실 > 강화학습' 카테고리의 다른 글
| Actor-Critic로 CartPole 학습하기 – REINFORCE에서 한 걸음 더 (1) | 2026.03.16 |
|---|---|
| Policy Gradient & REINFORCE – 정책 기반 에이전트 (1) | 2026.03.12 |
| Q-learning – 가장 유명한 가치 기반 강화학습 (0) | 2026.03.11 |
| Deep RL – 근사, 함수 근사, 신경망, 가치 기반·정책 기반 (0) | 2026.03.11 |
| TD Learning (Temporal Difference Learning) (0) | 2026.03.10 |