Open22

TensorFlowについて勉強していく

winnie279winnie279

グラフ(graph execution)やeager execution、tf.functionなどについて

winnie279winnie279

graph excutionではインタラクティブに使用できない反面、高速に演算できる。また、モデルをグラフとして保存することができる。printが使えないためtf.printを使う必要がある。また、Tensor.numpyで実際の値にアクセスすることはできない。Tensorshapedtypeだけを保持する。

winnie279winnie279

tf.functionを使用することで、PythonコードをTensorFlowのグラフに変換することができる。
初回はPythonとして実行される、それをもとにグラフが生成される。

tf.functionは以下のようにデコレータか、関数をラップする形で使用する。

# tf.functionでデコレーションする場合
@tf.function
def my_func(x):
  print('Tracing.\n')
  return tf.reduce_sum(x)

# tf.functionでラップする場合
my_graph_func = tf.function(my_func)
winnie279winnie279

高価な演算がいくつか含まれるグラフ(畳み込みなど)では、eager executionでもgraph executionでも速度の差があまり見られないらしい。

winnie279winnie279

tf.data.Datasetについて

winnie279winnie279

Dataset.map内でPythonコードを扱うには、以下のいずれかの方法を用いる。

  • AutoGraphを用いてPythonコードをグラフに変換する。
  • tf.py_functionを使う(AutoGraphと比較してパフォーマンスは低下する)。
  • tf.numpy_functionを使う。
winnie279winnie279

tf.py_functionは以下のように、Dataset.mapに渡したい関数をラップして使用する。

  def func(x):
-     # graph executionなのでprintは初回のみ実行され、numpytは使えない
-     print(x)
+     # eager executionなのでprintが使え、numpyで値にアクセスできる
+     print(x.numpy())
      return x, x + 5
  
  
  def map_func(x):
      """"
       tf.py_functionでラップする。
       funcはDataset.mapに渡す関数、inpはfuncの引数、Toutはfuncの戻り値の型。
       """
      return tf.py_function(func=func, inp=[x], Tout=[tf.int64, tf.int64])
  
  
  dataset = tf.data.Dataset.range(5)
- dataset = dataset.map(func)
+ dataset = dataset.map(map_func)  # tf.py_functionでラップした関数を渡す
  
  for data in dataset:
-     pass  # Tensor("args_0:0", shape=(), dtype=int64)
+     pass  # 0, 1, 2, 3, 4
winnie279winnie279

tf.numpy_functionは基本的にtf.py_functionと同様に使う。
ただ、tf.numpy_functionではTensor.numpy()のように値にアクセスする必要がなく、直接値にアクセスできる。

-     tensor.numpy()
+     tensor
winnie279winnie279

tf.keras.layer.Layertf.keras.models.Model)の__init__buildcallについて

winnie279winnie279

メソッドはそれぞれ呼び出されるタイミングが異なる。

class SimpleDense(Layer):

    def __init__(self, units=32):
        """インスタンス生成時に呼び出される。"""
        super(SimpleDense, self).__init__()
        self.units = units

    def build(self, input_shape):
        """モデルの初回実行時に呼び出される。"""
        self.w = self.add_weight(shape=(input_shape[-1], self.units),
                                 initializer='random_normal',
                                 trainable=True)
        self.b = self.add_weight(shape=(self.units,),
                                 initializer='random_normal',
                                 trainable=True)

     def call(self, inputs):
         """モデルの実行時に毎回呼び出される。"""
         return tf.matmul(inputs, self.w) + self.b
winnie279winnie279

note
文字列はTensor.numpy().decode()で取得する。
これDatasetだけ?graph executionのTensor全部?

winnie279winnie279

Saved Model

これを見る限り、Saved ModelではMode.get_config()Model.from_config()は必要ない。
https://www.tensorflow.org/guide/keras/custom_layers_and_models?hl=ja

ModelCheckPoint()でうまく行かないと思っていたら、デフォルトでsave_weights_only=Trueとなっていたため、これをFalseとする。
https://www.tensorflow.org/api_docs/python/tf/keras/callbacks/ModelCheckpoint

しかしながら、カスタムモデルまたはレイヤークラスを作成する場合は、常にget_configおよびfrom_configメソッドを使用して定義することをお勧めします。これにより、必要に応じて後で計算を簡単に更新できます。
https://www.tensorflow.org/guide/keras/save_and_serialize?hl=ja#savedmodel_によるカスタムオブジェクトの処理

は???

サブクラス化されたモデルとレイヤーのアーキテクチャは、メソッド__init__およびcallで定義されています。それらは Python バイトコードと見なされ、JSON と互換性のある構成にシリアル化できません。pickleなどを使用してバイトコードのシリアル化を試すことができますが、これは安全ではなく、モデルを別のシステムに読み込むことはできません。

カスタム定義されたレイヤーのあるモデル、またはサブクラス化されたモデルを保存/読み込むには、get_configおよびfrom_config(オプション) メソッドを上書きする必要があります。さらに、Keras が認識できるように、カスタムオブジェクトの登録を使用する必要があります。
https://www.tensorflow.org/guide/keras/save_and_serialize?hl=ja#カスタムオブジェクト