<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 Copyright 2018 The TensorFlow Authors.
Step1:  SavedModel 形式の使用
<table class="tfo-notebook-buttons" align="left">
  <td>     <a target="_blank" href="https
Step2:  実行例として、グレース・ホッパーの画像と Keras の次元トレーニング済み画像分類モデルを使用します（使いやすいため）。カスタムモデルも使用できますが、これについては後半で説明します。
Step3:  この画像の予測トップは「軍服」です。
Step4:  save-path は、TensorFlow Serving が使用する規則に従っており、最後のパスコンポーネント（この場合 1/）はモデルのバージョンを指します。Tensorflow Serving のようなツールで、相対的な鮮度を区別させることができます。
tf.saved_model.load で SavedModel を Python に読み込み直し、ホッパー将官の画像がどのように分類されるかを確認できます。
Step5:  インポートされるシグネチャは、必ずディクショナリを返します。シグネチャ名と出力ディクショナリキーをカスタマイズするには、「エクスポート中のシグネチャの指定」を参照してください。
Step6:  SavedModel から推論を実行すると、元のモデルと同じ結果が得られます。
Step7:  TensorFlow Serving での SavedModel の実行
SavedModels は Python から使用可能（詳細は以下参照）ですが、本番環境では通常、Python コードを使用せずに、推論専用のサービスが使用されます。これは、TensorFlow Serving を使用して SavedModel から簡単にセットアップできます。
エンドツーエンドのtensorflow-servingの例については、 TensorFlow Serving RESTチュートリアルをご覧ください。
ディスク上の SavedModel 形式
SavedModel は、変数の値や語彙など、シリアル化されたシグネチャとそれらを実行するために必要な状態を含むディレクトリです。
Step8:  saved_model.pb ファイルは、実際の TensorFlow プログラムまたはモデル、およびテンソル入力を受け入れてテンソル出力を生成する関数を識別する一連の名前付きシグネチャを保存します。
SavedModel には、複数のモデルバリアント（saved_model_cli への --tag_set フラグで識別される複数の v1.MetaGraphDefs）が含まれることがありますが、それは稀なことです。複数のモデルバリアントを作成する API には、tf.Estimator.experimental_export_all_saved_models と TensorFlow 1.x の tf.saved_model.Builder があります。
Step9:  variables ディレクトリには、標準のトレーニングチェックポイントが含まれます（「トレーニングチェックポイントガイド」を参照してください）。
Step10:  assets ディレクトリには、語彙テーブルを初期化するためのテキストファイルなど、TensorFlow グラフが使用するファイルが含まれます。この例では使用されません。
SavedModel には、SavedModel で何をするかといった消費者向けの情報など、TensorFlow グラフで使用されないファイルに使用する assets.extra ディレクトリがある場合があります。TensorFlow そのものでは、このディレクトリは使用されません。
カスタムモデルの保存
tf.saved_model.save は、tf.Module オブジェクトと、tf.keras.Layer や tf.keras.Model などのサブクラスの保存をサポートしています。
tf.Module の保存と復元の例を見てみましょう。
Step11:  tf.Module を保存すると、すべての tf.Variable 属性、tf.function でデコレートされたメソッド、および再帰トラバースで見つかった tf.Module が保存されます（この再帰トラバースについては、「チェックポイントのチュートリアル」を参照してください）。ただし、Python の属性、関数、およびデータは失われます。つまり、tf.function が保存されても、Python コードは保存されません。
Python コードが保存されないのであれば、SavedModel は関数をどのようにして復元するのでしょうか。
簡単に言えば、tf.function は、Python コードをトレースして ConcreteFunction（tf.Graph のコーラブルラッパー）を生成することで機能します。tf.function を保存すると、実際には tf.function の ConcreteFunctions のキャッシュを保存しているのです。
tf.function と ConcreteFunctions の関係に関する詳細は、「tf.function ガイド」をご覧ください。
Step12:  カスタムモデルの読み込みと使用
Python に SavedModel を読み込むと、すべての tf.Variable 属性、tf.function でデコレートされたメソッド、および tf.Module は、保存された元の tf.Module と同じオブジェクト構造で復元されます。
Step13:  Python コードは保存されないため、新しい入力シグネチャで tf.function で呼び出しても失敗します。
python
imported(tf.constant([3.]))
<pre>ValueError
Step14:  一般的な微調整
Keras の SavedModel は、より高度な微調整の事例に対処できる、プレーンな __call__ よりも詳細な内容を提供します。TensorFlow Hub は、微調整の目的で共有される SavedModel に、該当する場合は次の項目を提供することをお勧めします。
モデルに、フォワードパスがトレーニングと推論で異なるドロップアウトまたはほかのテクニックが使用されている場合（バッチの正規化など）、__call__ メソッドは、オプションのPython 重視の training= 引数を取ります。この引数は、デフォルトで False になりますが、True に設定することができます。
__call__ 属性の隣には、対応する変数リストを伴う .variable と .trainable_variable 属性があります。もともとトレーニング可能であっても、微調整中には凍結されるべき変数は、.trainable_variables から省略されます。
レイヤとサブモデルの属性として重みの正規化を表現する Keras のようなフレームワークのために、.regularization_losses 属性も使用できます。この属性は、値が合計損失に追加することを目的とした引数無しの関数のリストを保有します。
最初の MobileNet の例に戻ると、これらの一部が動作していることを確認できます。
Step15:  エクスポート中のシグネチャの指定
TensorFlow Serving や saved_model_cli のようなツールは、SavedModel と対話できます。これらのツールがどの ConcreteFunctions を使用するか判定できるように、サービングシグネチャを指定する必要があります。tf.keras.Model は、サービングシグネチャを自動的に指定しますが、カスタムモジュールに対して明示的に宣言する必要があります。
重要
Step16:  サービングシグネチャを宣言するには、signatures kwarg を使用して ConcreteFunction 指定します。単一のシグネチャを指定する場合、シグネチャキーは 'serving_default' となり、定数 tf.saved_model.DEFAULT_SERVING_SIGNATURE_DEF_KEY として保存されます。
Step17:  複数のシグネチャをエクスポートするには、シグネチャキーのディクショナリを ConcreteFunction に渡します。各シグネチャキーは 1 つの ConcreteFunction に対応します。
Step18:  デフォルトでは、出力されたテンソル名は、output_0 というようにかなり一般的な名前です。出力の名前を制御するには、出力名を出力にマッピングするディクショナリを返すように tf.function を変更します。入力の名前は Python 関数の引数名から取られます。
<ASSISTANT_TASK:>
Python Code:
#@title Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
Explanation: Copyright 2018 The TensorFlow Authors.
End of explanation
import os
import tempfile
from matplotlib import pyplot as plt
import numpy as np
import tensorflow as tf
tmpdir = tempfile.mkdtemp()
physical_devices = tf.config.list_physical_devices('GPU')
for device in physical_devices:
  tf.config.experimental.set_memory_growth(device, True)
