Reinforcement Learning CookBook


本文旨在协助快速理解并实际上手RL,不希望把RL的概念束之高阁。

Intro

What? Why? How?

为什么不是监督学习?

监督学习(supervised learning)假设我们有大量被标注的数据,比如汽车、飞机、椅子这些被标注的图片,这些图片都要满足独立同分布,即它们之间是没有关联关系的:

假设我们训练一个分类器,比如神经网络。为了分辨输入的图片中是汽车还是飞机,在训练过程中,需要把正确的标签信息传递给神经网络。 当神经网络做出错误的预测时,比如输入汽车的图片,它预测出来是飞机,我们就会直接告诉它,该预测是错误的,正确的标签应该是汽车。最后我们根据类似错误写出一个loss function,通过反向传播来训练神经网络。

总的来说,监督学习有如下两个特点:

输入的数据(也就是标注的数据)都应是没有关联的。因为如果输入的数据有关联,Learner 是不好学习的。

需要告诉learner正确的label是什么,这样它可以通过正确的label来修正自己的预测。

RL

强化学习(reinforcement learning,RL)讨论的问题是agent怎么在复杂、不确定的环境中最大化它能获得的奖励。如图所示,RL由两部分组成:Agent和环境。在RL过程中,Agent与环境一直在交互。Agent在环境中获取某个状态后,它会利用该状态输出一个动作,这个动作也称为决策。然后这个动作会在环境中被执行,环境会根据Agent采取的动作,输出下一个状态以及当前这个动作带来的奖励。Agent的目的就是尽可能多地从环境中获取奖励。

基础 & 核心概念(optional)

让我们先介绍几个枯燥的数学概念,尽管他们中的一些并不会显式地呈现在RL的过程中,但他们会对理解RL有更多的帮助:

MDP

理解马尔可夫决策是弄清RL的关键,让我们先聊一下马尔可夫过程:


“未来的状态只取决于当前状态,与过去的状态无关”。

如果一个随机过程的状态序列 $S_{1},S_{2},\ldots,S_{t}$满足$P\left( S_{t + 1}|S_{t},S_{t - 1},\ldots,S_{1} \right) = P\left( S_{t + 1}|S_{t} \right)$, 则称其为马尔可夫过程。

| 简单说,就是 “知道现在,就能预测未来,不需要回头看过去”。比如: |
| |
| 天气变化:明天是否下雨,只取决于今天的天气(假设无长期趋势); |
| |
| 游戏角色状态:下一秒的位置,只取决于当前位置和运动方向,与 10 分钟前的位置无关。 |

正如我们在开头所说,强化学习研究的是 “在复杂、不确定的环境中最大化它能获得的奖励”,而环境的动态规律恰好可以用MDP建模

MDP 是马尔可夫过程的扩展,增加了两个关键要素:

动作(Action):Agent可以选择的行为(如游戏中 “向左走””攻击”);

奖励(Reward):Agent执行动作后获得的即时反馈(如 “吃到金币 + 10 分””掉血 - 50 分”)。

Policy & Reward

在RL中,策略(Policy)和奖励(Reward)是两个核心概念,它们共同引导Agent学习如何在环境中做出最优决策。

策略(Policy)是Agent的行为准则,决定了在特定状态下应该采取什么动作。简单来说,策略就是一个从状态到动作的映射函数

| 策略可以想象成一本"行动指南": |
| |
| 如果你在迷宫的十字路口(状态),就向右转(动作) |
| |
| 如果你看到敌人(状态),就开火攻击(动作) |
| |
| 如果库存不足(状态),就补充库存(动作) |

策略通常用符号 $\pi$ 表示,可以分为两种主要类型:

确定性策略(Deterministic Policy):对于给定状态,总是输出同一个确定的动作。

表示为:$a = \pi(s)$

例如:在国际象棋中,特定局面总是选择同一个最佳走法

图为四回合将杀(Scholar’s mate),在初学者实战中常常出现

随机性策略(Stochastic Policy):对于给定状态,输出的是动作的概率分布。

表示为:$\pi\left( a|s \right) = P\left( A_{t} = a|S_{t} = s \right)$

例如:在石头剪刀布游戏中,可能以60%概率出石头,30%概率出剪刀,10%概率出布

随机性策略的一个重要优势是它天然支持探索,因为它允许Agent尝试各种可能的动作,而不仅仅局限于当前认为最优的动作。

奖励(Reward)是环境给予Agent的即时反馈信号,用于评价Agent采取的动作的好坏。奖励函数 $R\left( s,a,s^{‘} \right)$ 定义了在状态 $s$ 下执行动作 $a$ 并转移到状态 $s^{‘}$ 时获得的奖励值。

| 奖励就像是游戏中的积分系统: |
| |
| 在游戏中击败敌人:+100分 |
| |
| 收集金币:+10分 |
| |
| 掉入陷阱:-50分 |
| |
| 成功通关:+1000分 |

探索与利用

