基于RLLAB的强化学习 REINFORCE 算法解析

原文地址:https://rllab.readthedocs.io/en/latest/user/implement_algo_basic.html

本节,我们将学习一下经典 REINFORCE 算法的实现,这样被称为“基本”策略梯度方法。我们会从一个应用在固定策略和环境开始。下一节会实现进阶版本,使用框架提供的功能来让整个项目更加结构化并对命令行友好。

预备知识

首先,我们简要回顾一下算法和一些基本符号。我们采用定义为

,其中

是状态集合,

是行动集合,

是转移概率,

是奖励函数,

是折扣因子,而

是片段长度。REINFORCE 算法直接优化参数化的随机策略

,通过执行在期望奖励目标函数的梯度上升:

其中期望是隐式地覆盖所有可能的轨迹,按照采样过程

,而

。通过似然比例技巧,目标函数关于

的梯度如下式给出:

注意到对

我们可以降低估计量方差。

因此,

通常,我们使用下面的估计代替:

其中,

代替。我们将折扣因子看成是对无折扣目标函数的方差降低因子时,会得到更小偏差的梯度估计,会带来一定的方差增大。我们定义

为经验折扣奖励。

上面的公式是我们实现的核心。整个算法的伪代码如下:

  • 初始化参数为

的策略

.

  • 对迭代

:

  • 根据当前策略

采样

个轨迹

,其中

.注意到因为在观察到最后的状态时无行动了已经,所以最后的状态丢弃。

  • 计算经验策略梯度:
  • 进行一步梯度计算:

准备工作

作为开始,我们试着使用神经网络策略来解决 cartpole 平衡问题. 后面我们会推广算法来接受配置参数. 现在先看看最简单形式.

from __future__ import print_function
from rllab.envs.box2d.cartpole_env import CartpoleEnv
from rllab.policies.gaussian_mlp_policy import GaussianMLPPolicy
from rllab.envs.normalized_env import normalize
import numpy as np
import theano
import theano.tensor as TT
from lasagne.updates import adam
 
# normalize() makes sure that the actions for the environment lies
# within the range [-1, 1] (only works for environments with continuous actions)
env = normalize(CartpoleEnv())
# Initialize a neural network policy with a single hidden layer of 8 hidden units
policy = GaussianMLPPolicy(env.spec, hidden_sizes=(8,))
 
# We will collect 100 trajectories per iteration
N = 100
# Each trajectory will have at most 100 time steps
T = 100
# Number of iterations
n_itr = 100
# Set the discount factor for the problem
discount = 0.99
# Learning rate for the gradient update
learning_rate = 0.01

收集样本

现在,一次迭代中在我们当前的策略下收集样本.

paths = []
 
for _ in xrange(N):
observations = []
actions = []
rewards = []
 
observation = env.reset()
 
for _ in xrange(T):
# policy.get_action() returns a pair of values. The second one returns a dictionary, whose values contains
# sufficient statistics for the action distribution. It should at least contain entries that would be
# returned by calling policy.dist_info(), which is the non-symbolic analog of policy.dist_info_sym().
# Storing these statistics is useful, e.g., when forming importance sampling ratios. In our case it is
# not needed.
action, _ = policy.get_action(observation)
# Recall that the last entry of the tuple stores diagnostic information about the environment. In our
# case it is not needed.
next_observation, reward, terminal, _ = env.step(action)
observations.append(observation)
actions.append(action)
rewards.append(reward)
observation = next_observation
if terminal:
# Finish rollout if terminal state reached
break
 
# We need to compute the empirical return for each time step along the
# trajectory
returns = []
return_so_far = 0
for t in xrange(len(rewards) - 1, -1, -1):
return_so_far = rewards[t] + discount * return_so_far
returns.append(return_so_far)
# The returns are stored backwards in time, so we need to revert it
returns = returns[::-1]
 
paths.append(dict(
observations=np.array(observations),
actions=np.array(actions),
rewards=np.array(rewards),
returns=np.array(returns)
))

根据经验策略梯度的公式,我们可以将所有搜集来的数据合在一起,这样可以帮助我们向量化实现.

observations = np.concatenate([p["observations"] for p in paths])
actions = np.concatenate([p["actions"] for p in paths])
returns = np.concatenate([p["returns"] for p in paths])

构造计算图

我们使用 Theano 来实现,假设读者已经对其有了了解。如果没有,请参考some tutorials.

首先,我们构造输入数据的符号变量:

# Create a Theano variable for storing the observations
# We could have simply written `observations_var = TT.matrix('observations')` instead for this example. However,
# doing it in a slightly more abstract way allows us to delegate to the environment for handling the correct data
# type for the variable. For instance, for an environment with discrete observations, we might want to use integer
# types if the observations are represented as one-hot vectors.
observations_var = env.observation_space.new_tensor_variable(
'observations',
# It should have 1 extra dimension since we want to represent a list of observations
extra_dims=1
)
actions_var = env.action_space.new_tensor_variable(
'actions',
extra_dims=1
)
returns_var = TT.vector('returns')

注意到,我们可以将策略梯度公式变换如下:

其中

被称为 surrogate 函数. 因此,我们可以首先构造

的计算图,然后用其梯度获得经验策略梯度.

# policy.dist_info_sym returns a dictionary, whose values are symbolic expressions for quantities related to the
# distribution of the actions. For a Gaussian policy, it contains the mean and (log) standard deviation.
dist_info_vars = policy.dist_info_sym(observations_var, actions_var)
 