file = tf.keras.utils.get_file(
    "grace_hopper.jpg",
    "https://storage.googleapis.com/download.tensorflow.org/example_images/grace_hopper.jpg")
img = tf.keras.utils.load_img(file, target_size=[224, 224])
plt.imshow(img)
plt.axis('off')
x = tf.keras.utils.img_to_array(img)
x = tf.keras.applications.mobilenet.preprocess_input(
    x[tf.newaxis,...])
Explanation: SavedModel 形式の使用
<table class="tfo-notebook-buttons" align="left">
  <td>     <a target="_blank" href="https://www.tensorflow.org/guide/saved_model"><img src="https://www.tensorflow.org/images/tf_logo_32px.png">TensorFlow.org で表示</a>   </td>
  <td><a target="_blank" href="https://colab.research.google.com/github/tensorflow/docs-l10n/blob/master/site/ja/guide/saved_model.ipynb"><img src="https://www.tensorflow.org/images/colab_logo_32px.png">Google Colab で実行</a></td>
  <td><a target="_blank" href="https://github.com/tensorflow/docs-l10n/blob/master/site/ja/guide/saved_model.ipynb"><img src="https://www.tensorflow.org/images/GitHub-Mark-32px.png">GitHub でソースを表示</a></td>
  <td><a href="https://storage.googleapis.com/tensorflow_docs/docs-l10n/site/ja/guide/saved_model.ipynb"><img src="https://www.tensorflow.org/images/download_logo_32px.png">ノートブックをダウンロード</a></td>
