Gewichte lernen in einer Boltzmann-Maschine

14

Ich versuche zu verstehen, wie Boltzmann-Maschinen funktionieren, bin mir aber nicht sicher, wie Gewichte gelernt werden, und habe keine eindeutige Beschreibung gefunden. Ist das Folgende richtig? (Auch Hinweise auf gute Boltzmann-Maschinenerklärungen wären toll.)

Wir haben eine Reihe von sichtbaren Einheiten (z. B. entsprechend schwarz / weißen Pixeln in einem Bild) und eine Reihe von versteckten Einheiten. Die Gewichte werden auf irgendeine Weise initialisiert (z. B. einheitlich von [-0,5, 0,5]), und dann wechseln wir zwischen den folgenden beiden Phasen ab, bis eine Stoppregel erreicht ist:

  1. Clamped-Phase - In dieser Phase sind alle Werte der sichtbaren Einheiten festgelegt, sodass nur die Zustände der ausgeblendeten Einheiten aktualisiert werden (gemäß der stochastischen Boltzmann-Aktivierungsregel). Wir aktualisieren, bis das Netzwerk das Gleichgewicht erreicht hat. Sobald wir das Gleichgewicht erreicht haben, aktualisieren wir weitere Male (für einige vordefinierte N ), wobei wir den Durchschnitt von x i x j verfolgen (wobei x i , x j die Zustände der Knoten i und j sind ). Nach diesem N Gleichgewicht Updates aktualisieren wir w i j = w i j +NNxichxjxich,xjichjN, wobeiCeine Lernrate ist. (Oder, anstatt am Ende eine Stapelaktualisierung durchzuführen, aktualisieren wir nach dem Gleichgewichtsschritt?)wij=wij+1CAverage(xixj)C

  2. Freie Phase - In dieser Phase werden die Zustände aller Einheiten aktualisiert. Sobald wir das Gleichgewicht erreicht haben, aktualisieren wir auf ähnliche Weise N 'mehrmals, aber anstatt am Ende Korrelationen hinzuzufügen, subtrahieren wir: .wij=wij1CAverage(xixj)

Meine Hauptfragen sind also:

  1. Wenn wir uns in der Klemmphase befinden, setzen wir die sichtbaren Einheiten auf eines der Muster zurück, die wir lernen möchten (mit einer Frequenz, die die Wichtigkeit dieses Musters darstellt), oder lassen wir die sichtbaren Einheiten in dem Zustand, in dem sie sich befanden am Ende der freien Phase?

  2. Führen wir am Ende jeder Phase eine Stapelaktualisierung der Gewichte durch oder aktualisieren wir die Gewichte bei jedem Gleichgewichtsschritt in der Phase? (Oder ist einer in Ordnung?)

raegtin
quelle

Antworten:

6

Intuitiv können Sie sich sichtbare Einheiten als "das, was das Modell sieht" und versteckte Einheiten als "den Geisteszustand des Modells" vorstellen. Wenn Sie alle sichtbaren Einheiten auf bestimmte Werte setzen, "zeigen Sie die Daten dem Modell an". Wenn Sie dann ausgeblendete Einheiten aktivieren, passt das Modell seinen Geisteszustand an das an, was es sieht.

Als nächstes lässt du das Model frei und fantasierst. Es wird sich einschließen und buchstäblich einige Dinge sehen, die der Geist erzeugt, und neue Geisteszustände erzeugen, die auf diesen Bildern basieren.

Durch Anpassen der Gewichte (und Verzerrungen) wird das Modell dazu gebracht, mehr an die Daten und weniger an seine eigenen Fantasien zu glauben. Auf diese Weise wird es nach einigem Training an ein (hoffentlich) ziemlich gutes Datenmodell glauben, und wir können zum Beispiel fragen: "Glauben Sie an dieses Paar (X, Y)? Wie wahrscheinlich ist es, dass Sie es finden? Wie ist Ihre Meinung, mr. Boltzmann-Maschine? "

Abschließend folgt eine kurze Beschreibung der energiebasierten Modelle, die Ihnen eine Vorstellung davon geben soll, woher die geklemmten und freien Phasen kommen und wie wir sie ausführen möchten.

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

Es ist lustig zu sehen, dass die intuitiv eindeutigen Aktualisierungsregeln sich aus der Ableitung der Wahrscheinlichkeit ergeben, dass das Modell Daten generiert.

Mit diesen Intuitionen ist es jetzt einfacher, Ihre Fragen zu beantworten:

  1. Wir müssen die sichtbaren Einheiten auf einige Daten zurücksetzen, an die das Modell glauben soll. Wenn wir die Werte vom Ende der freien Phase verwenden, wird es einfach weiter phantasieren und seine eigenen fehlgeleiteten Überzeugungen durchsetzen.

  2. Es ist besser, Updates nach dem Ende der Phase durchzuführen. Insbesondere wenn es sich um die Clamp-Phase handelt, ist es besser, dem Modell etwas Zeit zu geben, um sich auf die Daten zu konzentrieren. Frühere Updates verlangsamen die Konvergenz, da sie die Verbindungen erzwingen, wenn das Modell seinen Geisteszustand noch nicht an die Realität angepasst hat. Das Aktualisieren der Gewichte nach jedem Gleichgewichtsschritt während des Phantasierens sollte weniger schädlich sein, obwohl ich keine Erfahrung damit habe.

Wenn Sie Ihre Intuition in EBM, BM und RBM verbessern möchten, empfehle ich Ihnen, einige der Vorträge von Geoffrey Hinton zu diesem Thema anzusehen. Er hat einige gute Analogien.

sjm.majewski
quelle
2
  1. Ja, "wir setzen die sichtbaren Einheiten auf eines der Muster zurück, die wir lernen möchten (mit einer Häufigkeit, die die Wichtigkeit dieses Musters darstellt)."

  2. Ja, "wir führen am Ende jeder Phase eine Stapelaktualisierung der Gewichte durch." Ich glaube nicht, dass die Aktualisierung der "Gewichte bei jedem Gleichgewichtsschritt in der Phase" zu einer schnellen Konvergenz führt, da das Netzwerk durch augenblickliche Fehler "abgelenkt" wird. Ich habe Boltzmann-Maschinen so implementiert und erinnere mich, dass sie nicht sehr gut funktionieren bis ich es zu einem Batch-Update geändert habe.

Neil G
quelle
0

Hier ist ein Python-Beispielcode für Boltzmann Machines, der auf Paul Ivanovs Code aus basiert

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

Es funktioniert, indem Patches von Daten erstellt werden. Dies kann jedoch so geändert werden, dass der Code immer für alle Daten gilt.

BBDynSys
quelle