前回作ったOpenAI GymをNeuroEvolution(ニューラルネット+実数値遺伝的アルゴリズム)で学習する実装をTensorFlowを使って高速化できないかなと思って試してみました。
結果としては、失敗しました。。。2~4倍の時間がかかるようになりました。
他の人が無駄な実装をしないように、迷走をしないようにメモとして残しておきます。
#TensorFlowに関して改めて復習
TensorFlow化するにあたって、引っかかった点を整理します。
##テンソル(Tensor)オブジェクトは数値の配列ではない
numpyと同じような計算ができるのごっちゃになりますが、あくまでも操作(オペレーション)を詰め込んだ箱です。
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の関数に渡すとエラーになります。
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の定数を書き換えても反映されない
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()を使う必要がある
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個体のシミュレーションの処理フローは以下のようにしていました。
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で実装するメリットはなさそうですね。