マサムネの部屋

Pythonによるニューラルネットワークの実装①

Python でニューラルネットワークを実装してみましょう。何回かに分けて作っていきます。
第一弾の今回は、行列データを受け取って、0から9までの10種類のラベルを出力する、3層のモデルを作ります。行列パラメーターの更新機能は無く、手動で成分を設定してラベルを出力します。

Python の環境が無い人は、google colab を使えるようにしましょう。Pythonファイルに色々まとめて置くのが便利ですが、最悪一つのnotebook にまとめても良いです。
Google Colabolatory とニューラルネットワークの話はこちらの記事でどうぞ。

Google Colab によるpython環境構築
機械学習を始めるにあたって、環境を作るのが第一の壁になります。既に作られたライブラリが沢山あるので、python がオススメです。Google が提供するサービスを使うことで、python 環境が簡単に作れます。さらに、性能の良いパソコンを計算に使うことが出来るようになります。
ニューラルネットワークの話
本当にお話程度の事しか書かないとは思いませんでした。おすすめの本のリンクを貼っておきます。 マサムネも読んでいる定番です。数学の人には細部が書いてなかったり当たり前の事を長々と書いていたりで物足りないかもしれませ...

ニューラルネットワークのモデルの実装は、以下の本を参考にしています。管理人はこの本でpythonがなんとなく書けるようになりました。

機械学習記事のマサムネが読んでる本です

記事で使っているソースコードはgithub に置いてあります。
https://github.com/msamunetogetoge

スポンサーリンク

使用するデータ

使うデータは Fashion MNIST という画像データです。10種類の衣類が\( 28 \times 28 \)の行列で表現されています。以下のような感じのデータです。

データのサンプル

実際のデータでは画像に対して、0~9の数字が割り振られています。単純に考えると、\(28 \times 28\)の数字から、0~9どのクラスに属しているのか当てる問題です。データを読み込むコードを以下に記します。
ただし、ちょっとした細工をしておきます。精度が上がるように画像は白黒に加工します。 また、画像データは\( 28 \times 28 \)の行列ですが、1つのデータが行列として与えられるのは、普段考える問題と違っています。いつも通りが一番なので、行列を1列のベクトルだと思いましょう。numpyのflatten 関数を使えばよいです。

import tensorflow as tf
from tensorflow import keras

fashion_mnist = keras.datasets.fashion_mnist
(train_images, train_labels), (test_images, test_labels) = fashion_mnist.load_data()

train_images = train_images / 255.0
test_images = test_images / 255.0

train_images.flatten().reshape(-1,784) #28*28=784
test_images.flatten().reshape(-1,784)

今回実装するニューラルネットワークモデルの部分

作ろうとしているモデルは、入力層1層、隠れ層1層、出力層1層のモデルです。隠れ層では、relu関数で活性化し、出力層ではsoftmax関数で10個の値を得て最も大きい値を出すクラスを予測値とします。
パラメーターの更新は単純な勾配法で行い、誤差関数は交差エントロピーを使用します。
今回は、データを受け取って予測ラベルを出力し、正解率を計算する関数を作ります。具体的には、以下の機能が必要です。

ニューラルネットワークモデルの予測部分の実装

以下のグラフが示すモデルで予測値を得られるように、コードを書きます。

作ったモデル

最終的には一つのクラスにまとめたいので、初めにクラスを作っておいて機能を増やしていきましょう。ニューラルネットワークのクラスとは別に、活性化関数や出力関数を作っておく必要があります。今のところは、reluとsoftmaxがあれば良いので、以下のように定義しておきましょう。

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

def softmax(x):
    if x.ndim == 2:
        x = x.T
        x = x - np.max(x, axis=0)
        y = np.exp(x) / np.sum(np.exp(x), axis=0)
        return y.T 

    x = x - np.max(x) # オーバーフロー対策
    return np.exp(x) / np.sum(np.exp(x))

今回の目玉である、行列の計算と活性化関数の計算、そして出力関数の定義をしましょう。行列の行や列に気を付ければ簡単です。クラスにまとめたいので、TwoLayerNet というクラスの中に、行列の生成や ニューラルネットワークでの予測、正答率の表示を組み込みました。

class TwoLayerNet:

    def __init__(self, input_size, hidden_size, output_size, weight_init_std=0.1):
        self.params = {}
        self.params['W1'] = weight_init_std * np.random.randn(input_size, hidden_size)
        self.params['b1'] = np.zeros(hidden_size)
        self.params['W2'] = weight_init_std * np.random.randn(hidden_size, output_size)
        self.params['b2'] = np.zeros(output_size)

    def predict(self, x):
        W1, W2 = self.params['W1'], self.params['W2']
        b1, b2 = self.params['b1'], self.params['b2']
    
        a1 = np.dot(x, W1) + b1
        z1 = relu(a1)
        a2 = np.dot(z1, W2) + b2
        y = softmax(a2)
        
        return y
    def accuracy(self, x, t):
        y = self.predict(x)
        y = np.argmax(y, axis=1)
        
        accuracy = np.sum(y == t) / float(x.shape[0])
        return accuracy

この状態で、トレーニング画像からラベルを予測させてみましょう。全く訓練していないパラメーターなので、正答率は10%前後が妥当です。

network=TwoLayerNet(input_size=len(train_images[0]),hidden_size=64, output_size=10)

np.argmax(network.predict(train_images[0])) #1番目の画像の予測
#管理人の環境での出力 1
 
network.accuracy(train_images , train_labels ) #トレーニング用画像全体の正答率の算出
#管理人の環境での出力 0.05976666666666667

正答率 5 %でした。パラメーターは適当なので正答率は何%でも良いのですが、無事にデータから予測値を得る関数を作ることが出来ました。次回からはpython上で作ったクラスに色々な関数を追加して、パラメーターの更新を自動で行ってくれるようにしていきます。

まとめ

・ Fashion MNIST という\(28 \times 28 \)の画像データがあり、10種類の分類問題に使える。
・計3層のニューラルネットワークモデルを作るために、クラスTwolayernet を作った。
・データに予測値を与える関数を作成した。
・pythonによるニューラルネットワークの実装➁はこちら
https://masamunetogetoge.com/make-neuralnetwork2