Pas à pas sur la théorie, l'implémentation en python et l'analyse à l'aide de scikit-learn sur l'algorithme précédemment repris dans "Classification of Machine Learning" J'étudierai avec. Je l'écris pour un apprentissage personnel, alors j'aimerais que vous oubliez toute erreur.
La dernière fois, j'ai écrit sur les bases de la machine vectorielle de support. La dernière fois, nous avons traité SVM, qui est appelé marge dure et peut séparer correctement les cas positifs et négatifs, mais cette fois
Je voudrais mentionner environ.
Prenons un exemple où les cercles rouge et bleu ne peuvent pas être subtilement séparés comme le montre la figure ci-dessous, contrairement à la fois précédente.
L'expression SVM à marge rigide est un ensemble de paramètres
Introduisez la variable slack $ \ xi $ et le paramètre $ C $ pour la relaxation. La variable slack est une variable de la quantité d'erreur autorisée entre le vecteur de support et la ligne de démarcation, et $ C (> 0) $ représente la rigueur de la condition de contrainte. Lorsque ceux-ci sont introduits, le problème à résoudre décrit ci-dessus change comme suit.
\frac{1}{2}|w|^2+C\sum_{i=1}^{N}\xi_i \\
t_n(\boldsymbol{w}^Tx_n+w_0) \geq 1-\xi_n \\
\xi_n \geq 0
Concernant la relation entre $ C $ et $ \ xi $, si $ C $ est grand, il ne peut être minimisé que si $ \ xi $ est petit, et si $ C $ est petit, il peut être minimisé même si $ \ xi $ est grand dans une certaine mesure. Cela signifie que. Si $ C $ est infini, c'est la même chose qu'un SVM à marge ferme, car $ \ xi $ ne peut tolérer que zéro (= ne pas autoriser les données dans la marge).
Contrairement à la marge ferme, la contrainte a été augmentée à deux, donc le multiplicateur de Lagrange est également défini sur $ \ lambda $ et $ \ mu $.
L(w,w_0,\lambda, \mu)=\frac{1}{2}|w|^2+C\sum_{i=1}^n\xi_i-\sum_{i=1}^{N}\lambda_i \{ t_i(\boldsymbol{w}^Tx_i+w_0)+\xi_i-1\}-\sum_{i=1}^n\mu_i\xi_i
Si cela est partiellement différencié pour $ w $, $ w_0 $ et $ \ xi $ et mis à zéro,
w=\sum_{i=1}^n\lambda_it_ix_i \\
\sum_{i=1}^n\lambda_it_i=0 \\
\lambda_i=C-\mu_i
Peut être obtenu, et lorsqu'il est affecté à la fonction de Lagrange,
L(\lambda)=\sum_{n=1}^{N}\lambda_n-\frac{1}{2}\sum_{n=1}^{N}\sum_{m=1}^{N}\lambda_n\lambda_mt_nt_mx_n^Tx_m
Et c'est exactement la même formule que pour la marge dure. Cependant, la contrainte est
\sum_{i=1}^n\lambda_it_n=0 \\
0 \leq \lambda_i \leq C
Ce sera. Comme pour la marge rigide, il est possible de trouver les paramètres à l'aide de SMO. (Omis cette fois)
Prenons l'exemple suivant, qui semble inséparable par une ligne droite.
S'il a une telle forme, déplacez le point vers un espace dimensionnel plus élevé, puis séparez les plans, par exemple 2D → 3D. La méthode de conversion à un ordre supérieur est appelée la ** méthode du noyau **, et la fonction de conversion est appelée la ** fonction du noyau **.
Une chaîne de données qui projette $ \ boldsymbol {x} = (x_0, x_1, \ cdots, x_ {n-1}) $ est $ \ boldsymbol {\ phi} = \ {\ phi_0 (\ boldsymbol {x) }), \ phi_1 (\ boldsymbol {x}), \ cdots, \ phi_ {m-1} (\ boldsymbol {x}) \} $. Cette $ \ phi (x) $ est appelée ** fonction de base **. Comme le SVM précédent était capable de gérer la séparation linéaire, la fonction de base était équivalente à
En appliquant la fonction de base, la partie $ x_n ^ Tx_m $ de la fonction de Lagrange se transforme en $ \ phi (x) _n ^ T \ phi (x) _m $.
L(\lambda)=\sum_{n=1}^{N}\lambda_n-\frac{1}{2}\sum_{n=1}^{N}\sum_{m=1}^{N}\lambda_n\lambda_mt_nt_m\phi(x)_n^T\phi(x)_m
Ce $ \ phi (x) _n ^ T \ phi (x) _m $ est un calcul de produit interne, et s'il y a beaucoup de points de données, la quantité de calcul sera énorme, nous allons donc en concevoir un peu.
En fait, $ \ phi (x) _n ^ T \ phi (x) _m $ peut être remplacé par $ k (x_n, k_m) $. $ k (x_n, k_m) $ est appelé ** fonction noyau **. En le remplaçant de cette manière, vous pouvez omettre le calcul interne du produit gênant. Cela s'appelle ** astuce du noyau **. Pour plus de détails, reportez-vous à «Kernel Trick».
En particulier, la fonction noyau utilisant la fonction de base gaussienne mentionnée ci-dessus est appelée ** noyau RBF (noyau de fonction de base radiale) **.
Enfin la fonction Lagrange
L(\lambda)=\sum_{n=1}^{N}\lambda_n-\frac{1}{2}\sum_{n=1}^{N}\sum_{m=1}^{N}\lambda_n\lambda_mt_nt_mk(x_n,x_m) \\
\text{subject.to }\sum_{i=1}^n\lambda_it_n=0,0 \leq \lambda_i \leq C
Ce sera. En fait, cette formule est résolue, et après avoir trouvé $ \ lambda $, trouvez $ \ boldsymbol {w} $ et $ w_0 $.
La dernière fois, nous avons classé par simple sklearn.svm.LinearSVC, mais plus général sklearn. Essayez d'utiliser .svm.SVC.
En regardant l'explication de l'API, c'est comme suit.
class sklearn.svm.SVC(C=1.0, kernel='rbf', degree=3, gamma='scale', coef0=0.0, shrinking=True, probability=False, tol=0.001, cache_size=200, class_weight=None, verbose=False, max_iter=-1, decision_function_shape='ovr', break_ties=False, random_state=None)
Si vous comprenez le contenu jusqu'à présent, vous serez progressivement en mesure de comprendre cette explication. Le paramètre «kernel» est le paramètre qui détermine la fonction de base, qui est «linéaire» pour le noyau linéaire et «rbf» pour le noyau gaussien. Les plus importants ici sont «C» et «gamma». «C» est un paramètre qui détermine la force de la condition de contrainte, et plus le paramètre est grand, plus la contrainte est stricte. «gamma» est un paramètre qui détermine l'étalement de la fonction de base gaussienne, et c'est un nombre inverse, donc plus il est petit, plus il devient lisse.
Utilisez les données affichées en premier comme données à classer. En fait, ces données utilisent une API appelée sklearn.datasets.make_moons. Vous pouvez spécifier le nombre d'échantillons et la force du bruit. La frontière de décision est également illustrée. La frontière de décision n'étant pas linéaire, elle est dessinée sous forme de ligne de contour. Plus précisément, nous utilisons une fonction appelée contourf de matplotlib.
import numpy as np
import pandas as pd
from sklearn import svm
from sklearn.datasets import make_moons
import matplotlib.pyplot as plt
%matplotlib inline
X, y = make_moons(n_samples=200,
shuffle = True,
noise = 0.1,
random_state = 2020,)
a0, b0 = X[y==0,0], X[y==0,1]
a1, b1 = X[y==1,0], X[y==1,1]
model = svm.SVC(C=1.0, kernel='rbf', gamma=1)
model.fit(X, y)
x1_min,x1_max = X[:,0].min() - 0.1,X[:,0].max() + 0.1
x2_min,x2_max = X[:,1].min() - 0.1,X[:,1].max() + 0.1
xx1,xx2 = np.meshgrid(np.arange(x1_min,x1_max,0.02),
np.arange(x2_min,x2_max,0.02))
Z = model.predict(np.array([xx1.ravel(),xx2.ravel()]).T)
Z = Z.reshape(xx1.shape)
plt.figure(figsize=(8, 7))
plt.contourf(xx1,xx2,Z,alpha = 0.4)
plt.xlim(xx1.min(),xx1.max())
plt.ylim(xx2.min(),xx2.max())
plt.scatter(a0, b0, marker='o', s=25, label="y = 0")
plt.scatter(a1, b1, marker='o', s=25, label="y = 1")
plt.legend()
plt.xlabel("x1")
plt.ylabel("x2")
plt.show()
Il semble qu'ils peuvent être séparés. Avec l'API, vous pouvez également obtenir des vecteurs de support, mais même si vous le comparez avec le nombre réel de données, vous pouvez l'approcher avec une petite quantité de données, ce qui contribue à économiser de la mémoire et à accélérer les calculs.
Dans ce qui précède, j'ai décidé de manière appropriée «C» et «gamma», mais que faire si je change cela? Dessinons-le réellement.
list_C = [0.1, 1, 20]
list_gamma = [0.05, 0.5, 20]
x1_min,x1_max = X[:,0].min() - 0.1,X[:,0].max() + 0.1
x2_min,x2_max = X[:,1].min() - 0.1,X[:,1].max() + 0.1
xx1,xx2 = np.meshgrid(np.arange(x1_min,x1_max,0.02),
np.arange(x2_min,x2_max,0.02))
plt.figure(figsize=(11, 11))
plt.xlim(xx1.min(),xx1.max())
plt.ylim(xx2.min(),xx2.max())
plt.xlabel("x1")
plt.ylabel("x2")
for i in range(len(list_C)):
for j in range(len(list_gamma)):
model = svm.SVC(C=list_C[i], kernel='rbf', gamma=list_gamma[j])
model.fit(X, y)
Z = model.predict(np.array([xx1.ravel(),xx2.ravel()]).T)
Z = Z.reshape(xx1.shape)
ax = plt.subplot(len(list_C), len(list_gamma), i*len(list_C)+j+1)
ax.set_title("C={}, gamma={}".format(list_C[i], list_gamma[j]))
ax.contourf(xx1,xx2,Z,alpha = 0.4)
ax.scatter(a0, b0, marker='o', s=25, label="y = 0")
ax.scatter(a1, b1, marker='o', s=25, label="y = 1")
plt.show()
Le résultat est le suivant.
Comme expliqué ci-dessus, plus le "C" est grand, meilleure est la séparation, et plus le "gamma" est grand, plus la courbe est complexe. Cependant, en bas à droite, il semble qu'il s'agisse d'un surapprentissage, et il semble qu'un réglage des paramètres sera nécessaire.
Afin d'ajuster les paramètres, il est nécessaire de diviser l'échantillon en données d'apprentissage et en données de vérification et de rechercher des paramètres qui ont un degré élevé d'accord lorsqu'ils sont prédits par les données de vérification. Cela s'appelle ** Validation croisée **, mais j'essaierai de le résumer à un autre moment.
La machine à vecteurs de support a été étendue de la marge dure à la marge souple pour gérer la séparation non linéaire. En regardant les choses de cette façon, j'ai senti que je pouvais rejeter même des classifications assez compliquées. Il est compréhensible qu'il était populaire avant le réseau de neurones.
Recommended Posts