Apprendimento dei pesi in una macchina Boltzmann


14

Sto cercando di capire come funzionano le macchine Boltzmann, ma non sono sicuro di come i pesi vengano appresi e non sono stato in grado di trovare una descrizione chiara. Il seguente è corretto? (Inoltre, i suggerimenti per qualsiasi buona spiegazione della macchina Boltzmann sarebbero anche ottimi.)

Abbiamo una serie di unità visibili (ad esempio, corrispondenti a pixel bianchi / neri in un'immagine) e una serie di unità nascoste. I pesi vengono inizializzati in qualche modo (ad esempio, uniformemente da [-0,5, 0,5]), quindi si alternano tra le due fasi seguenti fino a raggiungere una regola di arresto:

  1. Fase bloccata - In questa fase, tutti i valori delle unità visibili sono fissi, quindi aggiorniamo solo gli stati delle unità nascoste (secondo la regola di attivazione stocastica di Boltzmann). Aggiorniamo fino a quando la rete non raggiunge l'equilibrio. Una volta raggiunto l'equilibrio, continuiamo aggiornando più volte (per alcuni predefinito N ), tenendo traccia della media di x i x j (dove x i , x j sono stati di nodi i e j ). Dopo quegli aggiornamenti di equilibrio N , aggiorniamo w i j = w i j +NNXioXjXio,XjiojN, doveCè un tasso di apprendimento. (Oppure, invece di eseguire un aggiornamento batch alla fine, eseguiamo l'aggiornamento dopo il passaggio di equilibrio?)wioj=wioj+1CUNverun'ge(XioXj)C

  2. Fase libera - In questa fase, gli stati di tutte le unità vengono aggiornati. Una volta raggiunto l'equilibrio, allo stesso modo continuiamo ad aggiornare N 'più volte, ma invece di aggiungere correlazioni alla fine, sottraggiamo: .wioj=wioj-1CUNverun'ge(XioXj)

Quindi le mie domande principali sono:

  1. Ogni volta che siamo nella fase bloccata, reimpostiamo le unità visibili su uno dei modelli che vogliamo imparare (con una certa frequenza che rappresenta l'importanza di quel modello) o lasciamo le unità visibili nello stato in cui si trovavano al termine della fase libera?

  2. Effettuiamo un aggiornamento batch dei pesi alla fine di ogni fase o aggiorniamo i pesi ad ogni fase di equilibrio nella fase? (Oppure, o va bene uno?)

Risposte:


6

Intuitivamente, puoi pensare alle unità visibili come "ciò che il modello vede" e le unità nascoste come "stato d'animo del modello". Quando imposti tutte le unità visibili su alcuni valori, "mostri i dati al modello". Quindi, quando attivi le unità nascoste, il modello regola il suo stato d'animo a ciò che vede.

Successivamente lasci il modello libero e fantastichi. Diventerà chiuso e vedrà letteralmente alcune cose che la sua mente genera e genererà nuovi stati mentali basati su quelle immagini.

Ciò che facciamo regolando i pesi (e le inclinazioni) è far credere al modello di più nei dati e meno nelle sue fantasie. In questo modo dopo un po 'di allenamento crederà in un modello di dati (si spera) piuttosto buono, e possiamo ad esempio chiederci "credi in questa coppia (X, Y)? Con quale probabilità lo trovi? Qual è la tua opinione, signor. Boltzmann Machine? "

Infine, ecco una breve descrizione dei modelli basati sull'energia, che dovrebbe darti alcune intuizioni da dove provengono le fasi bloccate e libere e come vogliamo gestirle.

http://deeplearning.net/tutorial/rbm.html#energy-based-models-ebm

È divertente vedere che le regole di aggiornamento intuitivamente chiare derivano dalla derivazione della probabilità di log di generare dati dal modello.

Con queste intuizioni in mente ora è più facile rispondere alle tue domande:

  1. Dobbiamo ripristinare le unità visibili su alcuni dati in cui vorremmo che il modello credesse. Se usiamo i valori dalla fine della fase libera, continuerà semplicemente a fantasticare, e far valere le proprie convinzioni errate.

  2. È meglio fare aggiornamenti dopo la fine della fase. Soprattutto se si tratta della fase bloccata, è meglio concedere al modello un po 'di tempo per "concentrarsi" sui dati. Aggiornamenti precedenti rallenteranno la convergenza, poiché rafforzano le connessioni quando il modello non ha ancora adeguato il suo stato d'animo alla realtà. Aggiornare il peso dopo ogni passaggio di equilibrio mentre fantastichi dovrebbe essere meno dannoso, anche se non ho esperienza con quello.

Se vuoi migliorare la tua intuizione su EBM, BM e RBM, ti consiglio di guardare alcune delle lezioni di Geoffrey Hinton sull'argomento, che ha alcune buone analogie.


2
  1. Sì, "ripristiniamo (blocciamo) le unità visibili su uno dei pattern che vogliamo imparare (con una certa frequenza che rappresenta l'importanza di quel pattern)."

  2. Sì, "eseguiamo un aggiornamento batch dei pesi alla fine di ogni fase". Non credo che l'aggiornamento "dei pesi ad ogni fase di equilibrio nella fase" porterà a una rapida convergenza perché la rete "viene distratta" da errori istantanei - ho implementato le macchine Boltzmann in quel modo e ricordo che non funziona molto bene fino a quando non l'ho modificato in un aggiornamento batch.


0

Ecco un codice Python di esempio per Boltzmann Machines basato sul codice di Paul Ivanov di

http://redwood.berkeley.edu/wiki/VS265:_Homework_assignments

import numpy as np

def extract_patches(im,SZ,n):
    imsize,imsize=im.shape;
    X=np.zeros((n,SZ**2),dtype=np.int8);
    startsx= np.random.randint(imsize-SZ,size=n)
    startsy=np.random.randint(imsize-SZ,size=n)
    for i,stx,sty in zip(xrange(n), startsx,startsy):
        P=im[sty:sty+SZ, stx:stx+SZ];
        X[i]=2*P.flat[:]-1;
    return X.T

def sample(T,b,n,num_init_samples):
    """
    sample.m - sample states from model distribution

    function S = sample(T,b,n, num_init_samples)

    T:                weight matrix
    b:                bias
    n:                number of samples
    num_init_samples: number of initial Gibbs sweeps
    """
    N=T.shape[0]

    # initialize state vector for sampling
    s=2*(np.random.rand(N)<sigmoid(b))-1

    for k in xrange(num_init_samples):
        s=draw(s,T,b)

    # sample states
    S=np.zeros((N,n))
    S[:,0]=s
    for i in xrange(1,n):
        S[:,i]=draw(S[:,i-1],T,b)

    return S

def sigmoid(u):
    """
    sigmoid.m - sigmoid function

    function s = sigmoid(u)
    """
    return 1./(1.+np.exp(-u));

def draw(Sin,T,b):
    """
    draw.m - perform single Gibbs sweep to draw a sample from distribution

    function S = draw(Sin,T,b)

    Sin:      initial state
    T:        weight matrix
    b:        bias
    """
    N=Sin.shape[0]
    S=Sin.copy()
    rand = np.random.rand(N,1)
    for i in xrange(N):
        h=np.dot(T[i,:],S)+b[i];
        S[i]=2*(rand[i]<sigmoid(h))-1;

    return S

def run(im, T=None, b=None, display=True,N=4,num_trials=100,batch_size=100,num_init_samples=10,eta=0.1):
    SZ=np.sqrt(N);
    if T is None: T=np.zeros((N,N)); # weight matrix
    if b is None: b=np.zeros(N); # bias

    for t in xrange(num_trials):
        print t, num_trials
        # data statistics (clamped)
        X=extract_patches(im,SZ,batch_size).astype(np.float);
        R_data=np.dot(X,X.T)/batch_size;
        mu_data=X.mean(1);

        # prior statistics (unclamped)
        S=sample(T,b,batch_size,num_init_samples);
        R_prior=np.dot(S,S.T)/batch_size;
        mu_prior=S.mean(1);

        # update params
        deltaT=eta*(R_data - R_prior);
        T=T+deltaT;

        deltab=eta*(mu_data - mu_prior);
        b=b+deltab;


    return T, b

if __name__ == "__main__": 
    A = np.array([\
    [0.,1.,1.,0],
    [1.,1.,0, 0],
    [1.,1.,1.,0],
    [0, 1.,1.,1.],
    [0, 0, 1.,0]
    ])
    T,b = run(A,display=False)
    print T
    print b

Funziona creando patch di dati, ma questo può essere modificato in modo che il codice funzioni sempre su tutti i dati.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.