普通策略梯度算法原理及PyTorch实现【VPG】

有没有想过强化学习 (RL) 是如何工作的?

在本文中,我们将从头开始构建最简单的强化学习形式之一 —普通策略梯度(VPG)算法。 然后,我们将训练它完成著名的 CartPole 挑战 — 学习从左向右移动购物车以平衡杆子。 在此过程中,我们还将完成对 OpenAI 的 Spinning Up 学习资源的第一个挑战。

NSDT工具推荐: Three.js AI纹理开发包 - YOLO合成数据生成器 - GLTF/GLB在线编辑 - 3D模型格式在线转换 - 可编程3D场景编辑器 - REVIT导出3D模型插件 - 3D模型语义搜索引擎

本文的代码可以在 这里 找到。

1、我们的方法

我们将通过创建一个简单的深度学习模型来解决这个问题,该模型接受观察并输出随机策略(即采取每个可能行动的概率)。

然后,我们需要做的就是通过在环境中采取行动并使用此策略来收集经验。

当我们有足够的批量经验(几个episode经验的集合)后,我们需要转向梯度下降来改进模型。 在较高层面上,我们希望增加策略的预期回报,这意味着调整权重和偏差以增加高预期回报行动的概率。 就 VPG 而言,这意味着使用策略梯度定理,该定理给出了该预期回报的梯度方程(如下所示)。

这就是全部内容了—所以让我们开始编码吧!

2、创建模型

我们将首先创建一个带有一个隐藏层的非常简单的模型。 第一个线性层从 CartPole 的观察空间获取输入特征,最后一层返回可能结果的值。

def create_model(number_observation_features: int, number_actions: int) -> nn.Module:
    """Create the MLP model

    Args:
        number_observation_features (int): Number of features in the (flat)
        observation tensor
        number_actions (int): Number of actions

    Returns:
        nn.Module: Simple MLP model
    """
    hidden_layer_features = 32

    return nn.Sequential(
        nn.Linear(in_features=number_observation_features,
                  out_features=hidden_layer_features),
        nn.ReLU(),
        nn.Linear(in_features=hidden_layer_features,
                  out_features=number_actions),
    )

3、获取策略

我们还需要为每个时间步获取一个模型策略(以便我们知道如何采取行动)。 为此,我们将创建一个 get_policy 函数,该函数使用模型输出策略下每个操作的概率。 然后,我们可以返回一个分类(多项式)分布,该分布可用于选择根据这些概率随机分布的特定动作。

def get_policy(model: nn.Module, observation: np.ndarray) -> Categorical:
    """Get the policy from the model, for a specific observation

    Args:
        model (nn.Module): MLP model
        observation (np.ndarray): Environment observation

    Returns:
        Categorical: Multinomial distribution parameterized by model logits
    """
    observation_tensor = torch.as_tensor(observation, dtype=torch.float32)
    logits = model(observation_tensor)

    # Categorical will also normalize the logits for us
    return Categorical(logits=logits)

4、从策略中采样动作

从这个分类分布中,对于每个时间步长,我们可以对其进行采样以返回一个动作。 我们还将获得该动作的对数概率,这在稍后计算梯度时会很有用。

def get_action(policy: Categorical) -> tuple[int, float]:
    """Sample an action from the policy

    Args:
        policy (Categorical): Policy

    Returns:
        tuple[int, float]: Tuple of the action and it's log probability
    """
    action = policy.sample()  # Unit tensor

    # Converts to an int, as this is what Gym environments require
    action_int = action.item()

    # Calculate the log probability of the action, which is required for
    # calculating the loss later
    log_probability_action = policy.log_prob(action)

    return action_int, log_probability_action

5、计算损失

梯度的完整推导如这里所示。 宽松地说,它是每个状态-动作对的对数概率之和乘以该对所属的整个轨迹的回报的梯度。 额外的外层和汇总若干个情节(即一批),因此我们有重要的数据。

要使用 PyTorch 计算此值,我们可以做的是计算下面的伪损失,然后使用 .backward() 获取上面的梯度(注意我们刚刚删除了梯度项):

这通常被称为损失,但它并不是真正的损失,因为它不依赖于模型的性能。 它只是对于获取策略梯度有用。

