【AI】Kerasの計算誤差を確認!numpy計算との比較!

こんにちは、ヒガシです。

 

先日業務中にKerasで学習させたモデルをnumpyの行列計算で表した際に、ほぼ値は一致するんですが、微妙に結果が異なる事象に遭遇しました。

 

いろいろ調べてみると、GPUで計算する際の計算順序が毎度変わるらしく、その結果出力も微妙に変化してしまうとのこと。

 

詳しいことは不明!

 

ちなみにこのあたりの問題はPytorchでは解消されているが、Tensorflow系は対応できてないとのことです。

 

ということで実際のところどのくらい結果が変わるのが実際のKerasモデルを使って検証してみましょう。

 

それではさっそくやっていきます。

 

スポンサーリンク

KerasでNNモデルを構築する

まずはモデルがないと始まらないので以前構築したMNIST画像を用いたオートエンコーダーモデルを再利用したいと思います。

以下がその構築コードです。

from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Activation ,Conv2D, MaxPooling2D,Dropout, Flatten,BatchNormalization
from tensorflow.keras.optimizers import Adam
from tensorflow.keras.datasets import mnist
import numpy as np
import matplotlib.pyplot as plt
import random

# MNISTデータを読込む
(x_train, y_train), (x_test, y_test) = mnist.load_data()

# MNISTデータを加工する
inout_dim = 784
x_train  = x_train.reshape(60000, 784)
x_test   = x_test.reshape(10000, 784)
x_train  = x_train.astype('float32')
x_test   = x_test.astype('float32')
x_train /= 255
x_test  /= 255

#オートエンコーダーモデルの定義
model = Sequential()
model.add(Dense(128, input_dim = inout_dim))
model.add(Activation('relu'))
model.add(Dense(64))
model.add(Activation('relu'))
model.add(Dense(2))
model.add(Activation('tanh'))
model.add(Dense(64))
model.add(Activation('relu'))
model.add(Dense(128))
model.add(Activation('relu'))
model.add(Dense(inout_dim))
model.compile(loss = "mean_squared_error", optimizer = Adam(lr = 0.001))
model.summary()
history  =model.fit(x_train, x_train, batch_size = 32, epochs = 5, validation_data = (x_test , x_test))

 

今回はKerasの誤差を確認することが目的なので学習は適用で良いでしょう。

 

スポンサーリンク

学習済みモデルからnumpy計算用に重み、バイアスを取り出す

次に学習したモデルから重みとバイアスを取得します。

 

以下がそのコードです。

#エンコーダー部分の重み、バイアスを取得する
Enc_W1 = model.layers[0].get_weights()[0]
Enc_b1 = model.layers[0].get_weights()[1]
Enc_W2 = model.layers[2].get_weights()[0]
Enc_b2 = model.layers[2].get_weights()[1]
Enc_W3 = model.layers[4].get_weights()[0]
Enc_b3 = model.layers[4].get_weights()[1]

#デコーダー部分の重み、バイアスを取得する
Dec_W1 = model.layers[6].get_weights()[0]
Dec_b1 = model.layers[6].get_weights()[1]
Dec_W2 = model.layers[8].get_weights()[0]
Dec_b2 = model.layers[8].get_weights()[1]
Dec_W3 = model.layers[10].get_weights()[0]
Dec_b3 = model.layers[10].get_weights()[1]

 

あとはこれらを行列計算していくだけですね。

 

スポンサーリンク

AIモデルの行列計算をnumpyで記述する

次に先ほど取得した重み、バイアスを使ってAIの内部計算をnumpyの行列計算で再現していきます。

 

以下がそのコードです。

#エンコーダー部分の計算
def calc_encoder(input_data):
    L1P = np.dot(input_data,Enc_W1)+Enc_b1
    L1P = np.where(L1P<0,0,L1P)
    L2P = np.dot(L1P,Enc_W2)+Enc_b2
    L2P = np.where(L2P<0,0,L2P)
    L3P = np.dot(L2P,Enc_W3)+Enc_b3
    L3P = np.tanh(L3P)
    return L3P

#デコーダー部分の計算
def calc_decoder(input_data):
    L1P = np.dot(input_data,Dec_W1)+Dec_b1
    L1P = np.where(L1P<0,0,L1P)
    L2P = np.dot(L1P,Dec_W2)+Dec_b2
    L2P = np.where(L2P<0,0,L2P)
    L3P = np.dot(L2P,Dec_W3)+Dec_b3
    return L3P

別にエンコーダーとデコーダーに分ける意味もないのですが、一応分けておきました。

 

スポンサーリンク

Kerasの計算とnumpy計算での誤差を確認する

今回のモデルの出力は784次元のデータなのですが、一つ一つ見ていくのも面倒なので、まずは最初の5次元だけを比較してみましょう。

以下がそのサンプルコードです。

#サンプル入力データ
input_data = x_test[0]
#numpyで計算実行⇒結果出力
enc_out = calc_encoder(input_data)
dec_out = calc_decoder(enc_out)
print('numpy', dec_out[:5])
#kerasで計算実行⇒結果出力
keras_out = model.predict(np.array([input_data]))[0]
print('keras', keras_out[:5])

numpyの計算結果とKerasの計算結果を比較した結果

だいたいあってますが、微妙に最後の方の桁が違いますね。

 

次はnumpy結果÷keras結果で最大、最小、平均誤差がどのくらいか確認してみます。

rate = (dec_out / keras_out -1) * 100
print('numpy / keras(%): max, min, average')
print(max(rate),min(rate),np.average(rate))

誤差割合の最大値、最小値、平均値を算出した結果

最大で0.084& 最小で0.033%、平均だともはやほぼゼロ。

 

ということで誤差はあるものの、そこまで気にするほどのものではなさそうですね。

 

スポンサーリンク

おわりに

ということで今回はKerasのPredictとnumpyの行列計算でどのくらい結果に差が出るのかを検証してみました。

あくまでも今回のモデルだとこうなったという話なので、あなたのモデルで確認することをオススメします。

 

面倒ならPytorchを使いましょう。

 

このブログでは、このようなAIスキルを多数紹介しています。

ぜひ他のページもご覧ください。

過去記事一覧

 

それではまた!

コメント

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