LoginSignup
5
2

More than 3 years have passed since last update.

ニューラルネットの重みを実数値遺伝的アルゴリズムで最適化してみる ~その3:TensorFlow対応【失敗】~

Last updated at Posted at 2019-08-14

前回作ったOpenAI GymをNeuroEvolution(ニューラルネット+実数値遺伝的アルゴリズム)で学習する実装をTensorFlowを使って高速化できないかなと思って試してみました。

結果としては、失敗しました。。。2~4倍の時間がかかるようになりました。
他の人が無駄な実装をしないように、迷走をしないようにメモとして残しておきます。

TensorFlowに関して改めて復習

TensorFlow化するにあたって、引っかかった点を整理します。

テンソル(Tensor)オブジェクトは数値の配列ではない

numpyと同じような計算ができるのごっちゃになりますが、あくまでも操作(オペレーション)を詰め込んだ箱です。

tensor.py
import tensorflow as tf
import numpy as np

def sum(a , b) :
    return a + b

#TensorFlowの計算
tfa = tf.constant([1,2])
tfb = tf.constant([10,20])
tfc = tf.constant([100,200])

print('tfa : {0} : <type={1}>'.format(tfa  , type(tfa))) 
#>tfa : Tensor("Const:0", shape=(2,), dtype=int32) : <type=<class 'tensorflow.python.framework.ops.Tensor'>>

sum_op = sum(tfa , tfb)
print('sum_op : {0} : <type={1}>'.format(sum_op  , type(sum_op))) 
#>sum_op : Tensor("add:0", shape=(2,), dtype=int32) : <type=<class 'tensorflow.python.framework.ops.Tensor'>>

sum_op = sum(sum_op , tfc)
print('sum_op : {0} : <type={1}>'.format(sum_op  , type(sum_op))) 
#>sum_op : Tensor("add_1:0", shape=(2,), dtype=int32) : <type=<class 'tensorflow.python.framework.ops.Tensor'>>

sess = tf.Session()
result = sess.run(sum_op)
print('result : {0} : <type={1}>'.format(result  , type(result))) 
#>result : [111 222] : <type=<class 'numpy.ndarray'>>

#numpyの計算
npa = np.array([1,2])
npb = np.array([10,20])
npc = np.array([100,200])
npsum = sum(npa , npb)
npsum = sum(npsum , npc)
print('npsum : {0} : <type={1}>'.format(npsum  , type(npsum))) 
#>npsum : [111 222] : <type=<class 'numpy.ndarray'>>

sess.run()でオペレーションを実行することで初めて計算結果が受け取れます。

変数ではないので、テンソル(Tensor)オブジェクトをnumpyの関数に渡すとエラーになります。

TensorError.py
import tensorflow as tf
import numpy as np
#ReLU関数
def relu(x):
    return np.maximum(0, x)

npa = np.array([-1,2])
nprelu = relu( npa )
print('nprelu : {0} : <type={1}>'.format(nprelu  , type(nprelu))) 
#> nprelu : [0 2] : <type=<class 'numpy.ndarray'>>

tfa = tf.constant([-1,2])
relu_op = relu(tfa )

#> TypeError: Using a `tf.Tensor` as a Python `bool` is not allowed. Use `if t is not None:` instead of `if t:` to test if a tensor is defined, and use TensorFlow ops such as tf.cond to execute subgraphs conditioned on the value of a tensor.

オペレーション作成後にTensorFlowの定数を書き換えても反映されない

TensorConstSum.py
import tensorflow as tf
import numpy as np

def sum(a , b) :
    return a + b

tfc = tf.constant([1,2])
b = 10
sum_op = sum(tfc , b)

sess = tf.Session()

result = sess.run(sum_op)
print('result : {0} : <type={1}>'.format(result  , type(result))) 
#>result : [11 12] : <type=<class 'numpy.ndarray'>>

tfc = tf.constant([10,20])
b = 100
result = sess.run(sum_op)
print('result : {0} : <type={1}>'.format(result  , type(result))) 
#>result : [11 12] : <type=<class 'numpy.ndarray'>>

TensorFlowの変数を更新するにはassign()を使う必要がある

TensorVariableSum.py
import tensorflow as tf
import numpy as np

def sum(a , b) :
    return a + b

tfc = tf.constant([1,2])
tfv = tf.Variable(10)

sum_op = sum(tfc , tfv)

sess = tf.Session()
sess.run(tf.global_variables_initializer()) 

result = sess.run(sum_op)
print('result : {0} : <type={1}>'.format(result  , type(result))) 
#>result : [11 12] : <type=<class 'numpy.ndarray'>>

#変数 更新
assign_op = tfv.assign(100)
sess.run(assign_op)
result = sess.run(sum_op)
print('result : {0} : <type={1}>'.format(result  , type(result))) 
#>result : [101 102] : <type=<class 'numpy.ndarray'>>

NN+実数値GAのTensorFlow対応

OpenAI GymをNN+実数値GAで学習するとき、1個体のシミュレーションの処理フローは以下のようにしていました。

NNGA_OpenAI.JPG

OpenAI Gymはnumpyを使って実装されているので、TensorFlow化できるのは「NNで行動を推論」の部分だけに。。なおかつ、NNの重みとバイアスをTensorFlowの変数で表現すると、個体毎に変数の更新処理が必要になります。

結果

GoogleColaboratoryのGPUモードとCPUモードで速度計測しています。50個体を評価した平均です(時刻取得や出力にかかるコストもあるので、あくまで目安で)

計測区間 TensorFlowなし(GPU) TensorFlow対応(GPU) TensorFlow対応(CPU)
重みとバイアスセット 23[μsec] 21963[μsec] 25191[μsec]
200stepのシミュレート 88587[μsec] 255974[μsec] 186580[μsec]
合計 88610[μsec] 277937[μsec] 211771[μsec]

「重みとバイアスセット」に時間がかかるのは想定内ですが、シミュレートにも時間がかかってます。
1stepのシミュレートの内訳です。

計測区間 TensorFlowなし(GPU) TensorFlow対応(GPU) TensorFlow対応(CPU)
NNで行動を推論 132[μsec] 926[μsec] 559[μsec]
OpenAI Gymで1stepシミュレート 36[μsec] 53[μsec] 55[μsec]
合計 168[μsec] 979[μsec] 614[μsec]

高速化したかった「NNで行動を推論」自体に時間がかかってしまってます。そして、GPUよりCPUの方が速い。。TensorFlowのチュートリアル を見る限りでは、メモリのコピーがネックになっていそうな感じです。
「OpenAI Gymで1stepシミュレート」で時間がかかるようになってるのは、コンテキストの切り替えとかですかね??

結論

BPを用いた画像認識のように、1回のオペレーション実行で大量のバッチ処理を行うような学習ではない限り、TensorFlowで実装するメリットはなさそうですね。

5
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
2