Help us understand the problem. What is going on with this article?

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

More than 1 year has passed since last update.

前回作った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で実装するメリットはなさそうですね。

SwitchBlade
業務は組込み系の開発を中心にやってきましたが、2020年7月~株式会社マイスター・ギルドにてWeb系の開発を始めました。
m-gild
最先端技術のMEISTERを目指し、お互い切磋琢磨するGUILD。Webシステム/サービス開発、スマホアプリ開発、AR/VR/MR開発など、様々なニーズに応えます。
https://www.m-gild.com/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした