Uczenie maszynowe i sztuczne sieci neuronowe/Ćwiczenia 10

Z Brain-wiki
Wersja z dnia 16:30, 21 mar 2018 autorstwa Jarekz (dyskusja | edycje) (→‎Materiały)
(różn.) ← poprzednia wersja | przejdź do aktualnej wersji (różn.) | następna wersja → (różn.)

Uczenie_maszynowe_i_sztuczne_sieci_neuronowe_cw/SVM1

Klasyfikacja za pomocą algorytmu wektorów wspierających (SVM)

Materiały

Na tych ćwiczeniach zapoznamy się z zastosowaniem SVM do klasyfikacji. Poniżej znajduje się moduł dostarczający kilku funkcji, z których dziś będziemy korzystać. Proszę zapisać go w bieżącym katalogu.


Potrzebne będą nam też następujące zestawy danych: Plik:Dane1.txt, Plik:Dane2.txt, Plik:Dane3.txt. Proszę pobrać te pliki i zapisać je w bieżącym katalogu.

Ćwiczenie 1: Dane separowalne liniowo

Poniższy kod prezentuje zastosowanie SVM do problemu, który jest separowalny liniowo. Wykonując poniższy kod proszę zwrócić uwagę na punkt należący do klasy1 o współrzędnych (0.09, 4).

Jak pamiętamy z wykładu parametr C to współczynnik regularyzacji SVM, który karze za naruszanie marginesów. Proszę wykonać kod dla C o wartościach {1,2,5,10,20,30,60,120} i zaobserwować wyniki.

# -*- coding: utf-8 -*-
#importujemy potrzebne moduły i klasy
import numpy as np
import pylab as py
from svm_modul import *

#==================================================================
#                 Program
#==================================================================

# wczytywanie danych
dane = np.loadtxt('Dane1.txt') # dane zorganizowane są w trzech kolumnach
N_przyk, N_wej = dane.shape 
X = dane[:,0:2] # pierwsze dwie kolumny to wejście
y = dane[:,2] # trzecia kolumna to etykiety klas

# narysujmy te dane
rysujDaneGrup(X, y, marker=('or','xb'), xlabel='x0', ylabel='x1',legend_list=('klasa0','klasa1'))
py.show()

# trenujemy model
model  = svmTrain(X, y, C=100, kernelFunction = 'linearKernel', tol = 1e-3, max_passes = 20,sigma = 10) 

# prezentujemy podział przestrzeni wejść reprezentowany przez model
rysujDaneGrup(X, y, marker=('or','xb'), xlabel='x0', ylabel='x1',legend_list=('klasa0','klasa1'))
rysujPodzial(model,X)
py.show()

Ćwiczenie 2: jądro Gaussowskie

W poprzednim programie proszę zmodyfikować wywołanie svmTrain:

  • podmienić funkcję jądra na 'gaussianKernel'.
  • ustawić C = 10
  • zmieniać sigma na wartości: {0.1, 0.2, 0.4, 0.8, 1, 2, 4, 8}

Ćwiczenie 3: skomplikowany podział nieliniowy

Przy pomocy kodu z ćwiczenia 2 proszę dobrać parametry C i sigma aby otrzymać sensownie wyglądający podział przestrzeni dla danych zawartych w pliku dane2.txt.

Ćwiczenie 4: automatyzacja dobierania parametrów C i sigma

W wielu prawdziwych zastosowaniach chcielibyśmy aby nasz wybór parametrów był optymalny a jednocześnie możliwie obiektywny.

Powszechnie stosowaną metodą jest przeszukanie przestrzeni parametrów (C,sigma). Generuje się siatkę wartości (C,sigma) i dla każdego punktu siatki:

  1. estymuje się model
  2. ocenia się jakość generalizacji

Do oceny jakości w każdym punkcie siatki można zastosować albo zbiór monitorujący albo metody typu leave-one-out.

