N高校生python備忘録

N高校生python備忘録

python始めたけど一向に勉強しないのでいい加減やります

ゼロから作るDeep Learning 3章 雑感

前回のまとめ
2章ではパーセプトロンと呼ばれるアルゴリズムについて確認、実装し、さらにはパーセプトロン同士を繋げることによって単純な直線だけでなく非線形を描けることを確認しました
ここから難しくなっていきます(当社比)

ニューラルネットワーク

ニューラルネットワーク(神経回路網、英: neural network、略称: NN)は、脳機能に見られるいくつかの特性を計算機上のシミュレーションによって表現することを目指した数学モデルである。研究の源流は生体の脳のモデル化であるが、神経科学の知見の改定などにより次第に脳モデルとは乖離が著しくなり、生物学や神経科学との区別のため、人工ニューラルネットワーク(artificial neural network、ANN)とも呼ばれる。ニューラルネットワーク - Wikipedia

f:id:python_nnn:20180905154507j:plain:w300:right ニューラルネットワークは、文字通り生物の脳にあるニューロンを模して作られたものです
ニューラルネットワークパーセプトロンを複数繋げたような形をしており、一番左を入力層、一番右を出力層、そして間に挟まれているすべてのニューロンを中間層(隠れ層)と呼びます
一見するとニューラルネットワークパーセプトロンをつなげただけのようですね

活性化関数の導入

前章パーセプトロンにおいて0以下であれば0を、0より大きければ1を出力するようyが定義されていたが、それを一個の関数として扱うと次のような式となる

y=h(b + w1x1 + w2x2)

このhは仮説のH(hypothesis)
ここで登場したような、入力信号の総和を出力信号に変換する関数(h)を活性化関数と呼ぶ

なぜ活性化関数を導入するか:結局のところ、活性化関数を導入していないニューロン同士がやっていることは乗算や加算の単純な四則演算であり、それではいくらニューロンを積み重ねても排出されるのはただの回帰直線であって、非線形を表現できません

ということで有名な活性化関数、シグモイド関数を導入する

\displaystyle h(x)=\frac{1}{1+exp(-x)}

えっなにこれは…expってなに? ネイピア数 - Wikipedia

logとか対数は高校三年生までお預けなので今は無視する

このシグモイド関数ニューラルネットワーク内でどのような働きをしてくれるのか、今まで使っていた活性化関数と比べて理解する

前章パーセプトロンで使われていたような、ある値を境目に0か1の出力が決まる関数をステップ関数と呼ぶ

def step_function(x):
    if x > 0:
        return 1
    else:
        return 0

#今後のためにNumPyにも対応させる
def step_function(x):
    y = x > 0
    return y.astype(np.int)

NumPy配列に不等号の演算を行うと、各要素に対して不等号演算が行われる 今回の婆であれば0以下がFalse、0より大きい数がTrueに 我々が欲しいのは0か1かのint型なのでastype(np.int)でTrueが1、Falseが0へと変換され返される

続いてステップ関数のグラフ

def step_function(x):
    return np.array(x > 0, dtype=np.int)

X = np.arange(-5.0, 5.0, 0.1)
Y = step_function(X)
plt.plot(X, Y)
plt.ylim(-0.1, 1.1)  # 図で描画するy軸の範囲を指定
plt.show()

ここでmatplotlib登場 見ての通りでっかいビルか、はたまた階段のよう

続いてシグモイド関数の実装

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

ステップ関数とシグモイド関数ではなだらかさが違いますね ステップ関数は1か0かしか返さないのに対し、シグモイド関数では0.2232…などのような実数を返します
つまり表現の幅が広い、ということですね また、どのような値が入力されても0〜1以内で返してくれるので確率とも解釈できるようです

シグモイド関数は昔から使われてきた関数ですが、最近だとReLU(Rectified Liner Unit)関数がよく用いいられるそう

def relu(x):
    return np.maximum(0, x)

maximumは値の中から最大値を返すので、0未満であれば0が、0以上であればそのままの数値で出力される

行列計算については略します とりあえずスカラーとの計算や内積、行列同士の計算や単位行列などのポイントを軽く抑えて置けばいいと思います

ニューラルネットワークの行列の積

f:id:python_nnn:20180905160831j:plain:w230:right ニューラルネットワークではxに入力された信号をwの値と掛け合わせてそれをyへと出力するが、複数の層がある場合かなりめんどくさい(具体的にはforループ)
が、xとwをそれぞれ行列として一個のデータの塊のように扱えばとても簡単に計算できる それを確かめるためにもNumPyで簡単なニューラルネットワークを実装する

def init_network():
    network = {}
    network['W1'] = np.array([[0.1, 0.3, 0.5], [0.2, 0.4, 0.6]])
    network['b1'] = np.array([0.1, 0.2, 0.3])
    network['W2'] = np.array([[0.1, 0.4], [0.2, 0.5], [0.3, 0.6]])
    network['b2'] = np.array([0.1, 0.2])
    network['W3'] = np.array([[0.1, 0.3], [0.2, 0.4]])
    network['b3'] = np.array([0.1, 0.2])
    return network