</table>
SavedModel には、トレーニング済みのパラメータ（tf.Variable）や計算を含む完全な TensorFlow プログラムが含まれます。実行するために元のモデルのビルディングコードを必要としないため、TFLite、TensorFlow.js、TensorFlow Serving、または TensorFlow Hub との共有やデプロイに便利です。
以下の API を使用して、SavedModel 形式でのモデルの保存と読み込みを行えます。
低レベルの tf.saved_model API。このドキュメントでは、この API の使用方法を詳しく説明しています。
保存: tf.saved_model.save(model, path_to_dir)
読み込み: model = tf.saved_model.load(path_to_dir)
高レベルの tf.keras.Model API。Keras の保存とシリアル化ガイドをご覧ください。
トレーニング中の重みの保存/読み込みのみを実行する場合は、チェックポイントガイドをご覧ください。
Keras を使った SavedModel の作成
簡単な導入として、このセクションでは、事前にトレーニング済みの Keras モデルをエクスポートし、それを使って画像分類リクエストを送信します。SavedModels のほかの作成方法については、このガイドの残りの部分で説明します。
End of explanation
labels_path = tf.keras.utils.get_file(
    'ImageNetLabels.txt',
    'https://storage.googleapis.com/download.tensorflow.org/data/ImageNetLabels.txt')
imagenet_labels = np.array(open(labels_path).read().splitlines())
pretrained_model = tf.keras.applications.MobileNet()
result_before_save = pretrained_model(x)
decoded = imagenet_labels[np.argsort(result_before_save)[0,::-1][:5]+1]
print("Result before saving:\n", decoded)
Explanation: 実行例として、グレース・ホッパーの画像と Keras の次元トレーニング済み画像分類モデルを使用します（使いやすいため）。カスタムモデルも使用できますが、これについては後半で説明します。
End of explanation
mobilenet_save_path = os.path.join(tmpdir, "mobilenet/1/")
tf.saved_model.save(pretrained_model, mobilenet_save_path)
Explanation: この画像の予測トップは「軍服」です。
End of explanation
loaded = tf.saved_model.load(mobilenet_save_path)
print(list(loaded.signatures.keys()))  # ["serving_default"]
Explanation: save-path は、TensorFlow Serving が使用する規則に従っており、最後のパスコンポーネント（この場合 1/）はモデルのバージョンを指します。Tensorflow Serving のようなツールで、相対的な鮮度を区別させることができます。
tf.saved_model.load で SavedModel を Python に読み込み直し、ホッパー将官の画像がどのように分類されるかを確認できます。
End of explanation
infer = loaded.signatures["serving_default"]
print(infer.structured_outputs)
Explanation: インポートされるシグネチャは、必ずディクショナリを返します。シグネチャ名と出力ディクショナリキーをカスタマイズするには、「エクスポート中のシグネチャの指定」を参照してください。
End of explanation
labeling = infer(tf.constant(x))[pretrained_model.output_names[0]]
decoded = imagenet_labels[np.argsort(labeling)[0,::-1][:5]+1]
print("Result after saving and loading:\n", decoded)
Explanation: SavedModel から推論を実行すると、元のモデルと同じ結果が得られます。
End of explanation
!ls {mobilenet_save_path}
Explanation: TensorFlow Serving での SavedModel の実行
SavedModels は Python から使用可能（詳細は以下参照）ですが、本番環境では通常、Python コードを使用せずに、推論専用のサービスが使用されます。これは、TensorFlow Serving を使用して SavedModel から簡単にセットアップできます。
エンドツーエンドのtensorflow-servingの例については、 TensorFlow Serving RESTチュートリアルをご覧ください。
ディスク上の SavedModel 形式
SavedModel は、変数の値や語彙など、シリアル化されたシグネチャとそれらを実行するために必要な状態を含むディレクトリです。
End of explanation
!saved_model_cli show --dir {mobilenet_save_path} --tag_set serve
Explanation: saved_model.pb ファイルは、実際の TensorFlow プログラムまたはモデル、およびテンソル入力を受け入れてテンソル出力を生成する関数を識別する一連の名前付きシグネチャを保存します。
SavedModel には、複数のモデルバリアント（saved_model_cli への --tag_set フラグで識別される複数の v1.MetaGraphDefs）が含まれることがありますが、それは稀なことです。複数のモデルバリアントを作成する API には、tf.Estimator.experimental_export_all_saved_models と TensorFlow 1.x の tf.saved_model.Builder があります。
End of explanation
!ls {mobilenet_save_path}/variables
Explanation: variables ディレクトリには、標準のトレーニングチェックポイントが含まれます（「トレーニングチェックポイントガイド」を参照してください）。
End of explanation
class CustomModule(tf.Module):
  def __init__(self):
    super(CustomModule, self).__init__()
    self.v = tf.Variable(1.)
  @tf.function
  def __call__(self, x):
    print('Tracing with', x)
    return x * self.v
  @tf.function(input_signature=[tf.TensorSpec([], tf.float32)])
  def mutate(self, new_v):
    self.v.assign(new_v)
