Module pearl.neural_networks.common.epistemic_neural_networks

This module defines epistemic neural networks that can model posterior distributions and perform bayesian updates via deep learning

Expand source code
"""
This module defines epistemic neural networks that can model posterior distributions
    and perform bayesian updates via deep learning
"""

from abc import ABC, abstractmethod
from typing import List, Optional

import torch
import torch.nn as nn
from pearl.neural_networks.common.utils import mlp_block
from torch import Tensor


class EpistemicNeuralNetwork(ABC, nn.Module):
    """
    Epistemic Neural Network is an abstract neural network model that can model posterior of
        the expectation of a random variable, i.e. epistemic uncertainty.
    Args:
        input_dim: int. Input feature dimension.
        hidden_dims: List[int]. Hidden layer dimensions.
        output_dim: int. Output dimension.
    """

    def __init__(
        self, input_dim: int, hidden_dims: Optional[List[int]], output_dim: int = 1
    ) -> None:
        super(EpistemicNeuralNetwork, self).__init__()

    @abstractmethod
    def forward(self, x: Tensor, z: Optional[Tensor] = None) -> Tensor:
        """
        Input:
            x: Feature vector of state action pairs
            z: Optional. Epistemic indices
        Output:
            posterior samples (corresponding to index z if available)
        """
        pass


class MLPWithPrior(nn.Module):
    """
    MLP model with prior regularization.
    If used as a single model, this is equivalent to L2 regularization.
    Args:
        input_dim (int): The dimension of the input features.
        hidden_dims (List[int]): A list containing the dimensions of the hidden layers.
        output_dim (int): The dimension of the output.
        scale (float): The scale of the prior regularization.
    """

    def __init__(
        self,
        input_dim: int,
        hidden_dims: Optional[List[int]],
        output_dim: int = 1,
        scale: float = 1.0,
    ) -> None:
        super(MLPWithPrior, self).__init__()
        self.base_net: nn.Module = mlp_block(input_dim, hidden_dims, output_dim)
        self.prior_net: nn.Module = mlp_block(input_dim, hidden_dims, output_dim).eval()
        self.scale = scale

    def forward(self, x: Tensor) -> Tensor:
        """
        Input:
            x: Tensor. Feature vector input
        Output:
            regularized sample output from posterior
        """
        with torch.no_grad():
            prior = self.scale * self.prior_net(x)

        return self.base_net(x) + prior


class Ensemble(EpistemicNeuralNetwork):
    """
    An ensemble based implementation of epistemic neural network.
    Args:
        input_dim: int. Input feature dimension.
        hidden_dims: List[int]. Hidden layer dimensions.
        output_dim: int. Output dimension.
        ensemble_size: int. Number of particles in the ensemble
                            to construct posterior.
        prior_scale: float. prior regularization scale.
    """

    def __init__(
        self,
        input_dim: int,
        hidden_dims: Optional[List[int]],
        output_dim: int = 1,
        ensemble_size: int = 10,
        prior_scale: float = 1.0,
    ) -> None:
        super(Ensemble, self).__init__(input_dim, hidden_dims, output_dim)
        self.ensemble_size = ensemble_size

        self.models = nn.ModuleList(
            [
                MLPWithPrior(input_dim, hidden_dims, output_dim, scale=prior_scale)
                for _ in range(ensemble_size)
            ]
        )

        self._resample_epistemic_index()

    def forward(
        self, x: Tensor, z: Optional[Tensor] = None, persistent: bool = False
    ) -> Tensor:
        """
        Input:
            x: Feature vector of state action pairs
            z: Single integer tensor. Ensemble epistemic index
        Output:
            posterior samples corresponding to z
        """
        if z is not None:
            assert z.flatten().shape[0] == 1
            ensemble_index = int(z.item())
            assert ensemble_index >= 0 and ensemble_index < self.ensemble_size
        else:
            ensemble_index = self.z

        return self.models[ensemble_index](x)

        if not persistent:
            self._resample_epistemic_index()

    def _resample_epistemic_index(self) -> None:
        self.z = torch.randint(0, self.ensemble_size, (1,))

Classes

class Ensemble (input_dim: int, hidden_dims: Optional[List[int]], output_dim: int = 1, ensemble_size: int = 10, prior_scale: float = 1.0)

An ensemble based implementation of epistemic neural network.

Args

input_dim
int. Input feature dimension.
hidden_dims
List[int]. Hidden layer dimensions.
output_dim
int. Output dimension.
ensemble_size
int. Number of particles in the ensemble to construct posterior.
prior_scale
float. prior regularization scale.
Expand source code
class Ensemble(EpistemicNeuralNetwork):
    """
    An ensemble based implementation of epistemic neural network.
    Args:
        input_dim: int. Input feature dimension.
        hidden_dims: List[int]. Hidden layer dimensions.
        output_dim: int. Output dimension.
        ensemble_size: int. Number of particles in the ensemble
                            to construct posterior.
        prior_scale: float. prior regularization scale.
    """

    def __init__(
        self,
        input_dim: int,
        hidden_dims: Optional[List[int]],
        output_dim: int = 1,
        ensemble_size: int = 10,
        prior_scale: float = 1.0,
    ) -> None:
        super(Ensemble, self).__init__(input_dim, hidden_dims, output_dim)
        self.ensemble_size = ensemble_size

        self.models = nn.ModuleList(
            [
                MLPWithPrior(input_dim, hidden_dims, output_dim, scale=prior_scale)
                for _ in range(ensemble_size)
            ]
        )

        self._resample_epistemic_index()

    def forward(
        self, x: Tensor, z: Optional[Tensor] = None, persistent: bool = False
    ) -> Tensor:
        """
        Input:
            x: Feature vector of state action pairs
            z: Single integer tensor. Ensemble epistemic index
        Output:
            posterior samples corresponding to z
        """
        if z is not None:
            assert z.flatten().shape[0] == 1
            ensemble_index = int(z.item())
            assert ensemble_index >= 0 and ensemble_index < self.ensemble_size
        else:
            ensemble_index = self.z

        return self.models[ensemble_index](x)

        if not persistent:
            self._resample_epistemic_index()

    def _resample_epistemic_index(self) -> None:
        self.z = torch.randint(0, self.ensemble_size, (1,))

