编者按:环信开源国内首本免费深度学习理论和实战专著《深度学习理论与实战:提高篇 》,内容涵盖听觉,视觉,语言和强化学习,七百多页详尽的理论和代码分析。本文节选自《深度学习理论与实战:提高篇 》一书,原文链接http://fancyerii.github.io/2019/03/14/dl-book/ 。作者李理,环信人工智能研发中心vp,有十多年自然语言处理和人工智能研发经验,主持研发过多款智能硬件的问答和对话系统,负责环信中文语义分析开放平台和环信智能机器人的设计与研发。

深度学习.jpg

我们再来看一下Bellman公式,它是递归定义的——vπ(s)是由vπ(s)来定义的,对于有些简单问题,我们可以根据这个公式把vπ通过解方程解出来。

我们结合上图来分析上面公式的。当前状态是s,根据策略π,我们采取行为a的概率是π(a|s),而我们在状态a和行为s的条件下,环境反馈r和s’的概率是p(r,s|s,a),所有可能的(a,r,s’)组合我们都要求和,所以就得到aπ(a|s)s,rp(s,r|s,a),在每一条路径(每一种s,r,s’的组合)下Rt+1就是r,因此可以得到aπ(a|s)s,rp(s,r|s,a)[r]。而在给定路径的情况下,s,r,s都固定了,因此s’也是固定的了,而根据马尔科夫属性,Gt+1只与t+1时刻的状态St+1=s有关,因此第二项变成了aπ(a|s)s,rp(s,r|s,a)[γE[Gt+1|St+1=s]

最优价值函数(Optimal Value Functions)

解决强化学习任务,粗略来说,就是找到一个策略,使得长期的reward尽可能多。首先我们定义什么是一个策略π比另外一个策略π好(或者一样好),记作ππ。形式化的定义是ππsS,vπ(s)vπ(s)。 可以证明(这里略过)存在一个(可能有多个)最优的π,它比所有其它策略都“好”。最优策略对于的价值函数叫做最优价值函数,记作v(s)

v(s)=maxπvπ(s),sS

同理对于行为也有一个最优的行为价值函数:

q(s,a)=maxπqπ(s,a),sS,aA(s)

q(s,a)v(s)有如下关系:

q(s,a)=E[Rt+1+γv(St+1)|St=s,At=a]

我们可以这样解读这个公式:s和a确定后,它会进入St+1状态并得到Reward Rt+1,这是过程是有概率的,因此前面有一个期望E。但是这和Agent无关,和Agent有关的是在t+1时刻的行为,如果要得到最优的q(s,a),那么它必须在t+1时刻根据最优策略π来计算v(St+1),因此就是v(St+1)

需要注意:上面公式的随机变量只是Rt+1St+1,它由环境p(r,s|s,a)确定,而v(s)q(s,a)是两个常量(给定s,a的情况下)。

OpenAI Gym简介

OpenAI Gym是一个用来开发和比较强化学习算法的工具。它对Agent的实现没有任何约束,因此你可以用TensorFlow或者其它任何工具来实现Agent。它提供统一的Environment的接口,你可以用这个接口来定义一个具体的强化学习任务,此外它也提供很多常见的任务,比如很多Atari的游戏。

运行Environment

首先我们介绍一个很简单的游戏CartPole-v0,如下图所示。

QQ截图20190326151628.png

 图:CartPole-v0运行时的截图

这个游戏有一个小车,可以对车子施加+1或者-1的力(加速度),车上有一个杆子,我们的目标是要求车子的位置在-2.4到2.4之间,并且杆子相对于垂直的角度在-15°和15°之间。如果从物理的角度来分析,它有4个状态变量,车子的位置,车子的速度,杆的角度,杆的角速度。而我们施加的力会改变车子的速度,从而间接改变车子的位置。我们可以用几行代码运行CartPole-v0这个游戏:

import gym
env = gym.make('CartPole-v0')
env.reset()
for _ in range(1000):
    env.render()
    env.step(env.action_space.sample()) # take a random action

代码很简单,首先创建一个CartPole-v0 Environment对象env,重置(reset)使环境进入初始状态。接着循环1000次,每次首先把当前的游戏状态绘制出来(render),然后随机的选择一个Action env.action_space.sample(),接着调用env.step函数真正的“执行”这个Action。

观察(Observations)

观察就是MDP里的状态(State),Environment的step有4个返回值:

  1. observation  一个对象,代表观察,不同的环境返回的对象是不同的。

  2. reward float类型 表示Reward。

  3. done bool类型  表示任务是否结束。对于Episode类任务会有结束状态,进入结束状态后再调用step是没有意义的,必须要先调用reset

  4. info  调试用的一些信息

我们可以用如下代码打印出其中的一些信息:

import gym
env = gym.make('CartPole-v0')
for i_episode in range(20):
    observation = env.reset()
    for t in range(100):
        env.render()
        print(observation)
        action = env.action_space.sample()
        observation, reward, done, info = env.step(action)
        if done:
            print("Episode finished after {} timesteps".format(t+1))
            break

Spaces

Environment对象里有两个空间(Space):状态空间(State Space)和行为空间(Action Space),它们定义了所有可能的状态和行为。我们可以查看一些CartPole-v0的Space:

import gym
env = gym.make('CartPole-v0')
print(env.action_space)
#> Discrete(2)
print(env.observation_space)
#> Box(4,)

从输出可以看出,Discrete(2)表示这个任务有两个选的Action(分布表示向左和向右移动),Box(4,)表示状态由4维向量表示,物理意义分别是车子相对原点的位置和速度,杆相对于垂直方向的角度和角速度。我们可以用如下的代码检查其取值范围:

print(env.observation_space.high)
#> array([ 2.4       ,         inf,  0.20943951,         inf])
print(env.observation_space.low)
#> array([-2.4       ,        -inf, -0.20943951,        -inf])