def calculate_loss(epoch_log_probability_actions: torch.Tensor, epoch_action_rewards: torch.Tensor) -> float:
    """Calculate the 'loss' required to get the policy gradient

    Formula for gradient at
    https://spinningup.openai.com/en/latest/spinningup/rl_intro3.html#deriving-the-simplest-policy-gradient

    Note that this isn't really loss - it's just the sum of the log probability
    of each action times the episode return. We calculate this so we can
    back-propagate to get the policy gradient.

    Args:
        epoch_log_probability_actions (torch.Tensor): Log probabilities of the
            actions taken
        epoch_action_rewards (torch.Tensor): Rewards for each of these actions

    Returns:
        float: Pseudo-loss
    """
    return -(epoch_log_probability_actions * epoch_action_rewards).mean()

6、单个epoch训练

将以上所有内容放在一起,我们现在准备好训练一个epoch了。 为此,我们只需循环播放情节(episode)即可创建批次。 在每个情节中,创建一系列可用于训练模型的动作和奖励(即经验)。

def train_one_epoch(env: gym.Env, model: nn.Module, optimizer: Optimizer, max_timesteps=5000, episode_timesteps=200) -> float:
    """Train the model for one epoch

    Args:
        env (gym.Env): Gym environment
        model (nn.Module): Model
        optimizer (Optimizer): Optimizer
        max_timesteps (int, optional): Max timesteps per epoch. Note if an
            episode is part-way through, it will still complete before finishing
            the epoch. Defaults to 5000.
        episode_timesteps (int, optional): Timesteps per episode. Defaults to 200.

    Returns:
        float: Average return from the epoch
    """
    epoch_total_timesteps = 0

    # Returns from each episode (to keep track of progress)
    epoch_returns: list[int] = []

    # Action log probabilities and rewards per step (for calculating loss)
    epoch_log_probability_actions = []
    epoch_action_rewards = []

    # Loop through episodes
    while True:

        # Stop if we've done over the total number of timesteps
        if epoch_total_timesteps > max_timesteps:
            break

        # Running total of this episode's rewards
        episode_reward: int = 0

        # Reset the environment and get a fresh observation
        observation = env.reset()

        # Loop through timesteps until the episode is done (or the max is hit)
        for timestep in range(episode_timesteps):
            epoch_total_timesteps += 1

            # Get the policy and act
            policy = get_policy(model, observation)
            action, log_probability_action = get_action(policy)
            observation, reward, done, _ = env.step(action)

            # Increment the episode rewards
            episode_reward += reward

            # Add epoch action log probabilities
            epoch_log_probability_actions.append(log_probability_action)

            # Finish the action loop if this episode is done
            if done == True:
                # Add one reward per timestep
                for _ in range(timestep + 1):
                    epoch_action_rewards.append(episode_reward)

                break

        # Increment the epoch returns
        epoch_returns.append(episode_reward)

    # Calculate the policy gradient, and use it to step the weights & biases
    epoch_loss = calculate_loss(torch.stack(
        epoch_log_probability_actions),
        torch.as_tensor(
        epoch_action_rewards, dtype=torch.float32)
    )

    epoch_loss.backward()
    optimizer.step()
    optimizer.zero_grad()

    return np.mean(epoch_returns)

7、运行算法

现在可以运行算法了。

def train(epochs=40) -> None:
    """Train a Vanilla Policy Gradient model on CartPole

    Args:
        epochs (int, optional): The number of epochs to run for. Defaults to 50.
    """

    # Create the Gym Environment
    env = gym.make('CartPole-v0')

    # Use random seeds (to make experiments deterministic)
    torch.manual_seed(0)
    env.seed(0)

    # Create the MLP model
    number_observation_features = env.observation_space.shape[0]
    number_actions = env.action_space.n
    model = create_model(number_observation_features, number_actions)

    # Create the optimizer
    optimizer = Adam(model.parameters(), 1e-2)

    # Loop for each epoch
    for epoch in range(epochs):
        average_return = train_one_epoch(env, model, optimizer)
        print('epoch: %3d \t return: %.3f' % (epoch, average_return))


if __name__ == '__main__':
    train()

大约 40 个 epoch 后,可以看到模型已经很好地学习了环境(得分 180+/ 200):