module = CustomModule()
Explanation: assets ディレクトリには、語彙テーブルを初期化するためのテキストファイルなど、TensorFlow グラフが使用するファイルが含まれます。この例では使用されません。
SavedModel には、SavedModel で何をするかといった消費者向けの情報など、TensorFlow グラフで使用されないファイルに使用する assets.extra ディレクトリがある場合があります。TensorFlow そのものでは、このディレクトリは使用されません。
カスタムモデルの保存
tf.saved_model.save は、tf.Module オブジェクトと、tf.keras.Layer や tf.keras.Model などのサブクラスの保存をサポートしています。
tf.Module の保存と復元の例を見てみましょう。
End of explanation
module_no_signatures_path = os.path.join(tmpdir, 'module_no_signatures')
module(tf.constant(0.))
print('Saving model...')
tf.saved_model.save(module, module_no_signatures_path)
Explanation: tf.Module を保存すると、すべての tf.Variable 属性、tf.function でデコレートされたメソッド、および再帰トラバースで見つかった tf.Module が保存されます（この再帰トラバースについては、「チェックポイントのチュートリアル」を参照してください）。ただし、Python の属性、関数、およびデータは失われます。つまり、tf.function が保存されても、Python コードは保存されません。
Python コードが保存されないのであれば、SavedModel は関数をどのようにして復元するのでしょうか。
簡単に言えば、tf.function は、Python コードをトレースして ConcreteFunction（tf.Graph のコーラブルラッパー）を生成することで機能します。tf.function を保存すると、実際には tf.function の ConcreteFunctions のキャッシュを保存しているのです。
tf.function と ConcreteFunctions の関係に関する詳細は、「tf.function ガイド」をご覧ください。
End of explanation
imported = tf.saved_model.load(module_no_signatures_path)
assert imported(tf.constant(3.)).numpy() == 3
imported.mutate(tf.constant(2.))
assert imported(tf.constant(3.)).numpy() == 6
Explanation: カスタムモデルの読み込みと使用
Python に SavedModel を読み込むと、すべての tf.Variable 属性、tf.function でデコレートされたメソッド、および tf.Module は、保存された元の tf.Module と同じオブジェクト構造で復元されます。
End of explanation
optimizer = tf.optimizers.SGD(0.05)
def train_step():
  with tf.GradientTape() as tape:
    loss = (10. - imported(tf.constant(2.))) ** 2
  variables = tape.watched_variables()
  grads = tape.gradient(loss, variables)
  optimizer.apply_gradients(zip(grads, variables))
  return loss
for _ in range(10):
  # "v" approaches 5, "loss" approaches 0
  print("loss={:.2f} v={:.2f}".format(train_step(), imported.v.numpy()))
Explanation: Python コードは保存されないため、新しい入力シグネチャで tf.function で呼び出しても失敗します。
python
imported(tf.constant([3.]))
<pre>ValueError: Could not find matching function to call for canonicalized inputs ((&lt;tf.Tensor 'args_0:0' shape=(1,) dtype=float32&gt;,), {}). Only existing signatures are [((TensorSpec(shape=(), dtype=tf.float32, name=u'x'),), {})].
</pre>
基本の微調整
変数オブジェクトを使用でき、インポートされた関数を通じてバックプロパゲーションできます。単純なケースの場合、SavedModel をファインチューニング（再トレーニング）するには、これで十分です。
End of explanation
loaded = tf.saved_model.load(mobilenet_save_path)
print("MobileNet has {} trainable variables: {}, ...".format(
          len(loaded.trainable_variables),
          ", ".join([v.name for v in loaded.trainable_variables[:5]])))
trainable_variable_ids = {id(v) for v in loaded.trainable_variables}
non_trainable_variables = [v for v in loaded.variables
                           if id(v) not in trainable_variable_ids]
print("MobileNet also has {} non-trainable variables: {}, ...".format(
          len(non_trainable_variables),
          ", ".join([v.name for v in non_trainable_variables[:3]])))
