Aproximação Explícita do Mapa de Características para Kernels RBF

Beginner

This tutorial is from open-source community. Access the source code

Introdução

Este laboratório ilustra a aproximação do mapa de características de um kernel RBF usando RBFSampler e Nystroem para aproximar o mapa de características de um kernel RBF para classificação com uma SVM no conjunto de dados de dígitos. Os resultados usando uma SVM linear no espaço original, uma SVM linear usando as mapeamentos aproximados e usando uma SVM kernel são comparados. Os tempos de execução e a precisão para diferentes quantidades de amostras de Monte Carlo (no caso de RBFSampler, que usa recursos de Fourier aleatórios) e diferentes tamanhos de subconjuntos do conjunto de treinamento (para Nystroem) para o mapeamento aproximado são mostrados.

Dicas da Máquina Virtual

Após o início da VM, clique no canto superior esquerdo para mudar para a aba Notebook para acessar o Jupyter Notebook para praticar.

Às vezes, pode ser necessário esperar alguns segundos para que o Jupyter Notebook termine de carregar. A validação das operações não pode ser automatizada devido a limitações no Jupyter Notebook.

Se você enfrentar problemas durante o aprendizado, sinta-se à vontade para perguntar ao Labby. Forneça feedback após a sessão, e nós resolveremos prontamente o problema para você.

Importação do Pacote Python e do Conjunto de Dados, Carregamento do Conjunto de Dados

## Importações científicas padrão do Python
import matplotlib.pyplot as plt
import numpy as np
from time import time

## Importação de conjuntos de dados, classificadores e métricas de desempenho
from sklearn import datasets, svm, pipeline
from sklearn.kernel_approximation import RBFSampler, Nystroem
from sklearn.decomposition import PCA

## Conjunto de dados dígitos
digits = datasets.load_digits(n_class=9)

Gráficos de Tempo e Precisão

## Para aplicar um classificador a estes dados, precisamos achatá-los para
## transformar os dados numa matriz (amostras, características):
n_samples = len(digits.data)
data = digits.data / 16.0
data -= data.mean(axis=0)

