Source code for omnisafe.algorithms.on_policy.naive_lagrange.ppo_lag

# Copyright 2022-2023 OmniSafe Team. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
"""Implementation of the Lagrange version of the PPO algorithm."""

import torch

from omnisafe.algorithms import registry
from omnisafe.algorithms.on_policy.base.ppo import PPO
from omnisafe.common.lagrange import Lagrange


[docs]@registry.register class PPOLag(PPO): """The Lagrange version of the PPO algorithm. A simple combination of the Lagrange method and the Proximal Policy Optimization algorithm. """
[docs] def _init(self) -> None: """Initialize the PPOLag specific model. The PPOLag algorithm uses a Lagrange multiplier to balance the cost and reward. """ super()._init() self._lagrange = Lagrange(**self._cfgs.lagrange_cfgs)
[docs] def _init_log(self) -> None: r"""Log the PPOLag specific information. .. list-table:: * - Things to log - Description * - ``Metrics/LagrangeMultiplier`` - The Lagrange multiplier. """ super()._init_log() self._logger.register_key('Metrics/LagrangeMultiplier')
[docs] def _update(self) -> None: r"""Update actor, critic, running statistics as we used in the :class:`PolicyGradient` algorithm. Additionally, we update the Lagrange multiplier parameter, by calling the :meth:`update_lagrange_multiplier()` method. .. note:: The :meth:`_loss_pi()` is defined in the :class:`PolicyGradient` algorithm. When a lagrange multiplier is used, the :meth:`_loss_pi()` method will return the loss of the policy as: .. math:: L_{\pi} = \mathbb{E}_{s_t \sim \rho_{\pi}} \left[ \frac{\pi_\theta(a_t|s_t)}{\pi_\theta^{old}(a_t|s_t)} [A^{R}_{\pi_{\theta}}(s_t, a_t) - \lambda A^{C}_{\pi_{\theta}}(s_t, a_t)] \right] where :math:`\lambda` is the Lagrange multiplier parameter. Args: self (object): object of the class. """ # note that logger already uses MPI statistics across all processes.. Jc = self._logger.get_stats('Metrics/EpCost')[0] # first update Lagrange multiplier parameter self._lagrange.update_lagrange_multiplier(Jc) # then update the policy and value function super()._update() self._logger.store(**{'Metrics/LagrangeMultiplier': self._lagrange.lagrangian_multiplier})
[docs] def _compute_adv_surrogate(self, adv_r: torch.Tensor, adv_c: torch.Tensor) -> torch.Tensor: r"""Compute surrogate loss. PPOLag uses the following surrogate loss: .. math:: L = \frac{1}{1 + \lambda} [A^{R}_{\pi_{\theta}}(s, a) - \lambda A^C_{\pi_{\theta}}(s, a)] Args: adv (torch.Tensor): reward advantage cost_adv (torch.Tensor): cost advantage """ penalty = self._lagrange.lagrangian_multiplier.item() return (adv_r - penalty * adv_c) / (1 + penalty)