Uczenie maszynowe i sztuczne sieci neuronowe/Ćwiczenia 2

Z Brain-wiki
Wersja z dnia 18:22, 21 maj 2015 autorstwa Jarekz (dyskusja | edycje) (Utworzono nową stronę "=Pybrain= Część praktyczna naszych zajęć oparta będzie na bibliotece (zestawie modułów) [http://pybrain.org/pages/home PyBrain]. Jak twierdzą autorzy PyBrain je...")
(różn.) ← poprzednia wersja | przejdź do aktualnej wersji (różn.) | następna wersja → (różn.)

Pybrain

Część praktyczna naszych zajęć oparta będzie na bibliotece (zestawie modułów) PyBrain. Jak twierdzą autorzy PyBrain jest skrótem od Python-Based Reinforcement Learning, Artificial Intelligence and Neural Network Library, czyli sądząc po nazwie powinniśmy w nim znaleźć narzędzia do wszystkich naszych ćwiczeń.

W PyBrainie sieci tworzone są z Modułów połączonych za pomocą Połączeń. O sieciach tych można myśleć jak o acyklicznych grafach, w których węzłach są Moduły a krawędzie są Połączeniami.

Szybki start

Aby zapoznać się z podstawami posługiwania się narzędziami PyBraina wykorzystamy kilka przykładów z oryginalnego tutoriala.

Poniższe polecenia proszę wykonać interaktywnie z linii poleceń pythona.

Skrótowe polecenie do wytworzenia typowej sieci warstwowej to buildNetwork

from pybrain.tools.shortcuts import buildNetwork
net = buildNetwork(2, 3, 1)

To polecenie zwraca obiekt net, który reprezentuje sieć mającą dwa wejścia, trzy neurony ukryte i jeden wyjściowy. Warstwy są obiektami typu Moduł i są połączone za pomocą obiektów typu FullConnection.

Aby nasza sieć obliczyła swoje wyjście dla zadanego wejścia trzeba wywołać metodę activate.

net.activate([2, 1])

Strukturę sieci możemy zbadać wypisując różne jej elementy:

net['in']
net['hidden0']
net['out']
net.connections

A teraz powoli

Teraz zbudujmy najprostszą sieć liniową złożoną z jednego neuronu o dwóch wejściach i jednym wyjściu.

Importujemy potrzebne funkcje i obiekty:

from pybrain.structure import FeedForwardNetwork, LinearLayer, FullConnection

wytwarzamy pustą sieć

siec = FeedForwardNetwork()

tworzymy węzły wejściowe i wyjściowe

warstwaWejsciowa = LinearLayer(2)
warstwaWyjsciowa = LinearLayer(1)

dodajemy węzły do sieci

siec.addInputModule(warstwaWejsciowa)
siec.addOutputModule(warstwaWyjsciowa)

łączymy węzły

wej_do_wyj = FullConnection(warstwaWejsciowa, warstwaWyjsciowa)
siec.addConnection(wej_do_wyj)

inicjujemy strukturę sieć

siec.sortModules()

możemy podejrzeć wartości wag

print siec.params

przepuszczenie danych przez sieć

print siec.activate([1,3])

Sieć jako filtr liniowy

Poniższy przykład ma nam uświadomić możliwość wykorzystania sieci do filtrowania sygnałów. Przy okazji nauczymy się definiować ciąg uczący i stosować metody spadku gradientowego do uczenia sieci.

Przygotowanie danych

Najpierw przygotujemy dane. Dane wejściowe to szum gaussowski, zaś wyjście to przefiltrowany dolnoprzepustowo szum z częstością odcięcia 20Hz.

from scipy.signal import firwin, lfilter
import numpy as np

sampling = 128.0
# przygotowujemy dane tak aby nauczyć sieć filtrowania dolnoprzepustowego 
t = np.arange(0,2,1/sampling)
x = np.random.randn(len(t))
b= firwin(30,20.0/sampling)
y = lfilter(b,[1],x)

Sprawdźmy jak wygląda sygnał wejściowy, wyjściowy oraz ich widma:

from pylab import subplot, plot, show, title, xlabel

