🍉しいたげられたしいたけ

NO WAR! 戊争反察Ceasefire Now! 䞀刻も早い停戊を

排他的論理和EORを機械孊習で実珟しようずしたらバタフラむ効果が発生したその

盞倉わらず斎藀康毅『れロから䜜るDeep Learning ―Pythonで孊ぶディヌプラヌニングの理論ず実装』(O'REILLY) 読者限定の蚘事です。さらにバタフラむ効果やカオス珟象にある皋床の知識ず興味がある人ずいうこずで、さらに読者は限定されそうです。「ブログでやらず論文か玀芁に曞け」ず蚀われそうですが、そこたで深掘りできるかわからないので、ずりあえずブログに晒しおいたす。今回も新着お目汚しを避けるため日付をさかのがっお公開しおいたす。 

れロから䜜るDeep Learning ―Pythonで孊ぶディヌプラヌニングの理論ず実装

れロから䜜るDeep Learning ―Pythonで孊ぶディヌプラヌニングの理論ず実装

  • 䜜者:æ–Žè—€ 康毅
  • 発売日: 2016/09/24
  • メディア: 単行本゜フトカバヌ
 

前回「その2」では、排他的論理和EORを実珟しようずする䞭間局の圢状が重み2×4+4×2芁玠、バむアス4+2芁玠の2局ニュヌラルネットワヌクにおいお、ガりス分垃に基づく乱数により䞎えた重みの初期倀を、小数点以䞋䞀桁ず぀䞞めおいったずころ、繰り返し孊習における正解率ず損倱関数の倀のグラフが激しく倉化したこずを述べた。

同様の珟象は、䞭間局の圢状が重み2×3+3×2芁玠、バむアス3+2芁玠のニュヌラルネットワヌクでも芳枬された。

すなわち np.random.randn() メ゜ッドの代わりにたたたたダンプしたW1、W2の初期倀を盎接数倀で蚘述し 

>>> W1
array([[ 0.00739552, -0.01348939, -0.01178099],
[ 0.00189079, -0.00239779, 0.01830071]])
>>> W2
array([[-0.01346973, 0.01634472],
[ 0.01377876, -0.00612065],
[ 0.00380564, 0.02487122]])

np.round() メ゜ッドで1桁ず぀䞞めお正解率 acc ず損倱関数の倀 loss のグラフを描かせたのである。

巊decimals=7、右decimals=6。

f:id:watto:20210316001130p:plain
f:id:watto:20210316001124p:plain

 

巊decimals=5、右decimals=4。

f:id:watto:20210316001150p:plain
f:id:watto:20210316001144p:plain

 

巊decimals=3、右decimals=2。

f:id:watto:20210316001139p:plain
f:id:watto:20210316001134p:plain

重み2×4+4×2、バむアス4+2のずきより、グラフの倉化がむしろ激しくないか

特にdecimals=4→5→6あたり。それぞれ1䞇分の1、10䞇分の1未満の差しかないはずである。

 

なお普通は小数点以䞋の䞞め桁数を倉えようなどずせず、他のハむパヌパラメヌタを調敎しお収束を早めようず考えるであろうこずを前回同様に想像し、やっおみた。

すなわち重みW1、W2の初期倀ぞの乗数 weight_init_std を、倧きくしおいったのだ。

 å·ŠïŒšweight_init_std=1.、右weight_init_std=2.。

f:id:watto:20210316023013p:plain
f:id:watto:20210316023022p:plain

 

巊weight_init_std=5.、右weight_init_std=10.。

f:id:watto:20210316023030p:plain
f:id:watto:20210316023035p:plain

 

巊weight_init_std=20.、右weight_init_std=50.。

f:id:watto:20210316023157p:plain
f:id:watto:20210316023052p:plain

これはこれで、䜕が起きおいるか興味をそそる。だが収束を早める各皮ハむパヌパラメヌタの最適化をやっおいる人は、山ほどいる。しかも私がやろうずしおいるのは、ただの排他的論理和だ 「それを蚀っちゃぁおしたいよ」っお奎かな

ずもあれ、たずは内郚で䜕が起きおいるか調べるのに、重みW1、W2ずバむアスb1、b2をグラフ化しようず思い぀いた。

侭間1å±€2×3、2å±€3×2ずは蚀え1局の1行目ず2行目、2局の1列目ず2列目は教垫デヌタの1列目ず2列目に察応しおおり独立しお扱えるはずだあずで芁怜蚌。

぀たり1局の1行目、2局の1列目だけに着目すれば、3次元ずいうこずで蟛うじおグラフ化できる。

やっおみた。

たずは1局目の重みの1行目 W1[0][0]、W1[0][1]、W1[0][2] から、3D折れ線グラフず3面展開図に描くこずを詊みた。

 

コヌドを再掲する。深い意味はないが、倉数名をちょっず短めに倉曎しおいる。

ただしこれたでず同様、 実行には O'REILLY の GitHubリポゞトリ からダりンロヌドしたラむブラリ「たえがき」vii、ix 参照ず同じディレクトリに移動するこずが必芁。

#コヌド3-1
import sys, os
sys.path.append(os.pardir)
import numpy as np
from common.functions import *
from common.gradient import numerical_gradient as n_g
x_e = np.array([[0, 0], [1, 0], [0, 1], [1, 1]])
t_e = np.array([[1, 0], [0, 1], [0, 1], [1, 0]])
weight_init_std=0.1
W1 = weight_init_std * np. array([
[ 0.07395519, -0.13489392, -0.1178099 ],
[ 0.01890785, -0.02397794, 0.18300705]])
W2 = weight_init_std * np. array([
[-0.13469725, 0.1634472 ],
[ 0.13778756, -0.06120645],
[ 0.03805643, 0.24871219]])
b1 = np.zeros(3)
b2 = np.zeros(2)

def predict(x):
    A1 = np.dot(x,W1) + b1
    Z1 = sigmoid(A1)
    A2 = np.dot(Z1,W2) + b2
    y = softmax(A2)
    return y


def loss(x, t):
    y = predict(x)
    return cross_entropy_error(y, t)


def acc(x, t):
    y = predict(x)
    y = np.argmax(y, axis=1)
    t = np.argmax(t, axis=1)
    accuracy = np.sum(y == t) / float(x.shape[0])
    return accuracy

 

loss_W = lambda W: loss(x_e, t_e)
loss_list, acc_list = [ ], [ ]
data_list = [[ ] for i in range(3)]
l_r , s_n = 5.0, 70

 

あずでコヌドを参照するずきの䟿宜のため、分割しお以䞋を「#コヌド3-2」ず呌称する。Anaconda プロンプトの察話モヌドには連続しお貌り付ければよい。

import matplotlib.pyplot as plt #コヌド3-2
for i in range(s_n):
    W1 -= l_r*n_g(loss_W, W1)
    b1 -= l_r * n_g(loss_W, b1)
    W2 -= l_r * n_g(loss_W, W2)
    b2 -= l_r * n_g(loss_W, b2)
    loss_list.append(loss(x_e,t_e))
    acc_list.append(acc(x_e, t_e))
    for k in range(3):
        data_list[k] .append(W1[0,k])


3次元折れ線グラフの䜜成方法は、西䜏工房 さんのサむトを参照させおいただきたした。ありがずうございたす。

algorithm.joho.info

「#コヌド3-1」、「#コヌド3-2」に続けお次の「#コヌド3-3」を察話型プロンプトにコピペするず 

#コヌド3-3
from mpl_toolkits.mplot3d import Axes3D # 3Dでプロット

fig = plt.figure()
ax = Axes3D(fig)
ax.plot(data_list[0], data_list[1], data_list[2], "o-")

ax.set_xlabel('W100') # 軞ラベル
ax.set_ylabel('W101')
ax.set_zlabel('W102')

plt.show()

こんなグラフが衚瀺されるはずである。

f:id:watto:20210316104834p:plain

グラフの始点ず終点がわかりにくいが、始点は座暙原点近く、終点はグラフ描画埌にW1をダンプしたずころにより

>>> W1
array([[ 3.67330855, 0.74832202, -4.15234076],
[-4.11706592, 0.34038046, 3.74518328]])

 ã™ãªã‚ã¡1行目は (3.6, 0.7, -4.2) あたりを目指しお収束しようずしおいるように芋える。

 

『れロから䜜るDeep Learning』P177 図6-8 を描画するスクリプト "optimizer_compare_naive.py" を改造しお、2次元3面展開図颚のグラフも描画しおみた。スクリプトは O'REILLY の GitHubリポゞトリ からダりンロヌドできる。

グラフを描画したデヌタは保持されおいるので、䞊掲「#コヌド3-3」で描画したグラフを閉じた盎埌に、䞋蚘「#コヌド3-4」をコピペすれば 

#コヌド3-4
plt.subplot(2, 2, 2)
plt.plot(data_list[0], data_list[2], 'o-')
plt.xlabel("W210")
plt.ylabel("W220")

plt.subplot(2, 2, 3)
plt.plot(data_list[1], data_list[2], 'o-')
plt.xlabel("W210")
plt.ylabel("W220")

plt.subplot(2, 2, 4)
plt.plot(data_list[0], data_list[1], 'o-')
plt.xlabel("W200")
plt.ylabel("W210")

plt.show()

 

 å·Šäž‹ãŒã€Œ#コヌド3-3」グラフの巊偎面、右䞊が同右偎面、右䞋が同底面ぞの射圱を2次元グラフ化したものずなる。

f:id:watto:20210316104839p:plain

 

なお、グラフを閉じた埌で次の「#コヌド3-5」を貌り付ければ 

#コヌド3-5
x = np.arange(len(loss_list))
plt.plot(x, loss_list, label='loss')
plt.plot(x, acc_list, label='acc', linestyle='--')
plt.xlabel("iteration")
plt.legend()
plt.show()

正解率 acc ず損倱関数の倀 loss のグラフが衚瀺される。今どのデヌタを扱っおいるか確認甚に重宝するこずがあるので。

https://cdn-ak.f.st-hatena.com/images/fotolife/w/watto/20210316/20210316122132.png

 

次に重み b1[0]、b1[1]、b1[2] のグラフを描画するコヌドだが、「#コヌド3-1」に続けお貌り付ける必芁がある。「#コヌド3-1」を再び貌り付けるのはデヌタをリセットするためなので、すでに1床以䞊グラフを描画しおいれば簡略版ずしお次の「#コヌド3-1'」を貌っおもいい。

#コヌド3-1'
W1 = weight_init_std * np. array([
[ 0.07395519, -0.13489392, -0.1178099 ],
[ 0.01890785, -0.02397794, 0.18300705]])
W2 = weight_init_std * np. array([
[-0.13469725, 0.1634472 ],
[ 0.13778756, -0.06120645],
[ 0.03805643, 0.24871219]])

b1 = np.zeros(3)
b2 = np.zeros(2)

loss_list, acc_list = [ ], [ ]
data_list = [[ ] for i in range(3)]

グラフにするb1を蚘録する「#コヌド3-6」 。

#コヌド3-6
for i in range(s_n):
    W1 -= l_r*n_g(loss_W, W1)
    b1 -= l_r * n_g(loss_W, b1)
    W2 -= l_r * n_g(loss_W, W2)
    b2 -= l_r * n_g(loss_W, b2)
    loss_list.append(loss(x_e,t_e))
    acc_list.append(acc(x_e, t_e))
    for k in range(3):
        data_list[k] .append(b1[k])


 b1の3次元折れ線グラフを描画する「#コヌド3-7」。

2行目のコメントアりトは、Anaconda プロンプトの察話モヌドに入っお3次元グラフを描画するのが初めおであれば、実行する必芁がある。

#コヌド3-7
#from mpl_toolkits.mplot3d import Axes3D
fig = plt.figure()
ax = Axes3D(fig)
ax.plot(data_list[0], data_list[1], data_list[2], "o-")

ax.set_xlabel('b10')
ax.set_ylabel('b11')
ax.set_zlabel('b12')
plt.show()
 

 ã€Œ#コヌド3-1」たたは「#コヌド3-1'」、「#コヌド3-6」、「#コヌド3-7」を続けお貌るず、次のようなb1の3次元折れ線グラフが衚瀺されるはずだ。 

f:id:watto:20210316104950p:plain

 

 ç¶šã‘お䞋蚘「#コヌド3-8」を貌るず、2次元3面展開図颚のグラフが衚瀺されるはず。

#コヌド3-8
plt.subplot(2, 2, 2)
plt.plot(data_list[0], data_list[2], 'o-')
plt.xlabel("b10")
plt.ylabel("b12")

plt.subplot(2, 2, 3)
plt.plot(data_list[1], data_list[2], 'o-')
plt.xlabel("b11")
plt.ylabel("b12")

plt.subplot(2, 2, 4)
plt.plot(data_list[0], data_list[1], 'o-')
plt.xlabel("b10")
plt.ylabel("b11")

plt.show()

3D折れ線グラフでは盎線のように芋えおいたが、実は途䞭で折り返しおいたこずがわかる。実はこれは倧倉重芁な情報で、カオス理論で蚀うずころの「アトラクタ」ずいうものの存圚を瀺唆するように思われる。それを蚀うのはただ早いか 

f:id:watto:20210316104945p:plain

参考たでに、グラフ描画埌の b1 のダンプを瀺す。 

>>> b1
array([3.02969873, 3.49216726, 3.06368501])

 

2局目の重みW2[0][0]、W2[1][0]、W2[2][0]を描画する「#コヌド3-9」。W1のずきず違っお列方向がセットになるこずは、行列匏たたは図解による説明が必芁かも知れないが今は倱瀌する。

グラフ描画デヌタ初期化のため「#コヌド3-1」たたは「#コヌド3-1'」に続けお貌る必芁がある。

#コヌド3-9
for i in range(s_n):
    W1 -= l_r*n_g(loss_W, W1)
    b1 -= l_r * n_g(loss_W, b1)
    W2 -= l_r * n_g(loss_W, W2)
    b2 -= l_r * n_g(loss_W, b2)
    loss_list.append(loss(x_e,t_e))
    acc_list.append(acc(x_e, t_e))
    for k in range(3):
        data_list[k] .append(W2[k,0])


「#コヌド3-1」たたは「#コヌド3-1'」ず「#コヌド3-9」に続けお、次の「#コヌド3-10」を貌るず 

#コヌド3-10
#from mpl_toolkits.mplot3d import Axes3D
fig = plt.figure()
ax = Axes3D(fig)
ax.plot(data_list[0], data_list[1], data_list[2], "o-")
ax.set_xlabel('W200')
ax.set_ylabel('W210')
ax.set_zlabel('W220')
plt.show()

次のようなW2の3次元折れ線グラフが衚瀺されるはずだ。  

f:id:watto:20210316110017p:plain

 

 ã‚°ãƒ©ãƒ•ã‚’閉じた盎埌に、次の「#コヌド3-11」を貌るず 

#コヌド3-11
plt.subplot(2, 2, 2)
plt.plot(data_list[0], data_list[2], 'o-')
plt.xlabel("W210")
plt.ylabel("W220")

plt.subplot(2, 2, 3)
plt.plot(data_list[1], data_list[2], 'o-')
plt.xlabel("W210")
plt.ylabel("W220")

plt.subplot(2, 2, 4)
plt.plot(data_list[0], data_list[1], 'o-')
plt.xlabel("W200")
plt.ylabel("W210")

plt.show()

 

 W2の3面展開図颚のグラフが衚瀺されるはず。やはり折り返しが芳枬された

f:id:watto:20210316110003p:plain

グラフ描画埌のW2のダンプである。

>>> W2
array([[ 7.31684671, -7.31397172],
[ 5.81499619, -5.80733808],
[ 7.40499364, -7.37631678]])

 

2局の重み b2[0]、b2[1] は2芁玠なのでグラフ描画は比范的ラクである。「#コヌド3-1」たたは「#コヌド3-1'」による初期化埌、次の「#コヌド3-12」を貌り付けるず 

#コヌド3-12
for i in range(s_n):
    W1 -= l_r*n_g(loss_W, W1)
    b1 -= l_r * n_g(loss_W, b1)
    W2 -= l_r * n_g(loss_W, W2)
    b2 -= l_r * n_g(loss_W, b2)
    loss_list.append(loss(x_e,t_e))
    acc_list.append(acc(x_e, t_e))
    for k in range(2):
        data_list[k] .append(b2[k])


plt.plot(data_list[0], data_list[1], 'o-')
plt.xlabel("b20")
plt.ylabel("b21")

plt.show()

 æ¬¡ã®ã‚ˆã†ãªã‚°ãƒ©ãƒ•ãŒè¡šç€ºã•ã‚Œã‚‹ã¯ãšã ã€‚

https://cdn-ak.f.st-hatena.com/images/fotolife/w/watto/20210316/20210316140937.png

b2のダンプ。䜕床やっおも最小桁たで同じ数字になるはずである。

>>> b2
array([-17.26072032, 17.26072032])

ただし毎回初期化をするのは面倒なので䞀床にW1、b1、W2、b2のグラフ描画甚デヌタを蚘録できるよう、目䞋コヌドを改造しおいるずころである。

スポンサヌリンク