kerasとtf.kerasの差分と互換検証 #1

#Kerasの開発終了
投稿はかなり久しぶりになってしまいました。
githubにある通り、マルチバックエンドのKerasは2020年4月で開発終了となったようです。
今後はTensorflowにあるKerasに置き換わるとの事。
[keras-team](https://github.com/keras-team/keras)
（便宜上、マルチバックエンドのKerasをmb-keras、TensorflowのKerasをtf-kerasと表現する）
mb-kerasとtf-kerasの比較と検証を本記事でしておきたい。
※今回は#1としておき、随時記事を追加していきたい。
# mb-kerasのTensorflowのサポートについて
前述のgithubにある通り、Tensorflow2.0までのサポートとなっている模様です。
この記事を書いている2020年5月4日現在、Tensorflowの最新安定板は2.1.0です。
#環境
この記事を書くにあたって、TensorflowをCUDAなどから入れなおしたが、イマイチな環境を作ってしまった。
mb-kerasはPython3.6までのサポートだ・・・・（tensorflowはPython3.7までサポート）
mb-keras 2.3.1はtensorflow 2.0までサポートなので、こちらは良い。

```
python -V
3.7.6
```
```python
>>> import keras
>>> keras.__version__
'2.3.1'
>>> import tensorflow
>>> tensorflow.__version__
'2.0.0'
```
#エイリアス
基本的にそのままで、頭にtensorflowが付くだけです。

```python:mb-keras
from keras.layers import Dense, Conv2D
```
```python:tf-keras
from tensorflow.keras.layers import Dense, Conv2D
```

#オブジェクトの互換性
多分**無い**です。ただし、互換性の必要も無いかと・・・
下記コードにて、確認。
##ModelとLayerについて
```python
def mb_layers():
    from keras.layers import Input, Dense, Activation
    input_l = Input(shape=(64,))
    hidden = Dense(10)(input_l)
    output_l = Activation('softmax')(hidden)
    return input_l, output_l
def tf_layers():
    from tensorflow.keras.layers import Input, Dense, Activation
    input_l = Input(shape=(64,))
    hidden = Dense(10)(input_l)
    output_l = Activation('softmax')(hidden)
    return input_l, output_l

if __name__ == '__main__':
    mb_i, mb_o = mb_layers()
    tf_i, tf_o = tf_layers()
    
    from keras.models import Model as mbModel
    from tensorflow.keras.models import Model as tfModel
    
    # mb_in_tf = mbModel(tf_i, tf_o) #---- ※1
    # tf_in_mb = tfModel(mb_i, mb_o) #---- ※2
    mb_in_mb = mbModel(mb_i, mb_o)
    mb_in_mb.summary()               #---- ※3
    tf_in_tf = tfModel(tf_i, tf_o)
    tf_in_tf.summary()               #---- ※4
```
※1の実行時エラー発生（mb-kerasのModelにtf-kerasのLayerを突っ込む）
`TypeError: object of type 'Dense' has no len()`
※2の実行時エラー発生（tf-kerasのModelにmb-kerasのLayerを突っ込む）
`AttributeError: 'tuple' object has no attribute 'layer'`
※3の実行結果

```:stdout
Model: "model_7"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
input_23 (InputLayer)        (None, 64)                0         
_________________________________________________________________
dense_14 (Dense)             (None, 10)                650       
_________________________________________________________________
activation_12 (Activation)   (None, 10)                0         
=================================================================
Total params: 650
Trainable params: 650
Non-trainable params: 0
_________________________________________________________________
```
※4の実行結果

```:stdout
Model: "model_2"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
input_24 (InputLayer)        [(None, 64)]              0         
_________________________________________________________________
dense_14 (Dense)             (None, 10)                650       
_________________________________________________________________
activation_11 (Activation)   (None, 10)                0         
=================================================================
Total params: 650
Trainable params: 650
Non-trainable params: 0
_________________________________________________________________
```
InputLayerのOutput shapeの出方が違うんだが、同じアーキテクチャとして実装できているのだろうか・・・？
次回以降で確認したい。
とりあえず、Layerの作りがmb-kerasとtf-kerasで違うみたいなので、Modelに放り込めないことは確かだ。
##Optimizerについて
Optimizerはmb-kerasで作ったModelにtf-kerasのOptimizerが使える。

```python:model.compile
    from keras.optimizers import Adam as mbAdam
    from tensorflow.keras.optimizers import Adam as tfAdam
    mb_in_mb.compile(tfAdam(), 'mse')    #----※1
    tf_in_tf.compile(mbAdam(), 'mse')    #----※2
```
※1はエラーにならない。
※2は下記のエラー。
`ValueError: ('Could not interpret optimizer identifier:', <keras.optimizers.Adam object at 0x000001A4FC663F08>)`

#使えるレイヤーについて
これは結構な差がある模様。それぞれ○は実装あり、×は実装なし。
dir()で取り出したものをほとんどそのまま並べただけなので、すべてがLayerではないことに注意。
Attentionの差とか見ると、改廃はtf-kerasの方が進んでいるのかな・・・？
（オーバーライドメソッドと全小文字はfunctionぽいので一覧から削除した）

|Layer|mb-keras|tf-keras|
|---|:---:|:---:|
|AbstractRNNCell|×|○|
|Activation|○|○|
|ActivityRegularization|○|○|
|Add|○|○|
|AdditiveAttention|×|○|
|AlphaDropout|○|○|
|AtrousConvolution1D|○|×|
|AtrousConvolution2D|○|×|
|Attention|×|○|
|Average|○|○|
|AveragePooling1D|○|○|
|AveragePooling2D|○|○|
|AveragePooling3D|○|○|
|AvgPool1D|○|○|
|AvgPool2D|○|○|
|AvgPool3D|○|○|
|BatchNormalization|○|○|
|Bidirectional|○|○|
|Concatenate|○|○|
|Conv1D|○|○|
|Conv2D|○|○|
|Conv2DTranspose|○|○|
|Conv3D|○|○|
|Conv3DTranspose|○|○|
|ConvLSTM2D|○|○|
|ConvLSTM2DCell|○|×|
|ConvRecurrent2D|○|×|
|Convolution1D|○|○|
|Convolution2D|×|○|
|Convolution2D|○|×|
|Convolution3D|○|○|
|Convolution3DTranspose|×|○|
|Cropping1D|○|○|
|Cropping2D|○|○|
|Cropping3D|○|○|
|CuDNNGRU|○|×|
|CuDNNLSTM|○|×|
|Deconvolution2D|○|×|
|Deconvolution3D|○|×|
|Dense|○|○|
|DenseFeatures|×|○|
|DepthwiseConv2D|○|○|
|Dot|○|○|
|Dropout|○|○|
|ELU|○|○|
|Embedding|○|○|
|Flatten|○|○|
|GRU|○|○|
|GRUCell|○|○|
|GaussianDropout|○|○|
|GaussianNoise|○|○|
|GlobalAveragePooling1D|○|○|
|GlobalAveragePooling2D|○|○|
|GlobalAveragePooling3D|○|○|
|GlobalAvgPool1D|○|○|
|GlobalAvgPool2D|○|○|
|GlobalAvgPool3D|○|○|
|GlobalMaxPool1D|○|○|
|GlobalMaxPool2D|○|○|
|GlobalMaxPool3D|○|○|
|GlobalMaxPooling1D|○|○|
|GlobalMaxPooling2D|○|○|
|GlobalMaxPooling3D|○|○|
|Highway|○|×|
|Input|○|○|
|InputLayer|○|○|
|InputSpec|○|○|
|LSTM|○|○|
|LSTMCell|○|○|
|Lambda|○|○|
|Layer|○|○|
|LayerNormalization|×|○|
|LeakyReLU|○|○|
|LocallyConnected1D|○|○|
|LocallyConnected2D|○|○|
|Masking|○|○|
|MaxPool1D|○|○|
|MaxPool2D|○|○|
|MaxPool3D|○|○|
|MaxPooling1D|○|○|
|MaxPooling2D|○|○|
|MaxPooling3D|○|○|
|Maximum|○|○|
|MaxoutDense|○|×|
|Minimum|○|○|
|Multiply|○|○|
|PReLU|○|○|
|Permute|○|○|
|RNN|○|○|
|ReLU|○|○|
|Recurrent|○|×|
|RepeatVector|○|○|
|Reshape|○|○|
|SeparableConv1D|○|○|
|SeparableConv2D|○|○|
|SeparableConvolution1D|×|○|
|SeparableConvolution2D|×|○|
|SimpleRNN|○|○|
|SimpleRNNCell|○|○|
|Softmax|○|○|
|SpatialDropout1D|○|○|
|SpatialDropout2D|○|○|
|SpatialDropout3D|○|○|
|StackedRNNCells|○|○|
|Subtract|○|○|
|ThresholdedReLU|○|○|
|TimeDistributed|○|○|
|UpSampling1D|○|○|
|UpSampling2D|○|○|
|UpSampling3D|○|○|
|Wrapper ※|×|○|
|ZeroPadding1D|○|○|
|ZeroPadding2D|○|○|
|ZeroPadding3D|○|○|
※mb-kerasには`wrapper`が実装されている。
#今回のまとめ
mb-kerasとtf-kerasはほとんど互換性は無いことが分かった。
ただし、あまり必要性は感じない。

問題になると考えられるケースとしてはmb-kerasはPython3.6までのサポートなので、今後Pythonがアップデートしていってもこちらはサポートされない。
また、一方でtf-kerasの方は今後も開発が継続される。
mb-kerasを使ったAIシステムを作りこんでしまっていると、時代に置いてけぼりを食らう可能性があるのでtf-kerasへのリプレースを早急に検討すべきではないかと。
真っ先に思いつく具体例としては**mb-kerasで作った学習済みモデルはtf-kerasでロードして推論できるのか・・・？**とかとか・・・
（いつになるかわからない#2以降に記録したい。）

実はGW前にmb-kerasで社内AIシステムを構築したばかりである・・・
kerasのアップデートが最近ないなと思ったらこのザマである。
まずった・・・