การเรียนรู้น้ำหนักในเครื่อง Boltzmann


14

ฉันพยายามเข้าใจวิธีการทำงานของเครื่องจักร Boltzmann แต่ฉันไม่แน่ใจว่าจะเรียนรู้น้ำหนักได้อย่างไรและไม่สามารถหาคำอธิบายที่ชัดเจนได้ ถูกต้องหรือไม่? (เช่นกันตัวชี้ไปที่คำอธิบายเครื่อง Boltzmann ที่ดีก็จะดีเช่นกัน)

เรามีชุดของหน่วยที่มองเห็นได้ (เช่นตรงกับพิกเซลดำ / ขาวในรูปภาพ) และชุดของหน่วยที่ซ่อนอยู่ น้ำหนักถูกเริ่มต้นอย่างใด (เช่นสม่ำเสมอจาก [-0.5, 0.5]) จากนั้นเราสลับกันระหว่างสองเฟสต่อไปนี้จนกว่าจะถึงกฎการหยุดบางอย่าง:

  1. Clamped phase - ในระยะนี้ค่าทั้งหมดของหน่วยที่มองเห็นได้จะได้รับการแก้ไขดังนั้นเราจะอัปเดตสถานะของหน่วยที่ซ่อนอยู่เท่านั้น (ตามกฎการเปิดใช้งานสุ่มของ Boltzmann) เราอัปเดตจนกว่าเครือข่ายจะมาถึงจุดสมดุล เมื่อเราไปถึงจุดสมดุลเราจะทำการปรับปรุงครั้งต่อไป (สำหรับบางN ที่กำหนดไว้ล่วงหน้า) ติดตามค่าเฉลี่ยของx i x j (โดยที่x i , x jเป็นสถานะของโหนดiและj ) หลังจากการอัพเดทสมดุลของNเหล่านั้นแล้วเราจะอัปเดตw ฉัน j = w ฉัน j +ยังไม่มีข้อความยังไม่มีข้อความxผมxJxผม,xJผมJยังไม่มีข้อความโดยที่Cคืออัตราการเรียนรู้ (หรือแทนที่จะทำการอัปเดตเป็นชุดในตอนท้ายเราจะอัปเดตหลังจากเราดำเนินการตามขั้นตอนสมดุล)WผมJ=WผมJ+1Aโวลต์อีRaก.อี(xผมxJ)

  2. Free phase - ในระยะนี้สถานะของทุกหน่วยจะได้รับการอัพเดต เมื่อเราไปถึงจุดสมดุลเราก็ทำการปรับปรุง N 'อีกครั้งเหมือนกัน แต่แทนที่จะเพิ่มความสัมพันธ์ในตอนท้ายเราจะลบออก: )WผมJ=WผมJ-1Aโวลต์อีRaก.อี(xผมxJ)

ดังนั้นคำถามหลักของฉันคือ:

  1. เมื่อใดก็ตามที่เราอยู่ในช่วงแคลมป์เราจะรีเซ็ตหน่วยที่มองเห็นเป็นรูปแบบที่เราต้องการเรียนรู้ (ด้วยความถี่ที่แสดงถึงความสำคัญของรูปแบบนั้น) หรือไม่หรือเราปล่อยให้หน่วยที่มองเห็นอยู่ในสภาพที่พวกเขาอยู่ ในตอนท้ายของเฟสฟรี

  2. เราทำการปรับปรุงแบบชุดของน้ำหนักในตอนท้ายของแต่ละเฟสหรือทำการปรับปรุงน้ำหนักในแต่ละขั้นตอนของสมดุลในเฟสหรือไม่? (หรือเป็นหนึ่งเดียวที่ดี?)

คำตอบ:


6

โดยสังเขปคุณสามารถนึกถึงหน่วยที่มองเห็นได้ว่าเป็น "สิ่งที่โมเดลมองเห็น" และหน่วยที่ซ่อนอยู่ว่าเป็น "สภาวะของแบบจำลอง" เมื่อคุณตั้งค่าหน่วยที่มองเห็นได้ทั้งหมดเป็นค่าบางค่าคุณ "แสดงข้อมูลเป็นแบบจำลอง" จากนั้นเมื่อคุณเปิดใช้งานหน่วยที่ซ่อนอยู่โมเดลจะปรับสภาวะของสิ่งที่เห็น

