序章
TensorFlow Hub は、TensorFlow 2 の SavedModel などのアセットをホストします。これらは、 obj = hub.load(url)
[詳細] を使用して Python プログラムに再度読み込むことができます。返されるobj
はtf.saved_model.load()
の結果です (TensorFlow のSavedModel ガイドを参照してください)。このオブジェクトは、tf.functions、tf.Variables (事前にトレーニングされた値から初期化された)、その他のリソース、および再帰的にそのようなオブジェクトである任意の属性を持つことができます。
このページでは、TensorFlow Python プログラムで再利用するために、読み込まれたobj
によって実装されるインターフェイスについて説明します。このインターフェースに準拠する SavedModel は、再利用可能な SavedModelと呼ばれます。
再利用とは、微調整する機能を含め、 obj
を中心に大きなモデルを構築することを意味します。微調整とは、周囲のモデルの一部としてロードされたobj
の重みをさらにトレーニングすることを意味します。損失関数とオプティマイザーは、周囲のモデルによって決定されます。 obj
は、ドロップアウトやバッチ正規化などの手法を含む可能性のある、入力から出力へのアクティベーション (「フォワード パス」) のマッピングのみを定義します。
TensorFlow Hub チームは、上記の意味で再利用されるすべての SavedModel に Reusable SavedModel インターフェースを実装することを推奨しています。 tensorflow_hub
ライブラリの多くのユーティリティ、特にhub.KerasLayer
では、それを実装するために SavedModels が必要です。
SignatureDefs との関係
tf.functions およびその他の TF2 機能に関するこのインターフェイスは、TF1 から利用可能であり、推論のために TF2 で引き続き使用されている SavedModel の署名とは別のものです (SavedModels を TF Serving または TF Lite にデプロイするなど)。推論のための署名は、微調整をサポートするほど十分に表現力がありませんtf.function
は、再利用されたモデルに対してより自然で表現力豊かなPython APIを提供します。
モデル構築ライブラリとの関係
Reusable SavedModel は、Keras や Sonnet などの特定のモデル構築ライブラリとは無関係に、TensorFlow 2 プリミティブのみを使用します。これにより、モデル構築ライブラリ全体での再利用が容易になり、元のモデル構築コードへの依存がなくなります。
Reusable SavedModels を特定のモデル構築ライブラリにロードしたり、そこから保存したりするには、ある程度の適応が必要になります。 Keras の場合、 hub.KerasLayerが読み込みを提供し、Keras の SavedModel 形式での組み込みの保存は、このインターフェイスのスーパーセットを提供する目的で TF2 用に再設計されました (2019 年 5 月のRFCを参照)。
タスク固有の「共通の SavedModel API」との関連
このページのインターフェイス定義では、任意の数とタイプの入力と出力が可能です。 TF Hub の Common SavedModel API は、この一般的なインターフェイスを特定のタスクの使用規則で改良して、モデルを簡単に交換できるようにします。
インターフェース定義
属性
Reusable SavedModel は、 obj = tf.saved_model.load(...)
が次の属性を持つオブジェクトを返すような TensorFlow 2 SavedModel です。
__call__
.必須。以下の仕様に従うモデルの計算 (「フォワード パス」) を実装する tf.function。variables
: tf.Variable オブジェクトのリスト。トレーニング可能なものとトレーニング不可能なものの両方を含む、__call__
の可能な呼び出しによって使用されるすべての変数をリストします。このリストは、空の場合は省略できます。
trainable_variables
: v.trainable がすべての要素に対して true であるようなv.trainable
オブジェクトのリスト。これらの変数は、variables
のサブセットである必要があります。これらは、オブジェクトを微調整するときにトレーニングする変数です。 SavedModel の作成者は、微調整中に変更してはならないことを示すために、元々訓練可能だったいくつかの変数をここで省略することを選択する場合があります。特に、SavedModel が微調整をサポートしていない場合は、空の場合、このリストを省略できます。
regularization_losses
: tf.functions のリスト。それぞれがゼロ入力を取り、単一のスカラー浮動小数点テンソルを返します。微調整のために、SavedModel ユーザーはこれらを追加の正則化項として損失に含めることをお勧めします (最も単純なケースでは、それ以上のスケーリングはありません)。通常、これらは重みの正則化を表すために使用されます。 (入力がないため、これらの tf.functions はアクティビティ正規化子を表現できません。)特に、SavedModel が微調整をサポートしていないか、重みの正則化を規定したくない場合は、空の場合、このリストを省略できます。
__call__
関数
Restored SavedModel obj
には、復元された tf.function であるobj.__call__
属性があり、次のようにobj
を呼び出すことができます。
概要 (疑似コード):
outputs = obj(inputs, trainable=..., **kwargs)
引数
引数は次のとおりです。
SavedModel の入力アクティベーションのバッチには、位置指定の必須引数が 1 つあります。そのタイプは次のいずれかです。
- 単一の入力に対する単一の Tensor、
- 名前のない入力の順序付けられたシーケンスのテンソルのリスト、
- 入力名の特定のセットによってキー付けされた Tensor の辞書。
(このインターフェースの将来のリビジョンでは、より一般的なネストが許可される可能性があります。) SavedModel の作成者は、それらの 1 つと、テンソルの形状と dtype を選択します。必要に応じて、形状の一部の寸法を未定義にする必要があります (特にバッチ サイズ)。
Python ブール値の
True
またはFalse
を受け入れるオプションのキーワード引数training
がある場合があります。デフォルトはFalse
です。モデルが微調整をサポートし、その計算が 2 つの間で異なる場合 (ドロップアウトとバッチ正規化など)、その区別はこの引数で実装されます。それ以外の場合、この引数は存在しない可能性があります。__call__
が Tensor 値のtraining
引数を受け入れる必要はありません。それらの間でディスパッチする必要がある場合は、呼び出し元がtf.cond()
を使用する必要があります。SavedModel 作成者は、特定の名前のより多くのオプションの
kwargs
を受け入れることを選択できます。Tensor 値の引数については、SavedModel の作成者が許容される dtype と形状を定義します。
tf.function
は、tf.TensorSpec 入力でトレースされる引数で Python デフォルト値を受け入れます。このような引数を使用して、__call__
に含まれる数値ハイパーパラメーター (ドロップアウト率など) をカスタマイズできます。Python 値の引数については、SavedModel 作成者が許容値を定義します。このような引数は、トレースされる関数で個別の選択を行うためのフラグとして使用できます (ただし、トレースの組み合わせ爆発に注意してください)。
復元された__call__
関数は、許容されるすべての引数の組み合わせのトレースを提供する必要があります。 True
とFalse
の間でtraining
を反転させても、引数の許容性が変わってはなりません。
結果
obj
の呼び出しからのoutputs
は次のようになります。
- 単一の出力に対する単一の Tensor、
- 名前のない出力の順序付けられたシーケンスのテンソルのリスト、
- 出力名の特定のセットによってキー付けされた Tensor の辞書。
(このインターフェイスの将来のリビジョンでは、より一般的なネストが許可される可能性があります。) 戻り値の型は、Python 値の kwargs によって異なる場合があります。これにより、追加の出力を生成するフラグが可能になります。 SavedModel 作成者は、出力の dtype と shape および入力への依存性を定義します。
名前付き callable
再利用可能な SavedModel は、上記の方法で複数のモデル ピースを提供できます。たとえば、それらをobj.foo
、 obj.bar
などの名前付きサブオブジェクトに配置します。各サブオブジェクトは、 __call__
メソッドと、そのモデル部分に固有の変数などに関するサポート属性を提供します。上記の例では、 obj.foo.__call__
、 obj.foo.variables
などがあります。
このインターフェースは、裸の tf.function をtf.foo
として直接追加するアプローチをカバーしていないことに注意してください。
再利用可能な SavedModel のユーザーは、1 レベルのネスト ( obj.bar
であり、 obj.bar.baz
ではありません) のみを処理することが期待されています。 (このインターフェースの将来のリビジョンでは、より深いネストが許可される可能性があり、最上位オブジェクト自体が呼び出し可能であるという要件が放棄される可能性があります。)
閉会の辞
インプロセス API との関係
このドキュメントは、 tf.saved_model.save()
およびtf.saved_model.load()
) によるシリアライゼーションによるラウンドトリップを生き残る tf.function および tf.Variable のようなプリミティブで構成される Python クラスのインターフェースについて説明します。ただし、インターフェースはtf.saved_model.save()
に渡された元のオブジェクトに既に存在していました。そのインターフェースへの適応により、単一の TensorFlow プログラム内のモデル構築 API 間でモデル ピースの交換が可能になります。