In [1]:
%matplotlib inline
import matplotlib.pyplot as plt
import numpy as np
from sklearn.preprocessing import PolynomialFeatures
import bayesnet as bn

np.random.seed(1111)

In [2]:
x_train = np.random.uniform(-1, 1, 10)
X_train = PolynomialFeatures(3).fit_transform(x_train[:, None])
y_train = X_train @ np.array([0., -1., 0., 1.]) + np.random.normal(scale=0.1, size=x_train.size)

plt.scatter(x_train, y_train)
plt.xlim(-1, 1)
plt.show()



In [3]:
class LinearRegressor(bn.Network):
    
    def __init__(self, degree):
        super().__init__(
            w=np.zeros(degree + 1)
        )
        
    def __call__(self, x, y=None):
        self.py = bn.random.MultivariateGaussian((x * self.w).sum(axis=-1), np.eye(x.shape[0]), data=y)
        return self.py.mu.value

In [4]:
model = LinearRegressor(3)
optimizer = bn.optimizer.Adam(model, 1e-3)

for _ in range(10000):
    model.clear()
    model(X_train, y_train)
    log_likelihood = model.log_pdf()
    log_likelihood.backward()
    optimizer.update()

In [5]:
x = np.linspace(-1, 1, 100)
X = PolynomialFeatures(3).fit_transform(x[:, None])

y = model(X)
plt.scatter(x_train, y_train)
plt.plot(x, y, color="orange")
plt.xlim(-1, 1)
plt.show()



In [6]:
class BayesianLinearRegressor(bn.Network):
    
    def __init__(self, degree):
        super().__init__(
            w_mu=np.zeros(degree + 1),
            w_cov=np.eye(degree + 1)
        )
        
    def __call__(self, x, y=None):
        self.qw = bn.random.MultivariateGaussian(
            self.w_mu, self.w_cov @ self.w_cov.transpose(),
            p=bn.random.MultivariateGaussian(np.zeros(self.w_mu.size), np.eye(self.w_mu.size))
        )
        self.py = bn.random.MultivariateGaussian((x * self.qw.draw()).sum(axis=-1), 0.1 * np.eye(x.shape[0]), data=y)
        if y is None:
            return self.py.draw().value

In [7]:
model = BayesianLinearRegressor(3)
optimizer = bn.optimizer.Adam(model, 1e-3)

for _ in range(10000):
    model.clear()
    model(X_train, y_train)
    elbo = model.elbo()
    elbo.backward()
    optimizer.update()

In [8]:
x = np.linspace(-1, 1, 1000)
X = PolynomialFeatures(3).fit_transform(x[:, None])

y = [model(X) for _ in range(1000)]
y_mean = np.mean(y, axis=0)
y_std = np.std(y, axis=0)
plt.scatter(x_train, y_train)
plt.plot(x, y_mean, color="orange")
plt.fill_between(x, y_mean - y_std, y_mean + y_std, color="orange", alpha=0.2)
plt.xlim(-1, 1)
plt.show()



In [9]:
class AnalyticalBayesianLinearRegression(object):
    
    def __init__(self, alpha=1.0, beta=1.0):
        self.alpha = alpha
        self.beta = beta
        
    def fit(self, X, y):
        self.w_cov = np.linalg.inv(self.alpha * np.eye(X.shape[1]) + self.beta * X.T @ X)
        self.w_mean = self.beta * self.w_cov @ X.T @ y
        
    def predict(self, X):
        y_mean = X @ self.w_mean
        y_var = 1 / self.beta + np.sum(X @ self.w_cov * X, axis=-1)
        return y_mean, y_var

In [10]:
model = AnalyticalBayesianLinearRegression(alpha=1., beta=10.)
model.fit(X_train, y_train)

In [11]:
x = np.linspace(-1, 1, 1000)
X = PolynomialFeatures(3).fit_transform(x[:, None])

y_mean, y_var = model.predict(X)
y_std = np.sqrt(y_var)
plt.scatter(x_train, y_train)
plt.plot(x, y_mean, color="orange")
plt.fill_between(x, y_mean - y_std, y_mean + y_std, color="orange", alpha=0.2)
plt.xlim(-1, 1)
plt.show()



In [ ]: