84 lines
2.2 KiB
Python
Executable File
84 lines
2.2 KiB
Python
Executable File
import numpy as np
|
|
from prml.linear.classifier import Classifier
|
|
from prml.preprocess.label_transformer import LabelTransformer
|
|
|
|
|
|
class SoftmaxRegression(Classifier):
|
|
"""
|
|
Softmax regression model
|
|
aka
|
|
multinomial logistic regression,
|
|
multiclass logistic regression,
|
|
maximum entropy classifier.
|
|
|
|
y = softmax(X @ W)
|
|
t ~ Categorical(t|y)
|
|
"""
|
|
|
|
@staticmethod
|
|
def _softmax(a):
|
|
a_max = np.max(a, axis=-1, keepdims=True)
|
|
exp_a = np.exp(a - a_max)
|
|
return exp_a / np.sum(exp_a, axis=-1, keepdims=True)
|
|
|
|
def fit(self, X:np.ndarray, t:np.ndarray, max_iter:int=100, learning_rate:float=0.1):
|
|
"""
|
|
maximum likelihood estimation of the parameter
|
|
|
|
Parameters
|
|
----------
|
|
X : (N, D) np.ndarray
|
|
training independent variable
|
|
t : (N,) or (N, K) np.ndarray
|
|
training dependent variable
|
|
in class index or one-of-k encoding
|
|
max_iter : int, optional
|
|
maximum number of iteration (the default is 100)
|
|
learning_rate : float, optional
|
|
learning rate of gradient descent (the default is 0.1)
|
|
"""
|
|
if t.ndim == 1:
|
|
t = LabelTransformer().encode(t)
|
|
self.n_classes = np.size(t, 1)
|
|
W = np.zeros((np.size(X, 1), self.n_classes))
|
|
for _ in range(max_iter):
|
|
W_prev = np.copy(W)
|
|
y = self._softmax(X @ W)
|
|
grad = X.T @ (y - t)
|
|
W -= learning_rate * grad
|
|
if np.allclose(W, W_prev):
|
|
break
|
|
self.W = W
|
|
|
|
def proba(self, X:np.ndarray):
|
|
"""
|
|
compute probability of input belonging each class
|
|
|
|
Parameters
|
|
----------
|
|
X : (N, D) np.ndarray
|
|
independent variable
|
|
|
|
Returns
|
|
-------
|
|
(N, K) np.ndarray
|
|
probability of each class
|
|
"""
|
|
return self._softmax(X @ self.W)
|
|
|
|
def classify(self, X:np.ndarray):
|
|
"""
|
|
classify input data
|
|
|
|
Parameters
|
|
----------
|
|
X : (N, D) np.ndarray
|
|
independent variable to be classified
|
|
|
|
Returns
|
|
-------
|
|
(N,) np.ndarray
|
|
class index for each input
|
|
"""
|
|
return np.argmax(self.proba(X), axis=-1)
|