1 前言
- 玩个游戏(滑动杆CartPole),看下图。我们的目标是,我们通过向左或向右滑动滑块来保证杆子始终在滑块的上方。下图我设置随机滑动滑块,展现出来就是这样一个效果。
- 经过该篇文章学习后,你能通过强化学习操控滑块,达到如下的一个效果。Amazing?Let’s make it .
回到正题 - 首先需要安装Gym,即游戏仿真平台。使用pip install gym,即可完成安装。需要注意的是,如果使用google colab等在线编程平台就不能成功弹出可视化图像。建议本地运行。
- CartPole游戏比较有名,大多数强化学习入门教材都会使用这个例子。
- 文章末尾会给出完整源代码,建议先跑一下,看看效果,再进入如下的学习。
2 如何做
教学大纲:
- 介绍gym如何使用
- 强化学习之QLearning介绍
- 使用QLearning来学习CartPole游戏,得到Q表
- 运用Q表进行游戏中的决策
2.1 gym使用
import gym
import matplotlib.pyplot as plt
from PIL import Image
env = gym.make('CartPole-v1')
env.reset()
image_append = []
for _ in range(100):
current_img = env.render(mode="rgb_array")
current_img = Image.fromarray(current_img)
image_append.append(current_img)
env.step(env.action_space.sample())
env.close()
image_append[0].save('./sample_out.gif',save_all = True,append_images = image_append)
- 如上代码, gym.make:来生成对应的游戏环境。env.reset:将游戏环境初始化;env.render:将此可游戏环境画出;env.step:表示游戏画面更新,其参数为0时,表示滑块向左滑动,参数为1时,滑块向右滑动;env.action_space.sample:随机返回0或1。
- 看到这里不难发现,该游戏的行为(action)只有向左或向右移动滑块。也就是说,想要玩好这个游戏。我们需要有一个策略决定如何在不同的环境下,来向左或向右移动滑块。
- 什么是不同的环境?在该游戏的背景下,滑块的位置,滑块的速度,滑块的杆的角度以及滑块杆的角速度,这四点确定,是不是我们就可以说环境确定下来了。OK,先不管这么多,看结果输出。
Output:
- 对了,还有一个很重要的没讲。如下代码env.step将返回四个值。
obs, rew, done, info = env.step(env.action_space.sample())
- obs是一个数组,包含滑块的位置,滑块的速度,滑块的杆的角度以及滑块杆的角速度。
- rew即reward,强化学习里面的概念。如果游戏始终进行,其值就为1;game over 该值为0。
- done:要不怎么说这是游戏仿真器呢,如果滑块上的杆不在滑块上方,done为True,否则为False。当done为True是,也就意味着游戏结束。看如下代码,你的感触会更深。
- info:没什么用。
import gym
import time
import matplotlib.pyplot as plt
from PIL import Image
env = gym.make('CartPole-v1')
env.reset()
done = False
while not done:
env.render()
_,_,done,_ = env.step(env.action_space.sample())
time.sleep(0.1)
env.close()
Output:
2.2 QLearning介绍
就这个游戏进行展开:
问题定义:
玩好这个游戏,我们可以换一种具体的表述,即在环境观察值 observation确定的情况下,如何对行为 action进行预测。更具体点就是,给定滑块的位置,滑块的速度,滑块的杆的角度以及滑块杆的角速度,我们如何判断下一步的行为,即滑块向左还是向右滑动。emmmm,这样是不是太断然了?更合理的定义应该是:给定环境观测值以及相应地行为标识,我们输出对应行为的概率。
(
(
o
b
s
e
r
v
a
t
i
o
n
)
,
a
c
t
i
o
n
)
→
(
p
r
o
b
a
b
i
l
i
t
y
)
((observation),action) \rightarrow (probability)
((observation),action)→(probability)
问题分析:
我们自然想到使用字典来维护这个映射。
- 字典的keys由环境观察值的四元组+行为的标识组成(行为值为0向左,1向右)构成。
- values由一个数值构成,代表进行对应行为概率(置信度)。
- 如此,只要我们成功维护该字典,玩游戏时,就能通过字典的key(环境观察值及行为标识),找到其value,与环境观察值相同的其他行为标识value值进行比较,进而选择可能性更大的走法。
- Qlearning中的Q,其实就是我们这里的字典
字典如何维护?
刚玩游戏时,字典Q是空的,代表我们没有任何经验。引入一个概念,利用与探索(即经验与试错)。在让模型玩游戏的过程中,以一定的概率(
?
\epsilon
?)来进行利用与探索。利用:代表使用当前已有的Q字典进行决策,按照决策行动后,还没有game over的话,那就给这个决策奖励,即相应的行为probability增加。探索:代表随机进行决策,同样的,按照决策行动后,还没有game over的话,那就也给这个决策奖励。
- Tips:利用过程刚开始为字典空,那就意味着向左向右的概率相同,也就相当于探索。
- 那如何通过具体的奖励(reward)来更新行动的概率值呢?QLearning这样做,如下。
- QLearning公式:
Q
(
s
,
a
)
←
Q
(
s
,
a
)
+
α
(
r
+
γ
?
m
a
x
a
′
Q
(
s
′
,
a
′
)
?
Q
(
s
,
a
)
)
Q(s,a) ← Q(s,a)+α \left( r+γ \cdot max_{a'}Q(s',a')-Q(s,a)\right)
Q(s,a)←Q(s,a)+α(r+γ?maxa′?Q(s′,a′)?Q(s,a))
- 其中
s
s
s 就是当前环境观察值,
a
a
a 就是行为标识,
α
\alpha
α 就是学习率,
r
r
r 就是reward奖励,
s
′
与
a
′
s'与a'
s′与a′ 就是决策后的环境与行为,
γ
\gamma
γ 是对未来 reward 的衰减值。为什么如上公式有效,全网有很多理论证明,我这里就不细说了。
- 不断玩游戏,Q字典就不断得到完善。如上表示可能还不是很清晰,具体细节可看如下代码,也很简单。
2.3 生成Q表
其实讲到现在还有个问题没有解决。你想啊,我们的环境观察值虽然是四元组,但是其中每一个值都是连续的。这不就代表游戏中有无数多种环境吗?那这个字典还怎么维护的了。我们需要将其离散化。使用如下函数即可。
def discretize(x):
return tuple((x/np.array([0.25, 0.25, 0.01, 0.1])).astype(np.int))
训练生成Q表:
import gym
import matplotlib.pyplot as plt
import numpy as np
import random
import warnings
from PIL import Image
warnings.filterwarnings('ignore')
env = gym.make("CartPole-v1")
def discretize(x):
return tuple((x/np.array([0.25, 0.25, 0.01, 0.1])).astype(np.int))
Q = {}
actions = (0,1)
alpha = 0.3
gamma = 0.9
epsilon = 0.90
def qvalues(state):
return [Q.get((state,a),0) for a in actions]
def probs(v,eps=1e-4):
v = v-v.min()+eps
v = v/v.sum()
return v
for epoch in range(10000):
obs = env.reset()
done = False
while not done:
s = discretize(obs)
if random.random()<epsilon:
v = probs(np.array(qvalues(s)))
a = random.choices(actions,weights=v)[0]
else:
a = np.random.randint(env.action_space.n)
obs, rew, done, info = env.step(a)
ns = discretize(obs)
Q[(s,a)] = Q.get((s,a),0) + alpha * (rew + gamma * max(qvalues(ns))-Q.get((s,a),0))
- 如上代码进行了1万次的游戏。Q表已经维护的比较好了。接下来我们就要利用Q表信息,完成可视化。
2.4 Q表决策
obs = env.reset()
done = False
image_append = []
while not done:
s = discretize(obs)
current_img = env.render(mode="rgb_array")
current_img = Image.fromarray(current_img)
image_append.append(current_img)
v = probs(np.array(qvalues(s)))
a = random.choices(actions,weights=v)[0]
obs,_,done,_ = env.step(a)
image_append[0].save('./out.gif',save_all = True,append_images = image_append)
env.close()
Output:
3 源代码(可直接运行)
import gym
import matplotlib.pyplot as plt
import numpy as np
import random
import warnings
from PIL import Image
warnings.filterwarnings('ignore')
env = gym.make("CartPole-v1")
def discretize(x):
return tuple((x/np.array([0.25, 0.25, 0.01, 0.1])).astype(np.int))
Q = {}
actions = (0,1)
alpha = 0.3
gamma = 0.9
epsilon = 0.90
def qvalues(state):
return [Q.get((state,a),0) for a in actions]
def probs(v,eps=1e-4):
v = v-v.min()+eps
v = v/v.sum()
return v
for epoch in range(10000):
obs = env.reset()
done = False
while not done:
s = discretize(obs)
if random.random()<epsilon:
v = probs(np.array(qvalues(s)))
a = random.choices(actions,weights=v)[0]
else:
a = np.random.randint(env.action_space.n)
obs, rew, done, info = env.step(a)
ns = discretize(obs)
Q[(s,a)] = Q.get((s,a),0) + alpha * (rew + gamma * max(qvalues(ns))-Q.get((s,a),0))
obs = env.reset()
done = False
image_append = []
while not done:
s = discretize(obs)
current_img = env.render(mode="rgb_array")
current_img = Image.fromarray(current_img)
image_append.append(current_img)
v = probs(np.array(qvalues(s)))
a = random.choices(actions,weights=v)[0]
obs,_,done,_ = env.step(a)
image_append[0].save('./out1.gif',save_all = True,append_images = image_append)
env.close()
4 总结
-
关于QLearning中的超参数设置有讲究。不同的超参数得到的实验结果相差很大,如果是做一个陌生的课题,调参是很有必要的。 -
QLearning算法,像这种环境简单,决策也简单的模型,尚可驾驭。但象棋,围棋甚至王者荣耀这种决策游戏,环境状态可以多到比天上的星星还多,恐怕计算机内存再大也无法存储下Q表。这时候神经网络就来了,这两者的结合就是天造地设。神经网络能够识别模式,也就是说环境状态虽然多,但只要让网络学习到了环境状态到决策的映射,我们无需维护Q表,使用网络直接就能生成Q值。 -
想了解更多?正在码字途中(手动狗头)。
5 附录
参考资料:
- https://mofanpy.com/tutorials/machine-learning/reinforcement-learning/intro-q-learning/
- https://github.com/microsoft/ML-For-Beginners/tree/main/8-Reinforcement/1-QLearning
|