Pythonで機械学習 手書き数字認識 認識処理の実装 Part(9)

colaboratory

はじめに

こんにちは、swim-loverです。 Pythonで機械学習の一つである手書き数字認識を実装しています。Pythonを始めたばかりですが、「使いながら覚える」をコンセプトに勉強しています。 第8回は、 MNISTデータの準備で使用したpytorchのDataLoaderについて関数について勉強しました。今回から推論処理を実装していきたいと思います。今回は、pytorchのnnクラスをあえて用いず、参考図書にしたがって、自ら実装することにしてみました。

参考図書

今回、機械学習の参考書籍として、”斎藤康毅著 ゼロから作るDeep Learning オライリージャパン 2016年9月”を使用しました。 

学習済み重みパラメータ

学習済み重みパラメータは、参考図書のWebサイトからDownloadしました。git hubにファイル一式が登録されていましたので一括取得しました。

git clone https://github.com/oreilly-japan/deep-learning-from-scratch.git

sample_weight.pklというファイルが学習済み重みパラメータになります。

実行環境は、今回もGoogle Colabを使用しますので、このファイルをColab環境へUploadする必要があります。

下図のようにStep 1,Step2の操作を行うと、Uploadするファイルを選択することができます。lsコマンドでファイルがUploadされていることが確認できます。

実装

pythonにはpickle機能があるようで、プログラム中のオブジェクトをファイルとして保存できる機能らしいです。以下のコードは、pickle化されたファイルを復元するために用いています。

“network”はディクショナリ型の変数として保存してあります。したがって、”w 1” キーワードで保存した型のまま取り出すことができます。(Pythonの便利な機能をまた一つ知ることができました。)

import pickle
#function
def init_network(w_fname):
  with open(w_fname,'rb') as f:
    network=pickle.load(f)
    return network

def predict(network):
  w1,w2,w3 = network['W1'],network['W2'],network['W3']            
  b1,b2,b3 = network['b1'],network['b2'],network['b3']            
  print(w1.shape);print(w2.shape);print(w3.shape)
  print(b1.shape);print(b2.shape);print(b3.shape)

network=init_network("./sample_weight.pkl")
predict(network)

重み係数の行列サイズを表示してみました。

(784, 50) #w1
(50, 100) #w2
(100, 10) #w3
(50,) #b1
(100,) #b2
(10,) #b3

これによって、ネットワーク構成は、入力層784、隱れ層(1)50、隠れ層(2)100、出力層10となっていることがわかりました。

MNISTデータ(テストデータ)

第7回第8回の内容を流用して、get_data()関数を作成しました。Tensor型への変換処理”transform=transforms.ToTensor()”はしていません。Pytorchで演算する場合は、Tensor型に変換する必要があると初めて知りました。今回は、自作の演算なので、Tensor型への変換はしないことにしました。

import pickle
import torch;
import torchvision
from torchvision import transforms as transforms
import matplotlib.pyplot as plt
import numpy as np
from torch.utils.data import DataLoader

def get_data():
  #test data
  #test_data = torchvision.datasets.MNIST('~/tmp/mnist', train=False, download=True, transform=transforms.ToTensor())
  test_data = torchvision.datasets.MNIST('~/tmp/mnist', train=False, download=True)
  test_loader = DataLoader(test_data,batch_size=None, shuffle=True)
  return test_loader

評価関数

シグモイド関数とソフトマックス関数です。参考図書の内容そのままです。

def sigmoid(x):
  return 1/(1+np.exp(-x))
def softmax(x):
  c=np.max(x)
  exp_a=np.exp(x-c)
  sum_exp_a=np.sum(exp_a)
  y=exp_a/sum_exp_a
  return y

本体処理とpredict関数

本体処理とPredict処理(追加)を実装しました。

入力画像はPILイメージなのでnp.asarray()で28×28のarrayに変換しました。さらにreshape()によって784の一次元配列に変換してデータ形式を合わせています。

テストデータ数は10000件でした。

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

#main frogram
x= get_data() #get MNIST test data
network=init_network("./drive/MyDrive/sample_weight.pkl")

acc_cnt=0
for i in range(len(x)):
  data_iter = iter(x)
  imgs, labels=next(data_iter)
  img_array=np.asarray(imgs)
  y = predict(network,img_array.reshape(784,))
  p = np.argmax(y)
  if p==labels:
    acc_cnt+=1

print("predict acc="+str(float(acc_cnt)/len(x)))

予測結果

参考書籍の学習済みデータを使った認識率は、予測精度は92.3%でした。

predict acc=0.9234

まとめ

今回、学習済みデータを使用して、手書き数字の認識を実装してみました。

ColabへのFile Update、Pickle機能、ディクショナリー型、Tensor型、numpyの型変換についても新しく出てきました。

コメント

タイトルとURLをコピーしました