ต่อไปให้คุณปล่อยโมเดลให้เป็นอิสระและเพ้อฝัน มันจะกลายเป็นปิดและเห็นสิ่งที่ใจสร้างและสร้างสภาวะใหม่ของจิตใจตามภาพเหล่านั้น

สิ่งที่เราทำโดยการปรับน้ำหนัก (และอคติ) ทำให้ตัวแบบเชื่อในข้อมูลมากขึ้นและมีจินตนาการน้อยลง วิธีนี้หลังจากการฝึกอบรมบางอย่างมันจะเชื่อในแบบจำลองข้อมูลที่ดี (หวังว่า) และเราสามารถถามได้ว่า "คุณเชื่อในคู่นี้ (X, Y) หรือไม่คุณคิดว่าเป็นไปได้อย่างไร เครื่องจักร Boltzmann? "

ในที่สุดนี่คือคำอธิบายสั้น ๆ ของแบบจำลองการใช้พลังงานซึ่งควรให้สัญชาตญาณว่าเฟสของ Clamped และ Free มาจากไหนและเราต้องการเรียกใช้มันอย่างไร

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

เป็นเรื่องตลกที่จะเห็นว่ากฎการอัปเดตที่ชัดเจนอย่างสังหรณ์ใจออกมาในรูปแบบที่ได้มาจากความเป็นไปได้ในการสร้างข้อมูลโดยตัวแบบ

ด้วยความคิดเหล่านี้จึงง่ายต่อการตอบคำถามของคุณ:

  1. เราต้องรีเซ็ตหน่วยที่มองเห็นได้เป็นข้อมูลบางอย่างที่เราต้องการให้แบบจำลองเชื่อมั่นหากเราใช้ค่าจากจุดสิ้นสุดของช่วงฟรีเฟสมันจะเพ้อฝันต่อไปบังคับใช้เป็นความเชื่อที่เข้าใจผิด

  2. เป็นการดีกว่าที่จะอัปเดตหลังจากสิ้นสุดช่วง โดยเฉพาะอย่างยิ่งถ้ามันเป็นช่วงแคลมป์ก็จะดีกว่าที่จะให้แบบจำลองบางครั้งเพื่อ "มุ่งเน้น" กับข้อมูล การอัปเดตก่อนหน้านี้จะทำให้การบรรจบกันช้าลงเนื่องจากพวกเขาบังคับใช้การเชื่อมต่อเมื่อแบบจำลองไม่ได้ปรับมันเป็นสภาวะของความเป็นจริง การอัปเดตน้ำหนักหลังจากแต่ละขั้นตอนสมดุลในขณะที่เพ้อฝันควรเป็นอันตรายน้อยกว่าแม้ว่าฉันจะไม่มีประสบการณ์กับเรื่องนั้น

หากคุณต้องการปรับปรุงสัญชาตญาณของคุณใน EBM, BM และ RBM ฉันขอแนะนำให้ดูการบรรยายของ Geoffrey Hinton เกี่ยวกับเรื่องนี้เขามีอุปมาที่ดี


2
  1. ใช่ "เรารีเซ็ต (ที่หนีบ) หน่วยที่มองเห็นเป็นหนึ่งในรูปแบบที่เราต้องการเรียนรู้ (ด้วยความถี่บางอย่างที่แสดงถึงความสำคัญของรูปแบบนั้น)"

  2. ใช่ "เราทำการอัปเดตชุดข้อมูลของน้ำหนักในตอนท้ายของแต่ละเฟส" ฉันไม่คิดว่าการอัปเดต "น้ำหนักในแต่ละขั้นตอนของดุลยภาพ" จะนำไปสู่การบรรจบกันอย่างรวดเร็วเพราะเครือข่าย "เบี่ยงเบนความสนใจ" โดยมีข้อผิดพลาดเกิดขึ้นทันที - ฉันติดตั้งเครื่องจักร Boltzmann แล้ว จนกว่าฉันจะเปลี่ยนเป็นการอัปเดตแบบกลุ่ม


0

นี่คือตัวอย่างโค้ดไพ ธ อนสำหรับ Boltzmann Machines ตามรหัสของ Paul Ivanov จาก

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

มันทำงานได้โดยการสร้างแพทช์ของข้อมูล แต่สามารถแก้ไขได้เพื่อให้รหัสทำงานกับข้อมูลทั้งหมดตลอดเวลา

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.