Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

10.2) (Exercise) Introduction to Uncertainty Quantification and Generative Modeling

Open In Colab Open In Kaggle

We’re often tasked with filling voids and to express how sure we are of our answer.
How can we train an algorithm to do the same?

A Quick Introduction to Uncertainty

Uncertainty is one of those terms that you are likely very familiar with, whether in the colloquial sense (I’d have a hard time believing that any of us have never had a moment of doubt) or the scientific sense.

Today, we’ll be using Haynes et al.'s paper on uncertainty estimates with neural networks for environmental science applications as a guide for our efforts. Let us then begin as they did - by discussing the different types of uncertainty we expect to encounter.

Generally speaking, we expect to encounter two types of uncertainty - reducible and irreducible uncertainty. As you may imagine, irreducible uncertainty refers to the types of uncertainty that we can’t do anything about - largely associated with stochastic (a.k.a. random) processes.

Irreducible Uncertainty

Let’s imagine, for example, that you are the head of a seedy bookmaker organization that wants to make money on rubber duck races - similar to the one pictured below:

Loading...

You’d have a hard (even impossible) time trying to fix your odds for a single duck winning. Sure, maybe you could figure out what region of the box the winning duck is more likely to come from after enough trials. But the turbulent swirls (or eddies) in the flow in the river, the waterfall, and the collisions between ducks are all stochastic processes that will ultimately determine the average speed of the duck between the start and finish (and therefore the winner).

Many phenomena in this world are like these ducks - we can’t predict them precisely but we can talk about them in statistical terms (for example, the diffusion of milk into your morning coffee). As a result, many of the data that we are able to measure carry a degree of uncertainty that we have no way of reducing - e.g., was the mean flow that I measured influenced by turbulent eddies? And if so, by how much?

In Machine Learning literature, people sometimes even extend the concept of irreducible uncertainty to the uncertainty in the data itself (e.g., the measurements we’re working with). However, this type of unertainty is not strictly irreducible - better measurement technology, understanding of the phenomena, or includion of additional data might end up with us reducing the uncertainty in our current dataset. However, most of the time we’re stuck with the quality of the data that we have and thus some refer to this uncertainty as irreducible. We don’t recommend doing this, but hopefully this gives you context for their reasoning.

As a last note, you will also hear about irreducible uncertainty being referred to as aleatoric uncertainty, which comes from the latin word for random. (This will be more apparent to those of you who speak romantic languages, as aleatorio / aléatoire / aleatório mean random in Spanish / French / Portuguese)

Reducible Uncertainty

This brings us to the second kind of uncertainty: reducible uncertainty. This is the type of uncertainty that results from decisions made in the data sampling and model development process, i.e., it comes from our lack of knowledge. This can take form in our method for measuring, sampling, or even the technical aspects of how we build our models.

As a matter of fact, you’ve probably haven’t thought about how your own decisions in programming can affect the output of your models. Let’s look at the errors we can get depending on how we handle data operations.

The value of a is 1.0
b as a list: [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]
The sum of b is 1.0

By summing 0.1 to itself multiple times, we introduce errors (and hence uncertainty) because there is no way of representing 0.1 perfectly as a floating point number, and the error accumulates over the repetitions. Let’s try using numpy intead.

c as an array: [0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1]
The sum of c is 1.0

Does this mean that numpy is perfect? Well, the short answer is no - it’s just better at handling floating point operations that the default sum function in python. But it too accumulates errors.

d as an array: [0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05
 0.05 0.05 0.05 0.05 0.05 0.05]
The sum of d is 1.0000000000000002

You may imagine, then, that performing many operations on values can end up with a small accumulation of error. Still, this is typically one of the smaller sources of uncertainty in our models.

How accurate and precise was the instrument used to generate the data we’re working with? How much information is present in the variables/covariates we’ve chosen to model our problem? What variables/processes important for our problem are we ignorant of or unable to capture? These are all sources of uncertainty that we’re forced to deal with and, though these are reducible, in practice it’s generally something that is easier said than done.

Finally, before we move on to today’s problem, let’s introduce another term for reducible uncertainty: epistemic uncertainty. This term comes from the greek epistēmē, meaning knowledge, and thus reflects that this uncertainty comes from a lack of knowledge. 🙂

Q1) Can you think of sources of epistemic and aleatoric uncertainty in your field?

Add your reflections here 🧠

Data Preparation and Analysis

First, let’s download a dataset we prepared for this notebook and plot it. Like before, we’ll rely on pooch to load the data from OneDrive, and then save the file assocaited with the “x” values in x_file and that associated wit the “y” values in y_file.

<Figure size 1200x300 with 1 Axes>

