Uczenie maszynowe i sztuczne sieci neuronowe/Ćwiczenia 5
Z Brain-wiki
Regresja
Jednowymiarowa
W tym ćwiczeniu chcemy zastosować sieć do wykonania regresji nieliniowej.
Załóżmy, że mamy generator który dostarcza żądaną ilość par liczb zgodnie z pewnym modelem, np.:
def gen(ile):
x = np.sort(5*np.random.rand(ile))
y = (1+10*x+x**2)/(1+2*x**2)
y+= 0.1*y*np.random.randn(ile)
return(x,y)
- Niech generator dostarcza nam po 10 par liczb. Proszę narysować kilka realizacji.
- Proszę skonstruować sieć, którą można nauczyć zależności między punktami wejściowymi (x) i wyjściowymi (y). W tym celu najlepiej wykorzystać sieć z nieliniową warstwą ukrytą typu tangensa hiperbolicznego i liniową warstwę wyjściową buildNetwork(N_wej, N_hid, N_wyj, hiddenclass=TanhLayer, outclass=LinearLayer)
Taka kombinacja warstw nieliniowej i liniowej pozwala na reprezentację dowolniej ciągłej funkcji, pod warunkiem użycia właściwej ilości neuronów w warstwie ukrytej. Liniowa warstwa wyjściowa pozwala na rozszerzenie zbioru wartości.
- Podobnie jak w poprzednim zadaniu proszę zbadać ewolucję:
- wag
- błędu na zbiorze uczącym
- błędu na zbiorze monitorującym
- Powyższe zależności proszę zaobserwować dla kilku rozmiarów warstwy ukrytej.
- Proszę wykreślić funkcję reprezentowaną przez sieć na tle punktów zbioru uczącego i prawdziwej (niezaszumionej) relacji y(x).
- Czy dla ustalonej architektury sieci (rozmiarów warstw) i ustalonego zbioru uczącego sieć zbiega do jednego rozwiązania? Dlaczego?
- Dla kilku ustalonych architektur zbadaj zależność błędu od rozmiaru zbioru uczącego.
Szkielet rozwiązania:
# -*- coding: utf-8 -*-
import matplotlib
matplotlib.use('TkAgg')
import numpy as np
import pylab as py
from pybrain.tools.shortcuts import buildNetwork
from pybrain.structure import TanhLayer, LinearLayer
from pybrain.datasets import SupervisedDataSet
from pybrain.supervised import BackpropTrainer
def gen(ile):
x = np.sort(5*np.random.rand(ile))
y = (1+10*x+x**2)/(1+2*x**2)
y+= 0.1*y*np.random.randn(ile)
return(x,y)
N_przykladow =7
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.plot(x,y,'.')
py.show()
N_wej= ...
N_hid = ...
N_wyj = ...
#wytwarzam zbiór uczący
ZU = SupervisedDataSet(N_wej,N_wyj)
for i in range(N_przykladow):
ZU.addSample(...)
#wytwarzam sieć
net = buildNetwork(N_wej, N_hid, N_wyj, hiddenclass= ... , outclass= ...)
# inicjuję trenera
trener = BackpropTrainer...
py.ion()
N_epochs = 200
# inicjuję tablice na ewolucje
err = np.zeros(N_epochs)
err_m = np.zeros(N_epochs)
wagi = np.zeros((N_epochs,len(net.params)))
# inicjuję rysunki
py.subplot(2,1,1) # błędów
l_err, = py.plot(err,'b',label='zb. uczacy')
l_err_m, = py.plot(err_m,'r',label='zb. monitorujacy')
py.title(u'błąd')
py.legend()
py.ylim([0,1])
py.subplot(2,1,2) #wag
l_wagi = py.plot(wagi)
py.title('wagi')
py.ylim([-3,3])
py.draw()
# uczę
for n in range(N_epochs):
err[n] = ... # trenuję i odbieram błąd
for j, m in enumerate(x_m): # liczę średni błąd kwadratowy na zbiorze monitorującym:
err_m[n] += (y_m[ ... ] - net.activate(( ... ,)))**2
err_m[n] /= ... # normalizuję aby uzyskać średni błąd kwadratowy
l_err.set_ydata(err) # odrysowuję błąd na zb. uczącym
l_err_m.set_ydata(err_m) # odrysowuję błąd na zb. monitorującym
wagi[n,:] = ...
for k in range(len(l_wagi)):
l_wagi[k].set_ydata(wagi[:,k])
py.draw()
py.ioff()
py.show()
# funkcja reprezentowana przez sieć na tle punktów zbioru uczącego i prawdziwej (niezaszumionej) relacji y(x).
x_testowe = np.linspace(0.1,7,100)
y_testowe = np.zeros(100)
for i in range(len(x_testowe)):
y_testowe[i] = net.activate((...,))
z = (1+10*x_testowe+x_testowe**2)/(1+2*x_testowe**2) # prawdziwa relacja
py.plot(x_testowe,y_testowe,'r',label='regresja')
py.plot(x_testowe,z,'b',label='relacja prawdziwa')
py.plot(x,y,'bo',label='zb. uczacy')
py.plot(x_m,y_m,'mo',label='zb. monitorujacy')
py.legend()
py.show()
Dwuwymiarowa
W zadaniu tym chciałbym abyście zbadali na ile złożona (ile neuronów ukrytych) musi być sieć modelująca/interpolująca funkcję:
- [math] f(x,y) = 0.1 + \frac{1 + \sin(2x + 3y)}{3.5 + \sin(x-y)}[/math]
dla [math]x,y \in [-2,2][/math]
- Proszę wykreślić tą funkcję.
- Jako ciąg uczący proszę wykorzystać pary wejścia spróbkowane co 0.2 i odpowiadające im wartości funkcji.
- Test proszę przeprowadzić na danych próbkowanych gęściej, ale tak aby w zbiorze testowym nie było punktów ze zbioru uczącego (np.: np.arange(-2+0.05195,2,0.05195)).
Przydatne mogą być funkcje do:
- generowania danych np.:
def gen(vec):
x = vec
y = vec
f = np.zeros((len(x),len(y)))
for i, x_i in enumerate(x):
for j, y_j in enumerate(y):
f[i,j] = 0.1 + (1+np.sin(2*x_i + 3*y_j))/(3.5 + np.sin(x_i - y_j))
return(x,y,f)
(x,y,f)= gen(np.arange(-2,2,0.2))
- rysowania powierzchni 3D
from matplotlib.pyplot import plot, show, figure, draw
from mpl_toolkits.mplot3d import axes3d
def rysuj3d(x,y,f,fig):
X,Y = np.meshgrid(x,y)
ax = fig.gca(projection='3d')
ax.plot_surface(X, Y, f, rstride=3, cstride=3, alpha=0.3)
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_zlabel('f')
def scatter3d(x,y,f,fig,kolor):
X,Y = np.meshgrid(x,y)
ax = fig.gca(projection='3d')
ax.scatter(X, Y, f, c=kolor,marker='o')
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_zlabel('f')
#przykładowe użycie:
(x,y,f)= gen(np.arange(-2,2,0.2))
fig = figure()
rysuj3d(x,y,f,fig)
scatter3d(x,y,f,fig,'b')
show