chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,83 @@
|
||||
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)
|
||||
Reference in New Issue
Block a user