# policy.distribution returns a distribution object under rllab.distributions. It contains many utilities for computing
# distribution-related quantities, given the computed dist_info_vars. Below we use dist.log_likelihood_sym to compute
# the symbolic log-likelihood. For this example, the corresponding distribution is an instance of the class
# rllab.distributions.DiagonalGaussian
dist = policy.distribution
 
# Note that we negate the objective, since most optimizers assume a
# minimization problem
surr = - TT.mean(dist.log_likelihood_sym(actions_var, dist_info_vars) * returns_var)
 
# Get the list of trainable parameters.
params = policy.get_params(trainable=True)
grads = theano.grad(surr, params)

梯度更新和诊断

我们基本上完成了!现在,你可以使用自己喜欢的随机优化算法来执行参数的更新。我们使用 ADAM:

f_train = theano.function(
inputs=[observations_var, actions_var, returns_var],
outputs=None,
updates=adam(grads, params, learning_rate=learning_rate),
allow_input_downcast=True
)
f_train(observations, actions, returns)

因为算法是同策略的,我们可以通过查看收集的样本来评价其性能:

print('Average Return:', np.mean([sum(path["rewards"]) for path in paths]))

完整的代码参考 examples/vpg_1.py.

策略梯度的方差可以通过增加基准函数的方式进一步降低。重新定义的公式如下

由于

我们才能得到这个结果.

基准函数一般实现为

的估计。这里,

的估计. 该框架实现了一些类基准函数的不同选择。通过使用状态特征的线性基准函数在性能和准确度方面进行了较好的平衡,可在 rllab/baselines/linear_feature_baseline.py 中查看. 使用这个实现的相关的代码如下:

# ... initialization code ...
from rllab.baselines.linear_feature_baseline import LinearFeatureBaseline
baseline = LinearFeatureBaseline(env.spec)
# ... inside the loop for each episode, after the samples are collected
path = dict(observations=np.array(observations),actions=np.array(actions),rewards=np.array(rewards),)
path_baseline = baseline.predict(path)
advantages = []
returns = []
return_so_far = 0
for t in xrange(len(rewards) - 1, -1, -1):
return_so_far = rewards[t] + discount * return_so_far
returns.append(return_so_far)
advantage = return_so_far - path_baseline[t]
advantages.append(advantage)
# The advantages are stored backwards in time, so we need to revert it
advantages = np.array(advantages[::-1])
# And we need to do the same thing for the list of returns
returns = np.array(returns[::-1])

规范化回报

现在我们的学习率常会受到奖励的值范围的影响. 我们可以通过在计算梯度前进行白噪化 advantage 来降低这个依赖。用代码就是:

advantages = (advantages - np.mean(advantages)) / (np.std(advantages) + 1e-8)

训练基准函数

在每个迭代,我们使用最新获得的轨迹来训练基准函数:

baseline.fit(paths)

在计算基准函数之后执行本步骤的原因是在极端情形下,如果我们从每个状态仅仅有一个轨迹,并且基准函数能够完美地拟合数据,那么所有的advantages会变成 0,这样就没有梯度信号了。

现在,我们可以更快地训练策略(我们需要改变学习率因为重新规范化了). 完整的代码在examples/vpg_2.py 可得.

原文发布于微信公众号 - UAI人工智能(UniversityAI)

原文发表时间:2016-09-09

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏人工智能LeadAI

LSTM模型在问答系统中的应用

在问答系统的应用中,用户输入一个问题,系统需要根据问题去寻找最合适的答案。 1、采用句子相似度的方式。根据问题的字面相似度选择相似度最高的问题对应的答案,但是采...

4187
来自专栏MelonTeam专栏

机器学习入门系列01,Introduction

引用课程:http://speech.ee.ntu.edu.tw/~tlkagk/courses_ML16.html 先看这里,可能由于你正在查看这个平...

1878
来自专栏Coding迪斯尼

启动网络的自我训练流程,展示网络数字图片识别效果

954
来自专栏和蔼的张星的图像处理专栏

DSST详解

有一段时间没有看tracking了,前面一个月老师没有找,我也没有看文章,主要去看c++和cs231n去了。上周一老师找了我一次,于是赶紧把tracking又拾...

902
来自专栏专知

【干货】手把手教你Python实现自动贝叶斯调整超参数

【导读】机器学习中,调参是一项繁琐但至关重要的任务,因为它很大程度上影响了算法的性能。手动调参十分耗时,网格和随机搜索不需要人力,但需要很长的运行时间。因此,诞...

2045
来自专栏机器学习从入门到成神

交叉熵代价函数定义及其求导推导(读书笔记)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/sinat_35512245/articl...

1142
来自专栏量子位

刷剧不忘学习:用Faster R-CNN定位并识别辛普森一家中多个人物

王小新 编译自 Medium 量子位 出品 | 公众号 QbitAI Alexandre Attia是《辛普森一家》的狂热粉丝,在之前他已经写了一篇用卷积神经网...

34916
来自专栏marsggbo

论文笔记系列-Efficient Neural Architecture Search via Parameter Sharing

本文提出超越神经架构搜索(NAS)的高效神经架构搜索(ENAS),这是一种经济的自动化模型设计方法,通过强制所有子模型共享权重从而提升了NAS的效率,克服了NA...

891
来自专栏张耀琦的专栏

【机器学习入门系列】简介

本文深入浅出地介绍了什么是机器学习以及机器学习所研究的内容与机器学习的三大步骤;并举例深度学习、有监督学习、半监督学习、迁移学习、无监督学习、结构化学习、增强学...

1.2K0
来自专栏大数据文摘

利用 Scikit Learn的Python数据预处理实战指南

1735

扫码关注云+社区