(12-4-1)TRPO算法优化实战:基于矩阵低秩分解的TRPO

12.4  TRPO算法优化实战:基于矩阵低秩分解的TRPO

在现实应用中,强化学习中的大多数方法使用策略梯度(PG)方法来学习将状态映射到动作的参数化随机策略。标准方法是通过神经网络(NN)实现这种映射,其参数使用随机梯度下降进行优化。然而,PG方法容易产生大的策略更新,可能导致学习效率低下。而在本章介绍信赖区域策略优化(TRPO)这样的信赖区域算法限制了策略更新步骤,在本节的内容中,将介绍一个TRPO算法的优化策略:使用基于低秩矩阵的模型作为TRPO算法参数估计的高效替代方法,并通过具体实例进行了演示。通过将随机策略的参数收集到矩阵中并应用矩阵补全技术,促进并强制实施低秩。本实例的执行结果表明,基于低秩矩阵的策略模型有效地减少了与NN模型相比的计算和样本复杂性,同时保持了可比较的累积奖励。

实例12-5:TRPO算法优化:NN-TRPO 和 TRLRPO(源码路径:daima\12\matrix-low-rank-trpo-main

12.4.1  优化策略:NN-TRPO 和 TRLRPO

NN-TRPO(Neural Network Trust Region Policy Optimization)和TRLRPO(Trust Region Linear Regression Policy Optimization)都是 TRPO(Trust Region Policy Optimization)算法的变种,用于训练强化学习代理的策略。

1. NN-TRPO

NN-TRPO使用神经网络(Neural Network)作为策略(policy)的函数近似器。神经网络模型可以灵活地表示复杂的策略,并且通常包括输入层、隐藏层和输出层。NN-TRPO通过神经网络来建模和优化策略。NN-TRPO的特点是使用了一种称为"Trust Region"的方法,以确保每次策略更新都是小幅度的,从而保持策略的稳定性。这可以防止策略在训练过程中发生剧烈的变化,从而提高了收敛性和稳定性。

NN-TRPO通过优化策略以最大化累积奖励,同时在每次更新时限制策略的变化范围。它尝试找到策略参数的小幅度变化,以最大化期望奖励,同时保持策略的稳定性。

2. TRLRPO

TRLRPO与NN-TRPO不同,它使用线性回归(Linear Regression)模型来表示策略。线性回归是一种简化的函数逼近方法,它将策略表示为输入特征的线性组合。TRLRPO的特点是其代理模型更简单,参数较少,通常适用于状态空间较小的问题。由于使用线性模型,TRLRPO的策略更新通常更加保守,不容易引入大的变化。

TRLRPO的核心思想与NN-TRPO相似,都是通过优化策略以最大化累积奖励。但由于策略是线性的,它的更新相对较为保守。

总的来说,NN-TRPO和TRLRPO都是用于训练强化学习代理的策略优化算法,它们的主要区别在于代理模型的选择和策略更新的保守程度。NN-TRPO通常适用于复杂的环境和大规模状态空间,而TRLRPO适用于状态空间相对较小的问题。选择哪种算法取决于问题的性质和需求。

12.4.2  项目介绍

本项目是一个强化学习(Reinforcement Learning,RL)项目,旨在研究和比较使用两种不同的 TRPO(Trust Region Policy Optimization)算法,即 NN-TRPO 和 TRLRPO,来训练代理在不同的强化学习环境中执行任务的性能。

1. 项目目标

  1. 项目旨在研究和比较使用 TRPO 算法训练的代理在三个不同的强化学习环境中的性能。
  2. 项目关注两种 TRPO 变种:NN-TRPO 和 TRLRPO。

2. 项目组成

  1. 项目包含多个 Python 脚本,用于定义强化学习环境、代理模型、训练算法以及结果可视化。

3. 强化学习环境

  1. 项目使用三个标准的强化学习环境进行实验:Pendulum、Acrobot 和 Mountain Car。
  2. 这些环境具有不同的复杂性和动力学特性。

4. 代理模型

  1. 项目定义了两种类型的代理模型:NN(神经网络)代理和 LR(线性回归)代理。
  2. NN 代理使用神经网络来建模策略和价值函数,而 LR 代理使用线性回归模型。

5. 训练算法

  1. 项目采用了 TRPO 算法的两种变种,分别是 NN-TRPO 和 TRLRPO。
  2. 训练算法遵循 TRPO 的核心思想,通过优化代理的策略以最大化累积回报。

6. 实验和性能比较

  1. 项目在不同环境中使用两种代理类型和两种 TRPO 变种进行多次实验。
  2. 记录了每个实验的性能指标,如返回值。

7. 结果可视化

  1. 使用 matplotlib 对实验结果进行可视化,生成性能曲线和置信区间图表。
  2. 图表用于比较不同代理在不同环境下的性能。

12.4.3  经验数据管理和状态空间离散化

编写文件src/utils.py,功能是实现经验数据管理和状态空间离散化处理,用于支持强化学习算法的实现。提供了对数据的存储和状态表示的转换功能,以便于在强化学习任务中使用。文件src/utils.py的具体实现代码如下所示。

from typing import Tuple, List
import numpy as np

class Buffer:
    def __init__(self) -> None:
        self.actions = []
        self.states = []
        self.logprobs = []
        self.rewards = []
        self.terminals = []

    def clear(self) -> None:
        self.actions = []
        self.states = []
        self.logprobs = []
        self.rewards = []
        self.terminals = []

    def __len__(self) -> int:
        return len(self.states)


class Discretizer:
    def __init__(
        self,
        min_points: int,
        max_points: int,
        buckets: List[int],
        dimensions: List[List[int]],
        ) -> None:

        self.min_points = np.array(min_points)
        self.max_points = np.array(max_points)
        self.buckets = np.array(buckets)
        self.dimensions = dimensions

        self.range = self.max_points - self.min_points
        self.spacing = self.range / self.buckets

        self.n_states = np.round(self.buckets).astype(int)
        self.row_n_states = [self.n_states[dim] for dim in self.dimensions[0]]
        self.col_n_states = [self.n_states[dim] for dim in self.dimensions[1]]

        self.N = np.prod(self.row_n_states)
        self.M = np.prod(self.col_n_states)

        self.row_offset = [int(np.prod(self.row_n_states[i + 1:])) for i in range(len(self.row_n_states))]
        self.col_offset = [int(np.prod(self.col_n_states[i + 1:])) for i in range(len(self.col_n_states))]

    def get_index(self, state: np.ndarray) -> Tuple[np.ndarray, np.ndarray]:
        state = np.clip(state, a_min=self.min_points, a_max=self.max_points)
        scaling = (state - self.min_points) / self.range
        idx = np.round(scaling * (self.buckets - 1)).astype(int)

        row_idx = idx[:, self.dimensions[0]]
        row = np.sum(row_idx*self.row_offset, axis=1)

        col = None
        col_idx = idx[:, self.dimensions[1]]
        col = np.sum(col_idx*self.col_offset, axis=1)

        return row, col

上述代码包含了两个类:Buffer 和 Discretizer,具体说明如下所示:

(1)类Buffer

  1. 类Buffer是一个简单的数据缓存类,用于存储强化学习中的经验数据。
  2. actions 存储动作序列,states 存储状态序列,logprobs 存储对数概率序列,rewards 存储奖励序列,terminals 存储终止状态序列。
  3. clear 方法用于清空缓存,即将所有序列清空。
  4. __len__ 方法返回缓存中状态序列的长度。

(2)类Discretizer

  1. 类Discretizer用于将连续的状态空间离散化为有限数量的离散状态。
  2. 初始化方法接受一些参数,包括最小和最大状态值、分桶数、和状态空间的维度信息。
  3. get_index 方法接受一个连续状态作为输入,将其映射到离散状态的索引。该方法首先对输入状态进行剪切(限制在最小和最大状态值之间),然后将状态缩放到0到1之间,再将其映射到分桶的索引。
  4. get_index 方法返回两个分别表示行和列索引的数组,这可以用于在一个二维离散状态空间中定位状态的位置。

12.4.4  定义环境

编写文件src/environments.py,功能是自定义创建强化学习环境似,提供了对 Gym 中标准环境的一些扩展和修改,以适应特定的需求。具体实现代码如下所示。

import numpy as np
from gym.envs.classic_control.pendulum import PendulumEnv
from gym.envs.classic_control.acrobot import AcrobotEnv, wrap, bound, rk4


class CustomPendulumEnv(PendulumEnv):
    def reset(self):
        self.state = [np.random.rand()/100, np.random.rand()/100]
        self.last_u = None
        return self._get_obs(), {}

    def _get_obs(self):
        theta, thetadot = self.state
        return np.array([theta, thetadot])


class CustomAcrobotEnv(AcrobotEnv):
    def step(self, a):
        s = self.state
        assert s is not None, "Call reset before using AcrobotEnv object."
        torque = np.clip(a, -1, 1)

        if self.torque_noise_max > 0:
            torque += self.np_random.uniform(
                -self.torque_noise_max, self.torque_noise_max
            )

        s_augmented = np.append(s, torque)

        ns = rk4(self._dsdt, s_augmented, [0, self.dt])

        ns[0] = wrap(ns[0], -np.pi, np.pi)
        ns[1] = wrap(ns[1], -np.pi, np.pi)
        ns[2] = bound(ns[2], -self.MAX_VEL_1, self.MAX_VEL_1)
        ns[3] = bound(ns[3], -self.MAX_VEL_2, self.MAX_VEL_2)
        self.state = ns
        terminated = self._terminal()
        reward = -1.0 if not terminated else 100.0

        return (self._get_ob(), reward, terminated, False, {})

    def _get_ob(self):
        s = self.state
        return np.array([s[0], s[1], s[2], s[3]])

上述代码包含了两个自定义的环境类 CustomPendulumEnv 和 CustomAcrobotEnv,这些环境是基于 Gym 库的 PendulumEnv 和 AcrobotEnv 进行扩展和自定义的,具体说明如下所示:

(1)CustomPendulumEnv:继承自 Gym 中的 PendulumEnv 环境,具体说明如下:

  1. 重写了 reset 方法,用于初始化环境状态。在这里,状态被随机初始化为一个非常小的值。
  2. 重写了 _get_obs 方法,返回环境的观测值,这里只包括角度和角速度。

(2)CustomAcrobotEnv:继承自 Gym 中的 AcrobotEnv 环境,具体说明如下:

  1. 重写了 step 方法,该方法用于执行一步环境动态模拟。在这里,对动作进行了一些处理,包括截断动作的范围和添加扭矩噪声。
  2. 在 _get_ob 方法中返回环境的观测值,这里包括两个关节的角度和角速度。

12.4.5  创建强化学习模型

编写文件src/models.py,功能是创建机器学习模型,分别定义了两个神经网络模型的类PolicyNetwork 和 ValueNetwork,以及两个线性回归模型的类 PolicyLR 和 ValueLR。具体实现代码如下所示。

from typing import Tuple, List
import numpy as np
import torch

class PolicyNetwork(torch.nn.Module):
    def __init__(
            self,
            num_inputs: int,
            num_hiddens: List[int],
            num_outputs: int
        ) -> None:
        super(PolicyNetwork, self).__init__()
        self.layers = torch.nn.ModuleList()
        for h in num_hiddens:
            self.layers.append(torch.nn.Linear(num_inputs, h))
            self.layers.append(torch.nn.Tanh())
            num_inputs = h
        action_layer = torch.nn.Linear(num_inputs, num_outputs)
        action_layer.weight.data.mul_(0.1)
        action_layer.bias.data.mul_(0.0)
        self.layers.append(action_layer)
        self.log_sigma = torch.nn.Parameter(torch.zeros(1, num_outputs))

    def forward(self, x: torch.Tensor) -> Tuple[torch.Tensor]:
        for layer in self.layers:
            x = layer(x)
        return x, torch.clamp(self.log_sigma, min=-2.0, max=0.0)

class ValueNetwork(torch.nn.Module):
    def __init__(self,
            num_inputs: int,
            num_hiddens: List[int],
            num_outputs: int
        ) -> None:
        super(ValueNetwork, self).__init__()
        self.layers = torch.nn.ModuleList()
        for h in num_hiddens:
            self.layers.append(torch.nn.Linear(num_inputs, h))
            self.layers.append(torch.nn.Tanh())
            num_inputs = h
        action_layer = torch.nn.Linear(num_inputs, num_outputs)
        action_layer.weight.data.mul_(0.1)
        action_layer.bias.data.mul_(0.0)
        self.layers.append(action_layer)

    def forward(self, x: torch.Tensor) -> torch.Tensor:
        for layer in self.layers:
            x = layer(x)
        return x

class PolicyLR(torch.nn.Module):
    def __init__(
            self,
            n: int,
            m: int,
            k: int,
            scale: float=1.0
        ) -> None:
        super().__init__()

        L = scale*torch.randn(n, k, dtype=torch.float32, requires_grad=True)
        R = scale*torch.randn(k, m, dtype=torch.float32, requires_grad=True)

        self.L = torch.nn.Parameter(L)
        self.R = torch.nn.Parameter(R)

        self.log_sigma = torch.nn.Parameter(torch.zeros(1))

    def forward(
            self,
            indices: Tuple[np.ndarray, np.ndarray]
        ) -> Tuple[torch.Tensor]:
        rows, cols = indices
        prod = self.L[rows, :] * self.R[:, cols].T
        res = torch.sum(prod, dim=-1)
        return res, torch.clamp(self.log_sigma, min=-2.5, max=0.0)

class ValueLR(torch.nn.Module):
    def __init__(
            self,
            n: int,
            m: int,
            k: int,
            scale: float=1.0
        ) -> None:
        super().__init__()

        L = scale*torch.randn(n, k, dtype=torch.float32, requires_grad=True)
        R = scale*torch.randn(k, m, dtype=torch.float32, requires_grad=True)

        self.L = torch.nn.Parameter(L)
        self.R = torch.nn.Parameter(R)

    def forward(
            self,
            indices: Tuple[np.ndarray, np.ndarray]
        ) -> Tuple[torch.Tensor]:
        rows, cols = indices
        prod = self.L[rows, :] * self.R[:, cols].T
        return torch.sum(prod, dim=-1)

对上述代码的具体说明如下:

  1. 类PolicyNetwork:是一个用于表示策略的神经网络模型,通过神经网络的前向传播方法 forward 来计算策略。构造函数初始化了神经网络的结构,接受输入维度 num_inputs、隐藏层结构 num_hiddens 和输出维度 num_outputs。神经网络包含若干个全连接层和激活函数,最后输出策略的均值和对数标准差(用于连续动作空间的策略)。
  2. 类ValueNetwork:是一个用于表示值函数的神经网络模型,通过神经网络的前向传播方法 forward 来计算状态值。构造函数初始化了神经网络的结构,接受输入维度 num_inputs、隐藏层结构 num_hiddens 和输出维度 num_outputs。神经网络包含若干个全连接层和激活函数,最后输出状态值。
  3. 类PolicyLR:是一个用于表示策略的线性回归模型,其中构造函数初始化了两个矩阵 L 和 R,这些参数将用于计算策略。前向传播方法 forward 接受状态的索引,计算策略的输出。线性回归模型的输出是一个数值和对数标准差(用于连续动作空间的策略)。
  4. 类ValueLR:是一个用于表示值函数的线性回归模型。其中构造函数初始化了两个矩阵 L 和 R,这些参数将用于计算状态值。前向传播方法 forward 接受状态的索引,计算状态值的输出。

未完待续

  • 24
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码农三叔

感谢鼓励

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值