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

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

O'REILLY『れロから䜜るDeep Learning』4章のクラスを䜿ったら4セグメントLEDどころか7セグメントLEDの機械孊習ができたその1

 

前回の蚘事から1ヶ月以䞊経っおしたった。『れロから䜜るDeep Learning ―Pythonで孊ぶディヌプラヌニングの理論ず実装』ずいう本を読んでいる。3章でずおも難易床の高いず感じるカベにぶち圓たったので、自分自身の理解の床合いを確認するために、難易床の䜎い緎習問題を䜜っお解いおみたずいう内容の゚ントリヌだ。

watto.hatenablog.com

䞊掲曞3章には、「ニュヌラルネットワヌク」すなわち行列積ずいく぀かの関数の組み合わせを甚いお、MNISTデヌタセットすなわち手曞き数字のテストデヌタを認識させる方法に぀いお説明がある。それが初読時にはずおも難しく感じられたので、ごく簡単な䟋ずしお「4セグメントLED」ずいうのを考えおみたのだ。それをテキストP8486でいうずころの「機械孊習」ではない「人の考えたアルゎリズム」で、認識させるこずはできた。

では、それを「機械孊習」によっお実珟できるかが、自分自身に䞎えた次なる課題であった。

結論を先に曞くず、実珟できた。しかも驚くべきこずに、4ç« P113以降に掲げられた「2局ニュヌラルネットワヌクのクラス」に察し、適切ず思われるデヌタおよび匕数䞊掲曞で蚀うずころの「ハむパヌパラメヌタ」を䞎えるだけで、実珟できおしたった

さらに驚くべきこずに、4セグメントどころか、珟実に䜿甚されおいる7セグメントLEDに察しおも、同じクラスを甚いた機械孊習による認識が実珟できおしたった

そのこずを説明するため、䜕回かにわたる゚ントリヌを起こす。察象読者は『れロから䜜るDeep Learning』以䞋テキストず衚蚘する読者限定なので、い぀ものように遠慮しお、新着゚ントリヌから目立ちにくくするため日付をさかのがっお公開する。

スポンサヌリンク

 

 

テキスト4章では、募配法による2倉数の関数の最小倀の探玢が説明されるP109たで。それに続いお2次元6倉数のニュヌラルネットワヌクに察しお募配を蚈算する䟋が瀺されるP110112。このニュヌラルネットワヌクは、単なる数倀䟋に過ぎず、䜕か具䜓的なモデルがあるわけではない。

さらに続いお、2局ニュヌラルネットワヌクのクラスが瀺され、このテキストの栞心郚ずも蚀うべきMNISTデヌタセットに察するミニバッチ孊習の実装の説明が始たるのであるP117。ここでたた、断厖絶壁ずもいうべき難易床の倉化を感じた。「たた」ず曞いたのは、3章でも感じた感芚に䌌おいたからだ。

そこで今回もたた、自分でごく簡単な䟋題を䜜っお解いおみようず考えた。断厖絶壁にハシゎをかけるような぀もりである。

しかし、前回やった4セグメントLEDでも難易床高いず感じた。そこで2章たでさかのがっお、パヌセプトロンの実装を機械孊習でやらせられないかず考えた。パヌセプトロンずは、おおざっぱに蚀うず「重み」ず「バむアス」による論理回路の実珟である。

テキストP110には、2行×3列の「重みパラメヌタ」のみを有するニュヌラルネットワヌクに察しお募配を求めるクラス "simpleNet" ずしお、次のようなコヌドが瀺されおいる。

import sys, os
sys.path.append(os.pardir)
import numpy as np
from common.functions import softmax, cross_entropy_error
from common.gradient import numerical_gradient
class simpleNet:
    def __init__(self):

        self.W = np.random.randn(2,3) # ガりス分垃で初期化
    def predict(self, x):

        return np.dot(x, self.W)
    def loss(self, x, t):
        z = self.predict(x)
        y = softmax(z)
        loss = cross_entropy_error(y, t)
        return loss

Windowsコマンドプロンプトのpython察話モヌドにコピヌペヌストできるよう、䞀郚改行を削陀しおいたす

このコヌドを実行するこずにより、テキストP111に瀺されるような「重みパラメヌタ」「最倧倀のむンデックス」「損倱関数の倀」を蚈算するこずができるが、前述のずおりこれらの倀には特段の意味があるわけではない。

そこで「重みパラメヌタ」を2行×3列から1行3列に倉曎し、倉数名ずしおはちょっず倉だが、W[0]ずW[1]を改めお「重み」、W[2]を「バむアス」ずするこずにより、2章パヌセプトロンを機械孊習できないかず考えたのだ。

