Uczenie maszynowe i sztuczne sieci neuronowe/Ćwiczenia 2

Z Brain-wiki

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()