在强化学习中,探索(Exploration)与利用(Exploitation)的权衡是一个核心问题。这个问题可以用一个简单的比喻来理解:

| 想象你在一个陌生城市找餐厅吃饭: |
| |
| 探索:尝试从未去过的新餐厅(可能发现宝藏小店,也可能踩雷) |
| |
| 利用:去吃港知味(保证满意,但可能错过更好的选择) |

探索(Exploration)是指Agent尝试新的、未知的行为,以获取更多关于环境的信息。探索的目的是发现可能存在的更优策略。

探索的优点:

有助于发现潜在的高回报策略

防止陷入局部最优

增强对环境变化的适应能力

探索的缺点:

可能导致短期内获得较低的回报

过度探索会降低学习效率

利用(Exploitation)是指Agent基于已有的知识,选择当前认为能带来最高回报的行为。

利用的优点:

保证获得相对稳定的回报

加速学习过程中的收敛

利用的缺点:

可能错过更优的策略

容易陷入局部最优解

在强化学习中,我们需要在探索和利用之间找到平衡。如果过度探索,Agent可能花费太多时间在无用的尝试上;如果过度利用,Agent可能永远找不到最优策略。

| (摘自某知名RL书籍)常见的探索策略包括: |
| |
| ε-贪心(ε-greedy): |
| |
| 以概率 ε 选择随机动作(探索) |
| |
| 以概率 1-ε 选择当前估计最优的动作(利用) |
| |
| ε 通常会随时间衰减,从而逐渐从探索过渡到利用 |
| |
| 玻尔兹曼探索(Boltzmann Exploration): |
| |
| 根据每个动作的估计价值,计算选择该动作的概率 |
| |
| 使用温度参数控制探索程度:高温时行为更随机,低温时更倾向于选择高价值动作 |
| |
| 公式:$P\left( a|s \right) = \frac{e^{Q\left( s,a \right)/\tau}}{\sum_{a^{‘}}^{}e^{Q\left( s,a^{‘} \right)/\tau}}$,其中 τ 是温度参数 |
| |
| 上置信界(Upper Confidence Bound, UCB): |
| |
| 选择具有最高置信上界的动作 |
| |
| 结合了动作的估计价值和不确定性 |
| |
| 公式:$UCB(a) = Q(a) + c\sqrt{\frac{\ln(t)}{N(a)}}$,其中 $N(a)$ 是动作 $a$ 被选择的次数,$t$ 是总步数 |
| |
| 汤普森采样(Thompson Sampling): |
| |
| 维护每个动作回报的概率分布 |
| |
| 每次从这些分布中采样,选择样本值最高的动作 |
| |
| 自然地平衡了探索和利用 |
| |
| 内在动机(Intrinsic Motivation): |
| |
| 除了外部奖励,还给予智能体内在奖励来鼓励探索 |
| |
| 常见的内在奖励包括新颖性(novelty)、好奇心(curiosity)和惊奇度(surprise) |
| |
| 例如,可以奖励智能体访问新状态或减少预测误差 |
| |
| 在连续动作空间中,探索通常通过在策略输出上添加噪声来实现,如: |
| |
| 在确定性策略(如DDPG)中添加高斯噪声或奥恩斯坦-乌伦贝克过程噪声 |
| |
| 在随机策略中,通过增加策略的熵(entropy)来鼓励探索(如SAC算法) |

随着学习的进行,探索程度通常会逐渐减小,让Agent更多地利用已学到的知识。这种从"广泛试错"到"精益执行"的过渡是RL成功的关键。

那强化学习在业界又是如何?

目前业界应用

RL一直以在游戏领域的应用较为广泛,并且取得了可观的成果,从当初的97年的深蓝(严格来说不是RL)到几年前的AlphaGo再到现在的各种游戏智能NPC

AlphaGo

(摘自BBC)在三局两胜的比赛中人工智能AlphaGo赢得了第两局对战,捍卫了比赛的最终胜利。

在比赛过程中,DeepMind的创建者哈萨比斯(Demis Hassabis)形容柯洁"下得十分完美";赛后也称赞柯洁"几乎将AlphaGo的能力逼到了极限"。

比赛结束后,柯洁接受了记者的采访并表示:"其实我有一些遗憾,因为我觉得是可以打败它的。"

AlphaGo对阵柯洁的三番棋比赛于2017年5月23日、25日和27日在中国乌镇围棋峰会进行,AlphaGo Master以3:0战胜了当时世界排名第一的围棋棋手柯洁

逆水寒


图为网易的招牌游戏:逆水寒,它向我们展示了RL后的NPC,其作为游戏的一个巨大亮点,在市场上脱颖而出的同时为游戏收获了巨大的流量

Starcraft


下图为星际争霸通过RL取得的成果– AlphaStar

RL_for_starcraft