Uwaga: podział przestrzeni często wykonuje się w skali logarytmicznej.

Ćwiczenie wykonamy dla zbioru uczącego z pliku dane3.txt.

Musimy ten zbiór podzielić na dane do trenowania i dane do testowania np. w proporcji 3:1, Można to zrobić tak:

# wczytywanie danych
dane = np.loadtxt('dane3.txt') # dane zorganizowane są w trzech kolumnach
N_przyk, N_wej = dane.shape 
X = dane[:,0:2] # pierwsze dwie kolumny to wejście
y = dane[:,2] # trzecia kolumna to etykiety klas

#podział na zbiór uczący i testujący
grupa0, = np.where(y==-1)
grupa1, = np.where(y==1)

# mieszamy kolejność indexów
np.random.shuffle(grupa0)
np.random.shuffle(grupa1)

# kopiujemy dane do zbioru uczącego (pierwsze 75% grupy0 i grupy1)
Xu = X[np.concatenate((grupa0[0: int(0.75*len(grupa0))],grupa1[0:int(0.75*len(grupa0))]))]
yu = y[np.concatenate((grupa0[0: int(0.75*len(grupa0))],grupa1[0:int(0.75*len(grupa0))]))]
# kopiujemy dane do zbioru testowego (końcowe 25% grupy0 i grupy1)
Xt = X[np.concatenate((grupa0[int(0.75*len(grupa0)):], grupa1[int(0.75*len(grupa0)):]))]
yt = y[np.concatenate((grupa0[int(0.75*len(grupa0)):], grupa1[int(0.75*len(grupa0)):]))]


# narysujmy te dane

rysujDaneGrup(Xu, yu, marker=('xr','xb'), xlabel='x0', ylabel='x1',legend_list=('klasa0','klasa1'))
rysujDaneGrup(Xt, yt, marker=('or','ob'), xlabel='x0', ylabel='x1',legend_list=('klasa0_test','klasa1_test'))
py.show()


Mając taki podział danych możemy dopasować model SVM do części uczącej:

model  = svmTrain(Xu, yu, C=10, kernelFunction = 'gaussianKernel', tol = 1e-3, max_passes = 20,sigma = 0.5)

A następnie ocenić jego jakość na części testowej (funkcja svmPredict dostarczana jest przez moduł svm_modul.py):

TPR = np.sum(yt == svmPredict(model,Xt))/float(len(yt))


Proszę napisać program, który

  • skanuje przestrzeń (C,sigma): C w zakresie od 0.1 do 100, sigma w zakresie od 0.1 do 10. Do wygenerowania zakresu ze skalą logarytmiczną można wykorzystać np. takie polecenie: zakresC = np.logspace(np.log2(0.1),np.log2(100),8, base=2)
  • znajduje najlepsze parametry
  • rysuje podział przestrzeni dla najlepszych parametrów.


Dodatek: implementacja w oparciu o bibliotekę LIBSVM

Do praktycznych zastosowań zaleca się stosowanie zoptymalizowanych bibliotek, np. LIBSVM (http://www.csie.ntu.edu.tw/~cjlin/libsvm/). Poniżej prezentujemy przykłady implementacji ćwiczenia 3 i ćwiczenia 4 w oparciu o tą bibliotekę. Aby móc wykonać te programy potrzebna jest skompilowana biblioteka libsvm i moduły pythonowe svm.py oraz svmutil. Cały zestaw wraz z instrukcją komilacji można pobrać z http://www.csie.ntu.edu.tw/~cjlin/libsvm/#download. Uwaga: w bibliotece tej jest nieco inna konwencja notacji jądra Gaussowskiego: [math]K(x,z) =\exp(-g ||x-z||^2)[/math], tzn. parametr [math]g = \frac{1}{2 \sigma^2}[/math]

Uczenie_maszynowe_i_sztuczne_sieci_neuronowe_cw/SVM1