[PYTHON] Es war schwierig, Kernel-Tricks in Support-Vektor-Maschinen zu verstehen (Teil 2: Kernel-Regression, Ridge-Regression usw.)

Einführung

Ich versuche das Inferenzmodell zu verstehen, das beim maschinellen Lernen verwendet wird. Dieses Mal habe ich eine Technik namens Kernel-Trick zusammengefasst. Letztes Mal habe ich einen groben Überblick und Implementierungsbeispiele zusammengefasst.

Ich habe versucht, die Support-Vektor-Maschine sorgfältig zu verstehen (Teil 1: Ich habe den Polynom / RBF-Kernel am Beispiel von MakeMoons ausprobiert). https://qiita.com/Fumio-eisan/items/f2553266a509d6f2d3a3

Diese Methode namens Kernel-Trick war für mich sehr schwer zu verstehen und ich hatte große Probleme. Ich hatte das Gefühl, dass ich mehr mathematisches Wissen brauchte, als logistische Regression und neuronale Netze zu verstehen. .. Ich möchte es auf leicht verständliche Weise zusammenfassen und dabei die Punkte berücksichtigen, die schwer zu verstehen sind, um so viel wie möglich zu erreichen.

Der Umriss ist unten.

Ich möchte eine nichtlineare Funktion erstellen. Was soll ich also tun?

Die Support Vector Machine ist ein Klassifikator, der nichtlineare Grenzen (= Superplane Separation) klassifizieren kann. Wenn es eine Grenze gibt, die Sie teilen möchten, wie in der Abbildung links unten gezeigt, formulieren Sie eine Funktion entlang dieser Grenze, um sie zu unterscheiden. Nun gibt es drei Techniken (soweit ich weiß), um nichtlineare Funktionen zu erstellen. Eine ist eine Methode namens Taylor-Expansion, eine Methode zur ** Approximation ** von Dreiecksfunktionen wie $ sin und cos $ mit Funktionen höherer Ordnung. Als nächstes folgt eine Technik namens Fourier-Klasse. Diese Methode wird häufig in Themen verwendet, die sich auf Wellenbewegungen beziehen, und wird durch die Summe von $ sin und cos $, die ebenfalls periodisch sind, für eine periodische Welle ausgedrückt. Und die letzte ist die sogenannte Kernel-Methode. Dies ist eine Methode zum Ausdrücken mit Funktionen wie exp und Polynom, die Exponentialfunktionen sind.

image.png

Dann wird eine nichtlineare Regression durch diese Methode durchgeführt, die als Kernel-Methode bezeichnet wird. Zu diesem Zeitpunkt sollten Sie eine Funktion erstellen, die mit den Testdaten übereinstimmt (siehe Abbildung unten). Zu diesem Zeitpunkt kann eine Kurve gezeichnet werden, die nicht der gewünschten Funktion ähnelt. Dies wird als Überlernen bezeichnet. Als Gegenmaßnahme werden wir einen Regularisierungsbegriff hinzufügen, um Überlernen zu verhindern.

image.png

Erstellen Sie auf diese Weise die optimale Funktion. Ab dem nächsten Mal möchte ich es verstehen, während ich es implementiere, während ich ein bisschen mehr kaue.

Kernel-Regression verstehen

Kommen wir nun zur Kernel-Regression. Wie ich bereits kurz erwähnt habe, verstehe ich es als Mittel, um nichtlineare Linien zu zeichnen. Ein ähnlicher (denkender) Ausdruck ist die Fourier-Klasse. Die Idee ist, die Wellenbewegung durch Hinzufügen von Sinus- und Cosinuswellen auszudrücken. Bei der Arbeit habe ich diese Technik verwendet, um die Pulsationen zu analysieren, die durch die Gasleitungen fließen. Daher dachte ich, dass die Kernel-Regression eine ähnliche Logik hat.

image.png

Die Kernel-Regression wird nun als die Summe der $ N $ -Kernfunktionen dargestellt. Diese $ N $ -Nummer ist die Anzahl der Testdatenproben.

f({\bf x}) = \sum_{i=1}^{N} \alpha_i k({\bf x}^{(i)}, {\bf x})

Die durch dieses $ k ({\ bf x} ^ {(i)}, {\ bf x}) $ dargestellte Stelle wird als Kernelfunktion bezeichnet. Es gibt verschiedene Arten dieser Kernelfunktion. Typische sind der Gaußsche Kernel und der polymorphe Kernel. Es wird durch die folgende Formel ausgedrückt.

