当前位置: 首页 > news >正文

强化学习之 PPO 算法:原理、实现与案例深度剖析

目录

    • 一、引言
    • 二、PPO 算法原理
      • 2.1 策略梯度
      • 2.2 PPO 核心思想
    • 三、PPO 算法公式推导
      • 3.1 重要性采样
      • 3.2 优势函数估计
    • 四、PPO 算法代码实现(以 Python 和 PyTorch 为例)
    • 五、PPO 算法案例应用
      • 5.1 机器人控制
      • 5.2 自动驾驶
    • 六、总结


一、引言

强化学习作为机器学习中的一个重要领域,旨在让智能体通过与环境交互,学习到最优的行为策略以最大化长期累积奖励。近端策略优化(Proximal Policy Optimization,PPO)算法是强化学习中的明星算法,它在诸多领域都取得了令人瞩目的成果。本文将深入探讨 PPO 算法,从原理到代码实现,再到实际案例应用,力求让读者全面掌握这一强大的算法。

二、PPO 算法原理

2.1 策略梯度

在强化学习里,策略梯度是一类关键的优化方法,你可以把它想象成是智能体在学习如何行动时的 “指南针”。假设策略由参数 θ \theta θ 表示,这就好比是智能体的 “行动指南” 参数,智能体在状态 s s s 下采取行动 a a a 的概率为 π θ ( a ∣ s ) \pi_{\theta}(a|s) πθ(as) ,即根据当前的 “行动指南”,在这个状态下选择这个行动的可能性。

策略梯度的目标是最大化累计奖励的期望,用公式表示就是: J ( θ ) = E s 0 , a 0 , ⋯ [ ∑ t = 0 T γ t r ( s t , a t ) ] J(\theta)=\mathbb{E}_{s_0,a_0,\cdots}\left[\sum_{t = 0}^{T}\gamma^{t}r(s_t,a_t)\right] J(θ)=Es0,a0,[t=0Tγtr(st,at)]

这里的 γ \gamma γ 是折扣因子,它的作用是让智能体更关注近期的奖励,因为越往后的奖励可能越不确定,就像我们在做决策时,往往会更看重眼前比较确定的好处。 r ( s t , a t ) r(s_t,a_t) r(st,at) 是在状态 s t s_t st 下采取行动 a t a_t at 获得的奖励,比如玩游戏时,在某个游戏场景下做出某个操作得到的分数。

根据策略梯度定理,策略梯度可以表示为: ∇ θ J ( θ ) = E s , a [ ∇ θ log ⁡ π θ ( a ∣ s ) A ( s , a ) ] \nabla_{\theta}J(\theta)=\mathbb{E}_{s,a}\left[\nabla_{\theta}\log\pi_{\theta}(a|s)A(s,a)\right] θJ(θ)=Es,a[θlogπθ(as)A(s,a)]

这里的 A ( s , a ) A(s,a) A(s,a) 是优势函数,它表示采取行动 a a a 相对于平均策略的优势。简单来说,就是判断这个行动比一般的行动好在哪里,好多少,帮助智能体决定是否要多采取这个行动。

2.2 PPO 核心思想

PPO 算法的核心是在策略更新时,限制策略的变化幅度,避免更新过大导致策略性能急剧下降。这就好像我们在调整自行车的变速器,如果一下子调得太猛,可能车子就没法正常骑了。

它通过引入一个截断的目标函数来实现这一点: L C L I P ( θ ) = E t [ min ⁡ ( r t ( θ ) A ^ t , clip ( r t ( θ ) , 1 − ϵ , 1 + ϵ ) A ^ t ) ] L^{CLIP}(\theta)=\mathbb{E}_{t}\left[\min\left(r_t(\theta)\hat{A}_t, \text{clip}(r_t(\theta), 1 - \epsilon, 1+\epsilon)\hat{A}_t\right)\right] LCLIP(θ)=Et[min(rt(θ)A^t,clip(rt(θ),1ϵ,1+ϵ)A^t)]