少なからぬ苊劎をしたが、できた。結果のコヌドを瀺す。クラス名 "Perceptrn" ずしおみた。メ゜ッド "predict" は掚定倀を求める関数で、この倀が正なら "1"、負なら "0"。"loss" は掚定倀にシグモむド関数テキストP45、48を噛たせた䞊で、正解ずの二乗誀差により損倱を蚈算する関数である。

import sys, os
sys.path.append(os.pardir)
import numpy as np
from common.functions import sigmoid
from common.gradient import numerical_gradient

class Perceptrn:
    def __init__(self):
        self.W = np.random.randn(3)
    def predict(self, x):
        return x[0]* self.W[0]+ x[1] *self.W[1] + self.W[2]
    def loss(self, x, t):
        z1= sigmoid(self.predict(x))
        y = (z1-t)**2
        return y

テキストP110のクラス "simpleNet" が実行できる環境であれば、実行させられるはずである。

Windows の Anaconda Prompt で実行させたずころ、ガりス分垃で初期化した重みWの初期倀は、こうだった。

f:id:watto:20170629144414p:plain

掚定倀を芋やすくするためステップ関数テキストP45をむンポヌトする。

孊習率 "learning_rate" は 1.0 ずしおみた。

from common.functions import step_function

pct = Perceptrn()

f = lambda w: pct.loss(x, t)
learning_rate = 1.0 

python に䞍慣れなので、for文をこんなふうに蚘述するのが適切かどうかは、わからない。真理倀衚みたいに芋えないかずいう工倫の぀もりである。

for (x, t) in [\
(np.array([0, 0]), 0),(np.array([0, 1]), 0),(np.array([1, 0]), 0),(np.array([1, 1]), 1)]:
    print("p = " + str(pct.predict(x)) + " : " + str(step_function(pct.predict(x))))
    print(“l = " + str(pct.loss(x,t)))
    dW = numerical_gradient(f,pct.W)
    print("dW = " + str(dW))
    pct.W -= learning_rate * dW
    print("W = " + str(pct.W))

これを [Ctrl]+[v] で Anaconda Prompt に連続しお貌り付けた。

貌り付け1回目の結果。 "p" は掚定倀で正なら "1"、負なら "0"。ちょっずは芋やすくならないかなず、ステップ関数による "1"/"0"ぞの倉換を付け加えおみた。"l" は損倱、"dW" は損倱に募配法を適甚しお求めた重みの倉化、"W" は重みである。

圓然ながら真理倀衚はメチャクチャである。

f:id:watto:20170629202912p:plain

2回目の結果。損倱 "l" が枛っおいるこずが確認できる。いや、局所的には増える堎合もあるのか。重み "W" の埮調敎を繰り返すたびに、トヌタルでは枛少するはずである。

f:id:watto:20170629202908p:plain

18回目の貌り付け結果。぀いに正しい真理倀衚が埗られた 䜕床も詊したずころ、だいたい20回目くらいたでには正しい結果が埗られるようだ。

f:id:watto:20170629202905p:plain

W[0]、W[1]、W[2] の比は 111.51 くらいの倀に収束する。これがパヌセプトロンによるANDゲヌトの、機械孊習によっお求められた重みずバむアスず蚀えよう。

もちろん繰り返しペヌストする必芁はなく、for文を2重化するこずにより、䜕床でも繰り返すこずができる。ただペヌストするたびに倀が倉化するのが、芋おいお面癜かったのだ。

この面癜さ加枛をなんずか他人に䌝えられないかず、グラフを描いおみたりgifアニメ化しようずしたりしたが、どうもむマむチである。やはり自分でスクリプトを動䜜させるにしくはないようだ。

グラフだけ貌っおみようかな。䞊偎の青い実線が W[0]、䞋偎の緑の点線が W[2] である。暪軞は繰り返し回数だ。

f:id:watto:20170629213638p:plain

なお圓然ながら、for 文の繰り返し条件を

(np.array([0, 0]), 0),(np.array([0, 1]), 0),(np.array([1, 0]), 0),(np.array([1, 1]), 1)]:

から

(np.array([0, 0]), 0),(np.array([0, 1]), 1),(np.array([1, 0]), 1),(np.array([1, 1]), 1)]:

に倉えるずORゲヌトを実珟する重みずバむアスが、たた

(np.array([0, 0]), 1),(np.array([0, 1]), 1),(np.array([1, 0]), 1),(np.array([1, 1]), 0)]:

に倉えるずNANDゲヌトを実珟する重みずバむアスが埗られた。OR の堎合、W[0]、W[1]、W[2] の比は 110.47 くらいに収束した。たた NAND の堎合は、比は AND ず同じくらいだったが W[0]、W[1] 、W[2] の笊号が反転した。

                 

この結果に勇気を埗お、5月21日の゚ントリヌで自分自身に䞎えた宿題、すなわち機械孊習による「4セグメントLED」の認識にチャレンゞした。

この項぀づく。 

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

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

Â