Gaußscher Kernel:
k({\bf x}, {\bf x}') = exp(-\beta \|{\bf x} - {\bf x}'\|^2)\\

Polygonaler Kernel:
k({\bf x}, {\bf x}') =  ({\bf x} {\bf x}'+c)^p

Spielen Sie mit dem Gaußschen Kernel

Dieses Mal möchte ich es mit dem Gaußschen Kernel ausdrücken. Im Gaußschen Kernel können Sie sich den Wert von $ β $ als Höhe des Absolutwerts und $ x '$ als Position der Anzahl der Samples vorstellen. Die Funktion, wenn $ β $ und 'x' 'geändert werden, ist unten gezeigt.

kernel.ipynb


import numpy as np

def kernel(xi, xj, beta=1):
    return np.exp(- beta * np.sum((xi - xj)**2))

X = np.arange(-1.5, 1.5, 0.05)
Y = np.zeros(len(X))
for i in range(len(X)):
    Y[i] = kernel(X[i], 0, 10)
    
X1 = np.arange(-1.5, 1.5, 0.05)
Y1 = np.zeros(len(X1))
for i in range(len(X1)):
    Y1[i] = kernel(X[i], 0, 1)
    
X2 = np.arange(-1.5, 1.5, 0.05)
Y2 = np.zeros(len(X2))
for i in range(len(X2)):
    Y2[i] = kernel(X[i], -1, 1)


plt.figure(figsize=(7, 4))
plt.plot(X2, Y2,label='beta=1,x=-1')
plt.plot(X1, Y1,label='beta=1')
plt.plot(X, Y,label='beta=10')
plt.legend()
plt.show()

015.png

Sie können sehen, dass eine schärfere Funktion durch Erhöhen von $ β $ gezeichnet werden kann. Sie können auch sehen, dass sich durch Manipulieren des Werts von $ x '$ die Position des Scheitelpunkts verschiebt.

Lassen Sie uns nun über die Zusammensetzung dieser Kernelfunktion sprechen. Um die tatsächliche nichtlineare Funktion darzustellen, muss dieser Gaußsche Kern addiert werden. Im folgenden Programm werden die generierten Gaußschen Kernel addiert und geplottet.

kernel.ipynb


def kernel(xi, xj, beta=1):
    return np.exp(- beta * np.sum((xi - xj)**2))

X = np.arange(-1.5, 1.5, 0.01)
Y = np.zeros(len(X))

centers = [0,-1,1]
weights = [1,-1,2]
for i in range(len(X)):
    for weight, center in zip(weights, centers):
        Y[i] += weight * kernel(X[i], center, 10)

plt.figure(figsize=(7, 4))
plt.plot(X, Y)
plt.show()

016.png

Ich habe eine entsprechende Zahl eingegeben und berechnet, aber ich konnte eine entsprechend unordentliche nichtlineare Form ausdrücken.

Erstellen Sie eine optimierte Kernelfunktion gemäß den Testdaten

Nachdem wir nun wissen, dass wir eine nichtlineare Funktion haben, möchten wir das Verfahren zum Erstellen einer beliebigen nichtlinearen Funktion verstehen. Bei linearer Regression wird der Koeffizient durch Minimierung der Fehlerfunktion optimiert. Die Idee ist dieselbe für die Kernel-Regression. Optimiert für $ N $ von $ alpha_ {0 bis N} $ in $ N $ Beispieltestdaten (z. B. $ (x ^ {(1)}, y ^ {(1)}) $) Sie können eine Funktion erstellen, die durch Ausführen Nichtlinearität ausdrücken kann.

\hat{y} =
\left(\begin{matrix}
k({\bf x}^{(1)}, {\bf x}) & k({\bf x}^{(2)}, {\bf x}) & \cdots & k({\bf x}^{(N)}, {\bf x})
\end{matrix}\right)
\left(\begin{matrix}
\alpha_0 \\
\alpha_1 \\
\vdots \\
\alpha_N
\end{matrix}\right)

Und

{\bf y} = 
\left(\begin{matrix}
y^{(1)} \\
y^{(2)} \\
\vdots \\
y^{(N)}
\end{matrix}\right)
,\;
K=\left(\begin{matrix}
k({\bf x}^{(1)}, {\bf x}^{(1)}) & k({\bf x}^{(2)}, {\bf x}^{(1)}) & \cdots & k({\bf x}^{(N)}, {\bf x}^{(1)}) \\
k({\bf x}^{(1)}, {\bf x}^{(2)}) & k({\bf x}^{(2)}, {\bf x}^{(2)}) & & \vdots \\
\vdots & & \ddots & \vdots \\
k({\bf x}^{(1)}, {\bf x}^{(N)}) & \cdots & \cdots & k({\bf x}^{(N)}, {\bf x}^{(N)})
\end{matrix}\right) 
,\;
{\bf \alpha}
=
\left(\begin{matrix}
\alpha^{(1)} \\
\alpha^{(2)} \\
\vdots \\
\alpha^{(N)}
\end{matrix}\right)

Lassen Sie uns die Fehlerfunktion als $ R (α) $ ausdrücken und das Quadrat der Differenz zwischen den Testdatenwerten $ y $ und $ f (x) $ sein.

\begin{align}
R({\bf \alpha}) &= \sum_{i=1}^{N}\left\{y^{(i)}- f({\bf x}^{(i)})\right\}^2
=\sum_{i=1}^{N}\left\{y^{(i)}- \sum_{i=1}^{N} \alpha_i k({\bf x}^{(i)}, {\bf x})\right\}^2 \\
&=(\begin{array} yy_1 - \alpha_1k(\bf x^{(1)}-\bf x)&y_2 - \alpha_2k(\bf x^{(2)}-\bf x)  &\cdots&y_n - \alpha_Nk(\bf x^{(N)}-\bf x) \end{array})
\begin{pmatrix}
y_1 - \alpha_1k(\bf x^{(1)}-\bf x)\\
y_2 - \alpha_2k(\bf x^{(2)}-\bf x) \\
\vdots \\
y_n - \alpha_Nk(\bf x^{(N)}-\bf x)\\ 
\end{pmatrix}\\

&=({\bf y}- K {\bf \alpha})^{\mathrm{T}}({\bf y}- K {\bf \alpha})
\end{align}

Sie können die Fehlerfunktion wie folgt darstellen. Auch in Bezug auf $ \ alpha $,


\bf y = \bf K\bf α \\
∴\bf α = \bf K^{-1} \bf y

Kann unter Verwendung der inversen Matrix der Kernelfunktion erhalten werden.

Nun möchte ich die von der $ cos $ -Funktion gezeichnete Kurve als geeigneten Datensatz reproduzieren.

kernel.ipynb


import pandas as pd

def wave_dataset(size, xlim=[0, 2], scale=None):
    x = np.random.uniform(xlim[0], xlim[1], size)
    y = np.cos(x)
    if scale is not None:
        noize = np.random.normal(0, scale, size)
        y = y + noize
    df = pd.DataFrame()
    df['x'] = x
    df['y'] = y
    return df

data = wave_dataset(20, xlim=[-3.14, 3.14], scale=0.05)

plt.figure(figsize=(7, 4))
plt.scatter(data['x'].values, data['y'].values)
plt.ylim((-1.5, 1.5))
plt.show()

017.png

Sie können zufällige Werte mit der Methode np.random.uniform () generieren. Ich habe diesen Wert zu dem Wert hinzugefügt, den die $ cos $ -Funktion erhalten hat, um einen etwas anderen Wert zu generieren.

Als nächstes geben wir Werte in die Kernelfunktion ein. Berechnen Sie dann $ \ alpha $ aus der inversen Matrix.

kernel.ipynb


from itertools import combinations_with_replacement

X = data['x'].values
Y = data['y'].values

#Hyperparameter
beta = 1

#Die Anzahl der Daten
N = X.shape[0]

#Gramm-Matrix-Berechnung
K = np.zeros((N, N))
for i, j in combinations_with_replacement(range(N), 2):
    K[i][j] = kernel(X[i], X[j])
    K[j][i] = K[i][j]

#Gewicht berechnen
alpha = np.linalg.inv(K).dot(Y)

Jetzt können Sie loslegen. Lassen Sie uns abschließend eine Funktion generieren und schreiben, indem Sie die Kernel-Regression mithilfe eines Datasets durchführen.

kernel.ipynb


#Kernel-Regression
def kernel_predict(X, x, alpha, beta):
    Y = 0
    for i in range(len(X)):
        Y += alpha[i] * kernel(X[i], x, beta)
    return Y

#Prognostizieren Sie die Ergebnisse durch Regression
X_axis = np.arange(-3.14, 3.14, 0.01)
Y_predict = np.zeros(len(X_axis))
for i in range(len(X_axis)):
    Y_predict[i] = kernel_predict(X, X_axis[i], alpha, beta)

#Ergebnis zeichnen
plt.figure(figsize=(7, 4))

