TensorFlow强化学习入门(0)——Q-Learning的查找表实现和神经网络实现

我们将学习如何处理OpenAI FrozenLake问题,当然我们的问题不像图片中那样逼真

在我这系列的强化学习教程中,我们将探索强化学习大家族中的Q-Learning算法,它和我们后面的教程(1-3)中基于策略的算法有一些差异。在本节中,我们先放下复杂而笨重的深度神经网络,首先在一个简单的查找表基础上实现第一个算法版本,随后我们再考虑如何使用TensorFlow将神经网络的形式集成进来。考虑到该节主要是回顾基础知识,所以我把它归为第0部分。对Q-Learning中发生的细节有所了解对于我们后面学习将策略梯度(policy gradient)和Q-Learning结合来构建先进的RL agent大有裨益。(如果你对策略网络更感兴趣或者已经掌握了Q-Learning相关知识,可以等译者后面的翻译或者查阅原文

与利用函数直接将当前观测转化为行动的策略梯度方法不同,Q-Learning尝试学习给定状态下的对应值并据此在给定状态下作出特定的行动。尽管两者作出行动的手段不同,但是都可以达到在给定场合下作出智能的行动的效果。你之前可能听说过深度Q-网络已经可以玩雅达利游戏了。这其实只是我们下面讨论的Q-Learning算法的更大更复杂的实现而已。

查找表实现

# FrozenLake 问题的规则
SFFF       (S: 起始点, 安全)
FHFH       (F: 冰层, 安全)
FFFH       (H: 空洞, 跌落危险)
HFFG       (G: 目的地, 飞盘所在地)

本教程会基于OpenAI gym尝试解决上述的FrozenLake问题。OpenAI gym给定了描述这个简单游戏的数组,人们可以让agent基于此进行学习。FrozenLake问题发生在一个4*4的网格区域上,其中包括起始区,安全冰层区,危险空洞区和目标地点,,在任意的时刻agent可以上下左右移动,我们的目标是让agent在不跌落至空洞的前提下到达目的地。这里有一个特殊的问题就是偶尔会有一阵风吹过,使agent被吹到并非它选择的区域。因此在这个问题中每一时刻都作出最优解是不可能的,但是避开空洞抵达目的地还是可行的。只有到达目的地才可以得到1分,除此之外都是0分。由此我们需要一个基于长期过程后的奖惩进行学习的算法,这正是Q-Learning设计的目的。

在最简单的解法中,Q-Learning就是一个表格,包含了问题中所有可能发生情况,表格中的值表征着我们在当前情况下应当作出什么行动。在FrozenLake问题中,有16个状态(每一个表格单元对应一个情况),4个可选行动,这产生了一个16*4的Q值表格。我们首先将表格初始化为全0,当有行动得分之后我们据此对表格进行更新。

我们使用贝尔曼方程对Q值表进行更新,贝尔曼方程可以将一系列行动带来的奖励值分配至当前的行动上。在这个方法中,我们不断根据未来决策得到的奖励值来更新当前的表格! 其数学表达式可以写作:

Eq 1. Q(s,a) = r + γ(max(Q(s’,a’))

这个方程中,当前状态(s)和行动(a)对应的Q值等于当前的奖励值(r)加上折算系数乘上当前行动后的状态和下一步行动可能产生的最大Q值。这个可变的折算值可以控制可能的未来奖励值和当前奖励值相比下的重要程度。通过这种方法,表格开始缓慢逼近得到预期奖励值所需的当前各行动的精确度量值。下面给出FrozenLake问题中Q表算法的Python实现:

# Q-Table Learning
import gym
import numpy as np
# 加载实验环境
env = gym.make('FrozenLake-v0')

# 集成Q表学习算法
# 初始表(全0)
Q = np.zeros([env.observation_space.n,env.action_space.n])
# 设定超参数
lr = .8
y = .95
num_episodes = 2000
# 创建episodes中包含当前奖励值和步骤的列表
rList = []
for i in range(num_episodes):
    # 初始化环境,得到第一个状态观测值
    s = env.reset()
    rAll = 0
    d = False
    j = 0
    # Q表学习算法
    while j < 99:
        j += 1
        # 根据Q表和贪心算法(含噪)选定当前的动作
        a = np.argmax(Q[s,:] + np.random.randn(1, env.action_space.n) * (1./(i+1)))
        # 获取新的状态值和奖励值
        s1, r, d, _ = env.step(a)
        # 更新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
    rList.append(rAll)

print("Score over time: " +  str(sum(rList)/num_episodes))
print("Final Q-Table Values")
print(Q)

神经网络实现

在完成上面的例子的过程中,你可能已经意识到这一点:用表格的方式来实现固然不错,但是弹性太差了。上述的简单问题使用表格实现是很简单,但是有可能问题中的状态(s)和行动(a)会多到无法用表格来存储。不幸的是,大部分我们感兴趣的问题中可能的状态数和行动数都很多,无法使用上面的表格解法。这迫使我们寻找一种新的方式来描述状态,不再依赖Q表来决定下一步的行动:这正是神经网络擅长的地方。通过函数逼近的方法,我们可以将任意的状态表示为矢量形式并通过映射得到Q值。

在FrozenLake的例子中,我们使用单层网络来接受虚拟编码(One-hot encoding)后的当前状态(1x16),输出为包含4个Q值的矢量,每个Q值对应一个方向。这样一个简单的网络就可以充当上面的奖励值表格,网络中的权重值取代了之前的表格单元。更关键的一点是我们可以尝试增加层数,激活函数和不同的输入类型,这些在常规的表格中都是不可能实现的。除此之外,神经网络的更新方法也更胜一筹,和表格中直接更新值的做法不同,神经网络通过损失函数和反向传播的结合来实现权重更新。我们选取目标Q值和当前Q值差的平方和作为损失函数,“目标”值在计算之后其梯度会反馈于网络上。在理想的情况下,每一步之后的Q值应当都是不变的(当然如果一步一刮风的情况就不一定了~)

Eq2. Loss = ∑(Q-target - Q)²

下面给出我们的简易Q网络的TensorFlow集成:

import gym
import numpy as np
import random
import tensorflow as tf
import matplotlib.pyplot as plt
%matplotlib inline

# 加载实验环境
env = gym.make('FrozenLake-v0')
# Q网络解法
tf.reset_default_graph()
# 建立用于选择行为的网络的前向传播部分
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)
# 计算预期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)
# 训练网络
init = tf.initialize_all_variables()
# 设置超参数
y = .99
e = 0.1
num_episodes = 2000 # 为了快速设置为2000,实验调为20000时可以达到0.6的成功率
# 创建episodes中包含当前奖励值和步骤的列表
jList = []
rList = []
with tf.Session() as sess:
    sess.run(init)
    for i in range(num_episodes):
        # 初始化环境,得到第一个状态观测值
        s = env.reset()
        rAll = 0
        d = False
        j = 0
        # Q网络
        while j < 99:
            j += 1
            # 根据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()
            # 获取新的状态值和奖励值
            s1, r, d, _ = env.step(a[0])
            # 通过将新的状态值传入网络获取Q'值
            Q1 = sess.run(Qout, feed_dict={inputs1:np.identity(16)[s1:s1+1]})
            # 获取最大的Q值并选定我们的动作
            maxQ1 = np.max(Q1)
            targetQ = allQ
            targetQ[0, a[0]] = r + y*maxQ1
            # 用目标Q值和预测Q值训练网络
            _, W1 = sess.run([updateModel, W], feed_dict={inputs1:np.identity(16)[s:s+1], nextQ:targetQ})
            rAll += r
            s = s1
            if d == True:
                # 随着训练的进行不断减小随机行动的可能性
                e = 1./((i/50) + 10)
                break
        jList.append(j)
        rList.append(rAll)
print("Percent of succesful episodes: " + str(sum(rList)/num_episodes))
# 网络性能统计
plt.plot(rList)
plt.plot(jList)

虽然这个网络可以解决FrozenLake的问题,但是效率远远不及Q表。在Q-Learning中神经网络解法的灵活性是以牺牲稳定性的代价换来的。在我们上面简单的网络的基础上,我们有很多可供选择的扩展来提供更好的性能和更健壮的学习。这里特别强调两个方法:历程重现(Experience Replay)和目标网络冻结(Freezing Target Networks),这些调整和提升是深度Q网络能够玩转雅达利游戏的关键,这些部分我们在后面会一一提及。如果想进一步了解Q-Learning背后的理论基础,可以参考Tambet Matiisen的这篇文章。希望这篇文章可以帮助到对Q-Learning算法感兴趣的同学:)

