本文是对Arthur Juliani在Medium平台发布的强化学习系列教程的个人中文翻译。(This article is my personal translation for the tutorial written and posted by Arthur Juliani on Medium.com。)

原文地址(URL for original article):https://medium.com/emergent-future/simple-reinforcement-learning-with-tensorflow-part-0-q-learning-with-tables-and-neural-networks-d195264329d0


我们将学习如何解决OpenAI的冰湖(FrozenLake)问题。不过我们的冰湖版本和上图呈现的图片可不太一样~

作为本强化学习教程系列的第一章,我们将一同探索强化学习算法的一个大家庭———Q-Learning算法—。它们和后面章节基于策略的算法(Policy-based algorithms)(1-3 part)有些不一样。相对于用一个复杂而臃肿的深度神经网络,我们将以实现一个简单的查阅表(lookup-table)版本的算法为初始目标,然后再展示如何用Tensorflow框架来实现一个等价的神经网络版本的算法。考虑到我们将回归基础知识,所以本教程可以视作系列教程的第0部分。希望本教程能够帮助你理解Q-Learning的工作原理,基于此,我们将最终结合策略梯度(Policy Gradient)和Q-Learning来构造最先进的强化学习代理(Agents)。(如果你对策略网络(Policy Networks)更感兴趣,或者早就掌握了Q-Learning,你可以直接从这里开始。)

不像策略梯度方法那样试图学习到可以将一个观察(Observation)与一个动作(action)直接映射的函数,Q-Learning会尝试去学习给定一个状态(State)下,采取某个具体动作的值。虽然这两种方式最终都可以实现在给定情况下的智能行为决策,但是如何最终完成行为选择的过程是非常不一样的。你可能听说过可以玩Atari游戏的深度Q网络(Deep Q-Networs),而它其实本质上也就是更复杂的Q-Learning算法的实现。

表环境下的表方法(Tabular Approaches for Tabular Environments)

冰湖环境的规则:

在这个教程里,我们将试图解决OpenAI的gym项目中包含的冰湖FrozenLake问题。对于不熟悉gym项目的人来说,OpenAI gym提供了一种能方便简易地在一系列游戏中,对学习代理(learning agents)进行各类实验或测试的方式。而其中之一的冰湖环境是一个4*4的网格。格子包含三种类型:起始格,目标格,安全的冰格和危险的冰洞。我们的目标是让一个agent能够自己从起点到终点,并且不会在中途掉入洞中。在任何时候,agent都可以选择从上,下,左,右四个中选择一个方向进行一步移动。而后会使问题变复杂的是,在冰湖环境中,还有会偶尔把agent吹得偏离到一个并非它移动目标的格子上。因此,在这种环境下agent就不太可能每次都能表现完美,但是学习如何去避免掉入洞中并达到目标格还是可以做到的。agent每走一步的回报(reward)都是0,除了在达到目标时为1。因此,我们需要一个算法可以学习到长期期望回报。这也就是Q-Learning发挥用处的地方。

在这个算法最简单的实现中,Q-Learning会以一个表(table)的形式呈现。这个表的行代表不同的状态(所在方格的坐标),列代表不同的可采取的行动(上、下、左、右移动一步)。在冰湖环境中,我们有16个状态(每个方格算一个),以及四种动作,因此我们将得到一个16*4的Q值表,这个表的每一个具体值的含义是:该状态下,采取该行为的长期期望回报。我们从初始化一个一致的Q值表(全部赋值为0)开始,再根据我们观察得到的对各种行动的回报来更新Q值表的对应值。

我们对Q值表的更新准则是贝尔曼方程(Bellman Equation)。贝尔曼方程告诉我们:一个给定行动的期望长期回报等于【当前回报】加上【下一个状态下,采取期望中所能带来最优未来长期回报的行为对应的回报】。因此,我们可以在Q表上估计如何对未来行动的Q值进行更新。贝尔曼方程用数学公式表示如下:

Q(s,a)=r+γ(max(Q(s′,a′))

这个公式的描述了一个给定状态s下,采取行动a的Q值等于当即获得的回报r加上一个折现因子y乘以能够最大化的在下一状态s’采取时能获得的最大长期回报的动作a’对应的长期回报。折现因子y允许我们决定相对于当前就可以获得的回报,未来的可能回报的相对重要性。通过这种方式,Q表会慢慢开始获得更准确的任一给定状态下,采取任意动作所对应的期望未来回报值。以下是Python版的对于Q表版本的冰湖环境解决方案的完整实现:

import gym
import numpy as np env = gym.make('FrozenLake-v0') # Implement Q-Table learning algorithm
# 实现Q表学习算法
# Initialize table with all zeros
# 初始化Q表为全0值
Q = np.zeros([env.observation_space.n,env.action_space.n])
# Set learning parameters
# 设置学习参数
lr = .8
y = .95
num_episodes = 2000
# create lists to contain total rewards and steps per episode
# 创建列表以包含每个episode的总回报与总步数
#jList = []
rList = []
for i in range(num_episodes):
# Reset environment and get first new observation
# 初始化环境并获得第一个观察
s = env.reset()
rAll = 0
d = False
j = 0
# The Q-Table learning algorithm
# Q表学习算法
while j < 99:
j+=1
# Choose an action by greedily (with noise) picking from Q table
# 基于Q表贪婪地选择一个最优行动(有噪音干扰)
a = np.argmax(Q[s,:] + np.random.randn(1,env.action_space.n)*(1./(i+1)))
# Get new state and reward from environment
# 从环境中获得回报和新的状态信息
s1,r,d,_ = env.step(a) #Update Q-Table with new knowledge
# 用新的知识更新Q表
Q[s,a] = Q[s,a] + lr*(r + y*np.max(Q[s1,:]) - Q[s,a])
rAll += r
s = s1
if d == True:
break
#jList.append(j)
rList.append(rAll) print("Score over time: " + str(sum(rList)/num_episodes)) print("Final Q-Table Values")
print(Q)

Github源代码

(感谢Praneet D找到了该实现方法对应的最优的超参数)

基于神经网络的Q-Learning(Q-Learning with Neural Networks)

现在你可能认为:表格方法挺好的,但是它不能规模化(scale),不是吗?因为对一个简单的网格世界建立一个16*4的表是很容易的,但是在任何一个现在的游戏或真实世界环境中都有无数可能的状态。对于大多数有趣的问题,表格都无法发挥出作用。因此,我们需要一些代替性的方案来描述我们的状态,并生成对应动作的Q值:这也就是神经网络(Neural Network,简称NN)可以大展身手的地方。NN可以作为一个动作估计器(function approximator),我们能够输入任意多的可能状态,因为所有状态都可以被编码成一个个向量,并把它们和各自对应的Q值进行对应(map)。

在冰湖例子中,我们将使用一个一层的NN,它接受以one-hot形式编码的状态向量(1*16),并输出一个含有4个Q值的向量,每个分量对应一个动作的长期期望回报。这样一个简单的NN就像一个强化版的Q表,而网络的权重就发挥着曾经的Q表中的各个单元格的作用。关键的不同时我们可以方便简易地扩充Tensorflow网络,包括加新的层,激活函数以及不同的输出类型,而这些都是一个一般的表格无法做到的。于是,更新的方法也发生了一点变化。相比于之前直接更新表格,我们现在将使用逆传播(backpropagation)和损失函数(loss function)**来完成更新。我们的损失函数采取平方和损失的形式,即加总当前预测的Q值与目标值间的差值的平方,并以梯度形式在网络中传播。这种情况下,所选行动的目标Q值依然采用上面提到的贝尔曼方程中的计算方法。

Loss=Σ(Q−target−Q)2

以下是用Tensorflow实现简单Q网络的完整代码:

# Q-Network Learning
# Q网络学习 import gym
import numpy as np
import random
import tensorflow as tf
import matplotlib.pyplot as plt
%matplotlib inline # Load the environment
# 加载环境 env = gym.make('FrozenLake-v0') # The Q-Network Approach
# Q网络方法
# Implementing the network itself
# 实现网络 tf.reset_default_graph() # These lines establish the feed-forward part of the network used to choose actions
# 下面的几行代码建立了网络的前馈部分,它将用于选择行动
inputs1 = tf.placeholder(shape=[1,16],dtype=tf.float32)
W = tf.Variable(tf.random_uniform([16,4],0,0.01))
Qout = tf.matmul(inputs1,W)
predict = tf.argmax(Qout,1) # Below we obtain the loss by taking the sum of squares difference between the target and prediction Q values.
# 下面的几行代码可以获得预测Q值与目标Q值间差值的平方和加总的损失。
nextQ = tf.placeholder(shape=[1,4],dtype=tf.float32)
loss = tf.reduce_sum(tf.square(nextQ - Qout))
trainer = tf.train.GradientDescentOptimizer(learning_rate=0.1)
updateModel = trainer.minimize(loss) # Training the network
# 训练网络
init = tf.initialize_all_variables() # Set learning parameters
# 设置学习参数
y = .99
e = 0.1
num_episodes = 2000
#create lists to contain total rewards and steps per episode
# 创建列表以包含每个episode对应的总回报与总步数。
jList = []
rList = []
with tf.Session() as sess:
sess.run(init)
for i in range(num_episodes):
# Reset environment and get first new observation
# 初始化环境并获得第一个观察
s = env.reset()
rAll = 0
d = False
j = 0
# The Q-Network
# Q网络
while j < 99:
j+=1
#Choose an action by greedily (with e chance of random action) from the Q-network
# 基于Q网络的输出结果,贪婪地选择一个行动(有一定的概率选择随机行动)
a,allQ = sess.run([predict,Qout],feed_dict={inputs1:np.identity(16)[s:s+1]})
if np.random.rand(1) < e:
a[0] = env.action_space.sample()
# Get new state and reward from environment
# 从环境中获得回报以及新的状态信息
s1,r,d,_ = env.step(a[0])
# Obtain the Q' values by feeding the new state through our network
# 通过将新的状态向量输入到网络中获得Q值。
Q1 = sess.run(Qout,feed_dict={inputs1:np.identity(16)[s1:s1+1]})
# Obtain maxQ' and set our target value for chosen action.
# 获得最大的Q值,并为所选行为设定目标值
maxQ1 = np.max(Q1)
targetQ = allQ
targetQ[0,a[0]] = r + y*maxQ1
# Train our network using target and predicted Q values
# 用目标和预测的Q值训练网络
_,W1 = sess.run([updateModel,W],feed_dict={inputs1:np.identity(16)[s:s+1],nextQ:targetQ})
rAll += r
s = s1
if d == True:
# Reduce chance of random action as we train the model.
# 随着训练的进行,主键减少选择随机行为的概率
e = 1./((i/50) + 10)
break
jList.append(j)
rList.append(rAll)
print("Percent of succesful episodes: " + str(sum(rList)/num_episodes) + "%") # Percent of succesful episodes: 0.352%
# 成功的episode比例:0.352%
# Some statistics on network performance
# 一些网络性能的统计量
# We can see that the network beings to consistently reach the goal around the 750 episode mark.
# 我们可以看到,当网络训练了750个episode左右的时候,agent就可以比较稳定地到达目标了。 plt.plot(rList)

# It also begins to progress through the environment for longer than chance aroudn the 750 mark as well.
# 在750个episode之后,agent也一般需要更长的步数以到达目标。 plt.plot(jList)

虽然网络学会了解决冰湖问题,但是结果表明它似乎比如Q表方法那么高效。即虽然神经网络在Q-Learning问题上提供了更高的灵活性,但它也牺牲了一定的稳定性。还有很多可能的对我们的简单Q网络进行扩展的办法,这些扩展可以让NN获得更好的性能并实现更稳定的学习过程。两种需要提到的特别技巧分别是经验重放(Experience Replay)冰冻目标网络(Freezing Target Networks)。这些改进方式或者其它的一些技巧都是让DQN可以玩Atari游戏的关键所在,并且我们也将在后面探索这些相关知识。对于有关Q-Learning的更多理论,可以看Tambet Matiisen的这篇博文,希望本教程可以帮助对实现简单Q-Learning算法的人们一些帮助!


如果这篇博文对你有帮助,你可以考虑捐赠以支持未来更多的相关的教程、文章和实现。对任意的帮助与贡献都表示非常感激!

如果你想跟进我在深度学习、人工智能、感知科学方面的工作,可以在Medium上follow我 @Arthur Juliani,或者推特@awjliani。

用Tensorflow实现简单强化学习的系列教程:

  1. Part 0 — Q-Learning Agents
  2. Part 1 — Two-Armed Bandit
  3. Part 1.5 — Contextual Bandits
  4. Part 2 — Policy-Based Agents
  5. Part 3 — Model-Based RL
  6. Part 4 — Deep Q-Networks and Beyond
  7. Part 5 — Visualizing an Agent’s Thoughts and Actions
  8. Part 6 — Partial Observability and Deep Recurrent Q-Networks
  9. Part 7 — Action-Selection Strategies for Exploration
  10. Part 8 — Asynchronous Actor-Critic Agents (A3C)

强化学习之二:Q-Learning原理及表与神经网络的实现(Q-Learning with Tables and Neural Networks)的更多相关文章

  1. 强化学习(十二) Dueling DQN

    在强化学习(十一) Prioritized Replay DQN中,我们讨论了对DQN的经验回放池按权重采样来优化DQN算法的方法,本文讨论另一种优化方法,Dueling DQN.本章内容主要参考了I ...

  2. 强化学习(二)马尔科夫决策过程(MDP)

    在强化学习(一)模型基础中,我们讲到了强化学习模型的8个基本要素.但是仅凭这些要素还是无法使用强化学习来帮助我们解决问题的, 在讲到模型训练前,模型的简化也很重要,这一篇主要就是讲如何利用马尔科夫决策 ...

  3. 【转载】 强化学习(二)马尔科夫决策过程(MDP)

    原文地址: https://www.cnblogs.com/pinard/p/9426283.html ------------------------------------------------ ...

  4. MySQL学习(二)索引原理及其背后的数据结构

    首先区分几个概念: 聚集索引 主索引和辅助索引(即二级索引) innodb中每个表都有一个聚簇索引(clustered index ),除此之外的表上的每个非聚簇索引都是二级索引,又叫辅助索引(sec ...

  5. HTTPS学习(二):原理与实践

    div.example { background-color: rgba(229, 236, 243, 1); color: rgba(0, 0, 0, 1); padding: 0.5em; mar ...

  6. Neural Network学习(二)Universal approximator :前向神经网络

    1. 概述 前面我们已经介绍了最早的神经网络:感知机.感知机一个非常致命的缺点是由于它的线性结构,其只能做线性预测(甚至无法解决回归问题),这也是其在当时广为诟病的一个点. 虽然感知机无法解决非线性问 ...

  7. 鸟书shell 学习笔记(二) shell中正則表達式相关

    通配符与正則表達式的差别 通配符是bash原生支持的语法,正則表達式是处理字符串的一种表示方式, 正則表達式须要支持的工具支持才干够 语系设置 : export LANG=C grep alias 设 ...

  8. 吴恩达《深度学习》-第五门课 序列模型(Sequence Models)-第一周 循环序列模型(Recurrent Neural Networks) -课程笔记

    第一周 循环序列模型(Recurrent Neural Networks) 1.1 为什么选择序列模型?(Why Sequence Models?) 1.2 数学符号(Notation) 这个输入数据 ...

  9. 用深度强化学习玩FlappyBird

    摘要:学习玩游戏一直是当今AI研究的热门话题之一.使用博弈论/搜索算法来解决这些问题需要特别地进行周密的特性定义,使得其扩展性不强.使用深度学习算法训练的卷积神经网络模型(CNN)自提出以来在图像处理 ...

随机推荐

  1. 前端JS题

    题目如下: function Foo() { getName = function () { alert (1); }; return this; } Foo.getName = function ( ...

  2. 基于abp框架的数据库种子数据初始化

    目录 基于abp框架的数据库种子数据初始化 1.背景 2.参照 3.解决方案 3.1 初始化数据 3.2 依赖注入方法容器里获取数据库上下文 3.3 封装创建初始化数据列表方法 3.4 数据库中没有的 ...

  3. Ubuntu 18.04安装搜狗输入法

    Ubuntu 18.04安装搜狗输入法 打开 terminal,输入 fcitx,检查是否安装搜狗输入法依赖,若提示未安装使用以下命令安装 sudo apt-get install fcitx-bin ...

  4. 组件化思路:以selection为例子,使用prop-types实现组件化控制,重用

    需求 书接上文,UI 积累之select section 这里又来两个需求了. 当我点击选择了option后,我应该看到的是我选择的option的内容 多例重用,即同样是个selection,我只是需 ...

  5. Android html5 控制video currentTime不准确,精确,解决办法。

    早在flash时代 我们控制视频播放指定时间位置的画面也会有不准确的情况, 具体情况表现为:video.seek(time)   而实际画面会跳到此时间附近(1-2秒)的画面 而HTML5 我们通过 ...

  6. 【渗透】node.js经典问题

    1.循环问题 当循环调用 require() 时,一个模块可能在未完成执行时被返回.例如以下情况:a.js: exports.done = false; const b = require('./b. ...

  7. java调用DLL,打印二维码标签

    package com.ian.das.controller; import java.util.List; import org.xvolks.jnative.JNative; import org ...

  8. ASP.NET Core 快速入门(Razor Pages + Entity Framework Core)

    引子 自从 2009 年开始在博客园写文章,这是目前我写的最长的一篇文章了. 前前后后,我总共花了 5 天的时间,每天超过 3 小时不间断写作和代码调试.总共有 8 篇文章,每篇 5~6 个小结,总截 ...

  9. Flutter json 2 model with Built Value

    Flutter json 2 model with Built Value Flutter中json转换model, 除了手动转之外, 就是利用第三方库做一些代码生成. 流行的库有: json_ser ...

  10. C++ 读取配置文件结束指定进程

    #define _CRT_SECURE_NO_WARNINGS #include <string> #include <windows.h> #include <stdi ...