1 unstable release

0.1.0 Dec 6, 2022

#456 in Machine learning

MIT/Apache

52KB
1K SLoC

variational-regression

Regression models trained using variational inference

Motivation

This library provides implementations of Bayesian regression models that learn parameter values by optimizing a variational lower bound on the log likelihood. The benefit of using variational inference is that training is efficient, and we have a well defined objective function to optimize. The Bayesian approach also naturally incorporates regularization into the models.

Linear Regression

The model is specified as follows:

p(y | θ) = ∏ N(yi | θTxi, β-1)

p(θ | α) = ∏ N(θj | 0, αj-1)

p(α) = ∏ Gam(αj | a0, b0)

p(β) = Gam(β | c0, d0)

with the given notation:

y = labels

x = features

θ = model weights

α = weight precision (inverse variance)

β = noise precision (inverse variance)

Logistic Regression

The model is specified as follows:

p(y | θ) = ∏ σ(θTxi)yi {1 - σ(θTxi)}1-yi

p(θ | α) = ∏ N(θj | 0, αj-1)

p(α) = ∏ Gam(αj | a0, b0)

with the given notation:

y = labels

x = features

θ = model weights

α = weight precision (inverse variance)

σ = logistic sigmoid function

Reference

The models implemented here are heavily based on those presented in Chapter 10 of "Pattern Recognition and Machine Learning" (Bishop, 2006). However a key difference is that here, each model weight has its own distribution for precision, as does the noise term for the linear regression model.

Examples

use variational_regression::*;

fn main() -> Result<(), RegressionError> {

    // construct features
    let features: &[&[f64]] = &[
        &[-0.2, -0.9, -0.5, 0.3],
        &[0.6, 0.3, 0.3, -0.4],
        &[0.9, -0.4, -0.5, -0.6],
        &[-0.7, 0.8, 0.3, -0.3],
        &[-0.5, -0.7, -0.1, 0.8],
        &[0.5, 0.5, 0.0, 0.1],
        &[0.1, -0.0, 0.0, -0.2],
        &[0.4, 0.0, 0.2, 0.0],
        &[-0.2, 0.9, -0.1, -0.9],
        &[0.1, 0.4, -0.5, 0.9],
    ];
    
    // construct labels
    let labels: &[f64] = &[-0.4, 0.1, -0.8, 0.5, 0.6, -0.2, 0.0, 0.7, -0.3, 0.2];
    
    // configure and train model
    let config = LinearTrainConfig::default();
    let model = VariationalLinearRegression::train(features, labels, &config)?;
    
    // inspect model bias
    if let Some(bias) = model.bias() {
        println!("Bias: {}", bias);
    }

    // inspect model weights
    for (ind, weight) in model.weights().iter().enumerate() {
        println!("Weight {}: {}", ind + 1, weight);
    }

    // inspect noise variance
    println!("Noise Variance: {}", 1.0 / model.noise_precision.mean());
    
    // get predictive distribution
    let prediction = model.predict(&[0.1, -0.5, 0.3, 0.9])?;
    println!("Predictive mean: {}", prediction.mean());
    
    Ok(())
}
use variational_regression::*;

fn main() -> Result<(), RegressionError> {

    // construct features
    let features: &[&[f64]] = &[
        &[-0.2, -0.9, -0.5, 0.3],
        &[0.6, 0.3, 0.3, -0.4],
        &[0.9, -0.4, -0.5, -0.6],
        &[-0.7, 0.8, 0.3, -0.3],
        &[-0.5, -0.7, -0.1, 0.8],
        &[0.5, 0.5, 0.0, 0.1],
        &[0.1, -0.0, 0.0, -0.2],
        &[0.4, 0.0, 0.2, 0.0],
        &[-0.2, 0.9, -0.1, -0.9],
        &[0.1, 0.4, -0.5, 0.9],
    ];
    
    // construct labels
    let labels: &[bool] = &[true, false, true, false, true, false, true, false, true, false];
    
    // configure and train model
    let config = LogisticTrainConfig::default();
    let model = VariationalLogisticRegression::train(features, labels, &config)?;
    
    // inspect model bias
    if let Some(bias) = model.bias() {
        println!("Bias: {}", bias);
    }

    // inspect model weights
    for (ind, weight) in model.weights().iter().enumerate() {
        println!("Weight {}: {}", ind + 1, weight);
    }

    // get predictive distribution
    let prediction = model.predict(&[0.1, -0.5, 0.3, 0.9])?;
    println!("Predictive mean: {}", prediction.mean());

    Ok(())
}

Dependencies

~4MB
~82K SLoC