AlphaStar曾在BattleNet上与真实玩家对抗,玩家会有评级,根据MMR分值分成7个等级,最低的等级是青铜(Bronze),最高是大师(Grandmaster)。AlphaStar分为三个版本,一个是只进行监督学习的版本(AlphaStar Supervised)、一个是中间版本(AlphaStar Mid)和最终版本(AlphaStar Final)。从图中可见,”只进行监督学习的版本”达到84%的人类水平,中间版本达到99.5%,而最终版本达到99.85%。

举例这么多,是希望向大家说明:为什么我们关注强化学习,其中非常重要的一个原因就是强化学习得到的模型可以有远超人类的表现。 监督学习获取的监督数据,其实是人来标注的,比如 ImageNet 的图片的标签都是人类标注的。因此我们 可以确定监督学习算法的上限(upper bound)就是人类的表现,标注结果决定了它的表现永远不可能超越人类。

但是对于强化学习,它在环境里面自己探索,有非常大的潜力,它可以获得超越人类的能力的表现,比如 DeepMind 的 AlphaGo 这样一个强化学习的算法可以把人类顶尖的棋手(李世石,杰宝)打败。

Let’s Doom

无聊的理论讲完了,让我们快速上手一个demo来实际理解RL;在这里DOOM是一个好的选择:他是一个简单的、经典的最适合RL的训练场景

《Doom》于 1993 年在 DOS 系统发布,是第一人称射击游戏的先锋。它采用了包围游戏角色的 3D 环境绘图,支持多人游戏,并且拥有能让玩家自由创建扩展游戏内容的 WAD 架构。这些创新为后来的第一人称射击游戏奠定了基础,90 年代中期以后激增的此类游戏,通常被称为 “类 DOOM(Doom-like)” 游戏。


Traditional Deere tractor display


It runs DOOM!

让我们上手一个实际的场景来强化对RL的认识,为此我做了一个DOOM的demo

我们利用VizDoom

Vizdoom


VizDoom是一个基于经典游戏《DOOM》的RL研究平台,它允许AI Agent通过视觉信息(游戏屏幕)来学习玩游戏。VizDoom的特点是轻量级(几MB大小)、高性能(单线程可达每秒7000帧)、多平台支持(Linux、macOS、Windows)以及提供丰富的API(Python和C++)。

Training支持MPS加速,如果你使用M2pro以上的macbook,会得到较好的体验


github: https://github.com/nops1ed/doom-RL

训练过程中:Agent在每轮的奖励中了解到,自己移动开枪才有机会杀死敌人,获得加分

训练一段时间后:

在这里,我们定义了一个简单的Reward函数,对Agent的血量,弹药,杀敌,以及造成的伤害都进行统计,这不见得是一个好的奖励函数,但在这里训练一个只会打中敌人的agent来说,足够了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
def _calculate_custom_reward(self):
state = self.game.get_state()
game_vars = state.game_variables

current_health = game_vars[1]
current_ammo = game_vars[2]
current_kills = game_vars[0]
current_damage = game_vars[3]

reward = 0

if current_kills > self.prev_kills:
reward += self.reward_weights['kill'] * (current_kills - self.prev_kills)

if current_damage > self.prev_damage:
reward += self.reward_weights['damage_taken'] * (current_damage - self.prev_damage)

if current_ammo > self.prev_ammo:
reward += self.reward_weights['ammo_gain'] * (current_ammo - self.prev_ammo)

if current_health > self.prev_health:
reward += self.reward_weights['health_gain'] * (current_health - self.prev_health)

if self.game.get_episode_time() - self.episode_start_time > 50:
reward += self.reward_weights['survival']

reward += self.reward_weights['time_penalty']

self.prev_health = current_health
self.prev_ammo = current_ammo
self.prev_kills = current_kills
self.prev_damage = current_damage

return reward

RL vs. SL

对于一般的有监督学习任务,我们的目标是找到一个最优的模型函数,使其在训练数据集上最小化一个给定的Loss function。在训练数据独立同分布的假设下,这个优化目标表示最小化模型在整个数据分布上的泛化误差,用简要的公式可以概括为:

$\backslash text{ 最优模型}\ = \ \backslash arg\ \backslash min_{\backslash text{ 模型}}\ E_{(\backslash text{ 特征},\ \backslash text{ 标签})\backslash sim\backslash text{ 数据分布}}\ \lbrack\backslash text{ 损失函数}(\backslash text{ 标签},\ \backslash text{ 模型}(\backslash text{ 特征}))\rbrack
$

相比之下,强化学习任务的最终优化目标是最大化智能体策略在和动态环境交互过程中的价值。根据1.5节的分析,策略的价值可以等价转换成奖励函数在策略的占用度量上的期望,即:

$\backslash text{ 最优策略}\ = \ \backslash arg\backslash max_{\backslash text{ 策略}}\ E_{(\backslash text{ 状态},\ \backslash text{ 动作})\backslash sim\backslash text{ 策略的占用度量}}\ \lbrack\backslash text{ 奖励函数}(\backslash text{ 状态},\ \backslash text{ 动作})\rbrack
$

未来也许会…