Evidential Regression Model

Train an evidential regression model following the setup from https://arxiv.org/abs/1910.02600.

import matplotlib.pyplot as plt
import numpy as np
import torch
from torch import nn, optim
from torch.utils.data import DataLoader, TensorDataset
from tqdm import tqdm

from probly.train.evidential.torch import EvidentialNIGNLLLoss, EvidentialRegressionRegularization
from probly.transformation.evidential.regression import evidential_regression

Generate synthetic data

def f(x: np.ndarray) -> np.ndarray:
    """Cubic function to generate synthetic data.

    Args:
        x: numpy.ndarray, input data
    Returns:
        y: numpy.ndarray, output data
    """
    eps = np.random.normal(0, 3, x.shape)
    return x**3 + eps


X_train = np.random.uniform(-4, 4, 500)
X_test = np.random.uniform(-6, 6, 250)
y_train = f(X_train)
y_test = f(X_test)
X_train = torch.from_numpy(X_train).float().view(-1, 1)
X_test = torch.from_numpy(X_test).float().view(-1, 1)
y_train = torch.from_numpy(y_train).float().view(-1, 1)
y_test = torch.from_numpy(y_test).float().view(-1, 1)
train = TensorDataset(X_train, y_train)
test = TensorDataset(X_test, y_test)
train_loader = DataLoader(train, batch_size=128, shuffle=True)
test_loader = DataLoader(test, batch_size=128, shuffle=False)

Define a neural network

class Net(nn.Module):
    """Simple Neural Network class.

    Attributes:
        fc1: nn.Module, first fully connected layer
        fc2: nn.Module, second fully connected layer
        fc3: nn.Module, third fully connected layer
        fc4: nn.Module, fourth fully connected layer
        act: nn.Module, activation function
    """

    def __init__(self) -> None:
        """Initializes an instance of the Net class."""
        super().__init__()
        self.fc1 = nn.Linear(1, 100)
        self.fc2 = nn.Linear(100, 100)
        self.fc3 = nn.Linear(100, 100)
        self.fc4 = nn.Linear(100, 1)
        self.act = nn.ReLU()

    def forward(self, x: torch.Tensor) -> torch.Tensor:
        """Forward pass of the neural network.

        Args:
            x: torch.Tensor, input data
        Returns:
            torch.Tensor, output data
        """
        x = self.act(self.fc1(x))
        x = self.act(self.fc2(x))
        x = self.act(self.fc3(x))
        x = self.fc4(x)
        return x


net = Net()

Transform it into an evidential regression model

model = evidential_regression(net)
print(model)
Net(
  (fc1): Linear(in_features=1, out_features=100, bias=True)
  (fc2): Linear(in_features=100, out_features=100, bias=True)
  (fc3): Linear(in_features=100, out_features=100, bias=True)
  (fc4): NormalInverseGammaLinear()
  (act): ReLU()
)

Train the network with the evidential loss and regularization

optimizer = optim.Adam(model.parameters(), 5e-3)
criterion = EvidentialNIGNLLLoss()
regularization = EvidentialRegressionRegularization()
lmbda = 0.01
for _ in tqdm(range(500)):
    model.train()
    for inputs, targets in train_loader:
        optimizer.zero_grad()
        outputs = model(inputs)
        loss = criterion(outputs, targets) + lmbda * regularization(outputs, targets)
        loss.backward()
        optimizer.step()

# compute MSE on test set
squared_error = 0
total = 0
model.eval()
for inputs, targets in test_loader:
    outputs = model(inputs)
    squared_error += torch.sum((outputs["gamma"] - targets) ** 2)
    total += targets.size(0)
print(f"MSE: {squared_error / total}")
100%|██████████| 500/500 [00:02<00:00, 218.45it/s]
MSE: 287.8296813964844

Plot the predictions and the targets

plt.scatter(X_test, y_test, label="Targets", c="darkgreen")
preds = model(X_test)["gamma"].detach().numpy()
plt.scatter(X_test, preds, label="Predicted", c="darkorange")
plt.legend()
plt.show()
../../_images/6dda1916944730f52c5b32e217d11be5b7c014b6c6f4dc769f8fc991187ef0a9.png