ITの隊長のブログ

ITの隊長のブログです。Rubyを使って仕事しています。最近も色々やっているお(^ω^ = ^ω^)

Tensorflow2系のサブクラスモデルの構造は保存できない

import tensorflow as tf


class MyModel(tf.keras.Model):
  def __init__(self, output_node):
    super(MyModel, self).__init__()
    self.d1 = tf.keras.layers.Dense(128, activation='relu')
    self.d2 = tf.keras.layers.Dense(output_node, activation='softmax')
  
  def call(self, x):
    x = self.d1(x)
    return self.d2(x)

こんな簡単なモデルを用意します。

model = MyModel(output_node=10)
model.compile(loss='sparse_categorical_crossentropy', optimizer=tf.keras.optimizers.RMSprop())
model.build(input_shape=(32, 10))
model.summary()

モデルをビルドして構造確認するとこんな感じ

Model: "my_model"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
dense (Dense)                multiple                  1408      
_________________________________________________________________
dense_1 (Dense)              multiple                  1290      
=================================================================
Total params: 2,698
Trainable params: 2,698
Non-trainable params: 0
_________________________________________________________________

Keras触っているならなんら普通な流れ.

問題はここから。

tf.keras.experimental.export_saved_model(model, 'path_to_saved_model', serving_only=True)
# W0506 10:36:19.523535 140296071452544 saved_model.py:124] Skipped saving model JSON, subclassed model does not have get_config() defined.

ドキュメント確認すると↑のコードで保存ができるらしい。が、しかし

model2 = tf.keras.experimental.load_from_saved_model('path_to_saved_model')
# NotFoundError: path_to_saved_model/assets/saved_model.json; No such file or directory

???

前のコードをよくみると W0506 10:36:19.523535 140296071452544 saved_model.py:124] Skipped saving model JSON, subclassed model does not have get_config() defined. と、書いてあった。なるほど。。。

で、ここから下記対応したが駄目だった

  • サブクラスで、 get_config を実装する

  • pickle で保存できないか確認してみる

    • TypeError: can't pickle weakref objects なるほど。。。

というわけでうまくいかんかったので、 model.summary() の結果を保存することにした。。。

これいつか対応してくれるとうれしいな

保存できる方法について

サブクラスを使わずに、KerasのSequentialと、Functional APIを使えばいける。

Sequential

model = tf.keras.Sequential([
    tf.keras.layers.Input(shape=(10,), batch_size=32),
    tf.keras.layers.Dense(128, activation='relu'),
    tf.keras.layers.Dense(10, activation='softmax')
])

model.compile(loss='sparse_categorical_crossentropy', optimizer=tf.keras.optimizers.RMSprop())
model.build(input_shape=(32, 10))
tf.keras.experimental.export_saved_model(model, 'path_to_saved_model', serving_only=True)

Functional API

inputs = tf.keras.Input(shape=(32, 10))
x = tf.keras.layers.Dense(128, activation='relu')(inputs)
predictions = tf.keras.layers.Dense(10, activation='softmax')(x)
model = tf.keras.Model(inputs=inputs, outputs=predictions)

model.compile(loss='sparse_categorical_crossentropy', optimizer=tf.keras.optimizers.RMSprop())
model.build(input_shape=(32, 10))
tf.keras.experimental.export_saved_model(model, 'path_to_saved_model', serving_only=True)

Tensorflow2系の基本的なデータの読み込み方

Tensorflow2系触っていますが、情報が少なくて死にそうです。

しかし、ドキュメントは結構しっかりしているかなと思っています。ドキュメント読むべし。

参考URL

Importing Data  |  TensorFlow Core  |  TensorFlow

環境

  • colaboratory
  • !pip install tensorflow-gpu==2.0.0-alpha0
  • Python3.6.7

データの読み込み

import numpy as np
import tensorflow as tf
from sklearn.model_selection import train_test_split

# 検証用データの用意
# Tensorflowから関係ない形式でとってきたと想定でやる
val_x_data = np.random.uniform(0, 1, (60000, 32, 32))
val_y_data = np.random.randint(0, 5, (60000))
val_x_data.shape, val_y_data.shape
# ((60000, 32, 32), (60000,))

TensorflowはKerasも取り込みましたし、自身でのデータセットのロードも関数が用意されていますが、フォーマットがわからずイライラする方もいるんじゃないかと。また、今データ分析やっている人は、生データがあって、そこからTensorflowの世界にもってってディープラーニングしたい人が多いんじゃないかなーと思うので、それを想定して試してみました。

# モデルを構築するならtrain, test分割
X_train, X_test, y_train, y_test = train_test_split(val_x_data, val_y_data, test_size=0.3)

Tensorflowの世界に持ってくる

Tensorflowの世界にもっていくとPythonより速度が速く処理できるそうです。

train_data = tf.data.Dataset.from_tensor_slices((X_train, y_train))

読み込んで作成したデータは、TensorSliceDataset になる

train_data
# <TensorSliceDataset shapes: ((32, 32), ()), types: (tf.float64, tf.int64)>

TensorSliceDataset のデータで前処理したい

データを何かで処理したい場合は、mapを使う. pythonの世界にもってくると処理が遅いのでオススメしないらしいが一応できます.

# 今回、X_train, y_trainでデータを作ったので引数は2つです
def hogehoge(x, y):
    x = tf.reshape(x, [-1,])
    return x, y # 戻り値は用意する必要があります


train_data_map = train_data.map(hogehoge)

確認すると処理されたデータになっています.

# 変換されました.
train_data_map.take(1)
# <TakeDataset shapes: ((1024,), ()), types: (tf.float64, tf.int64)>

