强化学习是指agent通过与动态环境的反复试验交互来学习最佳行为的问题。强化学习的所有算法都有一个共同的特性,即agent的反馈被限制为一个奖励信号,该信号表明agent的行为有多好。与有监督的机器学习方法相比,任何关于如何改善其行为的指导都是不存在的。因此,强化学习的目标和挑战是改善只给予这种有限类型反馈的智能体的行为。
Installation
使用devtools包,你可以轻松安装ReinforcementLearning的最新开发版本,如下所示。
# install.packages("devtools")
# Option 1: download and install latest version from GitHub
devtools::install_github("nproellochs/ReinforcementLearning")
## Skipping install of 'ReinforcementLearning' from a github remote, the SHA1 (b14091a5) has not changed since last install.
## Use `force = TRUE` to force installation
# Option 2: install directly from bundled archive
##devtoos::install_local("ReinforcementLearning_1.0.0.tar.gz")
Package loading
之后,你只需要加载如下的强化学习包。
library(ReinforcementLearning)
Data preparation
强化学习包利用不同的强化学习机制,包括q -学习和经验重放。因此,它根据过去的经验,以由状态、行动和奖励组成的样本序列的形式学习最优策略。因此,每个训练示例由一个状态转换元组(si,ai,ri+1,si+1)组成,如下所示:
—si为当前环境状态。 - ai表示当前状态下选择的动作。 - ri+1指定从当前状态转换到下一个状态后收到的即时奖励。 - si+1为下一个环境状态。
强化学习的训练示例可以(1)从外部源收集并插入到表格数据结构中,或者(2)通过查询定义环境行为的函数动态生成。在这两种情况下,相应的输入必须遵循相同的元组结构(si,ai,ri+1,si+1)。我们将在下面详细介绍这两种变体。
Learning from pre-defined observations
当输入数据是预先确定的,或者需要训练复制过去行为的代理时,这种方法是有益的。在这种情况下,只需要将包含过去观察结果的表格数据结构插入到包中。当从外部源(如传感器数据)收集了状态转换元组,并且希望通过消除与环境的进一步交互来了解代理时,可能会出现这种情况。
下面的例子展示了一个包含随机抽样的一字棋游戏状态的代表性数据集的前5个观察结果。在这个数据集中,第一列包含匹配中当前板状态的表示。第二列表示玩家X在这种状态下观察到的动作,而第三列则表示执行该动作后产生的棋盘状态。第四列指定了玩家x的结果奖励。这个数据集足以作为学习agent的输入。
data("tictactoe")
head(tictactoe, 5)
## State Action NextState Reward
## 1 ......... c7 ......X.B 0
## 2 ......X.B c6 ...B.XX.B 0
## 3 ...B.XX.B c2 .XBB.XX.B 0
## 4 .XBB.XX.B c8 .XBBBXXXB 0
## 5 .XBBBXXXB c1 XXBBBXXXB 0
Dynamic learning from an interactive environment function
另一种策略是定义一个函数来模仿环境的行为。然后,我们可以学习从这个函数中抽取经验样本的代理。这里,环境函数接受状态-操作对作为输入。然后,它返回一个列表,其中包含下一个状态的名称和奖励。在这种情况下,还可以利用R访问外部数据源,比如传感器,并通过公共接口执行操作。这样一个函数的结构由以下伪代码表示:
environment <- function(state, action) {
...
return(list("NextState" = newState,
"Reward" = reward))
}
在指定了环境函数之后,我们可以使用它来收集随机序列。因此,输入指定了样本个数(N)、环境函数、状态集(即S)和动作集(即A)。然后,返回值是一个包含i=1,…,N的经历状态转换元组(si,ai,ri+1,si+1)的数据帧。下面的代码片段展示了如何从示例化的环境函数生成经验。
# Define state and action sets
states <- c("s1", "s2", "s3", "s4")
actions <- c("up", "down", "left", "right")
env <- gridworldEnvironment
# Sample N = 1000 random sequences from the environment
data <- sampleExperience(N = 1000,
env = env,
states = states,
actions = actions)
Learning phase
General setup
例程强化学习()捆绑了主要的功能,该功能使用先前的输入数据教强化学习代理。为此,它需要以下参数:(1)数据参数必须是一个数据帧对象,其中每一行表示一个状态转换元组(si,ai,ri+1,si+1)。(2)要求用户指定data中各个元组元素的列名。
下面的伪代码演示了来自外部源的预定义数据的用法,而后面的部分详细介绍了交互式设置。这里的参数s、a、r和s_new包含指定数据帧data中相应列名的字符串。
# Load dataset
data("tictactoe")
# Perform reinforcement learning
model <- ReinforcementLearning(data = tictactoe,
s = "State",
a = "Action",
r = "Reward",
s_new = "NextState",
iter = 1)
Parameter configuration
为了定制代理的学习行为,可以提供几个参数。
- alpha学习速率,设置在0到1之间。将其设置为0意味着q值永远不会更新,因此,什么也不会学到。设置一个较高的值,比如0.9,意味着学习可以很快进行。 -折现因子,设置在0和1之间。决定了未来回报的重要性。当因子为0时,只考虑当前的奖励就会使代理人变得目光短浅,而当因子接近1时,就会使代理人在长期内追求更大的奖励。 —epsilon探索参数,设置在0到1之间。定义ε-贪婪行为选择中的探索机制。在这种策略中,agent通过随机选择一个概率为ε的行为来探索环境。或者,agent通过选择概率为1−ε的最优行动来利用其当前知识。此参数仅在基于现有策略抽样新经验时需要。
- iter agent通过训练数据集的重复学习迭代次数。Iter为大于0的整数。默认值设置为1,其中每个状态转换元组只向代理显示一次。根据训练数据的大小,重复学习迭代次数越多,收敛效果越好,但需要的计算时间越长。这个参数直接传递给ReinforcementLearning()。 学习参数alpha、gamma和epsilon必须在传递给ReinforcementLearning()函数的可选控制对象中提供。
# Define control object
control <- list(alpha = 0.1, gamma = 0.1, epsilon = 0.1)
# Pass learning parameters to reinforcement learning function
## model <- ReinforcementLearning(data, iter = 10, control = control)
model <- ReinforcementLearning(data = tictactoe,
s = "State",
a = "Action",
r = "Reward",
s_new = "NextState",
iter = 1,
control = control)
Diagnostics
学习过程的结果是一个类型为rl的对象,该对象包含状态-动作表和在每个状态下具有最佳可能动作的最优策略。命令computePolicy(model)显示最优策略,而print(model)输出状态-动作表,即每个状态-动作对的q值。此外,摘要(模型)打印进一步的模型细节和摘要统计信息。
# Print policy
computePolicy(model)
## .XXBB..XB XXBB.B.X. .XBB..BXX BXX...B.. ..XB..... XBXBXB... XX.BB..XB
## "c1" "c5" "c5" "c4" "c5" "c9" "c3"
## X...BB..X BXX.....B BXBBXBX.X B.BBX.X.X BXX..BXB. .BBB.XXX. BXB.BX.X.
## "c4" "c5" "c8" "c8" "c5" "c9" "c1"
## ..BXB..X. ..XBBXX.B XBX..B.XB .XBXB.X.B BBXBXB.XX .BXXB.X.B X...BX.B.
## "c7" "c1" "c7" "c1" "c7" "c1" "c2"
## .XBBXX..B .BXB.XXB. XBB..XX.B X.B..XXBB BXXBXB.BX ....XBBX. XB..X.XBB
## "c8" "c5" "c4" "c4" "c7" "c2" "c4"
## ..XBXX.BB XBXB...BX .X..BX.B. .B..BX.X. ..X.B..XB XB..BX... .BB.X.XXB
## "c7" "c5" "c3" "c9" "c1" "c8" "c2"
## .XB.X.XBB ..XXB.XBB .XB.BBX.X XB.B.B.XX XB.XX.BB. .X.X...BB BXXXBXBB.
## "c2" "c1" "c8" "c7
# Print summary statistics
summary(model)
##
## Model details
## Learning rule: experienceReplay
## Learning iterations: 1
## Number of states: 1893
## Number of actions: 9
## Total Reward: 5449
##
## Reward details (per iteration)
## Min: 5449
## Max: 5449
## Average: 5449
## Median: 5449
## Standard deviation: NA
案例:Gridworld
本节将通过一个实例来演示强化学习包的功能。
Problem definition
我们的实际例子旨在教机器人在网格形迷宫中的最佳运动(改编自Sutton(1998))。在这里,代理必须从一个随机的起始位置导航到模拟的2×2网格上的最终位置(参见下图)。网格上的每个单元反映一种状态,总共产生4种不同的状态。在每个状态下,代理可以执行四种可能操作中的一种,即向上、向下、向左或向右移动,唯一的限制是它必须保持在网格上。换句话说,网格被一堵墙包围着,这使得代理无法离开网格。s1和s4之间的“墙”阻碍了这些状态之间的直接运动。最后,奖励结构如下:为了惩罚非最短路径的路线,每个移动都会导致负奖励-1。如果代理人达到目标位置,他将获得10英镑的奖励。
image.pngDefining an environment function
我们首先定义一组可用的状态(状态)和操作(动作)。
# Define state and action sets
states <- c("s1", "s2", "s3", "s4")
actions <- c("up", "down", "left", "right")
然后我们把上面的问题公式改写成下面的环境函数。如前所述,该函数必须以状态和操作作为输入。if条件决定当前状态和操作的组合。在我们的示例中,状态指的是代理在网格上的位置,动作表示预期的移动。基于这些,功能决定下一个状态和数值奖励。它们一起作为列表返回。
# Load built-in environment function for 2x2 gridworld
env <- gridworldEnvironment
print(env)
## function (state, action)
## {
## next_state <- state
## if (state == state("s1") && action == "down")
## next_state <- state("s2")
## if (state == state("s2") && action == "up")
## next_state <- state("s1")
## if (state == state("s2") && action == "right")
## next_state <- state("s3")
## if (state == state("s3") && action == "left")
## next_state <- state("s2")
## if (state == state("s3") && action == "up")
## next_state <- state("s4")
## if (next_state == state("s4") && state != state("s4")) {
## reward <- 10
## }
## else {
## reward <- -1
## }
## out <- list(NextState = next_state, Reward = reward)
## return(out)
## }
## <bytecode: 0x7fdcd2a93b00>
## <environment: namespace:ReinforcementLearning>
Learning an optimal policy
在指定了环境函数之后,我们可以使用内置的sampleExperience()函数从环境中采样观察序列。下面的代码片段生成了一个包含1000个随机状态转换元组(si,ai,ri+1,si+1)的数据帧数据。
# Sample N = 1000 random sequences from the environment
data <- sampleExperience(N = 1000,
env = env,
states = states,
actions = actions)
head(data)
## State Action Reward NextState
## 1 s3 right -1 s3
## 2 s1 left -1 s1
## 3 s4 up -1 s4
## 4 s3 up 10 s4
## 5 s3 right -1 s3
## 6 s2 down -1 s2
我们现在可以使用数据中的观察序列来了解agent的最佳行为。为此,我们首先通过定义一个控制对象来定制代理的学习行为。我们遵循默认的参数选择,将学习速率alpha设置为0.1,折现系数gamma设置为0.5,探索贪心设置为0.1。随后,我们使用ReinforcementLearning()函数来学习输入数据的最佳策略。
# Define reinforcement learning parameters
control <- list(alpha = 0.1, gamma = 0.5, epsilon = 0.1)
# Perform reinforcement learning
model <- ReinforcementLearning(data,
s = "State",
a = "Action",
r = "Reward",
s_new = "NextState",
control = control)
Evaluating policy learning
函数的作用是:返回一个rl对象。我们可以唤醒computePolicy(model),以便显示在每个状态下定义最佳可能操作的策略。另外,我们也可以使用print(model)将整个状态-动作表写入屏幕,即每个状态-动作对的q值。显然,agent已经学会了最优策略,允许它从任意起始位置走最短路径到目标位置s4。
# Print policy
computePolicy(model)
## s1 s2 s3 s4
## "down" "right" "up" "up"
# Print state-action function
print(model)
## State-Action function Q
## right up down left
## s1 -0.657079 -0.6435135 0.7560353 -0.6586489
## s2 3.562075 -0.6482063 0.7658358 0.7197767
## s3 3.573793 9.1307219 3.5880442 0.7561129
## s4 -1.876336 -1.8028849 -1.8147210 -1.8339686
##
## Policy
## s1 s2 s3 s4
## "down" "right" "up" "up"
##
## Reward (last iteration)
## [1] -197
最后,我们可以使用summary(model)来进一步检查模型。这个命令输出关于模型的额外诊断,比如状态和操作的数量。此外,它允许我们分析奖励的分配。例如,我们看到样本中的总奖励(游戏邦注:即奖励r列的总和)是非常负的。这表明,用于生成状态转移样本的随机策略偏离了最优情况。因此,下一节将解释如何使用新数据示例应用和更新学习到的策略。
# Print summary statistics
summary(model)
##
## Model details
## Learning rule: experienceReplay
## Learning iterations: 1
## Number of states: 4
## Number of actions: 4
## Total Reward: -197
##
## Reward details (per iteration)
## Min: -197
## Max: -197
## Average: -197
## Median: -197
## Standard deviation: NA
Applying a policy to unseen data
我们现在对看不见的数据应用一个现有的策略,以便评估代理的样本外性能。下面的示例演示如何从现有策略中采样新数据点。结果产生一个列,该列具有每个给定状态的最佳操作。
# Example data
data_unseen <- data.frame(State = c("s1", "s2", "s1"),
stringsAsFactors = FALSE)
# Pick optimal action
data_unseen$OptimalAction <- predict(model, data_unseen$State)
data_unseen
## State OptimalAction
## 1 s1 down
## 2 s2 right
## 3 s1 down
Updating an existing policy
最后,可以用新的观测数据更新现有的策略。例如,当额外的数据点可用时,或者当人们想要将奖励作为训练样本数量的函数时,这是有益的。为此,ReinforcementLearning()函数可以将现有的rl模型作为额外的输入参数。此外,它还附带了一个预定义的行动选择模式,即ε-greedy,从而遵循概率为1 - ε的最佳行动和ε的随机行动。
# Sample N = 1000 sequences from the environment
# using epsilon-greedy action selection
data_new <- sampleExperience(N = 1000,
env = env,
states = states,
actions = actions,
actionSelection = "epsilon-greedy",
model = model,
control = control)
# Update the existing policy using new training data
model_new <- ReinforcementLearning(data_new,
s = "State",
a = "Action",
r = "Reward",
s_new = "NextState",
control = control,
model = model)
下面的代码片段显示,与前一个策略相比,更新后的策略产生的回报明显更高。这些更改也可以通过plot(model_new)在学习曲线中可视化。
# Print result
print(model_new)
## State-Action function Q
## right up down left
## s1 -0.6420792 -0.6278631 0.7703925 -0.6464018
## s2 3.5397460 -0.6318365 0.7696272 0.7450224
## s3 3.5593900 9.0767870 3.5645303 0.7666640
## s4 -1.8950310 -1.9234186 -1.8490891 -1.8821899
##
## Policy
## s1 s2 s3 s4
## "down" "right" "up" "down"
##
## Reward (last iteration)
## [1] 1475
# Plot reinforcement learning curve
plot(model_new)
image
Notes on performance
强化学习保证收敛到最优策略。然而,该方法是计算的要求,因为它依赖于一个代理和它的环境之间的连续交互。为了解决这个问题,reinforcement learning包允许用户执行批处理强化学习。在大多数情况下,这种强化学习变体有利于计算性能,因为它减轻了纯在线学习中的“探索开销”问题。与经验回放相结合,它通过收集并反复回放观察到的状态转换到代理,就像它们是在与系统交互时收集到的新观察一样,从而加速收敛。尽管如此,由于这个程序包完全是用R编写的,所以它对于非常大规模的问题(例如计算机视觉的应用)的适用性仍然有限。下面,我们简要地总结一下这个包能够处理的场景,以及应该考虑使用“更快”编程语言编写的强化学习实现的情况。
强化学习R包能做什么:
-通过有限的状态和行动集,为现实世界的问题学习最佳策略(例如,为简单的游戏寻找最佳策略,训练一个简单的股票市场交易代理,从自然语言处理学习应用程序中的极性标签)。 -该包允许一个人通过调整学习参数和使用经验回放加速性能。 -该包允许一个人训练一个代理从预先定义的观察,而不需要建模的动态环境。通常,这种方法大大加快了收敛速度,并且在从外部源(如传感器数据)收集状态转换元组的情况下非常有用。 -该包为无模型强化学习任务提供了一个高度可定制的框架,在其中的功能可以很容易地扩展。例如,用户可能试图通过定义替代的强化学习算法并将它们集成到包代码中来提高性能。
强化学习R包不能做的事情:
-用高维状态-动作空间(如计算机视觉)解决大规模问题(用户可以考虑用“更快”的编程语言编写的强化学习实现) -解决需要实时交互的强化学习问题(例如与机器人的实时交互)
网友评论