UNISIA-SE Tech Blog

気まぐれお勉強日記

[Python] [7] MNISTを使った推論バッチ処理の実装サンプル

1. 前提条件


このページでは、MNISTを使った推論バッチ処理についての簡単な実装サンプルを記載する。

以下、必要な前提知識。

▼ 下記ページを理解していること。
[Python] [5] MNISTのダウンロード方法 (手書き数字画像セットを取込む) [Python] [6] MNISTを使ったニューラルネットワークの推論処理と実装サンプル

▼ Python3.6、NumPyがインストールされていること。
このページでは、venvの仮想環境(Python3.6)上にNumPyをインストールした環境で、Python対話モード(Pythonインタプリタ)にて実装サンプルを記載している。

※ Python対話モード、NumPyについては下記を参考。
Python対話モード:[Python] 対話モード (インタプリタ) の使用方法
NumPy:[Python] [NumPy] インストールとnumpy.ndarrayの使用方法

2. 推論バッチ処理の実行準備


下記、前ページ 2. 推論処理の実行準備 でダウンロードした ch03/neuralnet_mnist_batch.py を使ってバッチ処理を解説する。


※ ch03/neuralnet_mnist_batch.py は、ch03/neuralnet_mnist.py の実行部分をバッチ処理に書換えたもの (下記Pythonコードのコメントの "追記""書き換え" の部分) で3つの関数については全く同じ。

ch03/neuralnet_mnist_batch.py

import sys, os
sys.path.append(os.pardir) # 親ディレクトリのファイルをインポートするための設定
import numpy as np
import pickle
from dataset.mnist import load_mnist
from common.functions import sigmoid, softmax

def get_data():
    (x_train, t_train), (x_test, t_test) = load_mnist(normalize=True, flatten=True, one_hot_label=False)
    return x_test, t_test

def init_network():
    with open("sample_weight.pkl", 'rb') as f:
    network = pickle.load(f)
    return network

