Навчання ваг на машині Больцмана


14

Я намагаюся зрозуміти, як працюють машини Boltzmann, але я не зовсім впевнений, як вивчають ваги, і не зміг знайти чіткого опису. Чи правильно таке? (Також вказівки на будь-які хороші пояснення Болцмана також будуть чудовими.)

У нас є набір видимих ​​одиниць (наприклад, відповідних чорним / білим пікселям на зображенню) та набір прихованих одиниць. Ваги якось ініціалізуються (наприклад, рівномірно від [-0.5, 0.5]), а потім ми чергуємо дві наступні фази, поки не буде досягнуто якогось правила зупинки:

  1. Затиснута фаза - У цій фазі всі значення видимих ​​одиниць фіксуються, тому ми лише оновлюємо стани прихованих одиниць (відповідно до правила стохастичної активації Больцмана). Ми оновлюємось, поки мережа не досягне рівноваги. Як тільки ми досягнемо рівноваги, ми продовжуємо оновлення ще разів (для деяких заздалегідь визначених N ), відслідковуючи середнє значення x i x j (де x i , x j - стани вузлів i та j ). Після цих N оновлень рівноваги ми оновлюємо w i j = w i j +NNхiхjхi,хjijNшij=шij+1САvеrаге(хiхj)С

  2. шij=шij-1САvеrаге(хiхj)

Тому мої основні питання:

  1. Щоразу, коли ми перебуваємо у затиснутій фазі, чи повертаємо видимі одиниці до однієї з моделей, яку ми хочемо вивчити (з певною частотою, яка представляє важливість цієї картини), чи залишаємо видимі одиниці у стані, в якому вони були в кінці вільної фази?

  2. Чи робимо ми пакетне оновлення ваг в кінці кожної фази чи оновлюємо ваги на кожному етапі рівноваги у фазі? (Або один штраф?)

Відповіді:


6

Інтуїтивно можна бачити видимі одиниці як "те, що бачить модель", а приховані одиниці як "стан душі моделі". Встановлюючи всі видимі одиниці на деякі значення, ви "показуєте дані моделі". Потім, коли ви активуєте приховані блоки, модель підлаштовує стан душі до того, що бачить.

Далі ви відпустите модель і пофантазуйте. Він стане закритим і буквально побачить деякі речі, які його генерує розум, і створить нові стани душі на основі цих образів.

Те, що ми робимо, регулюючи вагу (і ухили), змушує модель більше вірити в дані і менше - власним фантазіям. Таким чином, після певного тренінгу він повірить у якусь (дуже сподіваюсь) досить гарну модель даних, і ми можемо, наприклад, запитати "чи вірите ви в цю пару (X, Y)? Наскільки ви її вважаєте? Яка ваша думка, г-н. Машина Больцмана? "

Нарешті, ось короткий опис моделей на основі енергії, який повинен дати вам інтуїцію, звідки беруться затиснуті та вільні фази та як ми хочемо їх запускати.

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

Смішно бачити, що інтуїтивно зрозумілі правила оновлення виходять із виведення ймовірності формування журналу даних за моделлю.

Маючи на увазі ці інтуїції, тепер простіше відповідати на ваші запитання:

  1. Ми повинні скинути видимі одиниці до деяких даних, у які б ми хотіли, щоб модель вірила. Якщо ми будемо використовувати значення з кінця вільної фази, вона просто продовжить фантазувати, і в кінцевому підсумку застосує власні помилкові переконання.

  2. Краще робити оновлення після закінчення етапу. Особливо, якщо це затиснута фаза, краще приділити моделі деякий час, щоб "зосередитися" на даних. Більш ранні оновлення уповільнюватимуть конвергенцію, оскільки вони нав'язують з'єднання, коли модель ще не адаптувала стан душі до реальності. Оновлення ваги після кожного кроку рівноваги під час фантазування повинно бути менш шкідливим, хоча я з цим не маю досвіду.

Якщо ви хочете вдосконалити свою інтуїцію щодо EBM, BM та RBM, я б радив переглянути деякі лекції Джеффрі Хінтона на цю тему, у нього є хороші аналогії.


2
  1. Так, "ми скидаємо (затискаємо) видимі одиниці до однієї із зразків, які ми хочемо вивчити (з певною частотою, яка представляє важливість цього шаблону)".

  2. Так, "ми робимо пакетне оновлення ваг в кінці кожної фази". Я не думаю, що оновлення "ваг на кожному етапі рівноваги на фазі" призведе до швидкої конвергенції, оскільки мережа "відволікається" миттєвими помилками - я реалізував машини Boltzmann таким чином, і я пам'ятаю, що це не дуже добре працює поки я не змінив його на пакетне оновлення.


0

Ось зразок коду Python для машин Больцмана на основі коду Павла Іванова від

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

Він працює, створюючи виправлення даних, але це можна змінити, щоб код працював на всіх даних постійно.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.