DiscretePolicyNetwork 定义概述
定义 PPO 中所使用的离散动作策略网络,其主要包含两部分:编码器(encoder)和决策输出头(head)
from typing import List
import torch
import torch.nn as nn
class DiscretePolicyNetwork(nn.Module):
def __init__(self, obs_shape: int, action_shape: int) -> None:
继承 PyTorch 神经网络类所必需的操作,自定义的神经网络必须是 nn.Module 的子类
super(DiscretePolicyNetwork, self).__init__()
定义编码器模块,将原始的状态映射为特征向量。对于不同的环境,可能状态信息的模态不同,需要根据情况选择适当的编码器神经网络,例如对于图片状态信息就常常使用卷积神经网络
这里我们用一个简单的单层 MLP 作为例子,即:
$$y = max(Wx+b, 0)$$
self.encoder = nn.Sequential(
nn.Linear(obs_shape, 32),
nn.ReLU(),
)
定义离散动作的决策输出头,一般仅仅一层全连接层即可,即:
$$y=Wx+b$$
self.head = nn.Linear(32, action_shape)
forward 函数功能概述
描述 PPO 中所使用的离散动作策略网络的前向计算图
x -> encoder -> head -> logit .
def forward(self, x: torch.Tensor) -> torch.Tensor:
将原始的状态信息转换为特征向量,维度变化为: $$(B, *) -> (B, N)$$
x = self.encoder(x)
为每个可能的离散动作选项,计算相应的 logit,维度变化为: $$(B, N) -> (B, A)$$
logit = self.head(x)
return logit
MultiDiscretePolicyNetwork 定义概述
定义 PPO 中所使用的多维离散动作策略网络,其主要包含两部分:编码器(encoder)和多维决策输出头(head)
class MultiDiscretePolicyNetwork(nn.Module):
def __init__(self, obs_shape: int, action_shape: List[int]) -> None:
继承 PyTorch 神经网络类所必需的操作,自定义的神经网络必须是 nn.Module 的子类
super(MultiDiscretePolicyNetwork, self).__init__()
定义编码器模块,将原始的状态映射为特征向量。对于不同的环境,可能状态信息的模态不同,需要根据情况选择适当的编码器神经网络,例如对于图片状态信息就常常使用卷积神经网络
这里我们用一个简单的单层 MLP 作为例子,即:
$$y = max(Wx+b, 0)$$
self.encoder = nn.Sequential(
nn.Linear(obs_shape, 32),
nn.ReLU(),
)
定义多维离散动作的决策输出头,即创建多个离散动作的预测器,整体用 nn.ModuleList 进行管理
self.head = nn.ModuleList()
for size in action_shape:
self.head.append(nn.Linear(32, size))
Overview
The computation graph of discrete action policy network used in PPO.
x -> encoder -> multiple head -> multiple logit .
def forward(self, x: torch.Tensor) -> List[torch.Tensor]:
将原始的状态信息转换为特征向量,维度变化为: $$(B, *) -> (B, N)$$
x = self.encoder(x)
为每个可能的离散动作选项,计算相应的 logit,维度变化为: $$(B, N) -> [(B, A_1), ..., (B, A_N)]$$
logit = [h(x) for h in self.head]
return logit
sample_action 函数功能概述
输入 logit 采样获得离散动作,输入维度为 (B, action_shape) 输出维度为 output shape = (B, )
在这个示例中,课程中提到的 distributions 工具库的三个维度分别为
batch_shape = (B, ), event_shape = (), sample_shape = ()
def sample_action(logit: torch.Tensor) -> torch.Tensor:
将 logit 转化为概率(logit 一般指神经网络的原始输出,不经过激活函数,例如最后一层全连接层的输出)
$$\text{Softmax}(x_{i}) = \frac{\exp(x_i)}{\sum_j \exp(x_j)}$$
prob = torch.softmax(logit, dim=-1)
构建广义伯努利分布。它的概率质量函数为: $$f(x=i|\boldsymbol{p})=p_i$$
Related Link
dist = torch.distributions.Categorical(probs=prob)
为一个 batch 里的每个样本采样一个离散动作,并返回它
return dist.sample()
test_sample_discrete_action 函数功能概述
离散动作空间的主函数,构建一个简单的策略网络,执行前向计算过程,并采样得到一组离散动作
def test_sample_discrete_action():
设置相关参数 batch_size = 4, obs_shape = 10, action_shape = 6.
B, obs_shape, action_shape = 4, 10, 6
从0-1 的均匀分布中生成状态数据
state = torch.rand(B, obs_shape)
定义策略网络
policy_network = DiscretePolicyNetwork(obs_shape, action_shape)
策略网络执行前向计算,即输入状态输出 logit
$$ logit = \pi(a|s)$$
logit = policy_network(state)
assert logit.shape == (B, action_shape)
根据 logit 采样得到最终的离散动作
action = sample_action(logit)
assert action.shape == (B, )
test_sample_multi_discrete_action 函数功能概述
多维离散动作空间的主函数,构建一个简单的策略网络,执行前向计算过程,并采样得到一组多维离散动作
def test_sample_multi_discrete_action():
Set batch_size = 4, obs_shape = 10, action_shape = [4, 5, 6].
B, obs_shape, action_shape = 4, 10, [4, 5, 6]
从0-1 的均匀分布中生成状态数据
state = torch.rand(B, obs_shape)
定义策略网络
policy_network = MultiDiscretePolicyNetwork(obs_shape, action_shape)
策略网络执行前向计算,即输入状态输出多个 logit
$$ logit = \pi(a|s)$$
logit = policy_network(state)
for i in range(len(logit)):
assert logit[i].shape == (B, action_shape[i])
对于多个 logit,依次调用采样函数,根据相应的 logit 采样得到最终的离散动作
for i in range(len(logit)):
action_i = sample_action(logit[i])
assert action_i.shape == (B, )
如果读者关于本文档有任何问题和建议,可以在 GitHub 提 issue 或是直接发邮件给我们 (opendilab@pjlab.org.cn) 。