def predict(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 = softmax(a3)
    return y

x, t = get_data()
network = init_network()

batch_size = 100    # … 追記
accuracy_cnt = 0

for i in range(0, len(x), batch_size):    # … 書き換え
    x_batch = x[i:i+batch_size]     # … 書き換え
    y_batch = predict(network, x_batch)     # … 書き換え
    p = np.argmax(y_batch, axis=1)    # … 書き換え
    accuracy_cnt += np.sum(p == t[i:i+batch_size])    # … 書き換え

print("Accuracy:" + str(float(accuracy_cnt) / len(x)))


3. 推論バッチ処理の実行


結局上記の実行部分は、ch03/neuralnet_mnist.py の実行部分を 100個単位 でバッチ実行しているため、当然ながら ch03/neuralnet_mnist_batch.py 内の実行部分を実行すると neuralnet_mnist.py の実行時と同じ Accuracy:0.9352 が出力される。

対話モードで確認。

$ cd gitlocalrep
$ cd deep-learning-from-scratch/ch03
$ source /var/www/vops/bin/activate
$ python neuralnet_mnist_batch.py
 Accuracy:0.9352

しかし、これでは、ch03/neuralnet_mnist_batch.py 内の実行部分で具体的にどのような型で どのような値がどのように変化しているのか イメージが難しいため、次項のサンプルで解説する。

4. 推論バッチ処理の解説


実行部分 (Pythonコードのコメントの "追記""書き換え"の部分) を (1)(6) と置く。
▼ ch03/neuralnet_mnist_batch.pyの実行部分

x, t = get_data()
network = init_network()

batch_size = 100    # … (1)
accuracy_cnt = 0

for i in range(0, len(x), batch_size):    # … (2)
    x_batch = x[i:i+batch_size]     # … (3)
    y_batch = predict(network, x_batch)     # … (4)
    p = np.argmax(y_batch, axis=1)    # … (5)
    accuracy_cnt += np.sum(p == t[i:i+batch_size])    # … (6)

print("Accuracy:" + str(float(accuracy_cnt) / len(x)))

(1) どの程度のバッチ(束)で処理するかの バッチ数

(2) 0 ~ len(x) のインデックスで 増加幅が 100となる i (1周の処理対象が100 要素) のループ処理。
※ range は、指定した開始と終了時のインデックスで配列を作成する。
第 3 引数は、増加するスパンを指定できる。

rangeの例

$ python
 >>> list(range(0, 10))   # 0 ~ 10 までの配列
 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
 >>> list(range(5, 10))    # 5 ~ 10 までの配列
 [5, 6, 7, 8, 9]
 >>> list(range(1, 27, 3))    # 1 ~ 27 までのインデックスを 3 ずつ増加
 [1, 4, 7, 10, 13, 16, 19, 22, 25]

(3) x の i ~ i + batch_size の配列 を x_batch に取得。
※ ループ1週目は、i = 0 なので x_batch には 0 ~ 99 の配列が格納される。ループ2週目は、i = 1 なのでx_batch には 100 ~ 199 の配列が格納される。

(4) predictの結果をy_batch に取得。

※ predict(network, x_batch)のsigmoid, softmaxについては、下記を参考。
[Python] [3] ニューラルネットワークの活性化関数と実装サンプル
[Python] [4] 活性化関数の実装サンプルまとめ(ステップ / シグモイド / ReLU / 恒等関数 /ソフトマックス関数)

(5) np.argmax で y_batch の最大値となるインデックス を取得。
axis = 1 は、それぞれの列を対象に最大値を取るインデックスを抽出するオプション。

argmax (axis = 1)の例
左から 4つ目の 0.9 (インデックス 3)、2つ目の 0.9 (インデックス 1)、1つ目の 0.9 (インデックス 0)が最大値となるので [3 1 0]となる。

$ python
 >>> import numpy as np
 >>> x = np.array([[0.1, 0.3, 0.2, 0.9, 0.5], [0.3, 0.9, 0.1, 0.4, 0.8], [0.9, 0.2, 0.1, 0.6, 0.5]])
 >>> y = np.argmax(x, axis=1)
 >>> print(y)
 [3 1 0]
>>>

※ 同様に axis = 1 は、それぞれの行を対象に最大値を取るインデックスを抽出するオプション。

argmax (axis = 0)の例
左から 3行目の 0.9 (インデックス 2)、2行目の 0.9 (インデックス 1)、1つ目の 0.2 (インデックス 0)、1つ目の 0.9 (インデックス 0)、2つ目の 0.9 (インデックス 1)が最大値となるので [2 1 0 0 1] となる。

$ python
 >>> import numpy as np
 >>> x = np.array([[0.1, 0.3, 0.2, 0.9, 0.5], [0.3, 0.9, 0.1, 0.4, 0.8], [0.9, 0.2, 0.1, 0.6, 0.5]])
 >>> y = np.argmax(x, axis=0)
 >>> print(y)
 [2 1 0 0 1]
 >>>

(6) バッチ単位で抽出した結果 p と 正解 t を 比較し、一致している個数 (合計値) を取得。
sum (bool値)の例
p と t の比較結果をbool値の配列にし、Trueの合計値 5 を取得。

$ python
 >>> import numpy as np
 >>> p = np.array([0.1, 0.3, 0.2, 0.9, 0.5, 0.3, 0.9, 0.1, 0.4, 0.8])
 >>> t = np.array([0.1, 0.4, 0.2, 0.9, 0.5, 0.4, 0.9, 0.2, 0.5, 0.9])
 >>> print(p==t)
 [ True False  True  True  True False  True False False False]
 >>> np.sum(p==t)
 5
 >>>

以上。


【参考文献】
斎藤 康毅 (2018) 『ゼロから作るDeep Learning - Pythonで学ぶディープラーニングの理論と実装』株式会社オライリー・ジャパン


Copyright UNISIA-SE All Rights Reserved.
s-hama@unisia-se.jp