強まっていこう

あっちゃこっちゃへ強まっていくためのブログです。

ディープラーニングは難しすぎ、とほっぽり出したプログラマへの助け舟

ディープラーニング、気軽な気持ちで調べてみるも「なんじゃこりゃ!」と撤退。ありますよね。

何がニューロンだ、何がシナプスだ、何がニューラルネットワークだ!うざいんじゃボケェ!!

こっちはなぁ、脳みその仕組みを知りたいわけじゃねぇんだよハゲが!!と思うでしょ?

そもそもね、インターネッツなウェッブサイツを作ろうとしているのに、さぁどうやってネットワークカードが通信しているか、その理論からお教えしましょう! なんてことを言っているのと同レベルのドキュメントばかりでうんざりなんですわ。

変な数式なんてこっちは知ったこっちゃ無い。道具の成り立ちなんて知るかよと。その使い方だけ教えろこのポンスケが、ときたもんです。

こんなの読んでね、プログラマに理解しろっつー方が無理ですよ。そんなに暇じゃないんでイラッイラします。

パーセプトロンだかパンシロンだか、デストロンだか知りませんが、変な丸と線を書いてキャッキャ喜んでんじゃねぇよ、と。何故に猫も杓子もすでにどこそこにあるようなものと同じものを書くんでしょう。自分が書いたらもっとわかりやすい絵になるとでも思ってんですかね。

なので、今回はプログラマ視点でこいつの倒し方のコツを伝えます。突破口を開くきっかけになれば、と思いますね。プログラマはね、コードが真っ先に来ないと理解出来ないもんなんですわ。

と言うわけで、はいコード。

#!/usr/bin/env python

import numpy as np

class NeuralNetwork():

  def __init__(self, inSize, outSize, hidSize):
    self.w1 = np.random.randn(inSize, hidSize)
    self.w2 = np.random.randn(hidSize, outSize)

  def forward(self, x):
    self.z = np.dot(x, self.w1)
    self.z2 = self.sigmoid(self.z)
    self.z3 = np.dot(self.z2, self.w2)
    return self.sigmoid(self.z3)

  def sigmoid(self, x): return 1 / (1 + np.exp(-x))

if __name__ == '__main__':
  sample = np.array(([ 0, 0 ], [ 0, 1 ], [ 1, 0 ], [ 1, 1 ]))
  sampleResult = np.array(([ 0 ], [ 1 ], [ 1 ], [ 1 ]))

  nn = NeuralNetwork(2, 1, 3)

  print("Prediction: \n" + str(nn.forward(sample)))
  print("Correct: \n" + str(sampleResult))


これは AND 回路をディープラーニングで作ろうとしています。まだ学習のロジックは入れていません。

と言うかそんなバカバカしいもんをわざわざディープラーニングで作るなよと思うかもしれませんが、結果が正しいのかどうかがわからない代物を作っても分かりづらいので。

どこぞのチュートリアルではいきなり画像の数字認識から始まりますが、あんなのややこしすぎます。最初はやはりシンプルなものから入るべきなんですよ。

コードの具体的な説明の前に、ディープラーニングについて雑に説明します。

「どんな天候の時、どんな色の服を着ていけばパチスロに勝てるかな?予測オカルトマシーン」みたいなものを作ろうと思い立ったとします。

それには何かしらの予測ロジックを組まなきゃいけません。

真っ先にやることと言えば、実際にスロを打った際の天候と服の色データと勝敗をエクセルに記録し続ける事でしょうか。

そのエクセルデータがある程度溜まったところで、天候と服の色で勝負率を計算し、それを反映したロジックを組むと。そのロジックからはじき出された予測に基づきスロットを打って、勝負けデータをさらに更新したりして。

そうこうしているうちに人間もっと欲が出て勝率を上げたくなってきます。降水確率、途中で赤信号を食らった数、かわいいおねーちゃんを見かけた回数なども入れて行きたいなぁ、と。

そうすると、どんどんロジックが複雑化します。どの数値とどの数値が勝利に貢献しているのか、その重み付けなんか考え始めると地獄の扉が開きます。

その赤扉(通常時は激弱)を全力で締め、めんどっちぃロジック作成を自動でやってしまおうってのがディープラーニングなわけです。

天候、色、降水確率、信号、ねーちゃん、これらの入力データと勝ち負けの結果データ、こいつらをブンブン回してると勝手にロジックが組み上がり、オカルト予測回路が出来るんですねぇ。楽でしょう。

楽なはずなんですが、世の説明見るとただひたすらに面倒くさい。微積とか覚えてねーんだよ!!数学出来んでなんがわるいとや!!と家出をすることになります。

ようやくさっきのコードの説明に戻ります。

numpy とかググレカスなので説明しません。

sample がエクセルデータみたいなもんです。sampleResult が勝敗データ。この例だと sample は AND 回路に投げ込む値で、sampleResult はその結果ですわ。

NeuralNetwork が予測マシーンです。こりゃ教育していないので、Prediction(予測)とCorrect(正解)が随分ズレます。

教育って具体的に何かと言うと、self.w1、self.w2 の値を最適化していくことなんですな。こいつらは重みになります。最初はランダムな値を突っ込んでます。

forward ってのがロジックですわ。dot ってのをまず呼んでますが、こいつは内積です。大雑把に言うと2つの配列をごにょごにょして合体させるやつです。

print(np.dot([ [ 1, 1 ], [ 2, 2 ] ], [ [ 3, 3 ], [ 4, 4 ] ]))

[[ 7, 7] [14, 14]]

になります。配列が一つにまとまって何やら数字がデカくなってるのがわかると思います。

この dot の結果と重みを渡して、sigmoid ってのを呼んでます。こいつは値が大きければ 1 に 小さければ 0 に、0 は 0.5 するだけのやつです。

通称活性化関数という良くわからなすぎる名前がついているやつらの一種なんですが、こいつらの仕事はデカくなり続けてしまう数字をちっこく抑えつけることです。

この sigmoid の結果と、重みを内積してまた sigmoid してます。この重みを実際の結果と照らし合わせながら正解に近づくように調整していくことを学習とか呼びやがるわけです。

何より大事なのって forward の組み方だったりします。この組み方が正解ってのは無いです。シンセサイザーとかDTM、ギターやってる人ならわかるかもしれませんが、いろんなエフェクターかまして波形を変えて音色を変えるみたいな。そんなイメージです。エフェクターが活性化関数ですね。実際こいつらってモノによっていろんな波形出すんで。

NeuralNetwork のコンストラクタに渡している、2 と 1 は、入力データと結果データの配列の要素数なんですが、3 つめは、中間で計算する際の要素数なんですが、少ないと結果が悪くなり、多いと計算が遅くなる、的なやつです。この数値の調整も一つの肝だったりします。

とにかくディープラーニングの肝は、数値調整と処理の間にかませていく関数の調整だと思っといてください。

どうです?いたるところでガチャガチャ説明されていることと比べて実際のコードは随分と単純じゃありませんか?世のドキュメント分かりづらすぎるんですわ、マジで。簡単なことを難しく書くなやと。

次回は実際この回路を正解を叩き出すものに近づけるディープラーニングな作業に移っていきたいと思うとります。