def spectrum(x,Fs):
    N = len(x)
    P = np.abs(np.fft.fft(x))**2/len(x)
    f = np.fft.fftfreq(len(x),1.0/Fs)
    P = P[0:N/2]
    P[1:-1] *=2
    f = f[0:N/2]
    return f,P
subplot(2,2,1)
plot(t,x)
title(u'wejście')
xlabel('s')
subplot(2,2,3)
plot(t,y)
title(u'wyjście')
xlabel('s')
subplot(2,2,2)
f,P = spectrum(x,sampling)
plot(f,P)
title(u'Widmo wejścia')
xlabel('Hz')
subplot(2,2,4)
f,P = spectrum(y,sampling)
plot(f,P)
title(u'Widmo wyjścia')
xlabel('Hz')

show()

Wytworzenie sieci

  • wytwarzamy pustą sieć
siec = FeedForwardNetwork()
  • tworzymy węzły wejściowe i wyjściowe
N_wej = 30
warstwaWejsciowa = LinearLayer(N_wej)
warstwaWyjsciowa = LinearLayer(1)
  • dodajemy węzły do sieci
siec.addInputModule(warstwaWejsciowa)
siec.addOutputModule(warstwaWyjsciowa)
  • łączymy węzły
wej_do_wyj = FullConnection(warstwaWejsciowa, warstwaWyjsciowa)
siec.addConnection(wej_do_wyj)
  • inicjujemy strukturę sieci
siec.sortModules()

Tworzenie ciągu uczącego

  • tworzymy ciąg uczący CU
from pybrain.datasets import SupervisedDataSet
CU = SupervisedDataSet(N_wej, 1)
for i in range(len(x)-N_wej-1):
    bufor_wejsciowy = x[i:i+N_wej]
    wartosc_wyjsciowa = y[i+N_wej]
    CU.addSample( bufor_wejsciowy, wartosc_wyjsciowa)

Uczenie sieci

  • za uczenie sieci metodami "z nauczycielem" odpowiada w pybrain moduł pybrain.supervised.trainers http://pybrain.org/docs/api/supervised/trainers.html, dostarcza on dwóch klas: BackpropTrainer i RPropMinusTrainer. Na razie zajmiemy się tą pierwszą klasą.
  • importujemy i tworzymy obiekt typu BackpropTrainer, któremu przekazujemy sieć, ciąg uczący oraz parametry uczenia: współczynnik uczenia i bezwładność.
from pybrain.supervised.trainers import BackpropTrainer
trainer = BackpropTrainer(siec, CU,learningrate=0.0001, momentum=0.5)
  • wywołujemy metodę uczącą sieć podanym ciągiem uczącym. maxEpochs oznacza, że uczenie prowadzimy do momentu uzyskania zpieżności,jednak nie dłużej niż 1000 iteracji.
trainer.trainUntilConvergence(maxEpochs = 1000)

Testowanie sieci

  • testujemy działanie sieci na zbiorze uczącym
y_est = np.zeros(x.shape)
for i in range(len(x)-N_wej-1):
    bufor_wejsciowy = x[i:i+N_wej]
    y_est[i+N_wej] = siec.activate(bufor_wejsciowy)
  • proszę zilustrować działanie na wykresach przebiegów czasowych i widm sygnału wejściowego i wyjściowego.
subplot(221)
plot(t,x)
subplot(223)
plot(t,y)
plot(t,y_est,'.')

subplot(222)
f,Px = spectrum(x,sampling)
plot(f,Px)

subplot(224)

f,Py = spectrum(y,sampling)
plot(f,Py)

f,P_est = spectrum(y_est,sampling)
plot(f,P_est)

show()
  • wytwarzamy nowy zbiór danych wejściowych
x_test  = np.zeros(len(t))
faza = np.zeros(len(range(1,64,2)))
for i,f in enumerate(range(1,64,2)):
    faza[i] = np.random.rand(1)*2*np.pi
    x_test += np.sin(2*np.pi*f*t + faza[i])
  • proszę przepuścić ten zbiór danych przez sieć i zilustrować wynik działania na wykresach przebiegów czasowych i widm sygnału wejściowego i wyjściowego.
  1. Proszę sprawdzić zbieżność algorytmu w zależności od parametrów uczenia
  2. Proszę sprawdzić działanie sieci w zależności od rozmiaru wejścia


Modelowanie i predykcja szeregu czasowego

