@yuichirominato 2019.02.26更新 137views

【RBM】イジングRBMの学習更新式の準備


はじめに

前回はイジング計算の準備をしました。今回は学習をしてみます。

前回までのコード

import matplotlib.pyplot as plt
from blueqat.opt import Opt
import networkx as nx
import numpy as np
import collections

class rbm:
    def __init__(self):
        self.J = []
        self.v = 0
        self.h = 0
        self.n = 0
     
    def setRBM(self,v=4,h=4):
        n = v+h
        self.v = v
        self.h = h
        self.n = n
        self.J = np.diag([np.random.randint(99)/100 for i in range(n)])
        for i in range(v):
            for j in range(v,n):
                self.J[i][j] = np.random.randint(99)/100
        return self
     
    def network(self):
        G= nx.Graph()     
        edges = []
        for i in range(self.v):
            edges += [(i,j) for j in range(self.v,self.n)]
        G.add_edges_from(edges)
        pos = {}
        for i in range(self.n):
            if i<self.v:
                pos[i] = [0.1,0.1*(self.v-i)]
            else:
                pos[i] = [0.2,0.1*(self.h+self.v-i)]
        nx.draw_networkx(G,pos)
        plt.show()

def counter(narr):
    dis = []
    for i in range(len(narr)):
        dis.append(''.join([str(x) for x in narr[i]]))
    return collections.Counter(dis)

def bars(cc):
    index = []
    value = []
    for k,v in counter(cc).items():
        index.append(k)
        value.append(v)
    plt.bar(index,value)
    plt.show()


#以下試してみます。
a = rbm().setRBM(4,4)
a.network()
c = Opt().add(a.J).run(shots=100)
counter(c)

#=>
Counter({'00000000': 100})

bars(c)
beta = 0.1
c = Opt().add(beta*a.J).run(shots=100)
bars(c)

ここまでが前回のおさらいでした。

学習式

学習式はバイアスと結合荷重で、

$$b_{i,t+1} = \alpha * b_{i,t} + \epsilon(v_{data} -v_{model})\\
c_{i,t+1} = \alpha * c_{i,t} + \epsilon(h_{data} -h_{model})\\
w_{ij,t+1} = \alpha * w_{ij,t} + \epsilon(vh_{data} -vh_{model})$$

$\alpha$はモーメンタムで$\epsilon$は学習率です。基本的にはvはそのまま計算し、hのdataはsigmoidを通してもとめ、wはNLLの計算というもので計算量が多いものです。wのdataはvからhを求めれば求まります。

また、最初にシグモイド関数を用意しておきます。

def sigm(xx):
     return 1/(1+np.exp(-xx))

例題

1100というvisible layerを学習させてみます。まずは100回普通に今の回路を計算してみます。

a = rbm().setRBM(4,4)
c = Opt().add(a.J).run(shots=100)
counter(c)

#=>
Counter({'00000000': 100})

#=>
array([[0.22, 0.  , 0.  , 0.  , 0.28, 0.58, 0.56, 0.02],
       [0.  , 0.33, 0.  , 0.  , 0.81, 0.87, 0.15, 0.86],
       [0.  , 0.  , 0.21, 0.  , 0.38, 0.03, 0.64, 0.33],
       [0.  , 0.  , 0.  , 0.15, 0.18, 0.7 , 0.71, 0.7 ],
       [0.  , 0.  , 0.  , 0.  , 0.77, 0.  , 0.  , 0.  ],
       [0.  , 0.  , 0.  , 0.  , 0.  , 0.51, 0.  , 0.  ],
       [0.  , 0.  , 0.  , 0.  , 0.  , 0.  , 0.78, 0.  ],
       [0.  , 0.  , 0.  , 0.  , 0.  , 0.  , 0.  , 0.87]])

こうなりました。visible layerは最初の4量子ビットなので期待値は、

0000/100 = 0000

となります。hidden layerも同様です。visible layerのデータは1100なので、更新式は、それぞれの量子ビットに対して、

$$b_{0,t+1} = 0.9*0.22+0.1*(1-0)\\b_{1,t+1} = 0.9*0.33+0.1*(1-0)\\b_{2,t+1} = 0.9*0.21+0.1*(0-0)\\b_{3,t+1} = 0.9*0.15+0.1*(0-0)$$

一方hidden layerの更新をするためには事前にhidden layerのデータ値を出しておく必要があります。例えば、

$$h_4 = sigm(v_0*w_{04}+v_1*w_{14}+v_2*w_{24}+v_3*w_{34}+c_4)$$

その上で、

$$c_{4,t+1} = 0.9*0.77+0.1*(h_4-0)$$

このようにして更新を。あとは、wに関しても同様に、データからの期待値と上記の$v*h$をしたものを使って地味にひとつずつ更新をしていきます。使いやすいように更新用のmatrixを作って、

$$J = \alpha*J + \epsilon*(M_{data}-M_{model})$$

と変数を導入して計算できるように、QUBOmatrixの形にしておきます。それぞれのMにはデータの期待値とモデルの期待値をQUBOmatrixの形にしておきます。getMdata(self,vdata)としてvdataをlistでいれたら計算できるように追加しました。

from blueqat.opt import Opt
import networkx as nx
import numpy as np
import collections

class rbm:
    中略、、、

    def getMdata(self,vdata):
        hdata = [0 for i in range(self.h)]
        for i in range(self.h):
            hdata[i] += self.J[self.v+i][self.v+i]
            for j in range(self.v):
                hdata[i] += vdata[j]*self.J[j][self.v+i]
            hdata[i] = sigm(hdata[i])
        Mdata = np.diag(vdata+hdata)
        for i in range(self.v):
            for j in range(self.h):
                Mdata[i][self.v+j] = vdata[i]*hdata[j]
        return Mdata

