一、环境构建
搭建一个简单的迷宫环境,红色位置出发,黑色位置代表失败,黄色位置代表成功,让红色块慢慢通过不断探索学习的方式走到黄色的位置
#初始化迷宫
def _build_maze(self):
h = self.MAZE_H*self.UNIT
w = self.MAZE_W*self.UNIT
#初始化画布
self.canvas = tk.Canvas(self, bg='white', height=h, width=w)
#画线
for c in range(0, w, self.UNIT):
self.canvas.create_line(c, 0, c, h)
for r in range(0, h, self.UNIT):
self.canvas.create_line(0, r, w, r)
# 陷阱
self.hells = [self._draw_rect(3, 2, 'black'),
self._draw_rect(3, 3, 'black'),
self._draw_rect(3, 4, 'black'),
self._draw_rect(3, 5, 'black'),
self._draw_rect(4, 1, 'black'),
self._draw_rect(4, 5, 'black'),
self._draw_rect(1, 0, 'black'),
self._draw_rect(1, 1, 'black'),
self._draw_rect(1, 2, 'black'),
self._draw_rect(1, 3, 'black'),
self._draw_rect(1, 4, 'black')]
self.hell_coords = []
for hell in self.hells:
self.hell_coords.append(self.canvas.coords(hell))
# 奖励
self.oval = self._draw_rect(4, 5, 'yellow')
# 玩家对象
self.rect = self._draw_rect(0, 0, 'red')
self.canvas.pack()
然后就是实现走迷宫的动作了,“上下左右”走到对应的位置得到不同的结果,如果走到了黑块就得到-1的惩罚并结束回合,走到黄块得到1的奖励并结束回合,当然需要返回当前的行走策略得到的奖励(或惩罚)
def step(self, action):
s = self.canvas.coords(self.rect)
base_action = np.array([0, 0])
if action == 0: # up
if s[1] > self.UNIT:
base_action[1] -= self.UNIT
elif action == 1: # down
if s[1] < (self.MAZE_H - 1) * self.UNIT:
base_action[1] += self.UNIT
elif action == 2: # right
if s[0] < (self.MAZE_W - 1) * self.UNIT:
base_action[0] += self.UNIT
elif action == 3: # left
if s[0] > self.UNIT:
base_action[0] -= self.UNIT
#根据策略移动红块
self.canvas.move(self.rect, base_action[0], base_action[1])
s_ = self.canvas.coords(self.rect)
#判断是否得到奖励或惩罚
done = False
if s_ == self.canvas.coords(self.oval):
reward = 1
done = True
elif s_ in self.hell_coords:
reward = -1
done = True
#elif base_action.sum() == 0:
# reward = -1
else:
reward = 0
self.old_s = s
return s_, reward, done
二、实现Q Learning
Q-Learning的原理很简单,就是用一张Q表来记录每个状态下取不同的策略(action)的权值,而权值是根据历史经验(得到的奖励、惩罚)来不断更新得到的
这是根据Q表来得到价值最高的步骤,当然为了有探索性所以给了一定权重进行完全随机
#选择动作
def choose_action(self, s):
self.check_state_exist(s)
if np.random.uniform() < self.e_greedy:
state_action = self.q_table.ix[s, :]
state_action = state_action.reindex(
np.random.permutation(state_action.index)) #防止相同列值时取第一个列,所以打乱列的顺序
action = state_action.argmax()
else:
action = np.random.choice(self.actions)
return action
另外就是记录当前的状态,下一步的动作,这个动作得到的奖励或惩罚根据这个核心算法更新到Q表中
#更新q表
def rl(self, s, a, r, s_):
self.check_state_exist(s_)
q_predict = self.q_table.ix[s, a] #q估计
if s_ != 'terminal':
q_target = r + self.reward_decay * self.q_table.ix[s_, :].max() #q现实
else:
q_target = r
self.q_table.ix[s, a] += self.learning_rate * (q_target - q_predict)
三、训练实验
训练的步骤是
1、根据当前的状态得到下一个步骤
2、执行这个步骤,得到执行后的状态
3、记录算法计算出的权值
def update():
for episode in range(100):
s = env.reset()
while True:
env.render()
#选择一个动作
action = RL.choose_action(str(s))
#执行这个动作得到反馈(下一个状态s 奖励r 是否结束done)
s_, r, done = env.step(action)
#更新状态表
RL.rl(str(s), action, r, str(s_))
s = s_
if done:
print(episode)
break
我在第25轮的时候得到第一次奖励,等到了第50轮基本就是走最短路径了