其中 r t ( θ ) = π θ ( a t ∣ s t ) π θ o l d ( a t ∣ s t ) r_t(\theta)=\frac{\pi_{\theta}(a_t|s_t)}{\pi_{\theta_{old}}(a_t|s_t)} rt(θ)=πθold(atst)πθ(atst) 是重要性采样比,它反映了新策略和旧策略对于同一个状态 - 行动对的概率差异。 A ^ t \hat{A}_t A^t 是估计的优势函数, ϵ \epsilon ϵ 是截断参数,通常设置为一个较小的值,如 0.2 。这个截断参数就像是给策略更新幅度设定了一个 “安全范围”,在这个范围内更新策略,能保证策略既有所改进,又不会变得太糟糕。

三、PPO 算法公式推导

3.1 重要性采样

重要性采样是 PPO 算法中的关键技术之一。由于直接从当前策略采样数据效率较低,我们可以从旧策略 π θ o l d \pi_{\theta_{old}} πθold 采样数据,然后通过重要性采样比 r t ( θ ) r_t(\theta) rt(θ) 来校正数据的分布。 E s ∼ π θ [ f ( s ) ] ≈ 1 N ∑ i = 1 N π θ ( s i ) π θ o l d ( s i ) f ( s i ) \mathbb{E}_{s\sim\pi_{\theta}}[f(s)]\approx\frac{1}{N}\sum_{i = 1}^{N}\frac{\pi_{\theta}(s_i)}{\pi_{\theta_{old}}(s_i)}f(s_i) Esπθ[f(s)]N1i=1Nπθold(si)πθ(si)f(si)

比如我们要了解一群鸟的飞行习惯,直接去观察所有鸟的飞行轨迹很困难,那我们可以先观察一部分容易观察到的鸟(旧策略采样),然后根据这些鸟和所有鸟的一些特征差异(重要性采样比),来推测整个鸟群的飞行习惯。

3.2 优势函数估计

优势函数 A ( s , a ) A(s,a) A(s,a) 可以通过多种方法估计,常用的是广义优势估计(Generalized Advantage Estimation,GAE): A ^ t = ∑ k = 0 ∞ ( γ λ ) k δ t + k \hat{A}_t=\sum_{k = 0}^{\infty}(\gamma\lambda)^k\delta_{t + k} A^t=k=0(γλ)kδt+k

其中 δ t = r t + γ V ( s t + 1 ) − V ( s t ) \delta_{t}=r_t+\gamma V(s_{t + 1})-V(s_t) δt=rt+γV(st+1)V(st) 是 TD 误差, λ \lambda λ 是 GAE 参数,通常在 0 到 1 之间。优势函数的估计就像是给智能体的行动打分,告诉它每个行动到底有多好,以便它做出更好的决策。

四、PPO 算法代码实现(以 Python 和 PyTorch 为例)