Imagine that you’ve taken this data from a physical variable you’re very familiar with - and thus you know that you can model the variable with a 4th degree polynomial. Let’s fit it quickly, e.g., with scikit-learn.

Q2) Model the data using a 4th degree polynomial

Tips
Scikit-learn doesn't include a polynomial regression model because they can be more easily made by extending the linear model! Since a polynomial regression is simply the linear combination of inputs to different powers, you can instead populate the feature space with these and fit a linear regression model.

See this scikit-learn module for more details.

This does a pretty good job, but we can clearly see that y isn’t a simple function of x - after all, there are multiple values of y for each value of x, so technically a function relating x to y does not exist!

Thus, we can say that there is a degree of uncertainty in the value we predict for y. One common way to express this in your model is to add simple error bars, which quantify how far away your predicted y is from the actual value of y - on average.

Q3) How would express the confidence in this model?

Imagine a stakeholder asks you for a measurement of the error and how confident you are in the model predictions.

Tips

Think of the many functions you already know for quantifying the error. Given the large number of samples that you have, how can you express the average error?

Once you have a way of quantifying the error, how can you express your confidence in the spread of the error?

Click here to read about one way you could answer question 1. Read it once you have your own answer 🙂

One way that you can quantify the error is by figuring out how far away your prediction is from the truth, on average. This can be done, e.g., by calculating the mean absolute error, i.e. \text{MAE} = \dfrac{1}{n}\sum_{i=0}^{n}|\hat{y}_i - y_i|.

If you were to calculate the MAE and its statistics, as well as the variance of y, you’d get the following values (see our code cell below for the calculation)

The mean absolute error is 0.91
The standard deviation of the error is 1.03
The maximum error is 17.95
The variance in y is 8.94

If one were to see the report of this model including this MAE, one could get the misplaced impression that the model is able to capture the data’s behavior quite well - an MAE of 0.91 compared to a variance of ~9 could give the appearance that the model does well enough (and for some applications, this could indeed be true).

We can see, however, that the model does significantly worse at explaining the behavior of y around values of x = 1, 3, and 5. Similarly, by having a single value to represent the error mean and standard deviation, we are underconfident in our predictions in areas where our model does better (e.g., around x=2 & x=4).

Like we discussed before, there can be many sources for the uncertainty we observe- for example, the spread in the values could be due to a stochastic process (i.e., a process we can only describe statistically), and this may lead us to have models that are better suited to predict conditions around specific inputs.

You may notice that simply using the average error for all xx is clearly unsatisfactory as we alternate between under-estimating and over-estimating the error 😞

Looking a bit more closely 🕵 it would seem as if we need a different error bar for each xx.

To get some intuition, let’s look at the distribution of y values in our data near x=1.1x = 1.1. Let’s do this by finding all of the points that are within .02 of 1.1, and then plotting the histogram.

<Figure size 1200x300 with 1 Axes>
image.png

Looking at this histogram, it looks like we could make the assumption that the distribution of y given a value of x can be approximated by a normal distribution (a.k.a. a bell curve, or a gaussian).

The question now becomes, how do we do this? 🤔

Distributional Regression

In order to make this adjustment, we can write a model that predicts a distribution for each value of x. In this way, we are writing a model for the joint probability of x and y. As you may know, the shape of a normal distribution is given by two values: the mean (mu, μ\mu) and the standard deviation (sigma, σ\sigma).

If you run the code below, you can play around with a gaussian distribution and see how the two parameters change the output.

Given that we can do this, why don’t we train a neural network to predict the mean (μ\mu) and standard deviation (σ\sigma) of y given a value of x? Well, if you use the techniques we’ve been using so far, this might seem straightforward, until you reach the following question:
what should I use as a training loss?

Before, you trained neural networks to reduce some kind of deterministic metric (e.g., the mean average error, root mean square error, or accuracy). However, these metrics require that we compare singular values against other singular values - if we predict μ\mu and σ\sigma, we will need a function that will return a singular value when comparing distributions.

Here is where the Continuous Ranked Probability Score (CRPS) comes in! Let’s walk through what we’re going to do in order for us to understand how our network will learn.

Explaining CRPS

The CRPS is a value that quantifies the absolute area between the cumulative distribution function of two distributions. Let’s say that we have two gaussians we want to compare to the standard gaussian distribution (μ=0\mu = 0 and σ=1\sigma = 1), the first with μ=0.5\mu = 0.5 and σ=1.2\sigma = 1.2, and the second with μ=0.1\mu=0.1 and σ=1.7\sigma = 1.7. Which of these two is closer to the standard gaussian?

<Figure size 1275x450 with 1 Axes>

Like we said, the CRPS depends on the area between the CDFs. Let’s plot the CDFs of the standard Gaussian with the two Gaussians. Calculating the CRPS between two Gaussians requires a bit of math that we don’t want to get into, so we’ll just give you the function to calculate it 😀

