Introduction
Dans ce laboratoire, nous allons démontrer comment utiliser la descente de gradient stochastique (SGD) pour approximer la solution d'un One-Class SVM dans le cas d'un noyau RBF.
Nous comparerons les résultats de cette approximation avec ceux obtenus en utilisant un One-Class SVM avec une approche à noyau. Le but de ce laboratoire n'est pas de montrer les avantages de l'approximation en termes de temps de calcul, mais plutôt de démontrer qu'il est possible d'obtenir des résultats similaires en utilisant la SGD sur un jeu de données simple.
Conseils sur la machine virtuelle
Une fois le démarrage de la machine virtuelle terminé, cliquez dans le coin supérieur gauche pour passer à l'onglet Notebook et accéder à Jupyter Notebook pour pratiquer.
Parfois, vous devrez peut-être attendre quelques secondes pour que Jupyter Notebook ait fini de charger. La validation des opérations ne peut pas être automatisée en raison des limitations de Jupyter Notebook.
Si vous rencontrez des problèmes pendant l'apprentissage, n'hésitez pas à demander à Labby. Donnez votre feedback après la session, et nous résoudrons rapidement le problème pour vous.
Importation des bibliothèques
Nous commençons par importer les bibliothèques nécessaires pour ce laboratoire : NumPy, Matplotlib et scikit-learn.
import numpy as np
import matplotlib.pyplot as plt
from sklearn.svm import OneClassSVM
from sklearn.linear_model import SGDOneClassSVM
from sklearn.kernel_approximation import Nystroem
from sklearn.pipeline import make_pipeline
Générer des données
Nous allons générer un jeu de données simple pour ce laboratoire. Nous allons générer 500 échantillons d'entraînement et 20 échantillons de test. Nous allons également générer 20 échantillons anormaux.
random_state = 42
rng = np.random.RandomState(random_state)
## Générer les données d'entraînement
X = 0.3 * rng.randn(500, 2)
X_train = np.r_[X + 2, X - 2]
## Générer quelques observations nouvelles régulières
X = 0.3 * rng.randn(20, 2)
X_test = np.r_[X + 2, X - 2]
## Générer quelques observations nouvelles anormales
X_outliers = rng.uniform(low=-4, high=4, size=(20, 2))
Ajuster un One-Class SVM
Nous allons tout d'abord ajuster un One-Class SVM avec un noyau RBF à notre ensemble de données.
## Hyperparamètres de l'OCSVM
nu = 0.05
gamma = 2.0
## Ajuster le One-Class SVM
clf = OneClassSVM(gamma=gamma, kernel="rbf", nu=nu)
clf.fit(X_train)
y_pred_train = clf.predict(X_train)
y_pred_test = clf.predict(X_test)
y_pred_outliers = clf.predict(X_outliers)
n_error_train = y_pred_train[y_pred_train == -1].size
n_error_test = y_pred_test[y_pred_test == -1].size
n_error_outliers = y_pred_outliers[y_pred_outliers == 1].size
Z = clf.decision_function(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)
Ajuster un One-Class SVM à l'aide de la SGD
Ensuite, nous allons ajuster un One-Class SVM à l'aide de la SGD. Nous utiliserons une approximation de noyau pour appliquer la SGD à notre ensemble de données.
## Ajuster le One-Class SVM à l'aide d'une approximation de noyau et de la SGD
transform = Nystroem(gamma=gamma, random_state=random_state)
clf_sgd = SGDOneClassSVM(
nu=nu, shuffle=True, fit_intercept=True, random_state=random_state, tol=1e-4
)
pipe_sgd = make_pipeline(transform, clf_sgd)
pipe_sgd.fit(X_train)
y_pred_train_sgd = pipe_sgd.predict(X_train)
y_pred_test_sgd = pipe_sgd.predict(X_test)
y_pred_outliers_sgd = pipe_sgd.predict(X_outliers)
n_error_train_sgd = y_pred_train_sgd[y_pred_train_sgd == -1].size
n_error_test_sgd = y_pred_test_sgd[y_pred_test_sgd == -1].size
n_error_outliers_sgd = y_pred_outliers_sgd[y_pred_outliers_sgd == 1].size
Z_sgd = pipe_sgd.decision_function(np.c_[xx.ravel(), yy.ravel()])
Z_sgd = Z_sgd.reshape(xx.shape)
Tracer les résultats
Enfin, nous allons tracer les résultats de notre One-Class SVM et de notre One-Class SVM utilisant la SGD.
## tracer les niveaux de la fonction de décision
plt.figure(figsize=(9, 6))
plt.title("One Class SVM")
plt.contourf(xx, yy, Z, levels=np.linspace(Z.min(), 0, 7), cmap=plt.cm.PuBu)
a = plt.contour(xx, yy, Z, levels=[0], linewidths=2, colors="darkred")
plt.contourf(xx, yy, Z, levels=[0, Z.max()], colors="palevioletred")
s = 20
b1 = plt.scatter(X_train[:, 0], X_train[:, 1], c="white", s=s, edgecolors="k")
b2 = plt.scatter(X_test[:, 0], X_test[:, 1], c="blueviolet", s=s, edgecolors="k")
c = plt.scatter(X_outliers[:, 0], X_outliers[:, 1], c="gold", s=s, edgecolors="k")
plt.axis("tight")
plt.xlim((-4.5, 4.5))
plt.ylim((-4.5, 4.5))
plt.legend(
[a.collections[0], b1, b2, c],
[
"frontière apprise",
"observations d'entraînement",
"nouvelles observations régulières",
"nouvelles observations anormales",
],
loc="upper left",
)
plt.xlabel(
"erreur d'entraînement : %d/%d ; erreurs nouvelles régulières : %d/%d ; erreurs nouvelles anormales : %d/%d"
% (
n_error_train,
X_train.shape[0],
n_error_test,
X_test.shape[0],
n_error_outliers,
X_outliers.shape[0],
)
)
plt.show()
plt.figure(figsize=(9, 6))
plt.title("Online One-Class SVM")
plt.contourf(xx, yy, Z_sgd, levels=np.linspace(Z_sgd.min(), 0, 7), cmap=plt.cm.PuBu)
a = plt.contour(xx, yy, Z_sgd, levels=[0], linewidths=2, colors="darkred")
plt.contourf(xx, yy, Z_sgd, levels=[0, Z_sgd.max()], colors="palevioletred")
s = 20
b1 = plt.scatter(X_train[:, 0], X_train[:, 1], c="white", s=s, edgecolors="k")
b2 = plt.scatter(X_test[:, 0], X_test[:, 1], c="blueviolet", s=s, edgecolors="k")
c = plt.scatter(X_outliers[:, 0], X_outliers[:, 1], c="gold", s=s, edgecolors="k")
plt.axis("tight")
plt.xlim((-4.5, 4.5))
plt.ylim((-4.5, 4.5))
plt.legend(
[a.collections[0], b1, b2, c],
[
"frontière apprise",
"observations d'entraînement",
"nouvelles observations régulières",
"nouvelles observations anormales",
],
loc="upper left",
)
plt.xlabel(
"erreur d'entraînement : %d/%d ; erreurs nouvelles régulières : %d/%d ; erreurs nouvelles anormales : %d/%d"
% (
n_error_train_sgd,
X_train.shape[0],
n_error_test_sgd,
X_test.shape[0],
n_error_outliers_sgd,
X_outliers.shape[0],
)
)
plt.show()
Sommaire
Dans ce laboratoire, nous avons démontré comment utiliser la descente de gradient stochastique (SGD) pour approximer la solution d'un One-Class SVM avec un noyau RBF. Nous avons comparé les résultats de cette approximation aux résultats de l'utilisation d'un One-Class SVM avec une approche à noyau. Nous avons généré un jeu de données simple et tracé les résultats de nos modèles.