Uczenie maszynowe i sztuczne sieci neuronowe/Ćwiczenia 7: Różnice pomiędzy wersjami
m (→Klasyfikacja) |
|||
(Nie pokazano 6 pośrednich wersji utworzonych przez tego samego użytkownika) | |||
Linia 1: | Linia 1: | ||
=Wstęp= | =Wstęp= | ||
− | Celem tych ćwiczeń jest zapoznanie się z | + | Celem tych ćwiczeń jest zapoznanie się z klasyfikacją za pomocą sieci neuronowych. |
+ | == Importy == | ||
+ | <source lang = python> | ||
+ | # -*- coding: utf-8 -*- | ||
+ | import matplotlib | ||
+ | %matplotlib notebook | ||
+ | #matplotlib.use('TkAgg') | ||
+ | import numpy as np | ||
+ | import pylab as py | ||
+ | from scipy import diag, arange, meshgrid, where | ||
+ | from numpy.random import multivariate_normal | ||
+ | |||
+ | </source> | ||
=Zbiór uczący = | =Zbiór uczący = | ||
− | + | Funkcja generująca zbiór uczący: | |
− | |||
− | |||
<source lang = python> | <source lang = python> | ||
− | + | def gen(ile): | |
+ | mu = [(-1,0),(2,4),(3,1)] | ||
+ | cov = [diag([1,1]), diag([0.5,1.2]), diag([1.5,0.7])] | ||
+ | X = np.zeros((ile*3, 2)) # miejsce na dane wejściowe | ||
+ | Y = np.zeros((ile*3,1),dtype = int) # miejsce na dane wyjściowe | ||
+ | for klasa in range(3): | ||
+ | X[klasa*ile:(klasa+1)*ile] = multivariate_normal(mu[klasa],cov[klasa],ile) | ||
+ | Y[klasa*ile:(klasa+1)*ile] = klasa | ||
+ | return (X,Y) | ||
+ | |||
</source> | </source> | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | + | Problem klasyfikacji jest zazwyczaj łatwiejszy do rozwiązania jeśli w warstwie wyjściowej umieścimy tyle neuronów ile jest klas i docelowe klasy są kodowane jako wysoki stan jednego z neuronów wyjściowych. Nawiązuje to trochę do rozwiązań jakie wyprowadziliśmy na wykładzie dla [[Uczenie_maszynowe_i_sztuczne_sieci_neuronowe/Wykład_6#Regresja_softmax_jako_GLM | regresji wielorakiej (softmax)]]. | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
+ | <source lang = python> | ||
+ | def convert_to_target(Y): | ||
+ | target = np.zeros((len(Y), len(np.unique(Y)))) | ||
+ | for i in range(len(Y)): | ||
+ | target[i,Y[i,0]] = 1 | ||
+ | return target | ||
</source> | </source> | ||
− | + | Testujemy: | |
− | <source lang = | + | <source lang = python> |
− | + | X,Y = gen(5) | |
− | print | + | print(Y) |
− | [ | + | py.scatter(X[:,0],X[:,1],c = Y,s = 10) |
− | + | target = convert_to_target(Y) | |
− | + | print(target) | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
</source> | </source> | ||
=Klasyfikacja= | =Klasyfikacja= | ||
W tym przykładzie pokażemy jak przy pomocy sieci neuronowej zbudować klasyfikator. Zadanie będzie polegało na zaliczaniu punktów do jednego z trzech typów. Dane będą pochodzić z trzech rozkładów normalnych dwuwymiarowych o różnych parametrach. | W tym przykładzie pokażemy jak przy pomocy sieci neuronowej zbudować klasyfikator. Zadanie będzie polegało na zaliczaniu punktów do jednego z trzech typów. Dane będą pochodzić z trzech rozkładów normalnych dwuwymiarowych o różnych parametrach. | ||
+ | Przygotujemy zestawy danych. Tablica mu zawiera wektory średnich dla każdego z trzech rozkładów, tablica cov zawiera macierze kowariancji dla tych rozkładów: | ||
− | + | <source lang = python> | |
− | <source lang = | + | N_przykladow =37 |
− | # | + | X, Y = gen(N_przykladow) # przykłady do ciągu uczącego |
− | + | X_m, Y_m = gen(N_przykladow) # przykłady do ciągu monitorującego | |
− | + | py.figure() | |
+ | py.scatter(X[:,0],X[:,1],c = Y,s = 10) | ||
+ | py.scatter(X_m[:,0],X_m[:,1],c = Y_m, s = 10, marker = 's') | ||
</source> | </source> | ||
− | + | Warto przekodować te dane tak aby jedna klasa była reprezentowana przez jeden neuron wyjściowy: | |
− | <source lang = | + | <source lang = python> |
− | + | target = convert_to_target(Y) | |
− | + | target_m = convert_to_target(Y_m) | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
</source> | </source> | ||
− | |||
− | <source lang = | + | Teraz wytworzymy sieć. Rozmiar wejścia i wyjścia muszą się zgadzać z rozmiarami danych wejściowych i wyjściowych, odpowiednio. |
− | + | <source lang = python> | |
− | + | class siec(object): | |
− | + | def __init__(self, X, Y, N_hid=3): | |
− | + | self.X = X | |
− | + | self.Y = Y | |
− | + | self.N_wej = X.shape[1] | |
− | + | self.N_wyj = Y.shape[1] | |
+ | self.N_hid = N_hid | ||
+ | |||
+ | # inicjujemy połączenia | ||
+ | # wagi ułożone są tak, że w kolejnych wierszach są kolejne neurony | ||
+ | # a w kolumnach wagi od konkretnego neuronu | ||
+ | # to +1 jest wagą dla obciążenia | ||
+ | self.w_1 = (2*np.random.random((self.N_hid, self.N_wej+1)) - 1)/self.N_wej # pomiędzy warstwą pierwszą (wejściem) a warstwą ukrytą | ||
+ | self.w_2 = (2*np.random.random((self.N_wyj, self.N_hid+1)) - 1)/self.N_hid | ||
+ | self.dw1 = np.zeros((self.N_hid, self.N_wej+1)) | ||
+ | self.dw2 = np.zeros((self.N_wyj, self.N_hid+1)) | ||
+ | |||
+ | def g1(self, x): | ||
+ | f = np.exp(-x) | ||
+ | f[f>1e8]=1e8 | ||
+ | y = 1./(1+f) | ||
+ | return y | ||
+ | def g1_prim(self, x): | ||
+ | y = x*(1-x) | ||
+ | return y | ||
+ | def g2(self, x): | ||
+ | y = x | ||
+ | return y | ||
+ | def g2_prim(self, x): | ||
+ | y = 1 | ||
+ | return y | ||
+ | def get_params(self): | ||
+ | return np.concatenate((self.w_1.reshape(-1), self.w_2.reshape(-1))) | ||
+ | |||
+ | def predict(self, x): | ||
+ | # propagacja "w przód" | ||
+ | self.a_0 = np.vstack((1,x)) # z warstwy wejściowej (zerowej) wychodzi a_0 | ||
+ | z_1 = np.dot( self.w_1, self.a_0 )# na warstwe 1 wchodzą iloczyny skalarne | ||
+ | self.a_1 = np.vstack((1,self.g1(z_1))) # dokładamy 1 i dostaję wyjście z warstwy 1 | ||
+ | z_2 = np.dot( self.w_2, self.a_1 ) # na warstwe 3 wchodzą iloczyny skalarne | ||
+ | self.a_2 = self.g2(z_2) | ||
+ | return self.a_2 | ||
+ | |||
+ | def get_error(self,X,trget): | ||
+ | self.bl = 0 | ||
+ | for i in range(0,self.X.shape[0]): | ||
+ | # weźmy przykład i-ty | ||
+ | x = self.X[i,:].reshape(self.N_wej,1) | ||
+ | y = self.Y[i,:].reshape(self.N_wyj,1) | ||
+ | self.a_2 = self.predict(x) | ||
+ | |||
+ | # delta | ||
+ | d_2 = (self.a_2 - y)*self.g2_prim(self.a_2) | ||
+ | |||
+ | self.bl += np.dot(d_2.T,d_2)/self.X.shape[0] | ||
+ | return self.bl | ||
+ | |||
+ | def fit_one_step(self, eta1,eta2): | ||
+ | self.bl = 0 | ||
+ | D_1 = np.zeros((self.N_hid, self.N_wej+1)) | ||
+ | D_2 = np.zeros((self.N_wyj, self.N_hid+1)) | ||
+ | for i in range(0,self.X.shape[0]): | ||
+ | # weźmy przykład i-ty | ||
+ | x = self.X[i,:].reshape(self.N_wej,1) | ||
+ | y = self.Y[i,:].reshape(self.N_wyj,1) | ||
+ | self.a_2 = self.predict(x) | ||
+ | |||
+ | # propagacja "wstecz" | ||
+ | d_2 = (self.a_2 - y)*self.g2_prim(self.a_2) | ||
+ | d_1 = np.dot(self.w_2.T, d_2) * self.g1_prim(self.a_1)#z_2 | ||
+ | |||
+ | # akumulujemy poprawki | ||
+ | D_2 += np.dot( d_2, self.a_1.T) | ||
+ | D_1 += np.dot( d_1[1:], self.a_0.T) | ||
+ | |||
+ | self.bl += np.dot(d_2.T,d_2)/self.X.shape[0] | ||
+ | # uaktualniamy wagi | ||
+ | self.w_1 -= eta1*D_1 + eta2*self.dw1 | ||
+ | self.w_2 -= eta1*D_2+ eta2*self.dw2 | ||
+ | self.dw1 = eta1*D_1 | ||
+ | self.dw2 = eta1*D_2 | ||
+ | return self.bl | ||
+ | |||
</source> | </source> | ||
− | |||
− | <source lang = | + | |
− | + | Proszę poeksperymentować z ilością i typem neuronów w warstwie ukrytej. Również ilość warstw ukrytych można zmieniać podając dodatkowe liczby pomiędzy parametrami określającymi rozmiar wejścia i wyjścia. Jako punkt startu zastosujemy 3 domyślnych (sigmoidalnych) neuronów w warstwie ukrytej: | |
+ | |||
+ | <source lang = python> | ||
+ | S = siec( X, target, N_hid= 3) | ||
</source> | </source> | ||
− | + | Przygotowujemy parametry: | |
− | <source lang = | + | <source lang = python> |
− | + | # liczba epok uczenia | |
− | + | N_epochs = 150 | |
+ | eta1 = 0.005 | ||
+ | eta2 = 0.9 | ||
</source> | </source> | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | + | Teraz przystępujemy do uczenia sieci (zapuścimy uczenie na 20 epok), przy czym po każdym kroku będziemy podglądać aktualny stan sieci, więc w metodzie <tt>trainEpochs</tt> podajemy 1 krok. | |
+ | <source lang = python> | ||
+ | # inicjuję tablice na ewolucje | ||
+ | |||
+ | err = np.zeros(N_epochs) #tablica na błąd zbioru uczącego | ||
+ | err_m = np.zeros(N_epochs) #tablica na błąd zbioru monitorującego | ||
+ | wagi = np.zeros((N_epochs,len(S.get_params()))) #tablica na wagi | ||
− | |||
− | |||
− | |||
− | + | py.figure() | |
− | + | for cykl in range(N_epochs): | |
− | + | err[cykl] = S.fit_one_step(eta1,eta2) # wykonaj krok uczenia | |
− | </source> | + | err_m[cykl] = S.get_error(X_m,target_m)# normalizuję aby uzyskać średni błąd kwadratowy |
+ | wagi[cykl,:] = S.get_params() #pobieram wagi do zapamiętania | ||
+ | </source> | ||
+ | Narysujmy co działo się z błędem i wagami: | ||
+ | <source lang = python> | ||
+ | # rysunki | ||
+ | py.figure() | ||
+ | py.subplot(2,1,1) # błędów | ||
+ | py.semilogy(err,'b',label='zb. uczacy') | ||
+ | py.semilogy(err_m,'r',label='zb. monitorujacy') | ||
+ | py.title(u'błąd') | ||
+ | py.legend() | ||
+ | #py.ylim([0,1]) | ||
+ | py.subplot(2,1,2) #wag | ||
+ | py.plot(wagi) | ||
+ | py.title('wagi') | ||
+ | py.ylim([-3,3]) | ||
+ | </source> | ||
+ | ==Rysunki dodatkowe== | ||
Tu przygotowujemy siatkę punktów, które będziemy stosować do zilustrowania podziału przestrzeni wejściowej na obszary należące do poszczególnych klas. Funkcja <tt>meshgrid</tt> pobiera na wejście wektor dla x i y, a zwraca tablicę dwuwymiarową reprezentującą siatkę o brzegach x i y. | Tu przygotowujemy siatkę punktów, które będziemy stosować do zilustrowania podziału przestrzeni wejściowej na obszary należące do poszczególnych klas. Funkcja <tt>meshgrid</tt> pobiera na wejście wektor dla x i y, a zwraca tablicę dwuwymiarową reprezentującą siatkę o brzegach x i y. | ||
− | + | ||
− | <source lang = | + | <source lang = python> |
ticks = arange(-3.,6.,0.2) | ticks = arange(-3.,6.,0.2) | ||
X, Y = meshgrid(ticks, ticks) | X, Y = meshgrid(ticks, ticks) | ||
− | + | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
</source> | </source> | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
Teraz przygotujemy się do ilustrowania działania sieci graficznie. Przepuścimy przez sieć zbiór danych zawierających siatkę punktów. Dla każdego punktu otrzymamy w zmiennej <tt>out</tt> aktywność neuronów warstwy wyjściowej. | Teraz przygotujemy się do ilustrowania działania sieci graficznie. Przepuścimy przez sieć zbiór danych zawierających siatkę punktów. Dla każdego punktu otrzymamy w zmiennej <tt>out</tt> aktywność neuronów warstwy wyjściowej. | ||
− | <source lang = | + | <source lang = python> |
− | out = | + | out = ... |
</source> | </source> | ||
Za pomocą metody <tt>argmax()</tt> pobieramy indeks neuronu, który miał największą aktywność. | Za pomocą metody <tt>argmax()</tt> pobieramy indeks neuronu, który miał największą aktywność. | ||
− | <source lang = | + | <source lang = python> |
out = out.argmax(axis=1) # the highest output activation gives the class | out = out.argmax(axis=1) # the highest output activation gives the class | ||
</source> | </source> | ||
Dopasowujemy kształt wyjścia do kształtu wejść. | Dopasowujemy kształt wyjścia do kształtu wejść. | ||
− | <source lang = | + | <source lang = python> |
out = out.reshape(X.shape) | out = out.reshape(X.shape) | ||
</source> | </source> | ||
Teraz możemy wykonać rysunek. | Teraz możemy wykonać rysunek. | ||
− | <source lang = | + | <source lang = python> |
− | figure( | + | py.figure() |
− | + | ||
− | + | ||
hold(True) # włączamy opcję dopisywania do bieżącego rysunku | hold(True) # włączamy opcję dopisywania do bieżącego rysunku | ||
for c in [0,1,2]: # iterujemy się przez możliwe klasy | for c in [0,1,2]: # iterujemy się przez możliwe klasy | ||
− | here, _ = | + | here, _ = ... # wybieramy indeksy punktów testowych należących do klasy c |
− | + | ... # rysujemy kółkami punkty testowe należące do klasy c | |
if out.max()!=out.min(): # safety check against flat field | if out.max()!=out.min(): # safety check against flat field | ||
contourf(X, Y, out) # przy pomocy zapełnionych konturów rysujemy wynik klasyfikacji punktów siatki, daje nam to ilustrację obszarów na jakie sieć aktualnie dzieli przestrzeń wejściową | contourf(X, Y, out) # przy pomocy zapełnionych konturów rysujemy wynik klasyfikacji punktów siatki, daje nam to ilustrację obszarów na jakie sieć aktualnie dzieli przestrzeń wejściową | ||
− | + | py.show() | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | show() | ||
</source> | </source> | ||
Aktualna wersja na dzień 18:53, 6 cze 2017
Spis treści
Wstęp
Celem tych ćwiczeń jest zapoznanie się z klasyfikacją za pomocą sieci neuronowych.
Importy
# -*- coding: utf-8 -*-
import matplotlib
%matplotlib notebook
#matplotlib.use('TkAgg')
import numpy as np
import pylab as py
from scipy import diag, arange, meshgrid, where
from numpy.random import multivariate_normal
Zbiór uczący
Funkcja generująca zbiór uczący:
def gen(ile):
mu = [(-1,0),(2,4),(3,1)]
cov = [diag([1,1]), diag([0.5,1.2]), diag([1.5,0.7])]
X = np.zeros((ile*3, 2)) # miejsce na dane wejściowe
Y = np.zeros((ile*3,1),dtype = int) # miejsce na dane wyjściowe
for klasa in range(3):
X[klasa*ile:(klasa+1)*ile] = multivariate_normal(mu[klasa],cov[klasa],ile)
Y[klasa*ile:(klasa+1)*ile] = klasa
return (X,Y)
Problem klasyfikacji jest zazwyczaj łatwiejszy do rozwiązania jeśli w warstwie wyjściowej umieścimy tyle neuronów ile jest klas i docelowe klasy są kodowane jako wysoki stan jednego z neuronów wyjściowych. Nawiązuje to trochę do rozwiązań jakie wyprowadziliśmy na wykładzie dla regresji wielorakiej (softmax).
def convert_to_target(Y):
target = np.zeros((len(Y), len(np.unique(Y))))
for i in range(len(Y)):
target[i,Y[i,0]] = 1
return target
Testujemy:
X,Y = gen(5)
print(Y)
py.scatter(X[:,0],X[:,1],c = Y,s = 10)
target = convert_to_target(Y)
print(target)
Klasyfikacja
W tym przykładzie pokażemy jak przy pomocy sieci neuronowej zbudować klasyfikator. Zadanie będzie polegało na zaliczaniu punktów do jednego z trzech typów. Dane będą pochodzić z trzech rozkładów normalnych dwuwymiarowych o różnych parametrach. Przygotujemy zestawy danych. Tablica mu zawiera wektory średnich dla każdego z trzech rozkładów, tablica cov zawiera macierze kowariancji dla tych rozkładów:
N_przykladow =37
X, Y = gen(N_przykladow) # przykłady do ciągu uczącego
X_m, Y_m = gen(N_przykladow) # przykłady do ciągu monitorującego
py.figure()
py.scatter(X[:,0],X[:,1],c = Y,s = 10)
py.scatter(X_m[:,0],X_m[:,1],c = Y_m, s = 10, marker = 's')
Warto przekodować te dane tak aby jedna klasa była reprezentowana przez jeden neuron wyjściowy:
target = convert_to_target(Y)
target_m = convert_to_target(Y_m)
Teraz wytworzymy sieć. Rozmiar wejścia i wyjścia muszą się zgadzać z rozmiarami danych wejściowych i wyjściowych, odpowiednio.
class siec(object):
def __init__(self, X, Y, N_hid=3):
self.X = X
self.Y = Y
self.N_wej = X.shape[1]
self.N_wyj = Y.shape[1]
self.N_hid = N_hid
# inicjujemy połączenia
# wagi ułożone są tak, że w kolejnych wierszach są kolejne neurony
# a w kolumnach wagi od konkretnego neuronu
# to +1 jest wagą dla obciążenia
self.w_1 = (2*np.random.random((self.N_hid, self.N_wej+1)) - 1)/self.N_wej # pomiędzy warstwą pierwszą (wejściem) a warstwą ukrytą
self.w_2 = (2*np.random.random((self.N_wyj, self.N_hid+1)) - 1)/self.N_hid
self.dw1 = np.zeros((self.N_hid, self.N_wej+1))
self.dw2 = np.zeros((self.N_wyj, self.N_hid+1))
def g1(self, x):
f = np.exp(-x)
f[f>1e8]=1e8
y = 1./(1+f)
return y
def g1_prim(self, x):
y = x*(1-x)
return y
def g2(self, x):
y = x
return y
def g2_prim(self, x):
y = 1
return y
def get_params(self):
return np.concatenate((self.w_1.reshape(-1), self.w_2.reshape(-1)))
def predict(self, x):
# propagacja "w przód"
self.a_0 = np.vstack((1,x)) # z warstwy wejściowej (zerowej) wychodzi a_0
z_1 = np.dot( self.w_1, self.a_0 )# na warstwe 1 wchodzą iloczyny skalarne
self.a_1 = np.vstack((1,self.g1(z_1))) # dokładamy 1 i dostaję wyjście z warstwy 1
z_2 = np.dot( self.w_2, self.a_1 ) # na warstwe 3 wchodzą iloczyny skalarne
self.a_2 = self.g2(z_2)
return self.a_2
def get_error(self,X,trget):
self.bl = 0
for i in range(0,self.X.shape[0]):
# weźmy przykład i-ty
x = self.X[i,:].reshape(self.N_wej,1)
y = self.Y[i,:].reshape(self.N_wyj,1)
self.a_2 = self.predict(x)
# delta
d_2 = (self.a_2 - y)*self.g2_prim(self.a_2)
self.bl += np.dot(d_2.T,d_2)/self.X.shape[0]
return self.bl
def fit_one_step(self, eta1,eta2):
self.bl = 0
D_1 = np.zeros((self.N_hid, self.N_wej+1))
D_2 = np.zeros((self.N_wyj, self.N_hid+1))
for i in range(0,self.X.shape[0]):
# weźmy przykład i-ty
x = self.X[i,:].reshape(self.N_wej,1)
y = self.Y[i,:].reshape(self.N_wyj,1)
self.a_2 = self.predict(x)
# propagacja "wstecz"
d_2 = (self.a_2 - y)*self.g2_prim(self.a_2)
d_1 = np.dot(self.w_2.T, d_2) * self.g1_prim(self.a_1)#z_2
# akumulujemy poprawki
D_2 += np.dot( d_2, self.a_1.T)
D_1 += np.dot( d_1[1:], self.a_0.T)
self.bl += np.dot(d_2.T,d_2)/self.X.shape[0]
# uaktualniamy wagi
self.w_1 -= eta1*D_1 + eta2*self.dw1
self.w_2 -= eta1*D_2+ eta2*self.dw2
self.dw1 = eta1*D_1
self.dw2 = eta1*D_2
return self.bl
Proszę poeksperymentować z ilością i typem neuronów w warstwie ukrytej. Również ilość warstw ukrytych można zmieniać podając dodatkowe liczby pomiędzy parametrami określającymi rozmiar wejścia i wyjścia. Jako punkt startu zastosujemy 3 domyślnych (sigmoidalnych) neuronów w warstwie ukrytej:
S = siec( X, target, N_hid= 3)
Przygotowujemy parametry:
# liczba epok uczenia
N_epochs = 150
eta1 = 0.005
eta2 = 0.9
Teraz przystępujemy do uczenia sieci (zapuścimy uczenie na 20 epok), przy czym po każdym kroku będziemy podglądać aktualny stan sieci, więc w metodzie trainEpochs podajemy 1 krok.
# inicjuję tablice na ewolucje
err = np.zeros(N_epochs) #tablica na błąd zbioru uczącego
err_m = np.zeros(N_epochs) #tablica na błąd zbioru monitorującego
wagi = np.zeros((N_epochs,len(S.get_params()))) #tablica na wagi
py.figure()
for cykl in range(N_epochs):
err[cykl] = S.fit_one_step(eta1,eta2) # wykonaj krok uczenia
err_m[cykl] = S.get_error(X_m,target_m)# normalizuję aby uzyskać średni błąd kwadratowy
wagi[cykl,:] = S.get_params() #pobieram wagi do zapamiętania
Narysujmy co działo się z błędem i wagami:
# rysunki
py.figure()
py.subplot(2,1,1) # błędów
py.semilogy(err,'b',label='zb. uczacy')
py.semilogy(err_m,'r',label='zb. monitorujacy')
py.title(u'błąd')
py.legend()
#py.ylim([0,1])
py.subplot(2,1,2) #wag
py.plot(wagi)
py.title('wagi')
py.ylim([-3,3])
Rysunki dodatkowe
Tu przygotowujemy siatkę punktów, które będziemy stosować do zilustrowania podziału przestrzeni wejściowej na obszary należące do poszczególnych klas. Funkcja meshgrid pobiera na wejście wektor dla x i y, a zwraca tablicę dwuwymiarową reprezentującą siatkę o brzegach x i y.
ticks = arange(-3.,6.,0.2)
X, Y = meshgrid(ticks, ticks)
Teraz przygotujemy się do ilustrowania działania sieci graficznie. Przepuścimy przez sieć zbiór danych zawierających siatkę punktów. Dla każdego punktu otrzymamy w zmiennej out aktywność neuronów warstwy wyjściowej.
out = ...
Za pomocą metody argmax() pobieramy indeks neuronu, który miał największą aktywność.
out = out.argmax(axis=1) # the highest output activation gives the class
Dopasowujemy kształt wyjścia do kształtu wejść.
out = out.reshape(X.shape)
Teraz możemy wykonać rysunek.
py.figure()
hold(True) # włączamy opcję dopisywania do bieżącego rysunku
for c in [0,1,2]: # iterujemy się przez możliwe klasy
here, _ = ... # wybieramy indeksy punktów testowych należących do klasy c
... # rysujemy kółkami punkty testowe należące do klasy c
if out.max()!=out.min(): # safety check against flat field
contourf(X, Y, out) # przy pomocy zapełnionych konturów rysujemy wynik klasyfikacji punktów siatki, daje nam to ilustrację obszarów na jakie sieć aktualnie dzieli przestrzeń wejściową
py.show()
Polecenia dodatkowe
- Proszę zbadać powtarzalność granic separacji
- Proszę zbadać klasyfikację punktu odległego od zbioru uczącego:
out = fnn.activate((100, 100))
print out
- Proszę zbadać zależność separacji i kształty powierzchni rozgraniczających w zależności od:
- liczby neuronów w warstwie ukrytej
- współczynnika weightdecay w trenerze
- Proszę sprawdzić działanie klasyfikatora dla innych konfiguracji klas wejściowych, np: łącząc kilka rozkładów normalnych o różnych parametrach w jedną klasę