## Aprendemos os dígitos na primeira metade dos dígitos
data_train, targets_train = (data[: n_samples // 2], digits.target[: n_samples // 2])

## Agora prevemos o valor do dígito na segunda metade:
data_test, targets_test = (data[n_samples // 2 :], digits.target[n_samples // 2 :])

## Criamos um classificador: um classificador de vetores de suporte
kernel_svm = svm.SVC(gamma=0.2)
linear_svm = svm.LinearSVC(dual="auto")

## Criamos um pipeline a partir da aproximação do kernel e da svm linear
feature_map_fourier = RBFSampler(gamma=0.2, random_state=1)
feature_map_nystroem = Nystroem(gamma=0.2, random_state=1)

fourier_approx_svm = pipeline.Pipeline([
  ("feature_map", feature_map_fourier),
  ("svm", svm.LinearSVC(dual="auto"))
])

nystroem_approx_svm = pipeline.Pipeline([
  ("feature_map", feature_map_nystroem),
  ("svm", svm.LinearSVC(dual="auto"))
])

## Ajustar e prever usando svm linear e kernel:
kernel_svm_time = time()
kernel_svm.fit(data_train, targets_train)
kernel_svm_score = kernel_svm.score(data_test, targets_test)
kernel_svm_time = time() - kernel_svm_time

linear_svm_time = time()
linear_svm.fit(data_train, targets_train)
linear_svm_score = linear_svm.score(data_test, targets_test)
linear_svm_time = time() - linear_svm_time

sample_sizes = 30 * np.arange(1, 10)
fourier_scores = []
nystroem_scores = []
fourier_times = []
nystroem_times = []

for D in sample_sizes:
  fourier_approx_svm.set_params(feature_map__n_components=D)
  nystroem_approx_svm.set_params(feature_map__n_components=D)

  start = time()
  nystroem_approx_svm.fit(data_train, targets_train)
  nystroem_times.append(time() - start)

  start = time()
  fourier_approx_svm.fit(data_train, targets_train)
  fourier_times.append(time() - start)

  fourier_score = fourier_approx_svm.score(data_test, targets_test)
  nystroem_score = nystroem_approx_svm.score(data_test, targets_test)
  nystroem_scores.append(nystroem_score)
  fourier_scores.append(fourier_score)

## plotar os resultados:
plt.figure(figsize=(16, 4))
accuracy = plt.subplot(121)
## segundo eixo y para tempos
timescale = plt.subplot(122)

accuracy.plot(sample_sizes, nystroem_scores, label="kernel aproximado Nystroem")
timescale.plot(sample_sizes, nystroem_times, "--", label="kernel aproximado Nystroem")

accuracy.plot(sample_sizes, fourier_scores, label="kernel aproximado Fourier")
timescale.plot(sample_sizes, fourier_times, "--", label="kernel aproximado Fourier")

## linhas horizontais para kernels rbf e lineares exatos:
accuracy.plot([sample_sizes[0], sample_sizes[-1]], [linear_svm_score, linear_svm_score], label="svm linear")
timescale.plot([sample_sizes[0], sample_sizes[-1]], [linear_svm_time, linear_svm_time], "--", label="svm linear")

accuracy.plot([sample_sizes[0], sample_sizes[-1]], [kernel_svm_score, kernel_svm_score], label="svm rbf")
timescale.plot([sample_sizes[0], sample_sizes[-1]], [kernel_svm_time, kernel_svm_time], "--", label="svm rbf")

## linha vertical para dimensionalidade do conjunto de dados = 64
accuracy.plot([64, 64], [0.7, 1], label="n_features")

## legendas e rótulos
accuracy.set_title("Precisão de classificação")
timescale.set_title("Tempos de treino")
accuracy.set_xlim(sample_sizes[0], sample_sizes[-1])
accuracy.set_xticks(())
accuracy.set_ylim(np.min(fourier_scores), 1)
timescale.set_xlabel("Passos de amostragem = dimensão da característica transformada")
accuracy.set_ylabel("Precisão de classificação")
timescale.set_ylabel("Tempo de treino em segundos")
accuracy.legend(loc="best")
timescale.legend(loc="best")
plt.tight_layout()
plt.show()

Superfícies de Decisão do Kernel RBF SVM e SVM Linear

## visualizar a superfície de decisão, projetada para os dois primeiros
## componentes principais do conjunto de dados
pca = PCA(n_components=8).fit(data_train)

X = pca.transform(data_train)

## Gerar grade ao longo dos dois primeiros componentes principais
multiples = np.arange(-2, 2, 0.1)
## passos ao longo do primeiro componente
first = multiples[:, np.newaxis] * pca.components_[0, :]
## passos ao longo do segundo componente
second = multiples[:, np.newaxis] * pca.components_[1, :]
## combinar
grid = first[np.newaxis, :, :] + second[:, np.newaxis, :]
flat_grid = grid.reshape(-1, data.shape[1])

## título para os gráficos
titles = [
    "SVC com kernel rbf",
    "SVC (kernel linear)\n com mapa de características rbf Fourier\nn_components=100",
    "SVC (kernel linear)\n com mapa de características rbf Nystroem\nn_components=100",
]

plt.figure(figsize=(18, 7.5))
plt.rcParams.update({"font.size": 14})
## prever e plotar
for i, clf in enumerate((kernel_svm, nystroem_approx_svm, fourier_approx_svm)):
    ## Plotar a fronteira de decisão. Para isso, atribuiremos uma cor a cada
    ## ponto na malha [x_min, x_max]x[y_min, y_max].
    plt.subplot(1, 3, i + 1)
    Z = clf.predict(flat_grid)

    ## Colocar o resultado num gráfico de cores
    Z = Z.reshape(grid.shape[:-1])
    levels = np.arange(10)
    lv_eps = 0.01  ## Ajustar um mapeamento dos níveis de contorno calculados para a cor.
    plt.contourf(
        multiples,
        multiples,
        Z,
        levels=levels - lv_eps,
        cmap=plt.cm.tab10,
        vmin=0,
        vmax=10,
        alpha=0.7,
    )
    plt.axis("off")

    ## Plotar também os pontos de treino
    plt.scatter(
        X[:, 0],
        X[:, 1],
        c=targets_train,
        cmap=plt.cm.tab10,
        edgecolors=(0, 0, 0),
        vmin=0,
        vmax=10,
    )

    plt.title(titles[i])
plt.tight_layout()
plt.show()

Resumo

Este laboratório ilustrou a aproximação do mapa de características de um kernel RBF usando RBFSampler e Nystroem para aproximar o mapa de características de um kernel RBF para classificação com uma SVM no conjunto de dados de dígitos. Foram comparados os resultados usando uma SVM linear no espaço original, uma SVM linear usando as mapeamentos aproximados e usando uma SVM kernel. Foram mostrados os tempos e a precisão para quantidades variáveis de amostras de Monte Carlo (no caso do RBFSampler, que usa recursos Fourier aleatórios) e diferentes subconjuntos do conjunto de treino (para Nystroem) para o mapeamento aproximado. Finalmente, as superfícies de decisão dos classificadores foram visualizadas, projetadas nos dois primeiros componentes principais dos dados.