#!pip install gymnasium
#---#
import gymnasium as gym
#---#
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
import IPython14wk-1: 강화학습 (2) – 4x4 Grid World (AgentRandom)
1. 강의영상
2. Imports
3. 4x4 Grid World
- 문제설명: 4x4 그리드월드에서 상하좌우로 움직이는 에이전트가 목표점에 도달하도록 학습하는 방법
- GridWorld에서 사용되는 주요변수
State: 각 격자 셀이 하나의 상태이며, 에이전트는 이러한 상태 중 하나에 있을 수 있음.Action: 에이전트는 현재상태에서 다음상태로 이동하기 위해 상,하,좌,우 중 하나의 행동을 취할 수 있음.Reward: 에이전트가 현재상태에서 특정 action을 하면 얻어지는 보상.Terminated: 하나의 에피소드가 종료되었음을 나타내는 상태.
4. 예비학습
A. gym.spaces
- 예시1
action_space = gym.spaces.Discrete(4)
action_space Discrete(4)
[action_space.sample() for _ in range(5)][1, 1, 2, 1, 2]
0 in action_spaceTrue
4 in action_spaceFalse
- 예시2
state_space = gym.spaces.MultiDiscrete([4,4])
state_spaceMultiDiscrete([4 4])
[state_space.sample() for _ in range(5)][array([3, 3]), array([3, 0]), array([3, 3]), array([3, 3]), array([2, 0])]
np.array([0,1]) in state_spaceTrue
np.array([3,3]) in state_spaceTrue
np.array([3,4]) in state_spaceFalse
B. 시각화
def show(states):
fig = plt.Figure()
ax = fig.subplots()
ax.matshow(np.zeros([4,4]), cmap='bwr',alpha=0.0)
sc = ax.scatter(0, 0, color='red', s=500)
ax.text(0, 0, 'start', ha='center', va='center')
ax.text(3, 3, 'end', ha='center', va='center')
# Adding grid lines to the plot
ax.set_xticks(np.arange(-.5, 4, 1), minor=True)
ax.set_yticks(np.arange(-.5, 4, 1), minor=True)
ax.grid(which='minor', color='black', linestyle='-', linewidth=2)
state_space = gym.spaces.MultiDiscrete([4,4])
def update(t):
if states[t] in state_space:
s1,s2 = states[t]
states[t] = [s2,s1]
sc.set_offsets(states[t])
else:
s1,s2 = states[t]
s1 = s1 + 0.5 if s1 < 0 else (s1 - 0.5 if s1 > 3 else s1)
s2 = s2 + 0.5 if s2 < 0 else (s2 - 0.5 if s2 > 3 else s2)
states[t] = [s2,s1]
sc.set_offsets(states[t])
ani = FuncAnimation(fig,update,frames=len(states))
display(IPython.display.HTML(ani.to_jshtml()))show([[0,0],[1,0],[2,0],[3,0],[4,0]])5. Env 클래스 구현
action_to_direction = {
0 : np.array([1, 0]), # row+, down
1 : np.array([0, 1]), # col+, right
2 : np.array([-1 ,0]), # row-, up
3 : np.array([0, -1]) # col-, left
}
action_to_direction2 = {0: 'down', 1: 'right', 2: 'up', 3: 'left'} # 당장쓰진 않지만 하는김에 action = action_space.sample()direction = action_to_direction[action]current_state = state_space.sample()
next_state = current_state + direction
current_state, direction, next_state(array([3, 0]), array([-1, 0]), array([2, 0]))
- Class 구현: 아래와 같은 느낌의 클래스를 구현해보자.
class GridWorld:
def __init__(self):
self.state_space = gym.spaces.MultiDiscrete([4,4])
self.action_space = gym.spaces.Discrete(4)
self._action_to_direction = {
0 : np.array([1, 0]), # row+, down
1 : np.array([0, 1]), # col+, right
2 : np.array([-1 ,0]), # row-, up
3 : np.array([0, -1]) # col-, left
}
self.reset()
self.state = None
self.reward = None
self.termiated = None
def step(self,action):
direction = self._action_to_direction[action]
self.state = self.state + direction
if np.array_equal(self.state,np.array([3,3])):
self.reward = 100
self.terminated = True
elif self.state not in self.state_space:
self.reward = -10
self.terminated = True
else:
self.reward = -1
return self.state, self.reward, self.terminated
def reset(self):
self.state = np.array([0,0])
self.terminated = False
return self.state env = GridWorld()
state = env.reset()
states = []
states.append(state)
for t in range(50):
action = env.action_space.sample()
state,reward,terminated = env.step(action)
states.append(state)
if terminated: break show(states)- 처음에 바로 죽는 경우가 많아 몇번 시도하고 위의 애니메이션을 얻음
6. AgentRandom
A. 에이전트 클래스 설계
- 우리가 구현하고 싶은 기능
.act(): 액션을 결정 –> 여기서는 그냥 랜덤액션.save_experience(): 데이터를 저장 –> 여기에 일단 초점을 맞추자.learn(): 데이터로에서 학습 –> 패스
class AgentRandom:
def __init__(self,env):
#--# define spaces
self.action_space = env.action_space
self.state_space = env.state_space
#--# replay buffer
self.action = None
self.actions = []
self.current_state = None
self.current_states = []
self.reward = None
self.rewards = []
self.next_state = None
self.next_states = []
self.terminated = None
self.terminations = []
#--# other information
self.n_episodes = 0
self.n_experiences = 0
self.score = 0
self.playtimes = []
self.scores = []
def act(self):
self.action = self.action_space.sample()
def learn(self):
pass
def save_experience(self):
self.current_states.append(self.current_state)
self.actions.append(self.action)
self.rewards.append(self.reward)
self.next_states.append(self.next_state)
self.terminations.append(self.terminated)
#--#
self.n_experiences = self.n_experiences + 1
self.score = self.score + self.rewardB. 환경과 상호작용
env = GridWorld()
agent = AgentRandom(env)
#--#
for _ in range(50):
agent.current_state = env.reset()
agent.score = 0
for t in range(100):
# step1: 행동
agent.act()
# step2: 보상
agent.next_state, agent.reward, agent.terminated = env.step(agent.action)
# step3: 저장 & 학습
agent.save_experience()
agent.learn()
# step4:
agent.current_state = agent.next_state
if agent.terminated: break
agent.scores.append(agent.score)
agent.playtimes.append(t+1)
agent.n_episodes = agent.n_episodes + 1
#---#
print(
f"에피소드: {agent.n_episodes} \t"
f"점수(에피소드): {agent.scores[-1]} \t"
f"게임시간(에피소드): {agent.playtimes[-1]}\t"
f"경험수: {agent.n_experiences}"
)에피소드: 1 점수(에피소드): -12 게임시간(에피소드): 3 경험수: 3
에피소드: 2 점수(에피소드): -15 게임시간(에피소드): 6 경험수: 9
에피소드: 3 점수(에피소드): -11 게임시간(에피소드): 2 경험수: 11
에피소드: 4 점수(에피소드): -10 게임시간(에피소드): 1 경험수: 12
에피소드: 5 점수(에피소드): -10 게임시간(에피소드): 1 경험수: 13
에피소드: 6 점수(에피소드): -12 게임시간(에피소드): 3 경험수: 16
에피소드: 7 점수(에피소드): -11 게임시간(에피소드): 2 경험수: 18
에피소드: 8 점수(에피소드): -18 게임시간(에피소드): 9 경험수: 27
에피소드: 9 점수(에피소드): -10 게임시간(에피소드): 1 경험수: 28
에피소드: 10 점수(에피소드): 91 게임시간(에피소드): 10 경험수: 38
에피소드: 11 점수(에피소드): -10 게임시간(에피소드): 1 경험수: 39
에피소드: 12 점수(에피소드): -10 게임시간(에피소드): 1 경험수: 40
에피소드: 13 점수(에피소드): -11 게임시간(에피소드): 2 경험수: 42
에피소드: 14 점수(에피소드): -10 게임시간(에피소드): 1 경험수: 43
에피소드: 15 점수(에피소드): -10 게임시간(에피소드): 1 경험수: 44
에피소드: 16 점수(에피소드): -10 게임시간(에피소드): 1 경험수: 45
에피소드: 17 점수(에피소드): -10 게임시간(에피소드): 1 경험수: 46
에피소드: 18 점수(에피소드): -15 게임시간(에피소드): 6 경험수: 52
에피소드: 19 점수(에피소드): -11 게임시간(에피소드): 2 경험수: 54
에피소드: 20 점수(에피소드): -10 게임시간(에피소드): 1 경험수: 55
에피소드: 21 점수(에피소드): -10 게임시간(에피소드): 1 경험수: 56
에피소드: 22 점수(에피소드): -12 게임시간(에피소드): 3 경험수: 59
에피소드: 23 점수(에피소드): -11 게임시간(에피소드): 2 경험수: 61
에피소드: 24 점수(에피소드): -11 게임시간(에피소드): 2 경험수: 63
에피소드: 25 점수(에피소드): -13 게임시간(에피소드): 4 경험수: 67
에피소드: 26 점수(에피소드): -10 게임시간(에피소드): 1 경험수: 68
에피소드: 27 점수(에피소드): -10 게임시간(에피소드): 1 경험수: 69
에피소드: 28 점수(에피소드): -11 게임시간(에피소드): 2 경험수: 71
에피소드: 29 점수(에피소드): -10 게임시간(에피소드): 1 경험수: 72
에피소드: 30 점수(에피소드): -13 게임시간(에피소드): 4 경험수: 76
에피소드: 31 점수(에피소드): -10 게임시간(에피소드): 1 경험수: 77
에피소드: 32 점수(에피소드): -10 게임시간(에피소드): 1 경험수: 78
에피소드: 33 점수(에피소드): -18 게임시간(에피소드): 9 경험수: 87
에피소드: 34 점수(에피소드): -13 게임시간(에피소드): 4 경험수: 91
에피소드: 35 점수(에피소드): -18 게임시간(에피소드): 9 경험수: 100
에피소드: 36 점수(에피소드): -10 게임시간(에피소드): 1 경험수: 101
에피소드: 37 점수(에피소드): -15 게임시간(에피소드): 6 경험수: 107
에피소드: 38 점수(에피소드): -10 게임시간(에피소드): 1 경험수: 108
에피소드: 39 점수(에피소드): -13 게임시간(에피소드): 4 경험수: 112
에피소드: 40 점수(에피소드): -17 게임시간(에피소드): 8 경험수: 120
에피소드: 41 점수(에피소드): -10 게임시간(에피소드): 1 경험수: 121
에피소드: 42 점수(에피소드): -10 게임시간(에피소드): 1 경험수: 122
에피소드: 43 점수(에피소드): -10 게임시간(에피소드): 1 경험수: 123
에피소드: 44 점수(에피소드): -10 게임시간(에피소드): 1 경험수: 124
에피소드: 45 점수(에피소드): -10 게임시간(에피소드): 1 경험수: 125
에피소드: 46 점수(에피소드): -17 게임시간(에피소드): 8 경험수: 133
에피소드: 47 점수(에피소드): -10 게임시간(에피소드): 1 경험수: 134
에피소드: 48 점수(에피소드): -13 게임시간(에피소드): 4 경험수: 138
에피소드: 49 점수(에피소드): -12 게임시간(에피소드): 3 경험수: 141
에피소드: 50 점수(에피소드): -11 게임시간(에피소드): 2 경험수: 143
C. 상호작용결과 시각화
[np.array([0,0])] + agent.next_states[28:38] # 에피소드10[array([0, 0]),
array([0, 1]),
array([0, 2]),
array([0, 3]),
array([1, 3]),
array([2, 3]),
array([2, 2]),
array([3, 2]),
array([3, 1]),
array([3, 2]),
array([3, 3])]
show([np.array([0,0])] + agent.next_states[28:38]) # 에피소드5