강화학습
패키지 설치¶
다음 코드는 세가지 패키지가 선행 되어야 합니다.
sudo apt-get install ffmpeg
pip install gym
pip install gym_minigrid
import numpy as np
import pandas as pd
import random
from collections import defaultdict
import gym
import gym_minigrid
import matplotlib.pyplot as plt
%matplotlib inline
환경¶
예제 코드는 그리드월드 예제에서 Q러닝 에이전트가 학습하는 코드 입니다.
에이전트가 최종 지점에 도달하면 보상을 받고,
에이전트가 취할 수 있는 행동은 다음 세가지 입니다.
- 왼쪽으로 회전
- 오른쪽으로 회전
- 전진
Q러닝 에이전트¶
먼저 Q러닝 에이전트 클래스를 만들어 줍니다. (설정은 SARSA와 모두 동일)
SARSA에이전트는 0.01의 학습율($\alpha$), 0.9의 감가율($\gamma$),
그리고 0.2의 입실론($\epsilon$)값을 가지고 학습합니다.
그리고 경험에 의해 학습될 q값을 저장합니다.
class QLearning:
def __init__(self, actions, agent_indicator=10):
self.actions = actions
self.agent_indicator = agent_indicator
self.alpha = 0.01
self.gamma = 0.9
self.epsilon = 0.2
self.q_values = defaultdict(lambda: [0.0] * actions)
...
입실론 그리디 정책¶
Q러닝 에이전트는 SARSA와 동일하게, 입실론 그리디 정책을 사용합니다.
입실론 그리디는 $\epsilon$값에 의해 랜덤한 행동을,
$1 - \epsilon$값에 의해 탐욕적으로 행동을 선택합니다.
(랜덤한 행동은 np.random.choice, 탐욕적 행동은 np.argmax에 의해 선정)
...
def act(self, state):
if np.random.rand() < self.epsilon:
action = np.random.choice(self.actions)
else:
state = self._convert_state(state)
q_values = self.q_values[state]
action = np.argmax(q_values)
return action
...
Q값 학습¶
현재상태 (S, state), 현재행동 (A, action), 보상 (R, reward),
다음상태 (S', next_state), 다음행동 (A', next_action)
위 다섯가지 원소를 가지고 시간차(TD)를 학습합니다.
여기서 SARSA 에이전트와 다른점은, TD에러를 계산할 때 다음 Q값의 max를 취해준 다는 것입니다.
...
def update(self, state, action, reward, next_state, next_action):
state = self._convert_state(state)
next_state = self._convert_state(next_state)
q_value = self.q_values[state][action]
next_q_value = max(self.q_values[next_state])
td_error = reward + self.gamma * next_q_value - q_value
self.q_values[state][action] = q_value + self.alpha * td_error
환경 & 에이전트 초기화¶
환경과 Q러닝 에이전트를 초기화 합니다.
env = gen_wrapped_env('MiniGrid-Empty-6x6-v0')
obs = env.reset()
agent_position = obs[0]
agent = QLearning(3, agent_position)
에피소드 학습¶
5000번의 에피소드를 통해 학습합니다.
각 20번의 에피소드마다 리워드 값을 출력합니다.
rewards = []
for ep in range(5000):
done = False
obs = env.reset()
action = agent.act(obs)
ep_rewards = 0
while not done:
next_obs, reward, done, info = env.step(action)
next_action = agent.act(next_obs)
agent.update(obs, action, reward, next_obs, next_action)
ep_rewards += reward
obs = next_obs
action = next_action
rewards.append(ep_rewards)
if (ep+1) % 20 == 0:
print("episode: {}, rewards: {}".format(ep+1, ep_rewards))
env.close()
학습된 Q값 출력¶
에이전트가 학습한 각 상태/행동별 Q값을 출력해봅니다.
이 때 dict의 key 수는 상태의 수, 즉 grid의 수가 되고,
각 key 별로 행동 3개의 리스트를 가지게 됩니다.
지난 포스팅의 SARSA의 Q값과 많이 다른 것을 확인할 수 있습니다.
SARSA는 사용된 Q값만 학습되기 때문에 왼쪽/오른쪽 회전의 Q값이 모두 0이었던 반면,
Q러닝은 최대 Q값을 고려하기 때문에, 각 grid에서 외전 방향까지 Q값이 존재하게 됩니다.
{s:np.round(q, 5).tolist() for s, q in agent.q_values.items()}
에피소드 시각화¶
다음은 최종 에피소드의 영상입니다.
show_video()
학습 곡선 시각화¶
다음은 학습 시 받은 보상의 이동 평균(Moving Average)을 시각화 한 그래프 입니다.
비교 분석을 위해 SARSA의 결과가 포함되었고,
두 기법 모두5번의 시도 중 가장 좋은 그래프를 시각화 하였습니다.
결과에서 볼 수 있는 것과 같이, Q러닝의 수렴 속도가 더 빠르고,
5000에피소드의 결과에서 더 높은 평균 리워드를 받은것을 알 수 있습니다.
sarsa_logs = pd.read_csv('./logs/rewards_sarsa.csv', index_col=False).iloc[:, 1]
q_logs = pd.read_csv('./logs/rewards_qlearning.csv', index_col=False).iloc[:, 1]
plt.figure(figsize=(16, 8))
plt.plot(q_logs.cumsum() / (pd.Series(np.arange(q_logs.shape[0]))+1), label="QLearning")
plt.plot(sarsa_logs.cumsum() / (pd.Series(np.arange(sarsa_logs.shape[0]))+1), label="SARSA")
plt.legend()
'데이터사이언스 > 강화학습' 카테고리의 다른 글
강화학습 - (21) 모델 (0) | 2020.11.15 |
---|---|
강화학습 - (20-2) Expected SARSA 코드예제 (0) | 2020.11.15 |
강화학습 - (20) Q러닝 (0) | 2020.11.05 |
강화학습 - (19) SARSA (0) | 2020.10.30 |
강화학습 - (18) 시간차 학습 (0) | 2020.10.04 |