import torchimport torch.nn as nnimport torch.optim as optimimport gymclass Policy(nn.Module):def __init__(self, state_dim, action_dim):super(Policy, self).__init__()self.fc1 = nn.Linear(state_dim, 64)self.fc2 = nn.Linear(64, 64)self.mu_head = nn.Linear(64, action_dim)self.log_std_head = nn.Linear(64, action_dim)def forward(self, x):x = torch.relu(self.fc1(x))x = torch.relu(self.fc2(x))mu = torch.tanh(self.mu_head(x))log_std = self.log_std_head(x)std = torch.exp(log_std)dist = torch.distributions.Normal(mu, std)return distclass Value(nn.Module):def __init__(self, state_dim):super(Value, self).__init__()self.fc1 = nn.Linear(state_dim, 64)self.fc2 = nn.Linear(64, 64)self.v_head = nn.Linear(64, 1)def forward(self, x):x = torch.relu(self.fc1(x))x = torch.relu(self.fc2(x))v = self.v_head(x)return vdef ppo_update(policy, value, optimizer_policy, optimizer_value, states, actions, rewards, dones, gamma=0.99,clip_epsilon=0.2, lambda_gae=0.95):states = torch.FloatTensor(states)actions = torch.FloatTensor(actions)rewards = torch.FloatTensor(rewards)dones = torch.FloatTensor(dones)values = value(states).squeeze(1)returns = []gae = 0for i in reversed(range(len(rewards))):if i == len(rewards) - 1:next_value = 0else:next_value = values[i + 1]delta = rewards[i] + gamma * next_value * (1 - dones[i]) - values[i]gae = delta + gamma * lambda_gae * (1 - dones[i]) * gaereturns.insert(0, gae + values[i])returns = torch.FloatTensor(returns)old_dist = policy(states)old_log_probs = old_dist.log_prob(actions).sum(-1)for _ in range(3):dist = policy(states)log_probs = dist.log_prob(actions).sum(-1)ratios = torch.exp(log_probs - old_log_probs)advantages = returns - values.detach()surr1 = ratios * advantagessurr2 = torch.clamp(ratios, 1 - clip_epsilon, 1 + clip_epsilon) * advantagespolicy_loss = -torch.min(surr1, surr2).mean()optimizer_policy.zero_grad()policy_loss.backward()optimizer_policy.step()value_loss = nn.MSELoss()(value(states).squeeze(1), returns)optimizer_value.zero_grad()value_loss.backward()optimizer_value.step()def train_ppo(env_name, num_episodes=1000):env = gym.make(env_name)state_dim = env.observation_space.shape[0]action_dim = env.action_space.shape[0]policy = Policy(state_dim, action_dim)value = Value(state_dim)optimizer_policy = optim.Adam(policy.parameters(), lr=3e-4)optimizer_value = optim.Adam(value.parameters(), lr=3e-4)for episode in range(num_episodes):states, actions, rewards, dones = [], [], [], []state = env.reset()done = Falsewhile not done:state = torch.FloatTensor(state)dist = policy(state)action = dist.sample()next_state, reward, done, _ = env.step(action.detach().numpy())states.append(state)actions.append(action)rewards.append(reward)dones.append(done)state = next_stateppo_update(policy, value, optimizer_policy, optimizer_value, states, actions, rewards, dones)if episode % 100 == 0:total_reward = 0state = env.reset()done = Falsewhile not done:state = torch.FloatTensor(state)dist = policy(state)action = dist.meannext_state, reward, done, _ = env.step(action.detach().numpy())total_reward += rewardstate = next_stateprint(f"Episode {episode}, Average Reward: {total_reward}")if __name__ == "__main__":train_ppo('Pendulum-v1')

五、PPO 算法案例应用

5.1 机器人控制

在机器人控制领域,PPO 算法可以用于训练机器人的运动策略。例如,训练一个双足机器人行走,机器人的状态可以包括关节角度、速度等信息,行动则是关节的控制指令。通过 PPO 算法,机器人可以学习到如何根据当前状态调整关节控制,以实现稳定高效的行走。

5.2 自动驾驶

在自动驾驶场景中,车辆的状态包括位置、速度、周围环境感知信息等,行动可以是加速、减速、转向等操作。PPO 算法可以让自动驾驶系统学习到在不同路况和环境下的最优驾驶策略,提高行驶的安全性和效率。

六、总结

PPO 算法作为强化学习中的优秀算法,以其高效的学习能力和良好的稳定性在多个领域得到了广泛应用。通过深入理解其原理、公式推导,结合代码实现和实际案例分析,我们能够更好地掌握和运用这一算法,为解决各种复杂的实际问题提供有力的工具。

相关文章:

强化学习之 PPO 算法:原理、实现与案例深度剖析

目录 一、引言二、PPO 算法原理2.1 策略梯度2.2 PPO 核心思想 三、PPO 算法公式推导3.1 重要性采样3.2 优势函数估计 四、PPO 算法代码实现(以 Python 和 PyTorch 为例)五、PPO 算法案例应用5.1 机器人控制5.2 自动驾驶 六、总结 一、引言 强化学习作为…...

vue-点击生成动态值,动态渲染回显输入框

1.前言 动态点击生成数值&#xff0c;回显输入框&#xff0c;并绑定。 2.实现 <template><div style"display:flex;align-items: center;flex-direction:row"><a-input:key"inputKey"v-model"uploadData[peo.field]"placehold…...

高性能 :OpenAI Triton Open-source GPU programming Language LINUX 环境配置

目录 配置triton环境cudabuild-essential带有pip的python环境直接安装pipanaconda 安装 triton 环境pip install tritonpip install torch 运行test示例vector-add.pylaunch.json 配置triton环境 cuda wget http://developer.download.nvidia.com/compute/cuda/11.0.2/local_…...

TCP 端口号为何位于首部前四个字节?协议设计的智慧与启示

知乎的一个问题很有意思&#xff1a;“为什么在TCP首部中要把TCP的端口号放入最开始的四个字节&#xff1f;” 这种问题很适合我这种搞历史的人&#xff0c;大年初一我给出了一个简短的解释&#xff0c;但仔细探究这个问题&#xff0c;我们将会获得 TCP/IP 被定义的过程。 文…...

HTML之JavaScript函数声明

HTML之JavaScript函数声明 1. function 函数名(){}2. var 函数名 function(){}<!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1…...

R 数组:高效数据处理的基础

R 数组&#xff1a;高效数据处理的基础 引言 在数据科学和统计分析领域&#xff0c;R 语言以其强大的数据处理和分析能力而备受推崇。R 数组是 R 语言中用于存储和操作数据的基本数据结构。本文将详细介绍 R 数组的创建、操作和优化&#xff0c;帮助读者掌握 R 数组的使用技巧…...

git服务器搭建,gitea服务搭建,使用systemclt管理服务

文章目录 页面展示使用二进制文件安装git服务下载选择架构使用wget下载安装 验证 GPG 签名服务器设置准备环境创建systemctl文件 备份与恢复备份命令 (dump)恢复命令 (restore) 页面展示 使用二进制文件安装git服务 所有打包的二进制程序均包含 SQLite&#xff0c;MySQL 和 Po…...

Pdf手册阅读(1)--数字签名篇

原文阅读摘要 PDF支持的数字签名&#xff0c; 不仅仅是公私钥签名&#xff0c;还可以是指纹、手写、虹膜等生物识别签名。PDF签名的计算方式&#xff0c;可以基于字节范围进行计算&#xff0c;也可以基于Pdf 对象&#xff08;pdf object&#xff09;进行计算。 PDF文件可能包…...

嵌入式WebRTC压缩至670K,目标将so动态库压缩至500K,.a静态库还可以更小

最近把EasyRTC的效果发布出去给各大IPC厂商体验了一下&#xff0c;直接就用EasyRTC与各个厂商的负责人进行的通话&#xff0c;在通话中&#xff0c;用户就反馈效果确实不错&#xff01; 这两天有用户要在海思hi3516cv610上使用EasyRTC&#xff0c;工具链是&#xff1a;gcc-2024…...

百度高德地图坐标转换

百度地图和高德地图的侧重点不太一样。同样一个地名&#xff0c;在百度地图网站上搜索到的地点可能是商业网点&#xff0c;在高德地图网站上搜索到的地点可能是自然行政地点。 高德地图api 在高德地图中&#xff0c;搜索地名&#xff0c;如“乱石头川”&#xff0c;该地名会出…...

ES 索引结构

ES 既不像 MySQL 这样有严格的 Schema&#xff0c;也不像 MongoDB 那样完全无 Schema&#xff0c;而是介于两者之间。 1️⃣ ES 的 Schema 模式 ES 默认是 Schema-less&#xff08;无模式&#xff09; 的&#xff0c;允许动态添加字段。 但 ES 也支持 Schema&#xff08;映射 …...