あとはmodelの方のMatrixができればいいですが、アニーリングが入るためちょっとめんどいですね。

    def getMmodel(self):
        c = Opt().add(self.J).run(shots=100)
        ccc = counter(c)
        print(ccc)
        Mmodel = np.diag([0 for i in range(self.n)])
        for i,j in ccc.items():
            temp = [*i]
            temp = list(map(lambda x:int(x)/j,temp))
            Mmodel = Mmodel + np.diag(temp)
            for k in range(self.v):
                for l in range(self.h):
                    Mmodel[k][self.v+l] = temp[k]*temp[self.v+l]
        return Mmodel

間違ってたら指摘してください。。。

早速使ってみる

更新はself.Jをどんどん更新します。

    def train(self,vdata,alpha=0.9,epsilon=0.1):
         a.J = alpha*a.J-epsilon*(a.getMdata(vdata)-a.getMmodel())
         return self

こちらを連続でやってみて値が固定されるかみてみます。

コード全体を確認

import matplotlib.pyplot as plt
from blueqat.opt import Opt
import networkx as nx
import numpy as np
import collections

class rbm:
    def __init__(self):
        self.J = []
        self.v = 0
        self.h = 0
        self.n = 0
     
    def setRBM(self,v=4,h=4):
        n = v+h
        self.v = v
        self.h = h
        self.n = n
        self.J = np.diag([np.random.randint(99)/100 for i in range(n)])
        for i in range(v):
            for j in range(v,n):
                self.J[i][j] = np.random.randint(99)/100
        return self
     
    def network(self):
        G= nx.Graph()     
        edges = []
        for i in range(self.v):
            edges += [(i,j) for j in range(self.v,self.n)]
        G.add_edges_from(edges)
        pos = {}
        for i in range(self.n):
            if i<self.v:
                pos[i] = [0.1,0.1*(self.v-i)]
            else:
                pos[i] = [0.2,0.1*(self.h+self.v-i)]
        nx.draw_networkx(G,pos)
        plt.show()

    def getMdata(self,vdata):
        hdata = [0 for i in range(self.h)]
        for i in range(self.h):
            hdata[i] += self.J[self.v+i][self.v+i]
            for j in range(self.v):
                hdata[i] += vdata[j]*self.J[j][self.v+i]
            hdata[i] = sigm(hdata[i])
        Mdata = np.diag(vdata+hdata)
        for i in range(self.v):
            for j in range(self.h):
                Mdata[i][self.v+j] = vdata[i]*hdata[j]
        return Mdata

    def getMmodel(self):
        c = Opt().add(self.J).run(shots=100)
        ccc = counter(c)
        print(ccc)
        Mmodel = np.diag([0 for i in range(self.n)])
        for i,j in ccc.items():
            temp = [*i]
            temp = list(map(lambda x:int(x)/j,temp))
            Mmodel = Mmodel + np.diag(temp)
            for k in range(self.v):
                for l in range(self.h):
                    Mmodel[k][self.v+l] = temp[k]*temp[self.v+l]
        return Mmodel

    def train(self,vdata,alpha=0.9,epsilon=0.1):
         a.J = alpha*a.J-epsilon*(a.getMdata(vdata)-a.getMmodel())
         return self
    
def counter(narr):
    dis = []
    for i in range(len(narr)):
        dis.append(''.join([str(x) for x in narr[i]]))
    return collections.Counter(dis)

def bars(cc):
    index = []
    value = []
    for k,v in counter(cc).items():
        index.append(k)
        value.append(v)
    plt.bar(index,value)
    plt.show()


#以下試してみます。
a = rbm().setRBM(4,4)
a.network()

a.J

#=>
array([[0.47, 0.  , 0.  , 0.  , 0.25, 0.  , 0.91, 0.23],
       [0.  , 0.1 , 0.  , 0.  , 0.21, 0.75, 0.09, 0.65],
       [0.  , 0.  , 0.45, 0.  , 0.43, 0.28, 0.11, 0.64],
       [0.  , 0.  , 0.  , 0.44, 0.57, 0.27, 0.06, 0.57],
       [0.  , 0.  , 0.  , 0.  , 0.62, 0.  , 0.  , 0.  ],
       [0.  , 0.  , 0.  , 0.  , 0.  , 0.45, 0.  , 0.  ],
       [0.  , 0.  , 0.  , 0.  , 0.  , 0.  , 0.73, 0.  ],
       [0.  , 0.  , 0.  , 0.  , 0.  , 0.  , 0.  , 0.37]])

for i in range(10):
    a.train([1,1,0,1])

#=>
Counter({'00000000': 99, '01000000': 1})
Counter({'00000000': 97, '01000000': 3})
Counter({'00000000': 67, '01000000': 33})
Counter({'01000000': 79, '01010000': 8, '01010010': 4, '10000100': 3, '11000000': 2, '00000000': 2, '10000000': 1, '10000101': 1})
Counter({'01010010': 100})
Counter({'01010010': 59, '01011010': 40, '01010011': 1})
Counter({'11011100': 98, '11011110': 2})
Counter({'11011111': 60, '11011101': 30, '11011110': 7, '11011100': 3})
Counter({'11011111': 100})
Counter({'11011111': 100})

この状態で、更新されたa.Jに局所磁場でq0=-10,q1=-10をかけてみて入力をして推論してみます。

c = Opt().add(a.J).add("-10*q0-10*q1").run(shots=100)
counter(c)

#=>
Counter({'11011111': 100})

再現できたような気がしますがどうでしょうか?これをベースに次回はパターン認識をしてみたいと思います。

Recommended


Wikiへ移動