Ancestors

Methods

def forward(self, x: torch.Tensor, z: Optional[torch.Tensor] = None, persistent: bool = False) ‑> torch.Tensor

Input

x: Feature vector of state action pairs z: Single integer tensor. Ensemble epistemic index

Output

posterior samples corresponding to z

Expand source code
def forward(
    self, x: Tensor, z: Optional[Tensor] = None, persistent: bool = False
) -> Tensor:
    """
    Input:
        x: Feature vector of state action pairs
        z: Single integer tensor. Ensemble epistemic index
    Output:
        posterior samples corresponding to z
    """
    if z is not None:
        assert z.flatten().shape[0] == 1
        ensemble_index = int(z.item())
        assert ensemble_index >= 0 and ensemble_index < self.ensemble_size
    else:
        ensemble_index = self.z

    return self.models[ensemble_index](x)

    if not persistent:
        self._resample_epistemic_index()
class EpistemicNeuralNetwork (input_dim: int, hidden_dims: Optional[List[int]], output_dim: int = 1)

Epistemic Neural Network is an abstract neural network model that can model posterior of the expectation of a random variable, i.e. epistemic uncertainty.

Args

input_dim
int. Input feature dimension.
hidden_dims
List[int]. Hidden layer dimensions.
output_dim
int. Output dimension.
Expand source code
class EpistemicNeuralNetwork(ABC, nn.Module):
    """
    Epistemic Neural Network is an abstract neural network model that can model posterior of
        the expectation of a random variable, i.e. epistemic uncertainty.
    Args:
        input_dim: int. Input feature dimension.
        hidden_dims: List[int]. Hidden layer dimensions.
        output_dim: int. Output dimension.
    """

    def __init__(
        self, input_dim: int, hidden_dims: Optional[List[int]], output_dim: int = 1
    ) -> None:
        super(EpistemicNeuralNetwork, self).__init__()

    @abstractmethod
    def forward(self, x: Tensor, z: Optional[Tensor] = None) -> Tensor:
        """
        Input:
            x: Feature vector of state action pairs
            z: Optional. Epistemic indices
        Output:
            posterior samples (corresponding to index z if available)
        """
        pass

Ancestors

  • abc.ABC
  • torch.nn.modules.module.Module

Subclasses

Methods

def forward(self, x: torch.Tensor, z: Optional[torch.Tensor] = None) ‑> torch.Tensor

Input

x: Feature vector of state action pairs z: Optional. Epistemic indices

Output

posterior samples (corresponding to index z if available)

Expand source code
@abstractmethod
def forward(self, x: Tensor, z: Optional[Tensor] = None) -> Tensor:
    """
    Input:
        x: Feature vector of state action pairs
        z: Optional. Epistemic indices
    Output:
        posterior samples (corresponding to index z if available)
    """
    pass
class MLPWithPrior (input_dim: int, hidden_dims: Optional[List[int]], output_dim: int = 1, scale: float = 1.0)

MLP model with prior regularization. If used as a single model, this is equivalent to L2 regularization.

Args

input_dim : int
The dimension of the input features.
hidden_dims : List[int]
A list containing the dimensions of the hidden layers.
output_dim : int
The dimension of the output.
scale : float
The scale of the prior regularization.

Initializes internal Module state, shared by both nn.Module and ScriptModule.

Expand source code
class MLPWithPrior(nn.Module):
    """
    MLP model with prior regularization.
    If used as a single model, this is equivalent to L2 regularization.
    Args:
        input_dim (int): The dimension of the input features.
        hidden_dims (List[int]): A list containing the dimensions of the hidden layers.
        output_dim (int): The dimension of the output.
        scale (float): The scale of the prior regularization.
    """

    def __init__(
        self,
        input_dim: int,
        hidden_dims: Optional[List[int]],
        output_dim: int = 1,
        scale: float = 1.0,
    ) -> None:
        super(MLPWithPrior, self).__init__()
        self.base_net: nn.Module = mlp_block(input_dim, hidden_dims, output_dim)
        self.prior_net: nn.Module = mlp_block(input_dim, hidden_dims, output_dim).eval()
        self.scale = scale

    def forward(self, x: Tensor) -> Tensor:
        """
        Input:
            x: Tensor. Feature vector input
        Output:
            regularized sample output from posterior
        """
        with torch.no_grad():
            prior = self.scale * self.prior_net(x)

        return self.base_net(x) + prior

Ancestors

  • torch.nn.modules.module.Module

Methods

def forward(self, x: torch.Tensor) ‑> torch.Tensor

Input

x: Tensor. Feature vector input

Output

regularized sample output from posterior

Expand source code
def forward(self, x: Tensor) -> Tensor:
    """
    Input:
        x: Tensor. Feature vector input
    Output:
        regularized sample output from posterior
    """
    with torch.no_grad():
        prior = self.scale * self.prior_net(x)

    return self.base_net(x) + prior