关于 CS 285 深度强化学习 Homework 1 的笔记很少,百度到 前年 一些同学的笔记,感觉有点不太对。。
这里写一些个人理解,敬供各位批评。
策略(Policy)函数的实现
连续动作空间 & 高斯策略实现
首先明确,这里的 “连续动作空间” ( $\pi(a|s)$ ) 就是单峰的高斯分布。即 动作向量的每个分量连续、独立且分别服从不同参数的高斯分布。
因此首先如果是高斯函数 ( $\pi_{\mu,\sigma}(a|s)$ ) , 则 待估计的 未知参数为 期望和标准差。动作值期望随观测值不同而变化。因此反映在 Pytorch 的实现上就是如下可梯度优化的张量。
nn.Parameter
是一个Tensor
的包装类。可理解为一个可参与反向传播的特殊张量。这个类可以帮助实现某一部分参数与网络输入无关。- 策略期望 $\mu$ 是与 observation 相关的参数。因此是承接观测输入的 MLP
class MLPPolicy(BasePolicy, nn.Module, metaclass=abc.ABCMeta):
def __init__(self, **kwargs):
super().__init__(**kwargs)
# init vars
if self.discrete:
pass
else:
self.logits_na = None
self.mean_net = ptu.build_mlp(
input_size=self.ob_dim, output_size=self.ac_dim,
n_layers=self.n_layers, size=self.size,
)
self.log_std = nn.Parameter(
torch.zeros(self.ac_dim, dtype=torch.float32, device=ptu.device)
)
离散动作空间 & 离散策略函数
Gym 框架(包括 Gymnasium)中离散动作空间用 Discrete
表示。
它只能表示 一个 维度的有限离散取值(多选一),而 MultiDiscrete
是表示多维的离散值(分别多选一)
因此在 CS285 Homework 1 代码中,self.logits_na
是一个动作维度 不同取值的 概率对数(log-likelihood)
class MLPPolicy(BasePolicy, nn.Module, metaclass=abc.ABCMeta):
def __init__(self, **kwargs):
super().__init__(**kwargs)
# init vars
if self.discrete:
self.logits_na = ptu.build_mlp(
input_size=self.ob_dim,
output_size=self.ac_dim,
n_layers=self.n_layers,
size=self.size,
)
self.mean_net = None
self.log_std = None
else:
pass
最后使用 torch.distributions.Distribution
(的不同子类)定义分布。在 Pytorch 中分布本身是可以传递梯度的。
- 使用
torch.distributions.Normal
定义一个正态分布(注意:是正态分布,而不是正态分布采样值)。 distributions.Categorical
定义离散分布。Categorical
本身可以定义多维离散分布
class MLPPolicy(BasePolicy, nn.Module, metaclass=abc.ABCMeta):
# This function defines the forward pass of the network.
# You can return anything you want, but you should be able to differentiate
# through it. For example, you can return a torch.FloatTensor. You can also
# return more flexible objects, such as a
# `torch.distributions.Distribution` object. It's up to you!
def forward(self, observation: torch.FloatTensor) -> Any:
if self.discrete:
return distributions.Categorical(self.logits_na(observation))
else:
mu = self.mean_net(observation)
std = self.log_std.exp().expand_as(mu)
return distributions.Normal(mu, std)
最终通过 sample()
方法对 Distribution
对象采样。注意这个采样值是没有梯度的。
def get_action(self, obs: np.ndarray) -> np.ndarray:
if len(obs.shape) > 1:
observation = obs
else:
observation = obs[None]
observation = ptu.from_numpy(observation)
distr = self.forward(observation)
return ptu.to_numpy(distr.sample())
上述的实现方法可以参考 PPO 的实现方法。(但优化原理上是不同的)
策略概率函数的优化
Stochastic Policy 的优化实现
如下分析属于个人理解。
上述 离散、连续 只是策略函数的一个分类。还可以是 Deterministic 或 Stochastic(见 Lecture 4:Tradeoff)
- Stochastic:策略函数是一个概率函数 $\pi(a_t|s_t)$ 。同一个 state 可能有不同的 action
- Deterministic:state 与 action 是完全的函数映射。比如 Policy 网络的输出就是 动作值,或 Q-Learning 中查表确定动作。
又因为, 这里实现的的是模仿学习,是 learned policy 与 experts' policy 的 拟合 (与其他的 RL 算法不同)。因此本质上是一种 参数估计 。(概率论 DNA 动了(大雾))
- 矩估计:需要对分布采样。learned policy 采样均值可以近似 一阶矩 $E(A)$,而 expert policy 采样均值是 $\bar{A}$ ,那么 两个 policy 采样并作 MSE Loss 即可。但是
Distribution.sample()
没有梯度信息 - 所以这里的方法实际是 极大似然估计:极大化如下 对数似然函数。其中 $a_i$ 是 $\pi_{expert}(a|s_i)$ 的采样
$$\log L(\mu,\sigma)=\log(\prod_{i=1}^n\pi_{\mu,\sigma}(a_i|s_i))=\sum_{i=1}^{n}\log(\pi_{\mu,\sigma}(a_i|s_i))$$
具体如下:
class MLPPolicySL(MLPPolicy):
def __init__(self, ac_dim, ob_dim, n_layers, size, **kwargs):
super().__init__(ac_dim, ob_dim, n_layers, size, **kwargs)
self.loss = nn.MSELoss()
def update(
self, observations, actions,
adv_n=None, acs_labels_na=None, qvals=None
):
# TODO: update the policy and return the loss
self.optimizer.zero_grad()
observations = ptu.from_numpy(observations)
actions = ptu.from_numpy(actions)
action_distribution = self.forward(observations)
loss = -action_distribution.log_prob(actions).mean()
loss.backward()
self.optimizer.step()
return {
# You can add extra logging information here, but keep this line
'Training Loss': ptu.to_numpy(loss),
}
Deterministic 和 Stochastic 不仅局限于 强化学习。
同样也是个人分析。
- Deterministic:有些模型本身就是 输入和输出的函数,是输入空间和输出空间的绝对映射。
- Stochastic:有些模型的输出 表示的是 概率分布。比如某些分类问题,网络输出表示的是每一类的概率,最终预测值选最大值的标号。
上述的 分类问题情形 常用的损失函数就是 交叉熵 $H(p, q)$:
$$H(p, q)=\mathrm{E}_{p}[-\log q]=H(p)+D_{\mathrm{KL}}(p | q)$$
它是目标分布 p 的熵,加上 p 与模型分布 q 的 KL散度。Stochastic 模型就是 概率分布之间 的趋近。而 Deterministic 模型 则是 值与值之间 的拟合,所以相应的目标函数就是输出预测值和真值的 误差。
本文参与了 SegmentFault 思否年度征文「一名技术人的 2022」,欢迎正在阅读的你也加入。