Files
mikoto10032--deeplearning/books/PRML/PRML-master-Python/prml/linear/variational_logistic_regression.py
T
2026-07-13 13:30:25 +08:00

89 lines
2.7 KiB
Python
Executable File

import numpy as np
from prml.linear.logistic_regression import LogisticRegression
class VariationalLogisticRegression(LogisticRegression):
def __init__(self, alpha:float=None, a0:float=1., b0:float=1.):
"""
construct variational logistic regressor
Parameters
----------
alpha : float
precision parameter of the prior
if None, this is also the subject to estimate
a0 : float
a parameter of hyper prior Gamma dist.
Gamma(alpha|a0,b0)
if alpha is not None, this argument will be ignored
b0 : float
another parameter of hyper prior Gamma dist.
Gamma(alpha|a0,b0)
if alpha is not None, this argument will be ignored
"""
if alpha is not None:
self.__alpha = alpha
else:
self.a0 = a0
self.b0 = b0
def fit(self, X:np.ndarray, t:np.ndarray, iter_max:int=1000):
"""
variational bayesian estimation of the parameter
Parameters
----------
X : (N, D) np.ndarray
training independent variable
t : (N,) np.ndarray
training dependent variable
iter_max : int, optional
maximum number of iteration (the default is 1000)
"""
N, D = X.shape
if hasattr(self, "a0"):
self.a = self.a0 + 0.5 * D
xi = np.random.uniform(-1, 1, size=N)
I = np.eye(D)
param = np.copy(xi)
for _ in range(iter_max):
lambda_ = np.tanh(xi) * 0.25 / xi
self.w_var = np.linalg.inv(I / self.alpha + 2 * (lambda_ * X.T) @ X)
self.w_mean = self.w_var @ np.sum(X.T * (t - 0.5), axis=1)
xi = np.sqrt(np.sum(X @ (self.w_var + self.w_mean * self.w_mean[:, None]) * X, axis=-1))
if np.allclose(xi, param):
break
else:
param = np.copy(xi)
@property
def alpha(self):
if hasattr(self, "__alpha"):
return self.__alpha
else:
try:
self.b = self.b0 + 0.5 * (np.sum(self.w_mean ** 2) + np.trace(self.w_var))
except AttributeError:
self.b = self.b0
return self.a / self.b
def proba(self, X:np.ndarray):
"""
compute probability of input belonging class 1
Parameters
----------
X : (N, D) np.ndarray
training data independent variable
Returns
-------
(N,) np.ndarray
probability of positive
"""
mu_a = X @ self.w_mean
var_a = np.sum(X @ self.w_var * X, axis=1)
y = self._sigmoid(mu_a / np.sqrt(1 + np.pi * var_a / 8))
return y