epoch:  26       return: 118.070
epoch:  27       return: 114.659
epoch:  28       return: 135.405
epoch:  29       return: 144.000
epoch:  30       return: 143.972
epoch:  31       return: 152.091
epoch:  32       return: 166.065
epoch:  33       return: 162.613
epoch:  34       return: 166.806
epoch:  35       return: 172.933
epoch:  36       return: 173.241
epoch:  37       return: 181.071
epoch:  38       return: 186.222
epoch:  39       return: 176.793

原文链接:普通策略梯度实现 - BimAnt

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/214938.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

正则表达式从放弃到入门(2):grep命令详解

正则表达式从放弃到入门(2):grep命令详解 总结 本博文转载自 这是一篇”正则表达式”扫盲贴,如果你还不理解什么是正则表达式,看这篇文章就对了。 如果你是一个新手,请从头阅读这篇文章,如果你…

苹果配件妙控鼠标、键盘、触控板值得入手吗

大家好,我是极智视界,欢迎关注我的公众号,获取我的更多前沿科技分享 邀您加入我的知识星球「极智视界」,星球内有超多好玩的项目实战源码和资源下载,链接:https://t.zsxq.com/0aiNxERDq 苹果的优质和成功绝…

[进程控制]模拟实现命令行解释器shell

文章目录 1.字符串切割函数2.chdir()接口3.模拟实现shell 1.字符串切割函数 2.chdir()接口 3.模拟实现shell 模拟实现的shell下删除: ctrlbackspace模拟实现下table/上下左右箭头无法使用[demo] #include <stdio.h> #include <stdlib.h> #include <string.h&g…

高级开发实战MySQL、Redis、MongoDB 数据库,让你一课掌握核心技能

在现代软件开发中&#xff0c;数据库是不可或缺的一部分。MySQL、Redis和MongoDB作为三种常见的数据库系统&#xff0c;具有各自独特的特点和优势&#xff0c;对于高级开发者来说&#xff0c;掌握这三种数据库的核心技能至关重要。本文将带您通过实战的方式&#xff0c;学习如何…

pybind11教程

pybind11教程 文章目录 pybind11教程1. pybind11简介2. cmake使用pybind11教程3. pybind11的历史 1. pybind11简介 项目的GitHub地址为&#xff1a; pybind11 pybind11 是一个轻量级的头文件库&#xff0c;用于在 Python 和 C 之间进行互操作。它允许 C 代码被 Python 调用&am…

22、为什么是卷积?

(本文已加入“计算机视觉入门与调优”专栏,点击专栏查看更多文章信息) 我们先看一看神经网络(或者叫一个AI模型),是如何完成一张图片的推理的。 你肯定听说过阿尔法狗大战柯洁的故事,当时新闻一出,不知大家什么反应,反正我是被震撼到了。机器竟然学到了那么多的棋谱,…

OpenAI发生的大事件总结!

在 11 月的最后一天&#xff0c;OpenAI 官网发布了一则公告&#xff0c;宣布 Sam Altman 再次担任首席执行官&#xff0c;并成立了新的初始董事会。这项持续了 12 天的事件终于得到了解决&#xff0c;OpenAI 回到了正常运营轨道上。 一切仍然保持不变&#xff1a; Sam Altman仍…

免费分享一套开源SpringCloud支持全套二轮四轮全套源码支持云快充1.5、云快充1.6

文章目录 一、产品功能部分截图1.手机端&#xff08;小程序、安卓、ios&#xff09;2.PC端 二、小程序体验账号以及PC后台体验账号1.小程序体验账号2.PC后台体验账号关注公众号获取最新资讯 三、产品简介&#xff1f;1. 充电桩云平台&#xff08;含硬件充电桩&#xff09;&…

若依框架分页

文章目录 一、分页功能解析1.前端代码分析2.后端代码分析3. LIMIT含义 二、自定义MyPage,多态获取total1.定义MyPage类和对应的调用方法 一、分页功能解析 1.前端代码分析 页面代码 封装的api请求 接口请求 2.后端代码分析 controller代码 - startPage() getDataTable(…

编程中常见的技术难题有哪些?By AI

编程对于现代社会发展的重要性 编程&#xff0c;即按照特定的规则和逻辑&#xff0c;为计算机设计指令的过程&#xff0c;已经深深地融入现代社会的各个角落。它对人们的生活、工作和科技发展产生了深远的影响。 首先&#xff0c;编程改变了人们的生活方式。如今&#xff0c;…

力扣 --- 最后一个单词的长度

题目描述&#xff1a; 给你一个字符串 s&#xff0c;由若干单词组成&#xff0c;单词前后用一些空格字符隔开。返回字符串中 最后一个 单词的长度。 单词 是指仅由字母组成、不包含任何空格字符的最大子字符串。 示例 1&#xff1a; 输入&#xff1a;s "Hello World&…

van-list的onload事件多次触发的问题

一、问题描述 如图所示&#xff0c;页面刷新的时候&#xff0c;调了3次接口&#xff08;总共27条数据&#xff0c;我分页10条&#xff09;&#xff0c;一直莫名奇妙的 我期望是默认加载第一页&#xff0c;然后我上拉的时候再push第二页的数据 二、解决方法 还是要多看文档 1…

非标设计之气缸概述

气缸的组成&#xff1a; 气缸的分类 单作用气缸&#xff1a; 活塞仅一侧供气&#xff0c;气压推动活塞产生推力伸出&#xff0c;靠弹簧或自重返回。 双作用气缸&#xff1a; 气缸活塞两侧都有气压力&#xff0c;来实现前进或后退动作。 气缸的缓冲 但是&#xff0c;气缸也…

基于Java SSM框架+Vue实现疫情期间医院门诊网站项目【项目源码+论文说明】

基于java的SSM框架Vue实现疫情期间医院门诊网站演示 摘要 21世纪的到来&#xff0c;国家的方方面面、各行各业都在努力与现代的先进技术接轨&#xff0c;智能科技时代崛起的优势&#xff0c;医院门诊管理系统当然也不能排除在外。疫情期间医院门诊管理系统是以实际运用为开发背…

WPF图像处理之像素操作

文章目录 框架准备图像转灰度像素操作 WPF Image控件的初步使用 框架准备 为了演示C#中的图像处理功能&#xff0c;先在xaml中导入一张图片&#xff0c;并且预留出一个WrapPanel&#xff0c;用于存放操作按钮。 <TabControl TabStripPlacement"Left"><Ta…

前后端数据传输格式(下)

作者简介&#xff1a;大家好&#xff0c;我是smart哥&#xff0c;前中兴通讯、美团架构师&#xff0c;现某互联网公司CTO 联系qq&#xff1a;184480602&#xff0c;加我进群&#xff0c;大家一起学习&#xff0c;一起进步&#xff0c;一起对抗互联网寒冬 上篇主要复习了HTTP以及…

MySQL 的 NULL 是怎么存储的?

目录 一、MySQL介绍 二、什么是NULL 三、MySQL 的 NULL 是怎么存储的 一、MySQL介绍 MySQL是一种关系型数据库管理系统&#xff08;RDBMS&#xff09;&#xff0c;它是一种开源软件&#xff0c;由瑞典MySQL AB公司开发&#xff0c;后被Sun Microsystems收购&#xff0c;现在…

阿里云租赁费用_阿里云服务器多配置报价表

阿里云服务器租用费用&#xff0c;云服务器ECS经济型e实例2核2G、3M固定带宽99元一年、轻量应用服务器2核2G3M带宽轻量服务器一年87元&#xff0c;2核4G4M带宽轻量服务器一年165元12个月&#xff0c;ECS云服务器e系列2核2G配置99元一年、2核4G配置365元一年、2核8G配置522元一年…

组网技术-交换机

交换机&#xff1a; 分类&#xff1a; 根据交换方式划分&#xff1a; 1.存储转发交换&#xff1a;交换机对输入的数据包先进行缓存、验证、碎片过滤&#xff0c;然后进行转发。 时延大&#xff0c;但是可以提供差错校验&#xff0c;并支持不同速度的输入、输出端口间的交换…

【Altera】Cyclone10 FPGA DDR3使用

目录 开发板 硬件 框图 原理图 测试工具 DDR IP核配置 调试及遇到的问题 读写仲裁时序 问题1.拉高read后&#xff0c;wait一直没反应 问题2.DDR校正不过的一个可能性 延伸学习 开发板 Intel官方提供c10的开发套件&#xff1a;Intel Cyclone 10 GX FPGA Development …