[PYTHON] Régression du noyau avec Numpy uniquement

20190426185334.png

La méthode du noyau est une arme puissante pour l'analyse de données non linéaires. Il apparaît fréquemment comme un élément de base d'algorithmes tels que la SVM à marge souple, le processus gaussien et le clustering. Dans cet article, j'ai essayé de reproduire la procédure de résolution du problème de régression en utilisant la méthode du noyau en Python.

TL;DR Please check this repository and see codes.

<img src = "https: //images-fe.ssl-images-amazon." com / images / I / 51xaudRn0LL.SL160.jpg "class =" hatena-asin-detail-image "alt =" Analyse multivariée du noyau - un nouveau développement dans l'analyse de données non linéaires (probabilité de séries et science de l'information) "title =" Analyse multivariée - Un nouveau développement dans l'analyse de données non linéaire (série Probabilité et science de l'information) "> <img src = "https: //images-fe.ssl-images-amazon." com / images / I / 41QTf1ofh-L.SL160.jpg "class =" hatena-asin-detail-image "alt =" Introduction à la méthode du noyau-analyse des données avec le noyau à valeur positive (série Multivariate Data Statistical Science) "title = "Introduction à l'analyse des données de la méthode du noyau avec le noyau à valeur positive (série Statistical Science of Multivariate Data)">


Qu'est-ce que la régression du noyau?

Fonction noyau et matrice gramme

$ n $ Échantillon de données $ \ mathcal {D} = \ left \ {x ^ {(i)}, y ^ {(i)} \ right \} , (i = 1, \ dots n) À partir de $, approximez la fonction $ y = f (x) $. Le modèle de régression est exprimé par l'équation suivante en utilisant la fonction noyau $ k (\ cdot, \ cdot) $ et le paramètre $ {\ alpha} _i , (i = 1 \ dots n) $.

\hat{y}^{(i)} = \sum\_{j=1}^{n} \alpha_j k(x^{(i)}, x^{(j)}) ~~~~ (i=1 \dots n)

La distance entre la valeur estimée $ \ hat {y} ^ {(i)} $ et la valeur vraie $ y ^ {(i)} $ est calculée comme le résidu. Ajustez le modèle à l'échantillon de données, dérivez la somme (ou moyenne) des résidus comme fonction de perte du modèle et trouvez les paramètres optimaux $ {\ alpha} _i , (i = 1 \ dots n) $.

\begin{align} residual(y^{(i)}, \hat{y}^{(i)}) &= y^{(i)} - \hat{y}^{(i)} \\\ &= y^{(i)} - \sum\_{j=1}^{n} \alpha\_j k(x^{(i)}, x^{(j)}) \end{align}
\begin{align} L(\alpha) &= \frac{1}{n} \sum\_{i=1}^{n} {residual(y^{(i)}, \hat{y}^{(i)}) }^{2} \\\ &= \frac{1}{n} \sum\_{i=1}^{n} { \left( y^{(i)} - \sum\_{j=1}^{n} \alpha\_j k(x^{(i)}, x^{(j)}) \right) }^{2} \\\ &= {({\bf y} - {\bf K} {\bf \alpha})}^{\mathrm{T}} ({\bf y} - {\bf K} {\bf \alpha}) \end{align}
where, \,\,\, {\bf K} = \begin{pmatrix} k(x^{(1)}, x^{(1)}) & \cdots & k(x^{(1)}, x^{(n)}) \\\ \vdots & \ddots & \vdots \\\ k(x^{(n)}, x^{(1)}) & \cdots & k(x^{(n)}, x^{(n)}) \end{pmatrix}

$ {\ bf K} $ est une matrice qui est calculée à partir d'un échantillon de données à partir d'une fonction noyau, et s'appelle une Gram Matrix.

Recherche de paramètres par méthode de descente de gradient

La méthode naïve de descente de gradient est utilisée pour rechercher le paramètre $ {\ alpha} \ _ i , (i = 1 \ dots n) $. Le coefficient $ \ gamma $ est le taux d'apprentissage.

