强化学习入门: Q-Learning的python实现
观摩了微软俱乐部游戏组大佬的一个unity+tensorflow搞出来的的游戏AI之后对强化学习产生了点兴趣(其实说起来我当时进俱乐部面试的是游戏组最后给我整到软件了???),准备从小白开始学习一下强化学习和游戏里的AI。不过,查了很多资料之后直观感受是,国内这方面的优质资源真的很少,尤其是面向新手的。。。讲的乱七八糟,看的头皮发麻。经过一番扒拉后,找到了两个非常nice的国外大神做的入门教程,链接分别在
当我看到这两个Tutorial的时候感觉就像这位朋友的评论一样hhh
这里的代码用到的环境是openAI-gym里的Taxi-v2,这个游戏的界面长这样
简单说下这个图的含义:
总共5*5个空格,RGBY是四个表示乘客/目的地的位置,每局的话有一个乘客,所在位置用蓝色字母表示,他有一个目的地,所在的位置用紫色字母表示,比如上面这个图就是表示有一个乘客在G,他的目的地是B。
图中字符 : 的表示相邻的两个空格是可以通过的的,| 的位置不能通过(可以理解为墙),每次玩家要做的就是在尽可能短的时间内到乘客点接上乘客并把它送到目的地。每次移动一个位置就需要耗费一个单位时间。
关于游戏得分的规则:
– 每次成功的运送一个乘客可以得到20分
– 随着时间推移,每经过一个单位时间就-1分
– 在错误的地点接或者放乘客会扣10分
嗯,我们现在要做的就是用强化学习的方法来让这个出租车自己走出一条完美的路线。
step0 导入依赖库
import numpy as np import gym import random
step1 创建环境
openAI集成了很多可以用于训练agent的环境,其中就包括了这里的Taxi-v2
env = gym.make(“Taxi-v2”)
env.render()
运行之后就可以看到渲染出来的界面了。
+---------+
|R: | : :G|
| : : : : |
| : : : : |
| | : | : |
|Y| : |B: |
+---------+
step2 初始化Q-table
按照游戏的设定,状态数总共有500种,一开始并没有想明白55的棋盘为什么是500种,后来感觉应该是分两种情况,第一种是接到乘客之前,有A_4^3 * 55=300种,接到乘客后目标可能的情况有4个,再考虑到可能提前把乘客给放下去了(除此之外想不出其他解释)也就是说车子本身的状态是分有乘客和无乘客两种,那么这时候就是425*5=200种,加一块就是500了。
然后可以采取的动作(action)有6种(上下左右四个方向移动以及pick和drop乘客)
由之前的知识可以知道,Q-table表示的是“在某一状态下采取某一动作的质量”(Q表示Quality),用于量化评价在特定状态下采取某个动作的优劣。所以Q-table是一个状态数x动作数的表。
用numpy构造一个初始值全为0的qtable出来。
qtable = np.zeros((state_size, action_size))
理想状态下在训练完成后将会得到一张完美的Q-table,在这种情况下对于任意状态只要在Q-table中对应行里最大的动作执行就可以获得最大得分。
step3 训练
先直接给出Q-leaning的训练伪代码
while 训练未达到停止条件:
初始化游戏,设定任意的乘客和目的地以及出租车的位置
while S != 结束状态:
使用策略π,获得动作a=π(S)
使用动作a进行游戏,获得出租车的新状态S',与奖励R(S,a)
Q[S,A] ← (1-α)*Q[S,A] + α*(R(S,a) + γ* max Q[S',a]) // 更新Q
S ← S'
关于这个算法的原理细节,具体来说:
- 停止条件可以是训练次数抵达设置的训练次数上限,或者是定义的某个关于Q-table和状态的函数达到收敛。
-
结束状态是出租车到达终点,或者它走的步数大于设置的单局步数上限
-
策略π的选择。最简单的策略是根据Q-table来选择效用最大的动作,如果相等则任选。但是这种策略会陷入一种自我循环的状态,用自己来改善自己,会陷入局部极值。比如第一次选择了动作1,得到了较好的收益,但是之后算法将永远无法对其他动作进行选择,即使全局来看选择其他动作最终会得到更好的结果。这种情况其实相当于完全依赖以往经验,而没有考虑探索新的动作。相对的另一个极端是完全不考虑之前学习的经验,但是这样就相当于每次都是瞎猜,学习就失去了意义。因此需要在已有知识和探索未知之间做一个均衡,这也就是经常说的Exploration/Exploitation trade off。在这里一般常用的方法是所谓ε-greedy方法,在每个状态下以ε的概率进行探索,这时将随机选取一个动作,然后以1-ε的概率进行开发,即按照Q-table的值选取收益最大的动作。
-
对Q-table进行更新。使用的公式Q[S,A] ← (1-α)Q[S,A] + α(R(S,a) + γ* max Q[S’,a]) 中,α为学习速率(learning-rate),γ为折扣因子(discount-factor),可以看出,α越大,保留之前训练的效果就越少,而折扣因子越大,max Q[S’,a]的影响就越大,智能体重视越以往经验,反之智能体越重视眼前利益R(S,a)。这里max Q[S’,a]的意义是:在已有经验中新位置S’能给出的最大利益值。直观理解的话就是,如果智能体在这个位置上得到过甜头,那么这个公式就可以驱使他下次再通过其他状态更倾向于进入到这个S’状态。
由此就可以写出Q-learning训练过程的主要代码了
# 2 For life or until learning is stopped for episode in range(total_episodes): # Reset the environment state = env.reset() step = 0 done = False for step in range(max_steps): # 3. Choose an action a in the current world state (s) ## First we randomize a number exp_exp_tradeoff = random.uniform(0,1) ## If this number > greater than epsilon --> exploitation (taking the biggest Q value for this state) if exp_exp_tradeoff > epsilon: action = np.argmax(qtable[state,:]) # Else doing a random choice --> exploration else: action = env.action_space.sample() # Take the action (a) and observe the outcome state(s') and reward (r) new_state, reward, done, info = env.step(action) # Update Q(s,a):= Q(s,a) + lr [R(s,a) + gamma * max Q(s',a') - Q(s,a)] qtable[state, action] = qtable[state, action] + learning_rate * (reward + gamma * np.max(qtable[new_state, :]) - qtable[state, action]) # Our new state is state state = new_state # If done : finish episode if done == True: break # Reduce epsilon (because we need less and less exploration) epsilon = min_epsilon + (max_epsilon - min_epsilon)*np.exp(-decay_rate*episode)
然后就是一个用这个训练好的agent来跑游戏的过程了。。。
完整的jupyter
jupyter 的代码不见了?
jupyter不见了
已经修复。
You get performance improvement ideas on the prime and particular person resources as they loaded.