データを回しながら取得する.

.take(n) で指定した n 個分、取得することができます。

# データを10個確認する
for x, y in train_data_map.take(10):
    print(x.shape, y)

# (1024,) tf.Tensor(4, shape=(), dtype=int64)
# (1024,) tf.Tensor(2, shape=(), dtype=int64)
# (1024,) tf.Tensor(0, shape=(), dtype=int64)
# (1024,) tf.Tensor(3, shape=(), dtype=int64)
# (1024,) tf.Tensor(0, shape=(), dtype=int64)
# (1024,) tf.Tensor(0, shape=(), dtype=int64)
# (1024,) tf.Tensor(0, shape=(), dtype=int64)
# (1024,) tf.Tensor(3, shape=(), dtype=int64)
# (1024,) tf.Tensor(1, shape=(), dtype=int64)
# (1024,) tf.Tensor(3, shape=(), dtype=int64)

numpyにしたい

TensorObject.numpy()でnumpyの世界にもってこれます

x.numpy()
# array([0.62607784, 0.52501669, 0.60375316, ..., 0.82408268, 0.24436969,
#        0.61117067])

batch sizeを指定して取得できるようにしたい

ディープラーニングで利用するなら、batch sizeを指定してデータを取り出したいですよね.

# batchサイズを指定して取り出したい
train_data_batch = train_data_map.batch(32)

すると、さっきと同様イテレートしてみると結果が変わります.

# take(10)してみる
for x, y in train_data_batch.take(10):
  print(x.shape, y.shape)

# (32, 1024) (32,)
# (32, 1024) (32,)
# (32, 1024) (32,)
# (32, 1024) (32,)
# (32, 1024) (32,)
# (32, 1024) (32,)
# (32, 1024) (32,)
# (32, 1024) (32,)
# (32, 1024) (32,)
# (32, 1024) (32,)

ドキュメントに書いてあるのに動かない

www.tensorflow.org

ドキュメントでは使えるような雰囲気だけどなんでじゃろ???

dataset1 = tf.data.Dataset.from_tensor_slices(tf.random.uniform([4, 10]))
print(dataset1.output_shapes)  # エラーになる.  AttributeError: 'TensorSliceDataset' object has no attribute 'output_types'

.take(n) しなくても確認できる方法がほしい.

学習するとき

# batch_sizeで取り出せるので、あとはループするだけ
model = lambda x: np.random.randint(0, 5, (32,))  # 構築したモデルと想定

for x, y in train_data_batch:
    predicted = model(x)
    
    # predictedとyで正答率を確認する...etc
    # ...
    

# test_data_batchは作っていないけどtrain側と一緒である
# for x, y in test_data_batch

雑感

他にも、TFRecode形式で保存されているデータ、テキストデータ、csvデータなど読み出す手法が書いてあったので、やっぱりドキュメントよんだほうがいいと思います.

2019年4月1週目の振り返り

やまです

体調管理

  • 4日ジムいきました
  • 引き続きがんばる
  • ワンパンマンの鍛え方真似したら1ヶ月でやせるとかやせないとか
    • 今5kmを必ず走るようにしているけど、これを10kmにすればいいらしい
  • ちなみに順調に体重は増えています。何故?

技術

数学

  • 赤本じっくり読んだ
  • 数式まだまだわかりません

個人開発

  • 何もしていない
  • 運動と赤本読んだら何もできないやばい

  • 統計学入門 (基礎統計学Ⅰ)の第二章を引き続きじっくり読んでいる

趣味

映画

  • みていない

ゲーム

  • まだメタモンの色違い見つからない
  • 100匹捕まえたことによって捕まえやすくなったので一旦諦めてもいいかもしれない

仕事

  • Tensorflow2.xを触っている
  • Optuna便利でよさそうだけど組み込むの大変そう

家庭

  • 土日は家族サービスっぽい感じ
  • 結婚式の打ち合わせがはじまる

雑感

  • 副業全く進めていないのでなんとかする(再掲。やばい
  • 個人開発全くススメきれていない
  • 何かが進むと何かが進まない
  • 4月の後半はLT、PyData.Okinawa講師などなどイベントが多いのでなるはやで進めたい

2019年3月5週目の振り返り

酔っぱらいです

体調管理

  • 4日ジムいったぞ!!!
  • 引き続きがんばる

技術

数学

  • 赤本読んだ
  • まだ難しくはない

個人開発

  • 何もしていない

趣味

映画

  • 1つみた

ゲーム

仕事

  • ぼちぼち
  • 色々学びがあった週間だった

家庭

  • 機嫌が悪くなること多しなので引き続きフォロー

雑感

  • 副業全く進めていないのでなんとかする
  • 明日から4月です

2019年3月4週目の振り返り

最近全く振り返れていないです。

ここ最近をまとめます。

体調管理

  • 22, 24, 25日でジムに(やっと。。。。やっと・・・・!
  • これが毎日続けられるといいな

技術

数学

個人開発

  • 何もしていない

趣味

映画

  • ちょこちょこ映画みてます

ゲーム

  • ぴかぶいでメタモンの色違いがほしくて100匹連続ゲットしたけどまだつかまらない

仕事

  • まだまだまだだけど整理はなんとかいけてるきがする

www.aipacommander.com

家庭

  • 平穏です(飲み会多くなると機嫌損ねるのでなんとかフォロアップ
    • 土日の家族サービスでなんとか

雑感

  • ダイエットまじで進めるぞ。課題は平日どれだけコミットできるか
  • 仕事、副業もきているので色々バタバタしそうだけど、引き続き頑張りたい