HPM_SDK应用本地化——基于6750evkmini

文章目录 前言一、准备工作1、下载官方的SDK2、解压SDK 二、实操1、新建目标工程文件夹2、回到SDK中将相关文件复制1、Borad文件夹2、hello_world文件夹 三、实验现象总结 前言 为什么要对sdk进行应用本地化&#xff1f;在嵌入式开发中我们一般将官方提供的SDK作为参考&#x…...

【deepseek-r1本地部署】

首先需要安装ollama,之前已经安装过了&#xff0c;这里不展示细节 在cmd中输入官网安装命令&#xff1a;ollama run deepseek-r1:32b&#xff0c;开始下载 出现success后&#xff0c;下载完成 接下来就可以使用了&#xff0c;不过是用cmd来运行使用 可以安装UI可视化界面&a…...

查询语句来提取 detail 字段中包含 xxx 的 URL 里的 commodity/ 后面的数字串

您可以使用以下 SQL 查询语句来提取 detail 字段中包含 oss.kxlist.com 的 URL 里的 commodity/ 后面的数字串&#xff1a; <p><img style"max-width:100%;" src"https://oss.kxlist.com//8a989a0c55e4a7900155e7fd7971000b/commodity/20170925/20170…...

堆排序

目录 堆排序&#xff08;不稳定&#xff09;&#xff1a; 代码实现&#xff1a; 思路分析&#xff1a; 总结&#xff1a; 堆排序&#xff08;不稳定&#xff09;&#xff1a; 如果想要一段数据从小到大进行排序&#xff0c;则要先建立大根堆&#xff0c;因为这样每次堆顶上都能…...

【MySQL】我在广州学Mysql 系列—— 数据备份与还原

ℹ️大家好&#xff0c;我是练小杰&#xff0c;今天周一&#xff0c;过两天就是元宵节了&#xff0c;今年元宵节各位又要怎么过呢&#xff01;&#xff01; 本文主要对Mysql数据库中的数据备份与还原内容进行讨论&#xff01;&#xff01; 回顾&#xff1a;&#x1f449;【MySQ…...

【LeetCode Hot100 双指针】移动零、盛最多水的容器、三数之和、接雨水

双指针 1. 移动零题目描述解题思路关键思路&#xff1a;步骤&#xff1a;时间复杂度&#xff1a;空间复杂度&#xff1a; 代码实现 2. 盛最多水的容器题目解析解题思路代码实现 3. 三数之和问题描述&#xff1a;解题思路&#xff1a;算法步骤&#xff1a;代码实现&#xff1a; …...

HTML应用指南:利用POST请求获取接入比亚迪业态的充电桩位置信息

在新能源汽车快速发展的今天,充电桩的分布和可用性成为了影响用户体验的关键因素之一。比亚迪作为全球领先的新能源汽车制造商,不仅在车辆制造方面取得了卓越成就,也在充电基础设施建设上投入了大量资源。为了帮助用户更方便地找到比亚迪充电桩的位置,本篇文章,我们将探究…...

Android车机DIY开发之软件篇(十二) AOSP12下载编译

Android车机DIY开发之软件篇(十二) AOSP12下载编译 sudo apt-get update sudo apt-get install git-core gnupg flex bison gperf build-essential zip curl zlib1g-dev gcc-multilib gmultilib libc6-dev-i386 lib32ncurses5-dev libx11-dev lib32z-dev ccache libgl1-mesa-…...

Jenkins+gitee 搭建自动化部署

Jenkinsgitee 搭建自动化部署 环境说明&#xff1a; 软件版本备注CentOS8.5.2111JDK1.8.0_211Maven3.8.8git2.27.0Jenkins2.319最好选稳定版本&#xff0c;不然安装插件有点麻烦 一、安装Jenkins程序 1、到官网下载相应的版本war或者直接使用yum安装 Jenkins官网下载 直接…...

【杂谈】-递归进化:人工智能的自我改进与监管挑战