译者计划翻译的系列文章:

  1. (0)Q-Learning的查找表实现和神经网络实现
  2. (1) 双臂赌博机
  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)

原文链接:https://medium.com/emergent-future/simple-reinforcement-learning-with-tensorflow-part-0-q-learning-with-tables-and-neural-networks-d195264329d0

原文作者:Arthur Juliani

编辑于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏从流域到海域

应用自然语言处理(NLP)解码电影

原文地址:https://dzone.com/articles/applying-nlp-to-decode-an-indian-classical-movie...

26480
来自专栏机器学习算法工程师

机器学习论文笔记—如何利用高效的搜索算法来搜索网络的拓扑结构

分层表示高效的架构搜索(HIERARCHICAL REPRESENTATIONS FOR EFFICIENT ARCHITECTURE SEARCH)这篇文章讲...

18420
来自专栏AI科技评论

开发 | TOP5%Kaggler:如何在 Kaggle 首战中进入前 10%

Introduction Kaggle 是目前最大的 Data Scientist 聚集地。很多公司会拿出自家的数据并提供奖金,在 Kaggle 上组织数据竞赛...

59080
来自专栏智能算法

10 种机器学习算法的要点(附 Python 和 R 代码)

本文由 伯乐在线 - Agatha 翻译,唐尤华 校稿。 英文出处:SUNIL RAY。欢迎加入翻译组。 前言 谷歌董事长施密特曾说过:虽然谷歌的无人驾驶汽车和...

