Aprendiendo pesas en una máquina Boltzmann

14

Estoy tratando de entender cómo funcionan las máquinas de Boltzmann, pero no estoy muy seguro de cómo se aprenden los pesos, y no he podido encontrar una descripción clara. ¿Es correcto lo siguiente? (Además, los consejos sobre cualquier buena explicación de la máquina Boltzmann también serían geniales).

Tenemos un conjunto de unidades visibles (por ejemplo, correspondientes a píxeles en blanco y negro en una imagen) y un conjunto de unidades ocultas. Los pesos se inicializan de alguna manera (p. Ej., Uniformemente desde [-0.5, 0.5]), y luego alternamos entre las siguientes dos fases hasta que se alcanza una regla de detención:

  1. Fase fija: en esta fase, todos los valores de las unidades visibles son fijos, por lo que solo actualizamos los estados de las unidades ocultas (de acuerdo con la regla de activación estocástica de Boltzmann). Actualizamos hasta que la red haya alcanzado el equilibrio. Una vez que alcanzamos el equilibrio, continuamos actualizando más veces (para algunos N predefinidos ), haciendo un seguimiento del promedio de x i x j (donde x i , x j son los estados de los nodos i y j ). Después de esas actualizaciones de equilibrio de N , actualizamos w i j = w i j 1nortenorteXyoXjXyo,Xjyojnorte, dondeCes una tasa de aprendizaje. (O, en lugar de hacer una actualización por lotes al final, ¿actualizamos después del paso de equilibrio?)wyoj=wyoj+1CUNvmirunsolmi(XyoXj)C

  2. Fase libre: en esta fase, se actualizan los estados de todas las unidades. Una vez que alcanzamos el equilibrio, continuamos actualizando N 'más veces, pero en lugar de sumar correlaciones al final, restamos: .wyoj=wyoj-1CUNvmirunsolmi(XyoXj)

Entonces mis preguntas principales son:

  1. Cada vez que estamos en la fase fija, ¿restablecemos las unidades visibles a uno de los patrones que queremos aprender (con alguna frecuencia que represente la importancia de ese patrón), o dejamos las unidades visibles en el estado en que se encontraban? al final de la fase libre?

  2. ¿Hacemos una actualización por lotes de los pesos al final de cada fase, o actualizamos los pesos en cada paso de equilibrio en la fase? (O, ¿está bien uno?)

raegtin
fuente

Respuestas:

6

Intuitivamente, puede pensar en las unidades visibles como "lo que el modelo ve" y las unidades ocultas como "el estado mental del modelo". Cuando establece todas las unidades visibles en algunos valores, "muestra los datos al modelo". Luego, cuando activas unidades ocultas, el modelo ajusta su estado mental a lo que ve.

Luego dejas que la modelo se vaya libre y fantasee. Se cerrará y literalmente verá algunas cosas que su mente genera, y generará nuevos estados de ánimo basados ​​en esas imágenes.

Lo que hacemos ajustando los pesos (y los sesgos) es hacer que el modelo crea más en los datos y menos en sus propias fantasías. De esta manera, después de un entrenamiento, creerá en algún modelo (con suerte) bastante bueno de datos, y podemos, por ejemplo, preguntar "¿crees en este par (X, Y)? ¿Qué tan probable es que lo encuentres? ¿Cuál es tu opinión, señor? ¿Máquina de Boltzmann?

Finalmente, aquí hay una breve descripción de los Modelos Basados ​​en Energía, que deberían darle una idea de dónde provienen las fases Sujetadas y Libres y cómo queremos ejecutarlas.

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

Es divertido ver que las reglas de actualización intuitivamente claras surgen de la derivación de la probabilidad de registro de generar datos por el modelo.

Con estas intuiciones en mente, ahora es más fácil responder sus preguntas:

  1. Tenemos que restablecer las unidades visibles a algunos datos en los que nos gustaría que creyera el modelo. Si usamos los valores del final de la fase libre, simplemente continuará fantaseando, y finalmente impondrá sus propias creencias equivocadas.

  2. Es mejor hacer actualizaciones después del final de la fase. Especialmente si es la fase fija, es mejor darle al modelo algo de tiempo para "enfocarse" en los datos. Las actualizaciones anteriores ralentizarán la convergencia, ya que imponen las conexiones cuando el modelo aún no ha ajustado su estado mental a la realidad. Actualizar el peso después de cada paso de equilibrio mientras fantasea debería ser menos dañino, aunque no tengo experiencia con eso.

Si desea mejorar su intuición sobre EBM, BM y RBM, le aconsejo que vea algunas de las conferencias de Geoffrey Hinton sobre el tema, tiene algunas buenas analogías.

sjm.majewski
fuente
2
  1. Sí, "restablecemos (sujetamos) las unidades visibles a uno de los patrones que queremos aprender (con cierta frecuencia que representa la importancia de ese patrón)".

  2. Sí, "hacemos una actualización por lotes de los pesos al final de cada fase". No creo que actualizar "los pesos en cada paso de equilibrio en la fase" conduzca a una convergencia rápida porque la red "se distrae" por errores instantáneos: he implementado máquinas Boltzmann de esa manera, y recuerdo que no funciona muy bien hasta que lo cambié a una actualización por lotes.

Neil G
fuente
0

Aquí hay un código de Python de muestra para máquinas Boltzmann basado en el código de Paul Ivanov de

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

Funciona creando parches de datos, pero esto se puede modificar para que el código funcione en todos los datos todo el tiempo.

BBDynSys
fuente