递归进化&#xff1a;人工智能的自我改进与监管挑战 文章目录 递归进化&#xff1a;人工智能的自我改进与监管挑战1、自我改进型人工智能的崛起2、人工智能如何挑战人类监管&#xff1f;3、确保人工智能受控的策略4、人类在人工智能发展中的角色5、平衡自主性与控制力6、总结与…...

黑马Mybatis

Mybatis 表现层&#xff1a;页面展示 业务层&#xff1a;逻辑处理 持久层&#xff1a;持久数据化保存 在这里插入图片描述 Mybatis快速入门 ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/6501c2109c4442118ceb6014725e48e4.png //logback.xml <?xml ver…...

uni-app学习笔记二十二---使用vite.config.js全局导入常用依赖

在前面的练习中&#xff0c;每个页面需要使用ref&#xff0c;onShow等生命周期钩子函数时都需要像下面这样导入 import {onMounted, ref} from "vue" 如果不想每个页面都导入&#xff0c;需要使用node.js命令npm安装unplugin-auto-import npm install unplugin-au…...

测试markdown--肇兴

day1&#xff1a; 1、去程&#xff1a;7:04 --11:32高铁 高铁右转上售票大厅2楼&#xff0c;穿过候车厅下一楼&#xff0c;上大巴车 &#xffe5;10/人 **2、到达&#xff1a;**12点多到达寨子&#xff0c;买门票&#xff0c;美团/抖音&#xff1a;&#xffe5;78人 3、中饭&a…...

【HTML-16】深入理解HTML中的块元素与行内元素

HTML元素根据其显示特性可以分为两大类&#xff1a;块元素(Block-level Elements)和行内元素(Inline Elements)。理解这两者的区别对于构建良好的网页布局至关重要。本文将全面解析这两种元素的特性、区别以及实际应用场景。 1. 块元素(Block-level Elements) 1.1 基本特性 …...

CMake控制VS2022项目文件分组

我们可以通过 CMake 控制源文件的组织结构,使它们在 VS 解决方案资源管理器中以“组”(Filter)的形式进行分类展示。 🎯 目标 通过 CMake 脚本将 .cpp、.h 等源文件分组显示在 Visual Studio 2022 的解决方案资源管理器中。 ✅ 支持的方法汇总(共4种) 方法描述是否推荐…...

大语言模型(LLM)中的KV缓存压缩与动态稀疏注意力机制设计

随着大语言模型&#xff08;LLM&#xff09;参数规模的增长&#xff0c;推理阶段的内存占用和计算复杂度成为核心挑战。传统注意力机制的计算复杂度随序列长度呈二次方增长&#xff0c;而KV缓存的内存消耗可能高达数十GB&#xff08;例如Llama2-7B处理100K token时需50GB内存&a…...

【电力电子】基于STM32F103C8T6单片机双极性SPWM逆变(硬件篇)

本项目是基于 STM32F103C8T6 微控制器的 SPWM(正弦脉宽调制)电源模块,能够生成可调频率和幅值的正弦波交流电源输出。该项目适用于逆变器、UPS电源、变频器等应用场景。 供电电源 输入电压采集 上图为本设计的电源电路,图中 D1 为二极管, 其目的是防止正负极电源反接, …...

Mysql8 忘记密码重置,以及问题解决

1.使用免密登录 找到配置MySQL文件&#xff0c;我的文件路径是/etc/mysql/my.cnf&#xff0c;有的人的是/etc/mysql/mysql.cnf 在里最后加入 skip-grant-tables重启MySQL服务 service mysql restartShutting down MySQL… SUCCESS! Starting MySQL… SUCCESS! 重启成功 2.登…...

Java数值运算常见陷阱与规避方法

整数除法中的舍入问题 问题现象 当开发者预期进行浮点除法却误用整数除法时,会出现小数部分被截断的情况。典型错误模式如下: void process(int value) {double half = value / 2; // 整数除法导致截断// 使用half变量 }此时...