强化学习讨论的问题是一个智能体(agent)怎么在一个复杂不确定的环境(environment)中取得奖励的最大值。
强化学习研究的问题是 agent 跟环境交互,上图左边画的是一个 agent,agent 一直在跟环境进行交互。这个 agent 把它输出的动作给环境,环境取得这个动作过后,会进行到下一步,然后会把下一步的观测跟它上一步是否得到奖励返还给 agent。通过这样的交互过程会产生很多观测,agent 就是为了从这些观测之中学到能极大化奖励的策略。
1、强化学习与监督学习的区别
区别 | 强化学习 | 监督学习 |
---|---|---|
样本 | 样本直接存在联系,agent得到的state并不是i.i.d分布 | 以图片分类为例子,label之间是没有关联的 |
反馈的即时性 | 强化学习中反馈不会立刻获得,得到training data序列的agent会输出一个决策,但是这个决策的正确与否,必须直到游戏结束(或者过几分钟)才可以。这里涉及到了延迟奖励(Delayed reward) | 监督学习可以直接判断出训练器的结果是否错误,并在下一轮训练中作出相应的参数调整(Backpropagation)。而这个错误量化为损失函数(loss function) |
模型的调整 | learner会告诉agent错误的行为是什么,但是不会告诉agent正确的行为是什么,agent只能通过trial-and-error exploration来寻找可以使自己获得奖励的行为,从而找到最有利的action。 | 通常在imageNet中我们会采取反向传播来调整参数 |
模型上限(强化学习的优势) | 强化学习可以在环境中自主探索,所以潜力很大,可以获得超越人类能力的表现 | 监督学习以人类标定的监督数据为极限 |
强化学习最大的不同点:
-
刚刚我们提到agent获得能力的过程是不断trial-and-error exploration,但是exploration寻找到的新行为可能让你获得更高的reward,也可能导致reward下降。Exploitation 就是就采取已知的可以获得最大奖励的行为,重复执行这个 action ,因为你已经知道可以获得一定的奖励。所以我们需要在exploration和exploitation直接取得一个权衡(trade-off)。
举一些例子来说明 Exploration 和 Exploitation 的定义。 -
以选择餐馆为例,
- Exploitation 是说我们直接去你最喜欢的餐馆,因为你去过这个餐馆很多次了,所以你知道这里面的菜都非常可口。
- Exploration 是说你把手机拿出来,你直接搜索一个新的餐馆,然后去尝试它到底好不好吃。这里的结果就是有可能这个新的餐馆非常不满意,你就这个钱就浪费了。
-
以做广告为例,
- Exploitation 就是说我们直接采取最优的这个广告策略。
- Exploration 就是说我们换一种广告方式,然后看这个新的广告策略到底可不可以得到奖励。
强化学习的特征:
- 强化学习的学习过程是trial-and-error exploration,需要通过探索环境来获取对这个环境的理解,它并不知道正确的行为是什么。
- 强化学习 的agent 会从环境里面获得延迟的奖励。
- 是在强化学习的训练过程中,时间非常重要。因为你得到的数据都是有这个时间关联的,而不是这个 i.i.d 分布的。在机器学习中,如果观测数据有非常强的关联,其实会使得这个训练非常不稳定。这也是为什么在监督学习中,我们希望 data 尽量是 i.i.d 了,这样就可以消除数据之间的相关性。
- 这个 agent 的行为会影响它随后得到的数据,这一点是非常重要的。在我们训练 agent 的过程中,很多时候我们也是通过正在学习的这个 agent 去跟环境交互来得到数据。所以如果在训练过程中,这个 agent 的模型很快死掉了,那会使得我们采集到的数据是非常糟糕的,这样整个训练过程就失败了。所以在强化学习里面一个非常重要的问题就是怎么让这个 agent 的行为一直稳定地提升。
2 、强化学习的例子:
- 国际象棋是一个强化学习的过程,因为这个棋手就是在做出一个选择来跟对方对战。
- 在自然界中,羚羊其实也是在做一个强化学习,它刚刚出生的时候,可能都不知道怎么站立,然后它通过 trial- and-error 的一个尝试,三十分钟过后,它就可以跑到每小时 36 公里,很快地适应了这个环境。
- 玩雅达利游戏或者一些电脑游戏,也是一个强化学习的过程。
2.1、pong
在这个 pong 的游戏里面,决策其实就是两个动作:往上或者往下。如果强化学习是通过学习一个 policy network 来分类的话,其实就是输入当前帧的图片,然后 policy network 就会输出所有决策的可能性。
在这种情况下面,对于监督学习的话,我们就可以直接告诉这个 agent 正确的 label 是什么。在这种游戏情况下面,我们并不知道它的正确的标签是什么。
在强化学习里面,我们是通过让它尝试去玩这个游戏,然后直到游戏结束过后,再去说你前面的一系列动作到底是正确还是错误
2.2、K-armed Bandit
根据第一节,我们知道与一般监督学习不同,强化学习任务的最终奖赏是在多步动作之后才能观察到,这里我们不妨先考虑比较简单的情形:最大化单步奖赏,即仅考虑一步操作。需注意的是,即便在这样的简化情形下,强化学习仍与监督学习有显著不同,因为机器需通过尝试来发现各个动作产生的结果,而没有训练数据告诉机器应当做哪个动作。
想要最大化单步奖赏需考虑两个方面:一是需知道每个动作带来的奖赏,二是要执行奖赏最大的动作。若每个动作对应的奖赏是一个确定值,那么尝试遍所有的动作便能找出奖赏最大的动作。然而,更一般的情形是,一个动作的奖赏值是来自于一个概率分布,仅通过一次尝试并不能确切地获得平均奖赏值。
实际上,单步强化学习任务对应了一个理论模型,即 K-臂赌博机(K-armed bandit)。K-臂赌博机也被称为 多臂赌博机(Multi-armed bandit) 。如上图所示,K-摇臂赌博机有 K 个摇臂,赌徒在投入一个硬币后可选择按下其中一个摇臂,每个摇臂以一定的概率吐出硬币,但这个概率赌徒并不知道。赌徒的目标是通过一定的策略最大化自己的奖赏,即获得最多的硬币。
-
若仅为获知每个摇臂的期望奖赏,则可采用仅探索(exploration-only)法:将所有的尝试机会平均分配给每个摇臂(即轮流按下每个摇臂),最后以每个摇臂各自的平均吐币概率作为其奖赏期望的近似估计。
-
若仅为执行奖赏最大的动作,则可采用仅利用(exploitation-only)法:按下目前最优的(即到目前为止平均奖赏最大的)摇臂,若有多个摇臂同为最优,则从中随机选取一个。
显然,仅探索法能很好地估计每个摇臂的奖赏,却会失去很多选择最优摇臂的机会;仅利用法则相反,它没有很好地估计摇臂期望奖赏,很可能经常选不到最优摇臂。因此,这两种方法都难以使最终的累积奖赏最大化。
事实上,探索(即估计摇臂的优劣)和利用(即选择当前最优摇臂)这两者是矛盾的,因为尝试次数(即总投币数)有限,加强了一方则会自然削弱另一方,这就是强化学习所面临的探索-利用窘境(Exploration-Exploitation dilemma)。显然,想要累积奖赏最大,则必须在探索与利用之间达成较好的折中。
2.3、MountainCar-v0 Example
该例子涉及到Gym库。
Gym 的用法:使用 env=gym.make(环境名) 取出环境,使用 env.reset()初始化环境,使用env.step(动作)执行一步环境,使用 env.render()显示环境,使用 env.close() 关闭环境。
每个环境都定义了自己的观测空间和动作空间。环境 env 的观测空间用env.observation_space表示,动作空间用 env.action_space 表示。观测空间和动作空间既可以是离散空间(即取值是有限个离散的值),也可以是连续空间(即取值是连续的)。在 Gym 库中,离散空间一般用gym.spaces.Discrete类表示,连续空间用gym.spaces.Box类表示。
(1) 这个任务的观测空间和动作空间:
import gym
env = gym.make('MountainCar-v0')
print('观测空间 = {}'.format(env.observation_space))
print('动作空间 = {}'.format(env.action_space))
print('观测范围 = {} ~ {}'.format(env.observation_space.low,
env.observation_space.high))
print('动作数 = {}'.format(env.action_space.n))
观测空间是Box(2,),表示观测可以用2个float值表示。
动作空间是Discrete(3),表示动作取值自{0,1,2}
对于离散空间,gym.spaces.Discrete类实例的成员 n 表示有几个可能的取值;对于连续空间,Box类实例的成员 low 和 high 表示每个浮点数的取值范围。
由输出可知,观测空间是形状为 (2,) 的浮点型 np.array,动作空间是取 {0,1,2} 的 int 型数值。
(2) 设计智能体。
class BespokeAgent:
def __init__(self, env):
pass
def decide(self, observation): # 决策
position, velocity = observation
lb = min(-0.09 * (position + 0.25) ** 2 + 0.03,
0.3 * (position + 0.9) ** 4 - 0.008)
ub = -0.07 * (position + 0.38) ** 2 + 0.07
if lb < velocity < ub:
action = 2
else:
action = 0
return action # 返回动作
def learn(self, *args): # 学习
pass
agent = BespokeAgent(env)
智能体的 decide() 方法实现了决策功能,而 learn() 方法实现了学习功能。
(3)实现智能体与环境交互。
def play_montecarlo(env, agent, render=False, train=False):
"""
:param env: 环境类
:param agent:智能体类
:param render:bool 类型变量,指示在运行过程中是否要图形化显示。如果函数参数 render为 True,那么在交互过程中会调用 env.render() 以显示图形化界面,而这个界面可以通过调用 env.close() 关闭。
:param train:bool 类型的变量,指示在运行过程中是否训练智能体。在训练过程中应当设置为 True,以调用 agent.learn() 函数;在测试过程中应当设置为 False,使得智能体不变。
:return:episode_reward,是 float 类型的数值,表示智能体与环境交互一个回合的回合总奖励。
"""
episode_reward = 0. # 记录回合总奖励,初始化为0
observation = env.reset() # 重置游戏环境,开始新回合
while True: # 不断循环,直到回合结束
if render: # 判断是否显示
env.render() # 显示图形界面,图形界面可以用 env.close() 语句关闭
action = agent.decide(observation)
next_observation, reward, done, _ = env.step(action) # 执行动作
episode_reward += reward # 收集回合奖励
if train: # 判断是否训练智能体
agent.learn(observation, action, reward, done) # 学习
if done: # 回合结束,跳出循环
break
observation = next_observation
return episode_reward # 返回回合总奖励
(4)使用下列代码让智能体和环境交互一个回合
env.seed(0) # 设置随机数种子,只是为了让结果可以精确复现,一般情况下可删去
episode_reward = play_montecarlo(env, agent, render=True)
print('回合奖励 = {}'.format(episode_reward))
env.close() # 此语句可关闭图形界面,直接关闭可能导致内存不能释放。
(5)为了系统评估智能体的性能,下列代码求出了连续交互 100 回合的平均回合奖励。
episode_rewards = [play_montecarlo(env, agent) for _ in range(100)]
print('平均回合奖励 = {}'.format(np.mean(episode_rewards)))
小车上山环境有一个参考的回合奖励值 -110,如果当连续 100 个回合的平均回合奖励大于 -110,则认为这个任务被解决了。BespokeAgent 类对应的策略的平均回合奖励大概就在 -110 左右。
测试 agent 在 Gym 库中某个任务的性能时,学术界一般最关心 100 个回合的平均回合奖励。至于为什么是 100 个回合而不是其他回合数(比如 128 个回合),完全是习惯使然,没有什么特别的原因。对于有些环境,还会指定一个参考的回合奖励值,当连续 100 个回合的奖励大于指定的值时,就认为这个任务被解决了。但是,并不是所有的任务都指定了这样的值。对于没有指定值的任务,就无所谓任务被解决了或者没有被解决。
深度学习与强化学习的结合
- 之前的强化学习,比如 TD-Gammon 玩 backgammon 这个游戏,它其实是设计特征,然后通过训练价值函数的一个过程,就是它先设计了很多手工的特征,这个手工特征可以描述现在整个状态。得到这些特征过后,它就可以通过训练一个分类网络或者分别训练一个价值估计函数来做出决策。
- 现在有了深度学习,有了神经网络,那么大家也把这个过程改进成一个 end-to-end training 的过程。你直接输入这个状态,我们不需要去手工地设计这个特征,就可以让它直接输出 action。那么就可以用一个神经网络来拟合我们这里的 value function 或 policy network,省去 了 feature engineering 的过程。
近几年强化学习得到应用的原因:
- GPU 的发展,可以进行更多的trail-and-error的尝试。
- 这个端到端的一个训练,可以把特征提取和价值估计或者决策一块来优化,这样就可以得到了一个更强的决策网络。
3、序列决策(Sequential Decision Making)
3.1、reward
奖励是由环境给的一个反馈信号,这个信号指定了这个 agent 在某一步采取了某个策略是否得到奖励。强化学习的目的就是为了极大化 agent 可以获得的奖励,agent 在这个环境里面存在的目的就是为了极大它的期望积累的奖励。
不同的环境,奖励也是不同的。
- 比如说一个下象棋的选手,它的目的其实就为了赢棋。奖励是说在最后棋局结束的时候,他知道会得到一个正奖励或者负奖励。
- 羚羊站立也是一个强化学习过程,它得到的奖励就是它是否可以最后跟它妈妈一块离开或者它被吃掉。
- 在玩雅达利游戏的时候,奖励就是你有没有在增加游戏的分数,奖励本身的稀疏程度决定了这个游戏的难度。
3.2、Sequential Decision Making
在一个强化学习环境里面,agent 的目的就是选取一系列的动作来极大化它的奖励,所以这些采取的动作必须有长期的影响。但在这个过程里面,它的奖励其实是被延迟了,就是说你现在采取的某一步决策可能要等到时间很久过后才知道这一步到底产生了什么样的影响。
例如在Pong游戏中,可能只有到最后游戏结束过后,才知道这个球到底有没有击打过去。中间你采取的 up 或 down 行为,并不会直接产生奖励。强化学习里面一个重要的课题就是近期奖励和远期奖励的一个 trade-off。怎么让 agent 取得更多的长期奖励是强化学习的问题。
在跟环境的交互过程中,agent 会获得很多观测。在每一个观测会采取一个动作,它也会得到一个奖励。所以历史是观测、行为、奖励的序列:
Agent 在采取当前动作的时候会依赖于它之前得到的这个历史,所以你可以把整个游戏的状态看成关于这个历史的函数:
Q | 状态和观测有什么关系? |
---|---|
A | 状态(state) s 是对世界的完整描述,不会隐藏世界的信息。观测(observation) o 是对状态的部分描述,可能会遗漏一些信息。 |
3.2.1、完全可观测和部分可观测
在 deep RL 中,我们几乎总是用一个实值的向量、矩阵或者更高阶的张量来表示状态和观测。举个例子,我们可以用 RGB 像素值的矩阵来表示一个视觉的观测,我们可以用机器人关节的角度和速度来表示一个机器人的状态。
在 agent 的内部也有一个函数来更新这个状态。当 agent 的状态跟环境的状态等价的时候,我们就说这个环境是 full observability,就是全部可以观测。换句话说,当 agent 能够观察到环境的所有状态时,我们称这个环境是完全可观测的(fully observed)。
但是有一种情况是 agent 得到的观测并不能包含所有环境运作的状态,因为在这个强化学习的设定里面,环境的状态才是真正的所有状态。比如 agent 在玩这个 black jack 这个游戏,它能看到的其实是牌面上的牌。或者在玩雅达利游戏的时候,观测到的只是当前电视上面这一帧的信息,你并没有得到游戏内部里面所有的运作状态。也就是说当 agent 只能看到部分的观测,我们就称这个环境是部分可观测的(partially observed)。在这种情况下面,强化学习通常被建模成一个 POMDP 的问题。
部分可观测马尔可夫决策过程(Partially Observable Markov Decision Processes, POMDP)是一个马尔可夫决策过程的泛化。POMDP 依然具有马尔可夫性质,但是假设智能体无法感知环境的状态
s
s
s,只能知道部分观测值
o
o
o。比如在自动驾驶中,智能体只能感知传感器采集的有限的环境信息。
POMDP可以用一个7元组描述: ( S , A , T , R , Ω , O , γ ) (S,A,T,R,\Omega,O,\gamma) (S,A,T,R,Ω,O,γ), 其中 S S S表示状态空间,为隐变量,A为动作空间, T ( s , ∣ s , a ) T(s^,|s,a) T(s,∣s,a)为状态转移概率, R R R为奖励函数, Ω ( o ∣ s , a ) \Omega(o|s,a) Ω(o∣s,a)为观测概率, O O O为观测空间, γ \gamma γ为折扣系数。
3.4、Action Spaces
不同的环境允许不同种类的动作。在给定的环境中,有效动作的集合经常被称为动作空间(action space)。
- 走迷宫机器人如果只有东南西北这 4 种移动方式,则其为离散动作空间;
- 如果机器人向 36 0 deg 360^{\deg} 360deg 中的任意角度都可以移动,则为连续动作空间。
4、agent的组成部分
对于一个强化学习agent,它主要有如下组成部分:
- 首先需要有一个policy function,agent会用这个函数选取下一步动作。
- 然后它可能会生成一个价值函数(value function)。我们用价值函数来对当前状态进行估价,它就是说你进入现在这个状态,可以对你后面的收益带来多大的影响。当这个价值函数大的时候,说明你进入这个状态越有利。
- 另外一个组成成分是模型(model)。模型表示了 agent 对这个环境的状态进行了理解,它决定了这个世界是如何进行的。
当我们有了这三个成分过后,就形成了一个 Markov Decision Process。这个决策过程可视化了状态之间的转移以及采取的行为。
4.1、policy
Policy 决定了这个 agent 的行为,它其实是一个函数,把输入的状态变成行为。这里有两种 policy:
- 一种是 stochastic policy(随机性策略),它就是 π \pi π 函数 π ( a ∣ s ) = P [ A t = a ∣ S t = s ] \pi(a | s)=P\left[A_{t}=a|S_{t}=s\right] π(a∣s)=P[At=a∣St=s]。当你输入一个状态 s 的时候,输出是一个概率。这个概率就是你所有行为的一个概率,然后你可以进一步对这个概率分布进行采样,得到真实的你采取的行为。比如说这个概率可能是有 70% 的概率往左,30% 的概率往右,那么你通过采样就可以得到一个 action。
- 一种是 deterministic policy(确定性策略),就是说你这里有可能只是采取它的极大化,采取最有可能的动作。
通常情况下,强化学习一般使用随机性策略。随机性策略有很多优点:
- 在学习时可以通过引入一定随机性来更好地探索环境;
- 随机性策略的动作具有多样性,这一点在多个智能体博弈时也非常重要。采用确定性策略的智能体总是对同样的环境做出相同的动作,会导致它的策略很容易被对手预测。
4.2、Value Function
价值函数是未来奖励的一个预测,用来评估状态的好坏即进入现在的状态,到底可以对你后面的收益带来多大的影响。。
价值函数里面有一个 discount factor,我们希望尽可能在短的时间里面得到尽可能多的奖励。如果我们说十天过后,我给你 100 块钱,跟我现在给你 100 块钱,你肯定更希望我现在就给你 100 块钱,因为你可以把这 100 块钱存在银行里面,你就会有一些利息。所以我们就通过把这个 discount factor 放到价值函数的定义里面,价值函数的定义其实是一个期望。这里有一个期望
E
π
\mathbb{E}_{\pi}
Eπ ,这里有个小角标是
π
\pi
π 函数,这个
π
\pi
π 函数就是说在我们已知某一个 policy function 的时候,到底可以得到多少的奖励。
另一种价值函数:Q 函数。Q 函数里面包含两个变量:状态和动作。所以你未来可以获得多少的奖励,它的这个期望取决于你当前的状态和当前的行为。这个 Q 函数是强化学习算法里面要学习的一个函数。因为当我们得到这个 Q 函数后,进入某一种状态,它最优的行为就可以通过这个 Q 函数来得到。
4.3、Model
**模型表示了 Agent 对这个Environment的状态进行的理解,决定了下一个状态会是什么样的,就是说下一步的状态取决于你当前的状态以及你当前采取的行为。**它由两个部分组成:
- 一个是probability, 它转移状态之间是怎么转移的。
- 另一个是奖励函数,当你在当前状态采取某一种行为,可以得到多大的奖励。
5、Types of RL Agents
5.1、根据RL Agents的学习内容分类
- 基于价值函数的 agent。这一类 agent 显式地学习的是价值函数,隐式地学习了它的策略。因为这个策略是从我们学到的价值函数里面推算出来的。
- 基于策略的 agent,它直接去学习 policy,就是说你直接给它一个 state,它就会输出这个动作的概率。在这个 policy-based agent 里面并没有去学习它的价值函数。
- 把 value-based 和 policy-based 结合起来就有了 Actor-Critic agent。这一类 agent 就把它的策略函数和价值函数都学习了,然后通过两者的交互得到一个最佳的行为。
Q: 基于策略迭代和基于价值迭代的强化学习方法有什么区别?
A: 对于一个状态转移概率已知的马尔可夫决策过程,我们可以使用动态规划算法来求解;从决策方式来看,强化学习又可以划分为基于策略迭代的方法和基于价值迭代的方法。决策方式是智能体在给定状态下从动作集合中选择一个动作的依据,它是静态的,不随状态变化而变化。
在基于策略迭代的强化学习方法中,智能体会制定一套动作策略(确定在给定状态下需要采取何种动作),并根据这个策略进行操作。强化学习算法直接对策略进行优化,使制定的策略能够获得最大的奖励。
而在基于价值迭代的强化学习方法中,智能体不需要制定显式的策略,它维护一个价值表格或价值函数,并通过这个价值表格或价值函数来选取价值最大的动作。基于价值迭代的方法只能应用在不连续的、离散的环境下(如围棋或某些游戏领域),对于行为集合规模庞大、动作连续的场景(如机器人控制领域),其很难学习到较好的结果(此时基于策略迭代的方法能够根据设定的策略来选择连续的动作)。
5.2、是否学习环境模型
- 第一种是 model-based(有模型) RL agent,它通过学习这个状态的转移来采取措施。
- 另外一种是 model-free(免模型) RL agent,它没有去直接估计这个状态的转移,也没有得到环境的具体转移变量。它通过学习 value function 和 policy function 进行决策。这种 model-free 的模型里面没有一个环境转移的一个模型。
Q: 有模型强化学习和免模型强化学习有什么区别?
A: 针对是否需要对真实环境建模,强化学习可以分为有模型学习和免模型学习。
-
有模型学习是指根据环境中的经验,构建一个虚拟世界,同时在真实环境和虚拟世界中学习;
-
免模型学习是指不对环境进行建模,直接与真实环境进行交互来学习到最优策略。
区别 | 有模型学习 | 免模型学习 |
---|---|---|
是否对环境建模(构建一个虚拟环境) | 是 | 否 |
泛化性 | 有模型的学习对环境建模,但是虚拟环境和真实环境存在差异,可能限制有模型算法的泛化性 | 优于有模型学习 |
反馈 | 有模型学习可以预测出虚拟世界所要发生的事,并采取对自己最有利的策略 | 免模型学习只能一步步采取策略,并等待真实环境的反馈 |
Q:如何判断是否可以使用有模型强化学习
A:在智能体执行动作前,是否能对下一步的状态和奖励进行预测,如果可以,就能够对环境进行建模,从而采用有模型学习。
Q:大部分深度强化学习方法都采用了免模型学习?
A:
- 免模型学习更为简单直观且有丰富的开源资料,像 DQN、AlphaGo 系列等都采用免模型学习;
- 在目前的强化学习研究中,大部分情况下环境都是静态的、可描述的,智能体的状态是离散的、可观察的(如 Atari 游戏平台),这种相对简单确定的问题并不需要评估状态转移函数和奖励函数,直接采用免模型学习,使用大量的样本进行训练就能获得较好的效果。
5.3、Maze example
下面有一个迷宫的例子。
Policy-based RL
如果我们采取的是 Policy-based RL,当我们学习好了这个环境过后,在每一个状态,我们就会得到一个最佳的行为。比如说现在在第一格开始的时候,我们知道它最佳行为是往右走,然后第二格的时候,得到的最佳策略是往上走,第三格是往右走。通过这个最佳的策略,我们就可以最快地到达终点。
value-based RL
value-based RL算法利用价值函数来作为导向,每一个状态会返回一个价值,比如说你在 start 位置的时候,价值是 -16,因为你最快可以 16 步到达终点。因为每走一步会减一,所以你这里的价值是 -16。当我们快接近最后终点的时候,这个数字变得越来越大。在拐角的时候,比如要现在在第二格 -15。然后 agent 会看上下,它看到上面值变大了,变成 -14 了,它下面是 -16,那么这个 agent 肯定就会采取一个往上走的策略。所以通过这个学习的值的不同,我们可以抽取出现在最佳的策略。