Załóżmy, że mamy pewien szereg czasowy. Dalej zakładamy, że jest on wynikiem pewnego procesu autoregresyjnego, tzn. że jego kolejna próbka jest pewną kombinacją liniową poprzednich próbek z dodanym szumem:

[math] x_t = \sum_{i=1}^p a_i x_{t-i} +\epsilon_t[/math]

Czy dałoby się zastosować techniki uczenia sieci neuronowej do oszacowania współczynników [math]a_i[/math]?

  1. Przy pomocy poniższego kodu proszę wygenerować realizację procesu AR o długości N = 2000 i współczynnikach a = [-0.5, 0.2], epsilon niech będzie = 0.1:
def generujAR(a, epsilon, N):
    x=np.zeros(N)
    rzad = len(a)
    for i in range(rzad,N):
        for p in range(len(a)):
            x[i] += a[p]*x[i-(p+1)]
        x[i] += epsilon*np.random.randn()
    return x
  1. Proszę wykreślić tą realizację
  2. Skonstruować ciąg uczący gdzie wejściem jest p poprzednich próbek zaś wyjściem kolejna próbka.
  3. Skonstruuj sieć o ilości wejść równej rzędowi modelu p
  4. Ucz sieć i obserwuj jak zmieniają się wagi.
  5. Zbadaj co dzieje się z estymowanymi parametrami oraz błędem popełnianym przez sieć gdy rozmiar wejścia nie jest zgodny z rzędem modelu.
# -*- coding: utf-8 -*-
from pybrain.structure import FeedForwardNetwork, LinearLayer, FullConnection
from pybrain.supervised.trainers import BackpropTrainer
from pybrain.datasets import SupervisedDataSet
from scipy.signal import firwin, lfilter
import numpy as np
import pylab as py


def generujAR(a, epsilon, N):
    x=np.zeros(N)
    rzad = len(a)
    for i in range(rzad,N):
        for p in range(len(a)):
            x[i] += a[p]*x[i-(p+1)]
        x[i] += epsilon*np.random.randn()
    return x

N = 2000
x = np.zeros(N)
a = np.array([ -0.5, 0.2]) #[0.1 -0.2 0.3 0.1 -0.1]
epsilon =0.1
x = generujAR(a,epsilon,N)
py.plot(x)
py.show()

# tworzymy ciąg uczący CU
N_wej = 2
CU = SupervisedDataSet(N_wej, 1)
for i in range(len(x)-N_wej-1):
    bufor_wejsciowy = x[i:i+N_wej]
    wartosc_wyjsciowa = x[i+N_wej]
    CU.addSample( bufor_wejsciowy[::-1], wartosc_wyjsciowa)#




# wytwarzamy pustą sieć
siec = FeedForwardNetwork()

# tworzymy węzły wejściowe i wyjściowe

warstwaWejsciowa = LinearLayer(N_wej)
warstwaWyjsciowa = LinearLayer(1)

# dodajemy węzły do sieci
siec.addInputModule(warstwaWejsciowa)
siec.addOutputModule(warstwaWyjsciowa)

# łączymy węzły
wej_do_wyj = FullConnection(warstwaWejsciowa, warstwaWyjsciowa)
siec.addConnection(wej_do_wyj)

# inicjujemy strukturę sieci
siec.sortModules()
  
    
trainer = BackpropTrainer(siec, CU,learningrate=0.01, momentum=0.8,verbose=True)
#trainer.trainUntilConvergence(maxEpochs = 500)
for i in range(10):
    trainer.trainEpochs(1)
    print i, siec.params

# test na zbiorze uczącym
y_est = np.zeros(x.shape)
for i in range(len(x)-N_wej-1):
    bufor_wejsciowy = x[i:i+N_wej]
    y_est[i+N_wej] = siec.activate(bufor_wejsciowy[::-1])
#py.plot(t,x)
py.subplot(2,1,1)
py.plot(x,'b')
py.plot(y_est,'r')
py.subplot(2,1,2)
py.plot(x-y_est)
print 'wariancja reziduum, ', np.var(x-y_est)
print 'wariancja procesu AR, ', epsilon**2
print 'parametry procesu: ', str(a)
print 'parametry wyestymowane: ', str(siec.params)
py.show()