Introdução
Neste laboratório, demonstraremos como utilizar o Gradiente Descendente Estocástico (SGD) para aproximar a solução de uma Máquina de Vetores de Suporte de Uma Classe (One-Class SVM) no caso de um kernel RBF.
Compararemos os resultados desta aproximação com os resultados de utilizar uma One-Class SVM com uma abordagem kernel. O objetivo deste laboratório não é mostrar os benefícios da aproximação em termos de tempo de computação, mas sim demonstrar que resultados semelhantes podem ser obtidos utilizando SGD num conjunto de dados de brinquedo.
Dicas da Máquina Virtual
Após o arranque da VM, clique no canto superior esquerdo para mudar para a aba Notebook para aceder ao Jupyter Notebook para a prática.
Por vezes, pode ser necessário esperar alguns segundos para o Jupyter Notebook terminar de carregar. A validação das operações não pode ser automatizada devido a limitações no Jupyter Notebook.
Se tiver problemas durante o aprendizado, não hesite em contactar o Labby. Forneça feedback após a sessão e resolveremos prontamente o problema para si.
Importar Bibliotecas
Começamos importando as bibliotecas necessárias para este laboratório: NumPy, Matplotlib e 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
Gerar Dados
Vamos gerar um conjunto de dados de brinquedo para este laboratório. Vamos gerar 500 amostras de treino e 20 amostras de teste. Também vamos gerar 20 amostras anormais.
random_state = 42
rng = np.random.RandomState(random_state)
## Gerar dados de treino
X = 0.3 * rng.randn(500, 2)
X_train = np.r_[X + 2, X - 2]
## Gerar algumas observações regulares e novas
X = 0.3 * rng.randn(20, 2)
X_test = np.r_[X + 2, X - 2]
## Gerar algumas observações anormais e novas
X_outliers = rng.uniform(low=-4, high=4, size=(20, 2))
Ajustar o SVM de Uma Classe
Primeiro, ajustaremos um SVM de uma classe com um kernel RBF ao nosso conjunto de dados.
## Hiperparâmetros do OCSVM
nu = 0.05
gamma = 2.0
## Ajustar o SVM de Uma Classe
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)
Ajustar o SVM de Uma Classe usando SGD
Em seguida, ajustaremos um SVM de uma classe usando SGD. Usaremos uma aproximação de kernel para aplicar SGD ao nosso conjunto de dados.
## Ajustar o SVM de Uma Classe usando uma aproximação de kernel e 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)
Plotar Resultados
Finalmente, plotaremos os resultados do nosso SVM de uma classe e do nosso SVM de uma classe usando SGD.
## plotar os conjuntos de nível da função de decisão
plt.figure(figsize=(9, 6))
plt.title("SVM de Uma Classe")
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],
[
"fronteira aprendida",
"observações de treinamento",
"novas observações regulares",
"novas observações anormais",
],
loc="upper left",
)
plt.xlabel(
"erro treinamento: %d/%d; erros novos regulares: %d/%d; erros novos anormais: %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("SVM de Uma Classe Online")
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],
[
"fronteira aprendida",
"observações de treinamento",
"novas observações regulares",
"novas observações anormais",
],
loc="upper left",
)
plt.xlabel(
"erro treinamento: %d/%d; erros novos regulares: %d/%d; erros novos anormais: %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()
Resumo
Neste laboratório, demonstramos como usar o Gradiente Descendente Estocástico (SGD) para aproximar a solução de um SVM de uma classe com um kernel RBF. Comparamos os resultados desta aproximação com os resultados de usar um SVM de uma classe com uma abordagem kernel. Geramos um conjunto de dados de brinquedo e plotamos os resultados dos nossos modelos.