46550
来自专栏AI研习社

利用摇滚乐队学习TensorFlow,Word2Vec模型和TSNE算法

学习“TensorFlow方式”来构建神经网络似乎是开始机器学习的一大障碍。在本教程中,我们将一步一步地介绍使用Kaggle的Pitchfork数据构建Band...

17820
来自专栏人工智能

长时间序贯任务结构的演示学习方法及其在手术机器人中的应用

本文总结了最近三篇论文的结果,这些论文提出了一些可以将更长的任务分解成更短子任务的学习算法。

366100
来自专栏AI研习社

TOP 5% Kaggler:如何在 Kaggle 首战中进入前 10% | 干货

编者按:本文作者章凌豪,复旦大学计算机科学专业。有兴趣的同学可以移步他的个人主页:https://dnc1994.com/Introduction(点击文末“阅...

39560
来自专栏人工智能

词向量fasttext,CNN is All,强化学习,自回归生成模型,可视化神经网络损失函数

【导读】专知内容组整理出最近arXiv放出的五篇论文,包括《Tomas Mikolov新作词向量表示,CNN Is All You Need,强化学习库, 自回...

29050
来自专栏专知

【2017年末AI最新论文精选】词向量fasttext,CNN is All,强化学习,自回归生成模型, 可视化神经网络损失函数

【导读】专知内容组整理出最近arXiv放出的五篇论文,包括《Tomas Mikolov新作词向量表示,CNN Is All You Need,强化学习库, 自回...

37660
来自专栏大数据智能实战

python3 下 tensorflow slim inceptionV4 问题修正与测试

自从残差网络出来之后,好多人就想着能不能对模型进行结合测试一下。Google Research的Inception模型和Microsoft Research的...

29760

扫码关注云+社区

领取腾讯云代金券