\frac{\partial L(\alpha)}{\partial {\bf \alpha}} = -2 \cdot {\bf K}^{\mathrm{T}} ({\bf y} - {\bf K} {\bf \alpha}) \\\ {\alpha}\_{new} = {\alpha}\_{old} + \gamma \cdot \frac{\partial L(\alpha)}{\partial {\bf \alpha}} \mid\_{ \alpha = {\alpha}\_{old} }

Le noyau RBF (noyau gaussien) est adopté comme fonction du noyau.

k(x, x') := \exp \left( {\large - \frac{{|| x - x' ||}^2}{2 {\sigma}^{2}} } \right)

Implémenter la régression du noyau en Python (numpy uniquement)

Tout le code se trouve dans le référentiel suivant. https://github.com/yumaloop/KernelRegression

import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline

# Kernel Function
class RBFkernel():
    def __init__(self, sigma=0.5):
        self.sigma = sigma
        
    def __call__(self, x, y):
        numerator = -1 * np.sum((x - y)**2)
        denominator = 2 * (self.sigma**2)
        return np.exp(numerator / denominator)
    
    def get_params(self):
        return self.sigma
    
    def set_params(self, sigma):
        self.sigma = sigma

# Regression Model
class KernelRegression():
    def __init__(self, kernel):
        self.kernel = kernel
        
    def fit_kernel(self, X, y, lr=0.01, nb_epoch=1000, log_freq=50):
        self.X = X
        self.y = y
        self.n = X.shape[0] # sample size
        self.alpha = np.full(self.n, 1) # param alpha: initialize
        self.gram_matrix = np.zeros((self.n, self.n))
        
        # Gradient Descent Algorithm to optimize alpha
        for epoch in range(nb_epoch):
            
            # Gram Matrix
            for i in range(self.n):
                for j in range(self.n):
                    self.gram_matrix[i][j] = self.kernel(self.X[i], self.X[j])
                    self.loss, self.loss_grad = self.mse(self.X, self.y, self.alpha, self.gram_matrix)
                    self.alpha = self.alpha - lr * self.loss_grad
                    
            if epoch % log_freq == 0:
                print("epoch: {} \t MSE of sample data: {:.4f}".format(epoch, self.loss))
                        
                        
    def mse(self, X, y, alpha, gram_matrix):
        loss = np.dot((y - np.dot(gram_matrix, alpha)), (y - np.dot(gram_matrix, alpha)))
        loss_grad = -2 * np.dot(gram_matrix.T, (y - np.dot(gram_matrix, alpha)))
        return loss, loss_grad
    
    def predict(self, X_new):
        n_new = X_new.shape[0]
        y_new = np.zeros(n_new)
        for i in range(n_new):
            for j in range(self.n):
                y_new[i] += self.alpha[j] * self.kernel(X_new[i], self.X[j])
        return y_new
# Experiment

def actual_function(x):
    return 1.7 * np.sin(2 * x) + np.cos(1.5 * x) + 0.5 * np.cos(0.5 * x) + 0.5 * x  + 0.1

sample_size = 100 # the number of data sample
var_noise = 0.7 # variance of the gaussian noise for samples

# make data sample
x_sample = np.random.rand(sample_size) * 10 - 5
y_sample = actual_function(x_sample) + np.random.normal(0, var_noise, sample_size)

# variables for plot (actual function)
x_plot = np.linspace(-5, 5, 100)
y_plot = actual_function(x_plot)

# plot figure
plt.plot(x_plot, y_plot, color="blue", linestyle="dotted", label="actual function")
plt.scatter(x_sample, y_sample, alpha=0.4, color="blue", label="data sample")
plt.title("Actual function & Data sample (N={})".format(sample_size))
plt.legend(loc="upper left")
plt.xlabel("x")
plt.ylabel("y")
plt.show()

20190426184220.png

# set kernel
sigma=0.2
kernel = RBFkernel(sigma=sigma)

# generate model
model = KernelRegression(kernel)

# fit data sample for the model
model.fit_kernel(x_sample, y_sample, lr=0.01, nb_epoch=1000, log_freq=100)
  epoch: 0      MSE of sample data: 35.2988
  epoch: 100 	 MSE of sample data: 30.3570
  epoch: 200 	 MSE of sample data: 29.4241
  epoch: 300 	 MSE of sample data: 28.8972
  epoch: 400 	 MSE of sample data: 28.5597
  epoch: 500 	 MSE of sample data: 28.3322
  epoch: 600 	 MSE of sample data: 28.1736
  epoch: 700 	 MSE of sample data: 28.0598
  epoch: 800 	 MSE of sample data: 27.9759
  epoch: 900 	 MSE of sample data: 27.9122

