In [1]:
%matplotlib inline
import matplotlib.pyplot as plt
import numpy as np
import bayesnet as bn
np.random.seed(1234)
In [2]:
x_train = np.array([
np.random.normal(loc=-7.5, scale=1, size=100),
np.random.normal(loc=-2.5, scale=1, size=100),
np.random.normal(loc=5, scale=2, size=100)
]).flatten()
plt.scatter(x_train, np.random.normal(scale=0.005, size=x_train.size), s=5)
plt.hist(x_train, bins=20, normed=True, alpha=0.2)
plt.show()
In [3]:
class GaussianMixture(bn.Network):
def __init__(self, n_component):
super().__init__(
c=np.ones(n_component),
mu=np.array([-10., 0., 10.]),
s=np.ones(n_component)
)
def __call__(self, x):
self.px = bn.random.GaussianMixture(bn.softmax(self.c), self.mu, bn.softplus(self.s), data=x)
return self.px.pdf().value
In [4]:
model = GaussianMixture(3)
optimizer = bn.optimizer.Adam(model, 1e-3)
for _ in range(10000):
model.clear()
model(x_train[:, None])
log_likelihood = model.log_pdf()
log_likelihood.backward()
optimizer.update()
In [5]:
plt.scatter(x_train, np.random.normal(scale=0.005, size=x_train.size), s=5)
plt.hist(x_train, bins=20, normed=True, alpha=0.2)
x = np.linspace(-10, 10, 1000)
p = model(x[:, None])
plt.plot(x, p)
plt.show()
In [6]:
class GaussianMixtureEM(bn.Network):
def __init__(self, n_component):
super().__init__(
c=np.ones(n_component),
mu=np.array([-10., 0., 10.]),
s=np.ones(n_component)
)
def __call__(self, x, z=None):
if z is None:
return bn.random.GaussianMixture(bn.softmax(self.c), self.mu, bn.softplus(self.s), data=x).pdf().value
self.pz = bn.random.Categorical(logit=bn.softmax(self.c), data=z)
self.px = bn.random.GaussianMixture(z, self.mu, bn.softplus(self.s), data=x)
return self.px.pdf().value * self.pz.pdf().value
In [7]:
model = GaussianMixtureEM(3)
optimizer = bn.optimizer.Adam(model, 1e-3)
for _ in range(10):
resp = np.stack([model(x_train[:, None], np.eye(3)[i]) for i in range(3)], axis=-1)
resp /= resp.sum(axis=-1, keepdims=True)
for _ in range(1000):
model.clear()
model(x_train[:, None], resp)
log_likelihood = model.log_pdf()
log_likelihood.backward()
optimizer.update()
In [8]:
resp = np.stack([model(x_train[:, None], np.eye(3)[i]) for i in range(3)], axis=-1)
resp /= resp.sum(axis=-1, keepdims=True)
plt.scatter(x_train, np.random.normal(scale=0.005, size=x_train.size), s=5, c=resp)
plt.hist(x_train, bins=20, normed=True, alpha=0.2)
x = np.linspace(-10, 10, 1000)
p = model(x[:, None])
plt.plot(x, p)
plt.show()
In [9]:
class VariationalGaussianMixture(bn.Network):
def __init__(self, n_component):
self.n_component = n_component
super().__init__(
c=np.ones(n_component),
m=np.linspace(-10, 10, n_component),
s=np.ones(n_component),
shape=np.ones(n_component),
rate=np.ones(n_component)
)
def gaussian(self, x, z):
self.qtau = bn.random.Gamma(self.shape, self.rate, p=bn.random.Gamma(1., 1.))
tau = self.qtau.draw()
pmu = bn.random.Gaussian(0., tau=tau)
self.qmu = bn.random.Gaussian(self.m, bn.softplus(self.s), p=pmu)
self.px = bn.random.GaussianMixture(z, self.qmu.draw(), 1 / bn.sqrt(tau), data=x)
def category(self, z):
coef = bn.softmax(self.c)
self.pc = bn.random.Dirichlet(np.ones(coef.shape) * 1., data=coef)
self.pz = bn.random.Categorical(coef, data=z)
def __call__(self, x, z=None):
if z is None:
self.gaussian(x, bn.softmax(self.c))
return self.px.pdf().value
self.category(z)
self.gaussian(x, z)
return self.pz.pdf().value * self.px.pdf().value
In [10]:
model = VariationalGaussianMixture(3)
optimizer_c = bn.optimizer.Adam([model.c], 1e-3)
optimizer_g = bn.optimizer.Adam([model.m, model.s, model.shape, model.rate], 1e-3)
for _ in range(10):
resp = 0
for _ in range(10):
resp_ = np.stack(
[model(x_train[:, None], np.eye(model.n_component)[i]) for i in range(model.n_component)],
axis=-1
)
resp_ /= resp_.sum(axis=-1, keepdims=True)
resp += resp_ / 10
for _ in range(100):
model.clear()
model.category(resp)
log_posterior = model.log_pdf()
log_posterior.backward()
optimizer_c.update()
for _ in range(1000):
model.clear()
model.gaussian(x_train[:, None], resp)
elbo = model.elbo()
elbo.backward()
optimizer_g.update()
In [11]:
resp = 0
for _ in range(10):
resp_ = np.stack(
[model(x_train[:, None], np.eye(model.n_component)[i]) for i in range(model.n_component)],
axis=-1
)
resp_ /= resp_.sum(axis=-1, keepdims=True)
resp = resp + resp_ / 10
plt.scatter(x_train, np.random.normal(scale=0.005, size=x_train.size), s=5, c=resp)
plt.hist(x_train, bins=20, normed=True, alpha=0.2)
x = np.linspace(-10, 10, 1000)
p = np.mean([model(x[:, None]) for _ in range(1000)], axis=0)
plt.plot(x, p)
plt.show()
In [ ]: