强化学习基础(RL)笔记
<h2 id="rl-简介">RL 简介</h2><p><strong>(1) 定义</strong></p>
<p><strong>强化学习(Reinforcement Learning)</strong>是一种机器学习方法,用于解决需要在一定环境下<strong>通过与环境交互来学习最有行为策略的问题</strong>。其核心思想是通过试错和奖励机制来指导智能体(Agent)学习如何在不同情境下采取行动,以最大化长期累积奖励</p>
<p><strong>(2) 强化学习流程</strong></p>
<p>强化学习中的 agent 用来表示做决策的机器,相比于传统的模型,agent 可以感知周围的环境并通过做决策来直接改变这个环境。一般来说,在经典的强化学习中 agent 的实现可以用一些简单的 MLP、RNN、CNN 等神经网络实现,与现在流行的 LLM-based Agent 有区别</p>
<p>最终目标是:找到一个策略,这个策略根据当前观测到的环境状态和奖励反馈,来选择最佳的动作</p>
<p><strong>(3) 强化学习的独特性</strong></p>
<p>一般的有监督学习任务,目标是找到一个最优的模型函数,使其在训练数据集上最小化一个给定的损失函数;相比之下,强化学习的最终优化目标是最大化智能体策略在和动态环境交互过程中的价值。<strong>策略的价值可以等价转换成奖励函数在策略的占用度量(这里简单理解策略的占用度量就是策略的分布即可)上的期望</strong></p>
<p>二者优化的途径是不同的,有监督学习直接通过优化模型对于数据特征的输出来优化目标,即修改目标函数而数据分布不变;强化学习则通过该改变策略来调整智能体与环境交互数据的分布,即修改数据分布而目标函数不变(一个学模型,一个学策略)</p>
<p><strong>(4) 强化学习的分类</strong></p>
<ul>
<li>
<p><strong>以数据来划分:</strong></p>
<ul>
<li>
<p><strong>Online:</strong>agent 一边与环境交互收集轨迹样本一边学习策略</p>
</li>
<li>
<p><strong>Offline:</strong>agent 学习用到的轨迹样本是提前收集好的,作为一个 offline dataset 提供给 agent,学习策略过程不涉及环境交互</p>
</li>
</ul>
</li>
<li>
<p><strong>以采样策略和更新策略划分</strong></p>
<ul>
<li>
<p><strong>On-Policy:</strong>用来采样的行为策略和用这些数据更新的目标策略是同一个策略,例如 SARSA</p>
</li>
<li>
<p><strong>Off-Policy:</strong>用来采样的行为策略和用这些数据更新的目标策略不是同一个策略,例如 Q-learning</p>
</li>
</ul>
</li>
<li>
<p><strong>以需不需要环境动态划分</strong></p>
<ul>
<li>
<p><strong>Model-based:</strong>环境动态已知,可以得到环境状态转移方程、奖励函数的模型,Agent 不需要真正的和环境交互学习策略</p>
</li>
<li>
<p><strong>Model-free:</strong>环境动态未知,不需要学习状态转移,通过 Agent 与环境交互学习策略</p>
</li>
</ul>
</li>
<li>
<p><strong>以如何学习策略划分(Value-based and Policy-based 见后述)</strong></p>
</li>
</ul>
<h2 id="rl-基础概念">RL 基础概念</h2>
<p><strong>(1) 马尔可夫决策过程</strong></p>
<p>强化学习解决实际问题的第一步就是把实际问题抽象成一个 <strong>Markov Decision Process(MDP)</strong></p>
<p>马尔可夫决策过程由五元组 <span class="math inline">\(<S,A,P,r,\gamma>\)</span> 构成,其中 <span class="math inline">\(S\)</span> 是状态的集合,<span class="math inline">\(A\)</span> 是智能体动作的集合,<span class="math inline">\(P(s'|s,a)\)</span> 是状态转移函数在状态 <span class="math inline">\(s\)</span> 执行动作 <span class="math inline">\(a\)</span> 之后转移到状态 <span class="math inline">\(s'\)</span> 的概率,<span class="math inline">\(r(s,a)\)</span> 是即时奖励函数取决于状态和动作,<span class="math inline">\(\gamma\)</span> 是折扣因子(未来第 t 步的奖励需要乘上 <span class="math inline">\(\gamma^t\)</span> 来降低影响)</p>
<p>策略用 <span class="math inline">\(\pi\)</span> 表示,其相当于在输入状态情况下采取不同动作的概率。当一个动作是确定性策略时,它在每个状态时只输出一个确定性的动作;当一个策略是随机性策略时,它在每个状态的输出是关于动作的概率分布,然后根据该分布进行采样就可以得到一个动作</p>
<p><strong>(2) 价值函数</strong></p>
<ul>
<li>
<p><strong>状态价值函数<span class="math inline">\(V(s)\)</span>:</strong>从一个 state 出发,对各个 trajectory 的回报求期望。公式为 <span class="math inline">\(v_\pi(s)=E(G_t|S_t=s)\)</span>,其表示从状态 <span class="math inline">\(s\)</span> 出发,遵循策略 <span class="math inline">\(\pi\)</span> 时,未来所有回报的期望总和</p>
</li>
<li>
<p><strong>状态动作价值函数 <span class="math inline">\(Q(s,a)\)</span>:</strong>状态-动作值函数评估的是在给定策略下,在某个状态 s 执行某个动作 a 后未来所有回报的期望总和</p>
</li>
</ul>
<p>当且仅当某时刻的状态只取决于上一时刻的状态时,一个随机过程被称为具有马尔可夫性质</p>
<p><strong>(3) 价值估计方法</strong></p>
<ul>
<li>
<p><strong>贝尔曼方法:</strong><span class="math inline">\(Q^*(s,a)=\sum_{s'}P(s'|s,a)\)</span></p>
<p>这里 <span class="math inline">\(*\)</span> 表示最优的,<span class="math inline">\(P(s'|s,a)\)</span> 表示状态转移概率,因为环境可能是随机的,我们需要考虑所有的可能性,所以我们需要对所有可能的下一个状态 <span class="math inline">\(s'\)</span> 进行加权求和,<span class="math inline">\(R(s,a,s')\)</span> 表示即时奖励,它表示状态 <span class="math inline">\(s\)</span> 执行动作 <span class="math inline">\(a\)</span> 并且转移到状态 <span class="math inline">\(s'\)</span> 之后可以立刻获得的回报;最后的 <span class="math inline">\(max_{a'}Q^*(s',a')\)</span> 是方程的精髓,其表示了下一个状态的最大未来价值</p>
<p>一句话总结:在状态 <span class="math inline">\(s\)</span> 选择动作 <span class="math inline">\(a\)</span> 的奖励 = 你马上能获得的奖励+未来所有可能的新状态 <span class="math inline">\(s'\)</span> 的最大价值,并根据其出现概率和折扣因子进行加权</p>
</li>
<li>
<p><strong>蒙特卡洛方法:</strong>蒙特卡洛方法也被称为统计模拟方法,是一种基于概率统计的数据计算方法。等一次完整过程结束后,计算整条路径的真实回报,对于每个状态,MC 算法在 MDP 上采样很多条策略最后求期望值(只要足够多就逼近真实)</p>
</li>
</ul>
<h2 id="基础学习方法">基础学习方法</h2>
<p><strong>(1) 动态规划方法</strong></p>
<p>动态规划是一种 model-based 方法,要求事先知道环境的状态转移函数和奖励函数,即 MDP 过程已知,这种情况下 Agent 并不需要与环境真正交互,直接利用 DP 就可以求解最优策略</p>
<ul>
<li>
<p><strong>策略迭代算法:</strong>分为两步,一是策略评估,先固定一个策略,基于贝尔曼方法计算当前策略的价值函数(需要遍历每一个状态,经过多轮迭代之后状态价值函数收敛);二是策略改进,在当前价值函数下选择回报最大的动作。然后循环往复,直至选择最佳策略</p>
</li>
<li>
<p><strong>价值迭代算法:</strong>值迭代就是解贝尔曼方程的算法,在每一个状态贪心的选择动作价值函数最大的动作来得到改进后的策略(遍历动作选最大动作价值函数)</p>
</li>
</ul>
<blockquote>
<p>知道 MDP 与环境动态,奖励会从终点向前传播</p>
</blockquote>
<p><strong>(2) 时序差分方法</strong></p>
<blockquote>
<p>实际交互,一般只考虑实际的一步动作的奖励</p>
</blockquote>
<p>时序差分是一种 model-free 方法啊,此时写不出 MDP 的状态转移方程,只能通过 agent 与环境交互采样得到的数据来学习策略(实际中大多数环境的状态转移方程都写不出来,所以 model-free 方法应用多)</p>
<p>时序差分方法和蒙特卡洛的相似之处在于可以从样本数据中学习,不需要事先知道环境;和动态规划的相似之处在于根据贝尔曼方程的思想,利用后续状态的价值估计来更新当前状态的估计</p>
<p><strong>SARSA 算法:</strong>SARSA 是一种在线(on-policy)学习算法。在更新 Q 函数时,它使用了智能体实际采取的下一个动作 <span class="math inline">\(a'\)</span> 的动作价值:<span class="math inline">\(Q_t(s', a')\)</span>。这意味着 SARSA 在学习过程中会考虑智能体当前的策略。因此,SARSA 学到的策略与智能体在训练过程中实际执行的策略密切相关</p>
<p><strong>SARSA-<span class="math inline">\(\lambda\)</span> 算法:</strong>考虑多步时序差分(传统是只考虑一步)</p>
<blockquote>
<p><strong><span class="math inline">\(\epsilon-greedy\)</span> 算法</strong>:选择动作,兼顾探索和利用,使用一个探索率小量 <span class="math inline">\(\epsilon\)</span> 来控制利用和探索的比例:生成一个 0-1 的随机数,如果小于 <span class="math inline">\(\epsilon\)</span> 就在所有可能动作中随机选择一个,不然就选择 <span class="math inline">\(Q\)</span> 最大的</p>
</blockquote>
<p><strong>(5) Q-learning 算法(时序差分的一种,很重要所以单列)</strong></p>
<p>在一些真实的场景中我们一开始完全不知道状态转移概率 <span class="math inline">\(P\)</span> 和奖励函数 <span class="math inline">\(R\)</span> 的完整分布,但 Q-learning 不需要知道 <span class="math inline">\(P,R\)</span>,而是在环境中实际探索、采样来学习</p>
<p>它会按照以下公式来更新 <span class="math inline">\(Q\)</span> 的估计值:</p>
<p><span class="math inline">\(Q(s,a)\leftarrow Q(s,a)+\alpha(r+\gamma \ \max_{a'}Q(s',a')-Q(s,a))\)</span></p>
<p><strong>公式说明:</strong></p>
<p>具体而言,他做了一个非常关键的简化,不计算期望,而是用实际观测到的样本来代替它。当智能体从 <span class="math inline">\(s\)</span> 执行 <span class="math inline">\(a\)</span> 得到一个具体的 <span class="math inline">\(r\)</span> 和 <span class="math inline">\(s\)</span> 时,这个组合 <span class="math inline">\((s,a,r,s')\)</span> 就是对环境真实动态的一次采样。然后 Q-learning 用这个样本更新 Q 值,与贝尔曼公式相比,其中 <span class="math inline">\(r\)</span> 是对 <span class="math inline">\(R(s,a,s')\)</span> 的一次采样,<span class="math inline">\(max_{a'}Q(s',a')\)</span> 是对 <span class="math inline">\(max_{a'}Q^*(s',a')\)</span> 的当前估计</p>
<p>可以看到在更新公式中,左边是旧知识,右边是新知识。<span class="math inline">\(\alpha\)</span> 表示学习率,如果 <span class="math inline">\(\alpha\)</span> 很小,智能体学习的比较慢,更相信过去的经验;反之</p>
<p>其核心是维护一个 <strong>Q-table</strong>,该表格记录了在每个状态 s 之下执行每个可能得动作 a 之后能够获得的可能的未来奖励的期望值。Agent 在执行任务的时候只需要查询 Q-table,选择在当前状态下 Q 值最大的那个动作执行</p>
<pre><code class="language-python">class QLearning:
def __init__(self, ncol, nrow, alpha, gamma, n_action=4):
self.Q_table = np.zeros()
self.n_action = n_action
self.alpha = alpha
self.gamma = gamma
self.epsilon = epsilon
def take_action(self, state):
if np.random().random() < self.epsilon:
action = np.random.randint(self.n_action)
else:
action = np.argmax(self.Q_table)
return action
def best_action(self, state):
Q_max = np.max(self.Q_table)
a =
for i in range(self.n_action):
if self.Q_table == Q_max:
a = 1
return a
def update(self, s0, a0, r, s1):
td_error = r + self.gamma * max(self.Q_table) - self.Q_table
self.Q_table += self.alpha * td_error
</code></pre>
<h2 id="dqn">DQN</h2>
<p><strong>(1) 概念</strong></p>
<p>前面讲到 Q-learning 算法使用表格来记录每个状态动作对的 Q 值,然后每次更新表格中对应位置的值就行了。但是如果状态动作空间非常大或者连续变量,那表格法就不能使用了。这个时候就可以用参数化的神经网络来拟合 Q 值函数,由此诞生了 DQN</p>
<p>DQN 使用参数为 w 的神经网络近似 Q 函数,表示为 <span class="math inline">\(Q_w(s,a)\)</span>,我们需要让 Q 值网络的输出与 TD 目标接近,因此可以使用均方误差(无监督学习经常用到,MSEloss)作为损失函数,形式如下:</p>
<p><span class="math inline">\(L_{DQN}=\frac{1}{2N}\sum_{i=1}^{N}^2\)</span></p>
<p><strong>(2) 经验回放</strong></p>
<p>维护一个 <strong>Replay Buffer</strong>,其中存储 <span class="math inline">\(<s,a,r,s'>\)</span> 四元组的样本,先进先出,一般提前订好采样数量和方法。训练的时候则从 Replay Buffer 中采样 batch 进行训练</p>
<p><strong>好处:</strong>使样本满足独立假设,从 MDP 中交互采样的数据不满足独立假设,因为这一时刻的状态和上一时刻的状态有关。非独立同分布的数据会让网络拟合到最近训练的数据上,而经验回放可以打破样本之间的相关性,让其满足独立假设</p>
<p><strong>(3) 目标网络</strong></p>
<p>由于 DQN 更新的目标是让 <span class="math inline">\(Q_w(s,a)\)</span> 逼近 TD 目标 <span class="math inline">\(r+\gamma \ Q_w(s',a')\)</span>,但是我们发现这两部分都是同一个 Q 值神经网络在计算,更新网络参数的时候相目标也在改变,相当于我一边追,目标一边跑,这种 Target Shift 现象很容易导致神经网络训练不稳定</p>
<p>因此 DQN <strong>引入一个目标网络 <span class="math inline">\(Q_{w-}\)</span> 来计算 TD 目标 <span class="math inline">\(y_i = r_i + \gamma \max_{a} Q_{\omega^-}(s_{i+1}, a)\)</span></strong>,初始化为与 Q 值网络一样,但不像 Q 值网络一样每一步都更新参数,而是每隔固定步数直接复制 Q值网络参数,这样就能一定程度保证训练稳定性了</p>
<p><strong>综上所述,DQN 算法的具体流程如下:</strong></p>
<ul>
<li>
<p>用随机的网络参数 <span class="math inline">\(\omega\)</span> 初始化网络 <span class="math inline">\(Q_\omega(s, a)\)</span></p>
</li>
<li>
<p>复制相同的参数 <span class="math inline">\(\omega^- \leftarrow \omega\)</span> 来初始化目标网络 <span class="math inline">\(Q_{\omega'}\)</span></p>
</li>
<li>
<p>初始化经验回放池 <span class="math inline">\(R\)</span></p>
</li>
<li>
<p><strong>for</strong> 序列 <span class="math inline">\(e = 1 \rightarrow E\)</span> <strong>do</strong></p>
<ul>
<li>
<p>获取环境初始状态 <span class="math inline">\(s_1\)</span></p>
</li>
<li>
<p><strong>for</strong> 时间步 <span class="math inline">\(t = 1 \rightarrow T\)</span> <strong>do</strong></p>
<ul>
<li>
<p>根据当前网络<span class="math inline">\(Q_\omega(s, a)\)</span>以<span class="math inline">\(\epsilon\)</span>-贪婪策略选择动作 <span class="math inline">\(a_t\)</span></p>
</li>
<li>
<p>执行动作<span class="math inline">\(a_t\)</span>,获得回报<span class="math inline">\(r_t\)</span>,环境状态变为 <span class="math inline">\(s_{t+1}\)</span></p>
</li>
<li>
<p>将<span class="math inline">\((s_t, a_t, r_t, s_{t+1})\)</span>存储进回放池 <span class="math inline">\(R\)</span> 中</p>
</li>
<li>
<p>若<span class="math inline">\(R\)</span>中数据足够,从<span class="math inline">\(R\)</span>中采样<span class="math inline">\(N\)</span>个数据 <span class="math inline">\(\{(s_i, a_i, r_i, s_{i+1})\}_{i=1,\dots,N}\)</span></p>
</li>
<li>
<p>对每个数据,用目标网络计算 <span class="math inline">\(y_i = r_i + \gamma \max_{a} Q_{\omega^-}(s_{i+1}, a)\)</span></p>
</li>
<li>
<p>最小化目标损失 <span class="math inline">\(L = \frac{1}{2N} \sum_{i}(y_i - Q_\omega(s_i, a_i))^2\)</span>,以此更新当前网络 <span class="math inline">\(Q_\omega\)</span></p>
</li>
<li>
<p>更新目标网络</p>
</li>
</ul>
</li>
<li>
<p><strong>end for</strong></p>
</li>
</ul>
</li>
<li>
<p><strong>end for</strong></p>
</li>
</ul>
<h2 id="策略梯度算法">策略梯度算法</h2>
<p>DQN 系列属于基于值的算法(Value-based),而策略梯度方法是基于策略的算法(Policy-based)</p>
<p>Value-based 算法遇到的问题:<span class="math inline">\(Q(s,a)\)</span> 的输入 <span class="math inline">\(s\)</span> 是智能体的感知态 <span class="math inline">\(s\)</span>,而非环境的真实状态,所有共享同一感知态 <span class="math inline">\(s\)</span> 的真实状态,其动作 <span class="math inline">\(a\)</span> 的 Q 值会被混合计算</p>
<blockquote>
<p>因为当我们使用特征来描述状态空间中的某一个状态时,有可能因为个体观测的限制或者建模的局限,导致真实环境下本来不同的两个状态却再我们建模后拥有相同的特征描述,进而很有可能导致我们的 Value-based 方法无法得到最优解</p>
</blockquote>
<p>那么如何直接显式学习策略呢?这里我们将策略参数化 <span class="math inline">\(\pi_\theta(s)=P(A|s;\theta)\)</span>,通过优化 <span class="math inline">\(\theta\)</span> 来让策略变好</p>
<p>定义一个目标函数 <span class="math inline">\(J(\theta)=\sum_\tau P(\tau,\theta)R(\tau)\)</span>,通过梯度上升来让 <span class="math inline">\(J(\theta)\)</span> 最大。其中 <span class="math inline">\(\tau\)</span> 代表一个 trajectory 轨迹,对目标函数 <span class="math inline">\(J(\theta)\)</span> 求导后得到一个本质上是期望的式子,再根据大数定律得到策略梯度定理:<span class="math inline">\(\nabla_\theta J(\theta)=\mathbb{E}_{\pi_\theta}\)</span></p>
<p>基于策略定理,REINFORCE 算法采用蒙特卡洛方法来估计 <span class="math inline">\(Q^{\pi_\theta}(s,a)\)</span>,对于一个有限步数的环境来说,REINFORCE 算法的策略梯度为:</p>
<p><span class="math inline">\(\nabla_\theta J(\theta)=\mathbb{E}_{\pi_\theta}[\sum_{t=0}^T(\sum_{t=t'}^T\gamma^{t'-t}r_{t'})\nabla_\theta \log\pi_\theta(a|s)]\)</span></p>
<p>通过多次采样轨迹来逼近期望,<span class="math inline">\(\gamma\)</span> 和 <span class="math inline">\(r\)</span> 前面解释过了</p>
<p><strong>REINFORCE 算法的具体算法流程如下:</strong></p>
<ul>
<li>
<p>初始化策略参数</p>
</li>
<li>
<p><strong>for</strong> 序列 <span class="math inline">\(e=1\to E\)</span> <strong>do</strong> :</p>
<ul>
<li>
<p>用当前策略 <span class="math inline">\(\pi_\theta\)</span> 采样轨迹 <span class="math inline">\(\{s_1,a_1,r_1,s_2,a_2,r_2,\cdots,s_T,a_T,r_T\}\)</span></p>
</li>
<li>
<p>计算当前轨迹每个时刻往后的回报 <span class="math inline">\(\sum_{t'=t}^T\gamma^{t'-t}r_{t'}\)</span>,记为 <span class="math inline">\(\psi_t\)</span></p>
</li>
<li>
<p>对 <span class="math inline">\(\theta\)</span> 进行更新,<span class="math inline">\(\theta = \theta+\alpha\sum_t^T\psi_t\nabla_\theta\log\pi_\theta(a_t|s_t)\)</span></p>
</li>
</ul>
</li>
<li>
<p><strong>end for</strong></p>
</li>
</ul>
<h2 id="actor-critic-算法">Actor-Critic 算法</h2>
<p>回顾一下策略梯度算法的公式,REINFORCE 算法使用蒙特卡洛方法(MC)去估计公式中的 Q 值,那么如果不用 MC 方法,而是学习一个 Q 值函数的话那就相当于结合了 Value-based 和 Policy-based 的方法。此时,用 actor 代表策略,用 critic 代表值函数,就有了 Actor-Critic 算法</p>
<p>可以简单理解 Actor-Critic 算法的思想就是:Actor 与环境交互采样轨迹,Critic 评判 Actor 状态、动作的好坏,指导其策略更新的步长和方向</p>
<p>首先我们知道 <span class="math inline">\(\psi_t\)</span> 是对当前 agent 的状态、动作的价值判断,其可以代表一种 Critic 给出的指导。首先,我们需要理解下面这些式子:</p>
<ul>
<li>
<p><strong>轨迹的总回报:</strong><span class="math inline">\(\sum_{t'=0}^T\gamma^{t'}r_{t'}\)</span></p>
</li>
<li>
<p><strong>动作 <span class="math inline">\(a_t\)</span> 之后的回报:</strong><span class="math inline">\(\sum_{t'=t}^T\gamma^{t'-t}r_{t'}\)</span></p>
</li>
<li>
<p><strong>加入基线的改进版本:</strong><span class="math inline">\(\sum_{t'=t}^T\gamma^{t'-t}r_{t'}-b(s_t)\)</span></p>
<p>其中基线函数 <span class="math inline">\(b(s_t)\)</span> 的作用是作为一个参考值,用来减去那些不依赖于当前动作选择的"背景回报"。此外减去基线值可以让不同动作的分数更加集中,从而减小方差。一个比较常用的基线就是状态价值函数 <span class="math inline">\(V(s_t)\)</span><strong>(由其定义可知相当于回报的平均期望,那每一个动作的回报只会优于或劣于它)</strong></p>
</li>
<li>
<p><strong>动作价值函数:</strong><span class="math inline">\(Q^{\pi_\theta}(s_t,a_t)\)</span></p>
<p>其定义是期望值,这里就是学习一个 Q 值网络作为 Critic 学习这个期望</p>
</li>
<li>
<p><strong>优势函数:</strong><span class="math inline">\(A^{\pi_\theta}(s_t,a_t)\)</span></p>
<p>优势函数就是从动作价值函数 Q 值函数减去作为基线的状态价值函数 V 值函数,<strong>意义是在当前状态下选择当前动作比起平均动作的优势(正负代表优于或劣于平均动作)</strong>,所以采用优势函数作为 Critic 是更加合理的指导策略更新的方法</p>
</li>
<li>
<p><strong>时序差分:</strong><span class="math inline">\(r_t+\gamma V^{\pi_\theta}(s_{t+1})-V^{\pi_\theta}(s_t)\)</span></p>
<p>如果要用优势函数来作为 Critic 的话,就意味着我们要同时学习 Q 和 V 两个函数的网络,估计不准确的风险直接变为两倍。因此,在实际的 Actor-Critic 算法中,我们利用 <span class="math inline">\(Q=r+\gamma V\)</span> 时序差分来近似优势函数的</p>
</li>
</ul>
<p>那么得到 Actor-Critic 的策略梯度之后,我们可以根据策略梯度更新 Actor,更新 Critic 则根据前面讲过的 DQN 的方式更新,MSE 损失如下:<span class="math inline">\(L(w)=\frac{1}{2}(r+\gamma V_w(s_{t+1})-V_w(s_t))^2\)</span></p>
<p><strong>Actor-Critic 算法的具体流程如下:</strong></p>
<ul>
<li>
<p>初始化策略网络参数 <span class="math inline">\(\theta\)</span>,价值网络参数 <span class="math inline">\(\omega\)</span></p>
</li>
<li>
<p><strong>for</strong> 序列 <span class="math inline">\(e = 1 \rightarrow E\)</span> <strong>do</strong>:</p>
<ul>
<li>
<p>用当前策略 <span class="math inline">\(\pi_\theta\)</span> 采样轨迹<span class="math inline">\(\{s_1, a_1, r_1, s_2, a_2, r_2, \dots\}\)</span></p>
</li>
<li>
<p>为每一步数据计算 <span class="math inline">\(\delta_t = r_t + \gamma V_\omega(s_{t+1}) - V_\omega(s_t)\)</span></p>
</li>
<li>
<p>更新价值参数 <span class="math inline">\(\omega = \omega + \alpha_\omega \sum_t \delta_t \nabla_\omega V_\omega(s_t)\)</span></p>
</li>
<li>
<p>更新策略参数 <span class="math inline">\(\theta = \theta + \alpha_\theta \sum_t \delta_t \nabla_\theta \log \pi_\theta(a_t|s_t)\)</span></p>
</li>
</ul>
</li>
<li>
<p><strong>end for</strong></p>
</li>
</ul>
<h2 id="ppo-算法">PPO 算法</h2>
<p><strong>(1) TRPO 算法</strong></p>
<p>在讲 PPO 算法之前先讲一下 PPO 的前身 TRPO 算法(信赖域策略优化)。之前讲到的策略梯度算法和 Actor-Critic 算法都是沿着策略梯度的方向更新策略参数 <span class="math inline">\(\theta\)</span>,这就带来一个问题,策略更新步长太长可能导致策略突然变坏,进而影响训练效果。所以 TRPO 就提出要找到一块信赖域 Trust Region,只在这里面更新策略,从而保障策略安全更新</p>
<p>TRPO 推导以及近似计算非常复杂难懂,这里只看 TRPO 的优化目标:</p>
<p><span class="math inline">\(\theta_{k+1} = \arg \max_{\theta} \mathcal{L}(\theta_k, \theta)\)</span><br>
<span class="math inline">\(\text{s.t. } \bar{D}_{KL}(\theta || \theta_k) \le \delta\)</span></p>
<p>其中 <span class="math inline">\(\mathcal{L}(\theta_k, \theta) = \mathbb{E}_{s, a \sim \pi_{\theta_k}} \left[ \frac{\pi_\theta(a|s)}{\pi_{\theta_k}(a|s)} A^{\pi_{\theta_k}}(s, a) \right]\)</span></p>
<p>优化目标用到了重要性采样的性质,这个在 PPO 里面讲解。整体看上述优化目标就是使用优势函数引导策略优化,同时使得当前策略优化的时候和上一个迭代策略的参数的 KL 散度(衡量策略的距离)不要太远(小于一个阈值)</p>
<p><strong>(2) PPO 算法</strong></p>
<p>PPO(近端策略优化)基于 TRPO 的优化目标作出了相应的简化,直接对策略更新的幅度进行 clip 操作,限制策略更新在一个相对安全的范围内</p>
<p>PPO 有两个版本,PPO-penalty 和 PPO-clip,这里分别展示这两个版本的式子:</p>
<ul>
<li>
<p><strong>PPO-penalty:</strong><img src="https://img2024.cnblogs.com/blog/3614753/202603/3614753-20260324144721528-527559386.png" alt="image-20260324114157500" loading="lazy"></p>
</li>
<li>
<p><strong>PPO-clip:</strong><img src="https://img2024.cnblogs.com/blog/3614753/202603/3614753-20260324144721567-2093405769.png" alt="image-20260324114105987" loading="lazy"></p>
</li>
</ul>
<p>其中 <span class="math inline">\(\pi_\theta\)</span> 为 Actor 的策略,<span class="math inline">\(A\)</span> 为该策略下的优势函数(这里式子太复杂了,主要看优化吧)</p>
<p>PPO 在 TRPO 基础上所做的优化解读:</p>
<ul>
<li>
<p><strong>重要性采样:</strong>上述简化的式子可以看出来 PPO 是一个 on-policy 算法,即采样的策略和更新的策略是同一个策略(动作是从 <span class="math inline">\(\pi_\theta\)</span> 采样出来的,优化的也是 <span class="math inline">\(\pi_\theta\)</span>),但是这样存在一个问题就是样本利用效率太低,所以 PPO 利用了重要性采样技术,这样就可以利用之前迭代的策略产生的数据了</p>
</li>
<li>
<p><strong>策略截断:</strong>PPO 实际上是基于 TRPO 算法改进的,但 TRPO 引入了 KL 散度约束并使用了很复杂的数学方法去估计 KL 散度的值。PPO 这里直接进行固定的策略截断,也就是 clip 操作,将当前策略的更新幅度控制在 <span class="math inline">\(\)</span> 之间</p>
<p>PPO-clip 其实就是用过设置一个安全区间,确保策略的更新不会偏离太远,每次策略更新时,PPO 就会计算新策略与旧策略的差异,如果这个差异过大,PPO 会将其裁剪回一个合理的范围内</p>
</li>
<li>
<p><strong>GAE 估计:</strong>PPO 采用了广义优势估计,传统的优势函数估计通常基于单步的 TD 误差或者使用蒙特卡洛方法计算的回报。GAE 通过对不同步数的优势估计进行指数加权平均,从而减少策略梯度方法中的方差,同时保持地偏差,从而提高算法的样本效率和收敛速度</p>
</li>
</ul>
<h2 id="总体回顾">总体回顾</h2>
<p>强化学习的核心就在于贝尔曼方程 <span class="math inline">\(Q^*(s,a)=\sum_{s'}P(s'|s,a)\)</span></p>
<p>回顾一下,TD-target 的意义是当前状态下采取最优动作所得到的回报,用 <span class="math inline">\(r+\gamma \ \max_{a'}Q(s',a')\)</span> 表示,学习的目标函数应该逼近它;传统的时序差分方法使用 TD-error 来更新 Q 值函数 <span class="math inline">\(Q(s,a)\leftarrow Q(s,a)+\alpha(r+\gamma \ \max_{a'}Q(s',a')-Q(s,a))\)</span>,DQN 通过神经网络学习 Q 值函数 <span class="math inline">\(Q_w(s,a)\)</span> 计算其与 TD-target 的 MSE 损失</p>
<blockquote>
<p>那么为什么 TD-target 能够表示最优呢,因为它是根据贝尔曼方程,从最后一步的最优回报(Outcome Reward)往前递归出来的</p>
</blockquote>
<p>策略梯度方法主要是用参数 <span class="math inline">\(\theta\)</span> 学习策略,通过最大化目标函数 <span class="math inline">\(J(\theta)=\sum_\tau P(\tau,\theta)R(\tau)\)</span>,该目标函数表示策略 <span class="math inline">\(\tau\)</span> 的期望回报。通过对该函数求导并利用大数定理可以计算得到策略梯度定理 <span class="math inline">\(\nabla_\theta J(\theta)=\mathbb{E}_{\pi_\theta}\)</span>。又因为 REINFORCE 通过实际采样策略轨迹来逼近期望,因此其策略梯度为 <span class="math inline">\(\nabla_\theta J(\theta)=\mathbb{E}_{\pi_\theta}[\sum_{t=0}^T(\sum_{t=t'}^T\gamma^{t'-t}r_{t'})\nabla_\theta \log\pi_\theta(a|s)]\)</span>,更新方式为 <span class="math inline">\(\theta = \theta+\alpha\sum_t^T\psi_t\nabla_\theta\log\pi_\theta(a_t|s_t)\)</span></p>
<p>Actor-Critic 算法结合了 value-based 和 policy-based 方法,用 actor 代表策略,用 critic 代表值函数。其与 DQN 一样需要学习动作价值函数 Q 函数,然后引入优势函数:<span class="math inline">\(A^{\pi_\theta}(s_t,a_t)\)</span>。优势函数就是从动作价值函数 Q 值函数减去作为基线的状态价值函数 V 值函数,意义是在当前状态下选择当前动作比起平均动作的优势</p>
<p>如果要用优势函数来作为 Critic 的话,就意味着我们要同时学习 Q 和 V 两个函数的网络,估计不准确的风险直接变为两倍。因此,在实际的 Actor-Critic 算法中,我们利用 <span class="math inline">\(Q=r+\gamma V\)</span> 时序差分来近似优势函数的。最后根据策略梯度更新 Actor,更新 Critic 则根据前面讲过的 DQN 的方式更新</p>
<p>TRPO 就提出要找到一块信赖域 Trust Region,只在这里面更新策略,从而保障策略安全更新;而 PPO 基于 TRPO 进行了进一步优化,接对策略更新的幅度进行 clip 操作。具体而言,PPO 通过重要性采样提升了样本利用效率(可以利用之前迭代的策略产生的数据);由于 TRPO 的 KL 散度计算很复杂,PPO 这里直接进行固定的策略截断,也就是 clip 操作;最后还使用 GAE,对不同步数的优势估计进行指数加权平均,从而减少策略梯度方法中的方差,同时保持地偏差</p><br><br>
来源:https://www.cnblogs.com/mianmaner/p/19714400
頁:
[1]