Explanation: 一般的な微調整
Keras の SavedModel は、より高度な微調整の事例に対処できる、プレーンな __call__ よりも詳細な内容を提供します。TensorFlow Hub は、微調整の目的で共有される SavedModel に、該当する場合は次の項目を提供することをお勧めします。
モデルに、フォワードパスがトレーニングと推論で異なるドロップアウトまたはほかのテクニックが使用されている場合（バッチの正規化など）、__call__ メソッドは、オプションのPython 重視の training= 引数を取ります。この引数は、デフォルトで False になりますが、True に設定することができます。
__call__ 属性の隣には、対応する変数リストを伴う .variable と .trainable_variable 属性があります。もともとトレーニング可能であっても、微調整中には凍結されるべき変数は、.trainable_variables から省略されます。
レイヤとサブモデルの属性として重みの正規化を表現する Keras のようなフレームワークのために、.regularization_losses 属性も使用できます。この属性は、値が合計損失に追加することを目的とした引数無しの関数のリストを保有します。
最初の MobileNet の例に戻ると、これらの一部が動作していることを確認できます。
End of explanation
assert len(imported.signatures) == 0
Explanation: エクスポート中のシグネチャの指定
TensorFlow Serving や saved_model_cli のようなツールは、SavedModel と対話できます。これらのツールがどの ConcreteFunctions を使用するか判定できるように、サービングシグネチャを指定する必要があります。tf.keras.Model は、サービングシグネチャを自動的に指定しますが、カスタムモジュールに対して明示的に宣言する必要があります。
重要: モデルを TensorFlow 2.x と Python 以外の環境にエクスポートする必要がない限り、おそらく明示的にシグネチャをエクスポートする必要はありません。特定の関数に入力シグネチャを強要する方法を探している場合は、tf.function への input_signature 引数をご覧ください。
デフォルトでは、シグネチャはカスタム tf.Module で宣言されません。
End of explanation
module_with_signature_path = os.path.join(tmpdir, 'module_with_signature')
call = module.__call__.get_concrete_function(tf.TensorSpec(None, tf.float32))
tf.saved_model.save(module, module_with_signature_path, signatures=call)
imported_with_signatures = tf.saved_model.load(module_with_signature_path)
list(imported_with_signatures.signatures.keys())
Explanation: サービングシグネチャを宣言するには、signatures kwarg を使用して ConcreteFunction 指定します。単一のシグネチャを指定する場合、シグネチャキーは 'serving_default' となり、定数 tf.saved_model.DEFAULT_SERVING_SIGNATURE_DEF_KEY として保存されます。
End of explanation
module_multiple_signatures_path = os.path.join(tmpdir, 'module_with_multiple_signatures')
signatures = {"serving_default": call,
              "array_input": module.__call__.get_concrete_function(tf.TensorSpec([None], tf.float32))}
tf.saved_model.save(module, module_multiple_signatures_path, signatures=signatures)
imported_with_multiple_signatures = tf.saved_model.load(module_multiple_signatures_path)
list(imported_with_multiple_signatures.signatures.keys())
Explanation: 複数のシグネチャをエクスポートするには、シグネチャキーのディクショナリを ConcreteFunction に渡します。各シグネチャキーは 1 つの ConcreteFunction に対応します。
End of explanation
class CustomModuleWithOutputName(tf.Module):
  def __init__(self):
    super(CustomModuleWithOutputName, self).__init__()
    self.v = tf.Variable(1.)
  @tf.function(input_signature=[tf.TensorSpec([], tf.float32)])
  def __call__(self, x):
    return {'custom_output_name': x * self.v}
module_output = CustomModuleWithOutputName()
call_output = module_output.__call__.get_concrete_function(tf.TensorSpec(None, tf.float32))
module_output_path = os.path.join(tmpdir, 'module_with_output_name')
tf.saved_model.save(module_output, module_output_path,
                    signatures={'serving_default': call_output})
imported_with_output_name = tf.saved_model.load(module_output_path)
imported_with_output_name.signatures['serving_default'].structured_outputs
Explanation: デフォルトでは、出力されたテンソル名は、output_0 というようにかなり一般的な名前です。出力の名前を制御するには、出力名を出力にマッピングするディクショナリを返すように tf.function を変更します。入力の名前は Python 関数の引数名から取られます。
End of explanation
<END_TASK>