Source code for omnisafe.algorithms.on_policy.penalty_function.ipo
# 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 IPO algorithm."""
import torch
from omnisafe.algorithms import registry
from omnisafe.algorithms.on_policy.base.ppo import PPO
[docs]@registry.register
class IPO(PPO):
"""The Implementation of the IPO algorithm.
References:
- Title: IPO: Interior-point Policy Optimization under Constraints
- Authors: Yongshuai Liu, Jiaxin Ding, Xin Liu.
- URL: `IPO <https://arxiv.org/pdf/1910.09615.pdf>`_
"""
[docs] def _init_log(self) -> None:
r"""Log the IPO specific information.
.. list-table::
* - Things to log
- Description
* - ``Misc/Penalty``
- The penalty coefficient.
"""
super()._init_log()
self._logger.register_key('Misc/Penalty')
[docs] def _compute_adv_surrogate(self, adv_r: torch.Tensor, adv_c: torch.Tensor) -> torch.Tensor:
r"""Compute surrogate loss.
IPO uses the following surrogate loss:
.. math::
L = \mathbb{E}_{s_t \sim \pi_\theta} \left[
\frac{\pi_\theta^{'}(a_t|s_t)}{\pi_\theta(a_t|s_t)} A(s_t, a_t)
- \kappa \frac{J^{C}_{\pi_\theta}(s_t, a_t)}{C - J^{C}_{\pi_\theta}(s_t, a_t) + \epsilon}
\right]
Where :math:`\kappa` is the penalty coefficient, :math:`C` is the cost limit,
:math:`\epsilon` is a small number to avoid division by zero.
Args:
adv (torch.Tensor): reward advantage
adv_c (torch.Tensor): cost advantage
"""
Jc = self._logger.get_stats('Metrics/EpCost')[0]
penalty = self._cfgs.algo_cfgs.kappa / (self._cfgs.algo_cfgs.cost_limit - Jc + 1e-8)
if penalty < 0 or penalty > self._cfgs.algo_cfgs.penalty_max:
penalty = self._cfgs.algo_cfgs.penalty_max
self._logger.store(**{'Misc/Penalty': penalty})
return (adv_r - penalty * adv_c) / (1 + penalty)