def forward(network, x):
    W1, W2, W3 = network['W1'], network['W2'], network['W3']
    b1, b2, b3 = network['b1'], network['b2'], network['b3']
    a1 = np.dot(x, W1) + b1
    z1 = sigmoid(a1)
    a2 = np.dot(z1, W2) + b2
    z2 = sigmoid(a2)
    a3 = np.dot(z2, W3) + b3
    y = identity_function(a3)    
    return y

network = init_network()
x = np.array([1.0, 0.5])
y = forward(network, x)
print(y) # [ 0.31682708 0.69627909 ]

さて確認をします
 W1は2×3、W2は3×2、W3は2×2次元の行列 b1は1×3、b2、b3は1×2次元の行列である 入力であるxは1×2次元
次元数の確認 x[1, 2] * W1[2, 3] = a1[1, 3] (バイアスの次元数とも一致) z1[1, 3] * W2[3, 2] = a2[1, 2] z2[1, 2] * W3[2, 2] = a3[1, 2] 答えと次元数は一致する
コードに書かれていることはまだ私でも理解できるので省略

ソフトマックス関数

機械学習の問題は大別して二つ、「分類問題」と「回帰問題」である 前者は類似傾向から画像等を分類する、後者は金額予想などの連続値に関する予測だが、結局のところ両者とも線形を描いていることになるので、どちらもニューラルネットで扱うことができる ただどちらの問題を扱うかによって微妙な違いがあるようで、出力層においては回帰問題に恒等関数を、分類問題にはソフトマックス関数が使われる

恒等関数は入力された値をそのまま出力する関数、上記のコードでの identity_function に相当する なので特に説明なし

一方でソフトマックス関数は次のような式で表される

yk=\displaystyle \frac{exp(ak)}{\sum_{i=1}^{n}exp(ai)}

またexpend、今度はシグマ
出力層が全部でn個あるとして、k番目の出力ykを求める計算式らしい
図にするとこう→

f:id:python_nnn:20180905161102j:plain:h200:right んにゃぴ……よくわからないですね

とりあえず実装

def softmax(a):
    exp_a = np.exp(a)
    sum_exp_a = np.sum(exp_a)
    y = exp_a / sum_exp_a
    return y

あー、一度シグマで合計を出した上でそれを分母にしているから、層aのk番目が層a全体から見てどれほどの大きさなのか(占める割合の多さ、つまりは重要度?)を指数関数を使って出している……?
よく分かんないっす
他サイトを巡っても微妙でわからなかったのだが、重要なのは一つ これが確率を表しているということ
なるほど、だから分類問題に適しているのですね

初級者向けMNISTデータのインポートの解説

三章では、このあとMNISTデータセットと呼ばれる画像認識の実験においてよく使われるデータセットを使って、手書き文字認識をおこなっていくのですが省略します

ただこのデータのインポートが私のような初級者にはかなり大変でして、またあまりにも初歩的な問題であることからか、グーグルで調べて上位に出てくるようなブログだと記述も非常に少ない
私はこれを解決するのに一晩かかりましたので、今後私みたいな人(多分出ないしこの記事にたどり着かないと思うけど!)を出さないために電子の藻屑に流しときます といっても苦労して解決した割には作業はめちゃ楽です

まずデータのインポートのためにGitHubからダウンロードしたファイルをカレントディレクトリに設定しなければなりません python上でディレクトリ変更(チェンジディレクトリ)をするにはまずosモジュールをインポートします

import os

os.chdir('絶対パス')

chdirはchange directory の略 絶対パスというのは郵便番号みたいなものですが、とりあえず置きたいディレクトリ(フォルダ、今回でいうと「ch03」)からコマンドプロンプト(ターミナル)にドラッグ&ドロップした際に表示される長い文だと思えばいいです てか私が理解できてないし

あとは記載されたコードを打ち込むだけですね!

import sys, os
sys.path.append(os.pardir)  
import numpy as np
from dataset.mnist import load_mnist
from PIL import Image


def img_show(img):
    pil_img = Image.fromarray(np.uint8(img))
    pil_img.show()

(x_train, t_train), (x_test, t_test) = load_mnist(flatten=True, normalize=False)

これでロードが始まったら成功です

お疲れ様でした!

次回

python-nnn.hatenadiary.jp

ゼロから作るDeep Learning ? ―自然言語処理編

ゼロから作るDeep Learning ? ―自然言語処理編



参考にさせていただいたサイト様 こっちの方がわかりやすくて素敵な解説が付いてますよ!

ゼロから作るDeepLearning第三章 ニューラルネットワーク
ゼロから作るDeep Learning 3章「ニューラルネットワーク」 - Miyamo’s blog

ブログの書き方参考

はてなブログで数式が綺麗に書けるTeXの便利ワザ for 見たままモード - cBlog
機械学習でも定番のPythonライブラリ「NumPy」の初心者向け使い方チュートリアル - paiza開発日誌