# check Gram Matrix of the model
print(model.gram_matrix)
  array([[1.00000000e+000, 3.24082380e-012, 1.86291046e-092, ...,
        3.45570112e-030, 7.50777061e-016, 6.18611768e-129],
       [3.24082380e-012, 1.00000000e+000, 5.11649994e-039, ...,
        1.78993799e-078, 1.05138357e-053, 1.15421467e-063],
       [1.86291046e-092, 5.11649994e-039, 1.00000000e+000, ...,
        6.88153992e-226, 4.47677881e-182, 8.98951607e-004],
       ...,
       [3.45570112e-030, 1.78993799e-078, 6.88153992e-226, ...,
        1.00000000e+000, 4.28581263e-003, 2.58161981e-281],
       [7.50777061e-016, 1.05138357e-053, 4.47677881e-182, ...,
        4.28581263e-003, 1.00000000e+000, 3.95135557e-232],
       [6.18611768e-129, 1.15421467e-063, 8.98951607e-004, ...,
        2.58161981e-281, 3.95135557e-232, 1.00000000e+000]])

# check loss
print(model.loss)
  12.333081499130776

# array for plot (predicted function)
x_new = np.linspace(-5, 5, 100)
y_new = model.predict(x_new)

 plot result
plt.plot(x_plot, y_plot, color="blue", linestyle="dotted", label="actual function")
plt.scatter(x_sample, y_sample, alpha=0.3, color="blue", label="data sample")
plt.plot(x_new, y_new, color="red", label="predicted function")
plt.title("Kernel Regression \n RBF kernel (sigma={}), sample size ={}".format(sigma, sample_size))
plt.legend(loc="upper left")
plt.xlabel("x")
plt.ylabel("y")
plt.show()

20190426185334.png


c'est tout. Merci d'avoir lu jusqu'au bout!

Recommended Posts

Régression du noyau avec Numpy uniquement
Effectuer une analyse de régression avec NumPy
Implémentation de la régression logistique avec NumPy
"Processus Gauss et apprentissage automatique" Régression de processus Gauss implémentée uniquement avec Python numpy
Régression linéaire avec statsmodels
Méthode Kernel avec Python
Moyenne mobile avec numpy
Régression avec un modèle linéaire
Premiers pas avec Numpy
Apprenez avec Chemo Informatics NumPy
Concaténation de matrices avec Numpy
Code de bourdonnement avec numpy
Essayez la régression avec TensorFlow
Étendre NumPy avec Rust
J'ai écrit GP avec numpy
Implémentation CNN avec juste numpy
Génération artificielle de données avec numpy
Analyse de régression multiple avec Keras
Noyau Linux auto-construit avec clang
[Python] Méthode de calcul avec numpy
Essayez l'opération matricielle avec NumPy
Ridge retour avec Mllib à Pyspark
Animation de l'équation de diffusion avec NumPy
Simulation de remboursement de dette avec numpy
Implémentation de SMO avec Python + NumPy
Coller les chaînes avec Numpy
Apprentissage profond du noyau avec Pyro
Méthode de régression linéaire utilisant Numpy
Gérez les tableaux numpy avec f2py
[Python] Régression linéaire avec scicit-learn
Utilisez OpenBLAS avec numpy, scipy
Implémentation de réseau neuronal (NumPy uniquement)
Régression linéaire robuste avec scikit-learn
Effectuez un ajustement carré minimum avec numpy.
Paramètre de fonction uniquement pour l'astérisque '*'
Dessinez un beau cercle avec numpy
Régression linéaire avec distribution t de Student
Implémenter Keras LSTM feed forward avec numpy
Extraire plusieurs éléments avec le tableau Numpy
Analyse de régression logistique Self-made avec python
Utiliser un noyau personnalisé avec WSL2
Prédiction des ondes de Sin (retour) avec Pytorch
J'ai essayé de mettre en œuvre un apprentissage en profondeur qui n'est pas profond avec uniquement NumPy