Double DQN 핵심: agent 네트워크에서 다음 상태의 최대 Q-값을 가지는 행동 선택, target 네트워크에서 선택된 행동의 Q-값 계산
예측 Q-값과 타겟 Q-값 비교하여 Loss Function 계산
Backpropagation 및 가중치 업데이트
def train(batch_size):
minibatch = random.sample(memory, batch_size)
states = torch.tensor(np.array([transition[0] for transition in minibatch]), dtype=torch.float32)
actions = torch.tensor(np.array([transition[1] for transition in minibatch]), dtype=torch.long)
rewards = torch.tensor(np.array([transition[2] for transition in minibatch]), dtype=torch.float32)
next_states = torch.tensor(np.array([transition[3] for transition in minibatch]), dtype=torch.float32)
dones = torch.tensor(np.array([transition[4] for transition in minibatch]), dtype=torch.float32)
# Double DQN 핵심: agent 네트워크에서 다음 상태의 최대 Q-값을 가지는 행동 선택
next_actions = agent(next_states).argmax(1).unsqueeze(1)
# target 네트워크에서 선택된 행동의 Q-값 계산
target_q_values = target_agent(next_states).gather(1, next_actions).squeeze()
targets = rewards + gamma * target_q_values * (1 - dones)
predicted_q_values = agent(states).gather(1, actions.unsqueeze(1)).squeeze()
loss = criterion(predicted_q_values, targets)
optimizer.zero_grad()
loss.backward()
optimizer.step()
7. 학습 루프
episodes만큼 에피소드 반복
각 에피소드마다 환경 초기화 및 상태 설정
ε-탐욕적 정책으로 행동 선택
환경에서 행동 실행 후 다음 상태, 보상, 종료 여부 얻음
경험 리플레이 버퍼에 경험 추가
버퍼 크기가 batch_size 이상이면 학습 함수 호출
타겟 네트워크 업데이트 및 탐험 확률 감소
에피소드 결과 출력
# 학습 루프
episodes = 100
for e in range(episodes):
state, _ = env.reset()
state = torch.tensor(state, dtype=torch.float32)
done = False
total_reward = 0
while not done:
if random.random() < epsilon:
action = env.action_space.sample()
else:
action = agent(state).argmax().item()
next_state, reward, terminated, truncated, _ = env.step(action)
next_state = torch.tensor(next_state, dtype=torch.float32)
done = terminated or truncated
total_reward += reward
memory.append((state, action, reward, next_state, done))
if len(memory) >= batch_size:
train(batch_size)
state = next_state
if e % target_update_frequency == 0:
target_agent.load_state_dict(agent.state_dict())
if epsilon > epsilon_min:
epsilon *= epsilon_decay
if (e+1) % 20 == 0:
print(f"Episode {e + 1}/{episodes}, Total Reward: {total_reward}, Epsilon: {epsilon:.3f}")
Episode 20/100, Total Reward: 302.0, Epsilon: 0.010
Episode 40/100, Total Reward: 133.0, Epsilon: 0.010
Episode 60/100, Total Reward: 132.0, Epsilon: 0.010
Episode 80/100, Total Reward: 124.0, Epsilon: 0.010
Episode 100/100, Total Reward: 138.0, Epsilon: 0.010
8. 학습된 에이전트 검증 (렌더링 with GIF)
import imageio
import os
frames = []
state, _ = env.reset()
state = torch.tensor(state, dtype=torch.float32)
done = False
for i in range(3000): # 3000 steps simulation
action = agent(state).argmax().item()
next_state, reward, terminated, truncated, _ = env.step(action)
next_state = torch.tensor(next_state, dtype=torch.float32)
state = next_state
done = terminated or truncated
frames.append(env.render())
if done:
break
imageio.mimsave('cartpole_simulation_doubleDQN.gif', frames, duration=33) # save to gif file
print("GIF saved as cartpole_simulation.gif")