- 先观察效果
上图是训练过程中的图片
上图是训练结束后测试阶段的效果,依次选择0,1,2,3四个位置,智能体均能自行到达终点
-
环境解释
状态空间S:共有5个状态,从左到右一次为0,1,2,3,4
动作空间A:共有3个动作,0,1,2分别表示原地不动,向左,向右
Q值表为S*A的表格,每个Q值表示在状态s下选择动作a的Q值(s跟a搭配的合适程度,越大越合适,回报越高,根据一个收敛的Q值表进行动作选择可以保证选择处一条全局收益最高的路线)
上图中的环境时我在gym模块的框架下自行构建的可视化环境,关于gym可视化环境的构建可以参见 分类目录——强化学习
-
Q_Learning算法部分
import numpy as np import pandas as pd import time from gymTest.ttenvline import EnvLine class QLearning: def __init__(self, actions_space, target, learning_rate=0.01, reward_decay=0.9, e_greedy=0.9): self.actions = actions_space # 可以选择的动作空间 self.target = target # 目标状态(终点) self.lr = learning_rate # 学习率 self.gamma = reward_decay # 回报衰减率 self.epsilon = e_greedy # 探索/利用 贪婪系数 self.q_table =pd.DataFrame(columns=range(self.actions.n), dtype=np.float64) # Q值表 def choose_action(self, observation): self.check_state_exist(observation) # 调用这个函数的作用是检查Q值表中有无该状态,如果没有就向表中追加 # 选择动作 # 假设epsilon=0.9,下面的操作就是有0.9的概率按Q值表选择最优的,有0.1的概率随机选择动作 # 随机选动作的意义就是去探索那些可能存在的之前没有发现但是更好的方案/动作/路径 if np.random.uniform() < self.epsilon: # 选择最佳动作(Q值最大的动作) state_action = self.q_table.loc[observation, :] # 如果几个动作的Q值同为最大值,从中选一个 action = np.random.choice(state_action[state_action == np.max(state_action)].index) else: # 随机选择一个动作 action = self.actions.sample() return action # 学习,主要是更新Q值 def learn(self, s, a, r, s_): self.check_state_exist(s_) q_predict = self.q_table.loc[s, a] if s_ != self.target: # 如果下一个状态不是终点 q_target = r + self.gamma * self.q_table.loc[s_, :].max() # 这就是Q值的迭代更新公式 else: q_target = r # 下一个状态不是终点 self.q_table.loc[s, a] += self.lr * (q_target - q_predict) # update # 检查Q值表中有无状态state,如果没有就向表中追加 def check_state_exist(self, state): if state not in self.q_table.index: # 向Q表中追加一个状态 self.q_table = self.q_table.append( pd.Series( [0]*len(self.q_table.columns), index=self.q_table.columns, name=state ) ) if __name__ == '__main__': env = EnvLine() # 这就是图示的画面环境 model = QLearning( env.action_space, env.target, ) # 训练 for episode in range(100): # 初始化状态 observation = env.reset() env.render() while True: # 基于当前状态选择动作 action = model.choose_action(observation) # 执行动作,获取回报 observation_, reward, done = env.step(action) # 刷新画面 env.render() # 学习,更新Q表 model.learn(observation, action, reward, observation_) # 推进状态(当前状态前移) observation = observation_ # 如果达到终点,获得done=True,跳出循环 if done: break time.sleep(0.1) # 延时可以提供更好的可视化效果,相对的也会减慢训练 time.sleep(0.5) # 如果训练顺利,此时model中的q_table就已经收敛了 print(model.q_table) # 0 1 2 # 4 2.063857 - 0.008877 0.100000 # 3 0.083175 - 0.015520 5.341192 # 2 - 0.056166 - 0.060211 0.806275 # 1 - 0.237123 - 0.236387 - 0.235704 # 0 - 0.372681 - 0.372961 - 0.372209 # 测试 model.epsilon = 1 # 因为是测试(应用),讲epsilon设置成1,省掉“探索”的过程,直接“利用” for episode in range(10): print('episode', episode, '----------') for i in range(env.observation_space.n): print(i) # 初始化转态 observation = env.reset(i) # 遍历着在状态空间里初始化 env.render() time.sleep(1) while True: action = model.choose_action(observation) observation_, reward, done = env.step(action) # 执行动作,获得下一个状态,回报 env.render() observation = observation_ if done: break time.sleep(0.5) time.sleep(1)
-
收敛后的Q值表分析
# 0 1 2 # 4 2.063857 - 0.008877 0.100000 # 3 0.083175 - 0.015520 5.341192 # 2 - 0.056166 - 0.060211 0.806275 # 1 - 0.237123 - 0.236387 - 0.235704 # 0 - 0.372681 - 0.372961 - 0.372209
其中竖向为状态,横向为动作。
观察Q值表的分布,可以发现,越靠近终点的位置,Q值的差距拉的越大,这是因为回报衰减gamma存在的原因,终点的较大回报r在经过数轮前项传递之后,在开始的0状态上产生的影响已经很小了,但是还是能区分出最佳动作。
在状态0下,动作2(向右)的Q值最大,选择动作2进入状态1
在状态1下,动作2(向右)的Q值最大,选择动作2进入状态3
. . .
直到到达终点
-
参考文献
什么是gym
gym自定义可视化环境绘制
gym自定义可视化环境实例
强化学习调用gym环境实例
从Q_Learning看强化学习
一个Q_Learning强化学习自定义gym环境可视化实例