We now have a way to evaluate the distance between two distributions (and it’s even a proper score !!!) - but if you recall what we’re going to be doing is comparing the gaussian that we predict to deterministic observations (i.e., we’ll predict a distribution but our target is a single value).

How do we go about doing this? Well, one way that we can do this is to represent our observations with what is known as a degenerate distribution (a.k.a. a dirac distribution), whose PDF is a step function with a value between 0 and 1, where the change happens at the value of our observation. Let’s make a quick plot, since a picture is worth 1000 words! 📸

With this, we have two distributions that we can compare using the CRPS! Let’s take a single value of x in our dataset, and see if we can manually minimize the CRPS value for the observations for that single value of X.

There are 98 y values for x = 1.02
The mean of the sample is 44.87 and the standard deviation is 0.24

Setting up the Neural Network

Today, we’ll be modeling the conditional uncertainty by setting up a simple neural network using PyTorch.

Q4) Set up a simple neural network using PyTorch

We need to define the other aspcets for our model training in torch as well. This includes the batch size, optimizer, & loss function. Let’s make a list of the things we need to do:

  1. Since we know the underlying relationship is well represented using 4th degree polynomials, let’s make polynomial features of the x array

  2. Convert the numpy arrays to pytorch tensors.

  3. Convert the tensors into a tensor dataset and use the dataset to make a dataloader.

  4. Instantiate the model. Remember that the model you defined above may need a number of arguments in order to be instantiated, depending on how you defined it.

  5. Define the loss function and optimizer

  6. Write and run the training loop. It should include an early stopping criterion or two :

Q5) Implement steps 1-5 detailed above in the code cells below.

Q6) Update the training loop as needed, and train a model.

<Figure size 640x480 with 1 Axes>

Model Performance Overview

Model Evaluation

Now that we have a probabilistic model, we need to discuss ways in which to evaluate how well our model performs. However, up to now we’ve focused on deterministic metrics (e.g., RMSE, accuracy, MAE) in order to evaluate the performance of our models. As we saw before, these metrics are less useful when we predict a whole distribution as our outputs (whether it be via distributional regression as we did above, or even when making predictions with ensembles).

Furthermore, we used the one probabilistic metric we’ve discussed as our optimization target (i.e., we trained the model to minimize the CRPS) - if we use it as an evaluation metric we’ll get an overly optimistic view of how well our model performs. We’re therefore going to introduce two more metrics to evaluate the performance of our model.

Note that these metrics also work when using other methods for quantifying uncertainty, such as cross-validation or model ensembles. However, the scores will be much worse for models whose errors aren’t conditional on the inputs!

Spread Skill Score

The Spread Skill Score (SSC) is used to quantify how large the spread predicted by your model(s) is (e.g., the predicted sigma in our case) compared to the mean error associated with predicted mean (i.e., its skill).

<Figure size 600x600 with 1 Axes>

Note that the ideal spread skill score is a line where the error in your prediction is equal to the spread that you predict!

Additionally, if you use a method of uncertainty quantification that isn’t conditional on the inputs (like the error bars we produced way up in Question 2), you’ll have a vertical line whose intersection with the diagonal will be whereever your error is as large as the spread in the data!

Probability Integral Transform (PIT) Histogram

While this visualization carries a name that some may find intimidating (one of your T.A.'s will readily admit to waking from a nightmare muttering something about it with a far off look on his face), it’s simply a way of quantifying how well calibrated your models are. It’s simply a matter of calculating the CDF of random samples from the observations and plotting a histogram.

Q7) Is the model over-dispersive or under-dispersive?

Write your thoughts here 📉

Bonus Challenge

As you can imagine, the data that you used today does not, in fact, associate a gaussian distribution of values for each value of x. Instead, the distribution is a weibull distribution whose shape and scale parameters depend on x!

We’ve gone ahead and prepared an interactive demo for you to get familiar with the weibull distribution.

The challenge, however, is to repeat the fitting of the neural network by predicting a weibull instead of a gaussian distribution. Note that this means that the CRPS we implemented above is not correct for use with the weibull distribution - and as your TA ran out of time and energy to figure it out for you, it’s up to you to figure it out.

“You really shouldn’t spend too much time on this. I’d rather you work on your final project, or have a coffee” - that same TA.

References
  1. Haynes, K., Lagerquist, R., McGraw, M., Musgrave, K., & Ebert-Uphoff, I. (2023). Creating and Evaluating Uncertainty Estimates with Neural Networks for Environmental-Science Applications. Artificial Intelligence for the Earth Systems, 2(2). 10.1175/aies-d-22-0061.1