##Beobachtungsdaten
plt.scatter(data['x'].values, data['y'].values)
##Wahre Funktion
plt.plot(X_axis, np.cos(X_axis), c='red')
##Voraussichtliche Funktion
plt.plot(X_axis, Y_predict)

plt.ylim((-1.5, 1.5))
plt.show()

019.png

Blau ist die Funktion, die durch die Kernel-Regression erzeugt wird. Sicher, es ist nahe am Punkt der Testdaten, aber es unterscheidet sich von der $ cos $ -Funktion. Dies ist ein Problem beim Modellübertraining. Tatsächlich ist der Wert von $ α $ wie folgt.

image.png

Sie können sehen, dass es einen sehr großen Wert in der Größenordnung von $ 10 ^ {9-13} $ enthält. Damit nimmt auch der maximal erreichbare Wert einen großen Wert an.

Als Gegenmaßnahme wird es gelöst, indem ein Verfahren zum Einfügen eines Regularisierungsterms durchgeführt wird.

Kammregression verstehen

Übrigens besteht der Regularisierungsterm darin, den quadratischen Fehler durch Hinzufügen eines Terms zu regulieren, der als Regularisierungsterm bezeichnet wird.

\begin{align}
R({\bf \alpha})
&=({\bf y}- K {\bf \alpha})^{\mathrm{T}}({\bf y}- K {\bf \alpha}) + \lambda {\bf \alpha}^{\mathrm{T}} K {\bf \alpha}
\end{align}

Das Minimieren der Verlustfunktion durch Hinzufügen von $ \ lambda {\ bf \ alpha} ^ {\ mathrm {T}} K {\ bf \ alpha} $ wird als ** Ridge-Regression ** bezeichnet. Dieser Begriff wird als Regressionsbegriff für die Gratregression bezeichnet. Grundsätzlich wollen wir den Wert dieser Verlustfunktion minimieren, also müssen wir auch $ α $ reduzieren. Wenn Sie unter dieser Bedingung nach $ \ alpha $ fragen, kann dies wie folgt ausgedrückt werden.

{\bf \alpha} = (K+\lambda I_N)^{-1}{\bf y}

Mit dieser Idee möchte ich $ \ alpha $ neu berechnen und erneut zeichnen.

kernel.ipynb



#Regularisierungstermkoeffizient
lam = 0.5
alpha_r = np.linalg.inv(K + lam * np.eye(K.shape[0])).dot(Y)

#Prognostizieren Sie die Ergebnisse durch Regression
Y_predict_r = np.zeros(len(X_axis))
for i in range(len(X_axis)):
    Y_predict_r[i] = kernel_predict(X, X_axis[i], alpha_r, beta)

#Ergebnis zeichnen
plt.figure(figsize=(6.472, 4))

##Beobachtungsdaten
plt.scatter(data['x'].values, data['y'].values)
##Wahre Funktion
plt.plot(X_axis, np.cos(X_axis), c='red')
##Voraussichtliche Funktion
plt.plot(X_axis, Y_predict_r)

plt.ylim((-1.5, 1.5))
plt.show()

020.png

Es ist fertig. Ich denke, ich könnte sagen, dass ich es reproduzieren konnte (obwohl der Bereich um $ x = 3 $ aufgrund des Mangels an Testdaten ein Wendepunkt ist).

abschließend

Es mag ein Ansturm gewesen sein, aber ich habe das Verfahren zum Erstellen einer nichtlinearen Funktion in einer Support-Vektor-Maschine zusammengefasst. Es war schwer, weil ich es oft mathematisch verstehen musste. Andererseits habe ich das Gefühl, dass ich durch den Verständnis der Idee auf die Attraktivität dieses Algorithmus aufmerksam geworden bin.

Hier ist ein Artikel, auf den ich viel Bezug genommen habe.

Lineare Methode und Kernel-Methode (Regressionsanalyse) https://qiita.com/wsuzume/items/09a59036c8944fd563ff

Das vollständige Programm finden Sie hier. https://github.com/Fumio-eisan/SVM_20200417

Recommended Posts

Es war schwierig, Kernel-Tricks in Support-Vektor-Maschinen zu verstehen (Teil 2: Kernel-Regression, Ridge-Regression usw.)
PyTorchs Buch war schwer zu verstehen, deshalb habe ich es ergänzt
Ich habe versucht, die Support-Vektor-Maschine sorgfältig zu verstehen (Teil 1: Ich habe den Polynom / RBF-Kernel am Beispiel von MakeMoons ausprobiert).