SavedModel 포맷 사용하기

TensorFlow.org에서 보기 구글 코랩(Colab)에서 실행하기 깃허브(GitHub) 소스 보기 Download notebook

SavedModel에는 가중치 및 연산을 포함한 완전한 텐서플로 프로그램이 포함됩니다. 기존에 설계했던 모델 코드를 실행할 필요가 없어 공유하거나 (TFLite, TensorFlow.js, TensorFlow Serving, TFHub와 같은 환경으로) 배포하는 데 유용합니다.

파이썬 모델 코드를 가지고 있고 파이썬 내에서 가중치를 불러오고 싶다면, 체크포인트 훈련 가이드를 참조하세요.

빠른 소개를 위해 이 섹션에서는 미리 훈련된 케라스 모델을 내보내고 그 모델로 이미지 분류 요청을 처리합니다. 나머지 가이드에서는 세부 정보와 SavedModel을 만드는 다른 방법에 대해 설명합니다.

import tensorflow as tf
from matplotlib import pyplot as plt
import numpy as np
file = tf.keras.utils.get_file(
    "grace_hopper.jpg",
    "https://storage.googleapis.com/download.tensorflow.org/example_images/grace_hopper.jpg")
img = tf.keras.preprocessing.image.load_img(file, target_size=[224, 224])
plt.imshow(img)
plt.axis('off')
x = tf.keras.preprocessing.image.img_to_array(img)
x = tf.keras.applications.mobilenet.preprocess_input(
    x[tf.newaxis,...])
Downloading data from https://storage.googleapis.com/download.tensorflow.org/example_images/grace_hopper.jpg
65536/61306 [================================] - 0s 0us/step

png

실행 예제로 그레이스 호퍼(Grace Hopper)의 이미지와 사용이 쉬운 케라스 사전 훈련 이미지 분류 모델을 사용할 것입니다. 사용자 정의 모델도 사용할 수 있는데, 자세한 것은 나중에 설명합니다.

#tf.keras.applications.vgg19.decode_predictions
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())
Downloading data from https://storage.googleapis.com/download.tensorflow.org/data/ImageNetLabels.txt
16384/10484 [==============================================] - 0s 0us/step

pretrained_model = tf.keras.applications.MobileNet()
result_before_save = pretrained_model(x)
print()

decoded = imagenet_labels[np.argsort(result_before_save)[0,::-1][:5]+1]

print("저장 전 결과:\n", decoded)
Downloading data from https://storage.googleapis.com/tensorflow/keras-applications/mobilenet/mobilenet_1_0_224_tf.h5
17227776/17225924 [==============================] - 0s 0us/step

저장 전 결과:
 ['military uniform' 'bow tie' 'suit' 'bearskin' 'pickelhaube']

이 이미지의 가장 가능성 있는 예측은 "군복"입니다.

tf.saved_model.save(pretrained_model, "/tmp/mobilenet/1/")
WARNING:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow/python/ops/resource_variable_ops.py:1817: calling BaseResourceVariable.__init__ (from tensorflow.python.ops.resource_variable_ops) with constraint is deprecated and will be removed in a future version.
Instructions for updating:
If using Keras pass *_constraint arguments to layers.
INFO:tensorflow:Assets written to: /tmp/mobilenet/1/assets

저장 경로의 마지막 경로 요소(여기서는 1/)는 모델의 버전 번호인 텐서플로 서빙(TensorFlow Serving) 컨벤션을 따릅니다 - 텐서플로 서빙과 같은 도구가 최신 모델을 구분할 수 있게 합니다.

SavedModel은 시그니처(signatures)라 불리는 이름있는 함수를 가집니다. 케라스 모델은 serving_default 시그니처 키를 사용하여 정방향 패스(forward pass)를 내보냅니다. SavedModel 커맨드 라인 인터페이스는 디스크에 저장된 SavedModel을 검사할 때 유용합니다.

saved_model_cli show --dir /tmp/mobilenet/1 --tag_set serve --signature_def serving_default
The given SavedModel SignatureDef contains the following input(s):
  inputs['input_1'] tensor_info:
      dtype: DT_FLOAT
      shape: (-1, 224, 224, 3)
      name: serving_default_input_1:0
The given SavedModel SignatureDef contains the following output(s):
  outputs['predictions'] tensor_info:
      dtype: DT_FLOAT
      shape: (-1, 1000)
      name: StatefulPartitionedCall:0
Method name is: tensorflow/serving/predict

파이썬에서 tf.saved_model.load로 SavedModel을 다시 불러오고 해군대장 호퍼(Admiral Hopper)의 이미지가 어떻게 분류되는지 볼 수 있습니다.

loaded = tf.saved_model.load("/tmp/mobilenet/1/")
print(list(loaded.signatures.keys()))  # ["serving_default"]
['serving_default']

가져온 시그니처는 항상 딕셔너리를 반환합니다.

infer = loaded.signatures["serving_default"]
print(infer.structured_outputs)
{'predictions': TensorSpec(shape=(None, 1000), dtype=tf.float32, name='predictions')}

SavedModel로부터 추론을 실행하면 처음 모델과 같은 결과를 제공합니다.

labeling = infer(tf.constant(x))[pretrained_model.output_names[0]]

decoded = imagenet_labels[np.argsort(labeling)[0,::-1][:5]+1]

print("저장과 불러오기 이후의 결과:\n", decoded)
저장과 불러오기 이후의 결과:
 ['military uniform' 'bow tie' 'suit' 'bearskin' 'pickelhaube']

텐서플로 서빙으로 모델 배포하기

SavedModel은 파이썬에서 사용하기에 적합하지만, 일반적으로 프로덕션 환경에서는 추론을 위한 전용 서비스를 사용합니다. 이는 텐서플로 서빙을 사용한 SavedModel로 쉽게 구성할 수 있습니다.

tensorflow_model_server를 노트북이나 로컬 머신에 설치하는 방법을 포함한 텐서플로 서빙에 대한 자세한 내용은 TensorFlow Serving REST 튜토리얼을 참조하십시오. 간단한 예를 들면 앞서 내보낸 mobilenet 모델을 배포하기 위해 모델 경로를 SavedModel 디렉토리로 설정합니다:

nohup tensorflow_model_server \
  --rest_api_port=8501 \
  --model_name=mobilenet \
  --model_base_path="/tmp/mobilenet" >server.log 2>&1

이제 요청을 보냅니다.

!pip install -q requests
import json
import numpy
import requests
data = json.dumps({"signature_name": "serving_default",
                   "instances": x.tolist()})
headers = {"content-type": "application/json"}
json_response = requests.post('http://localhost:8501/v1/models/mobilenet:predict',
                              data=data, headers=headers)
predictions = numpy.array(json.loads(json_response.text)["predictions"])

predictions의 결과는 파이썬에서와 같습니다.

SavedModel 포맷

SavedModel은 변수값과 상수를 포함하고 직렬화된 시그니처와 이를 실행하는 데 필요한 상태를 담은 디렉토리입니다.

ls /tmp/mobilenet/1  # assets    saved_model.pb  variables
assets  saved_model.pb  variables

saved_model.pb 파일은 각각 하나의 함수로 된 이름있는 시그니처 세트를 포함합니다.

SavedModel에는 다중 시그니처 세트(saved_model_clitag_set 매개변수 값으로 확인된 다중 MetaGraph)를 포함할 수 있지만 이런 경우는 드뭅니다. 다중 시그니처 세트를 작성하는 API에는 tf.Estimator.experimental_export_all_saved_models 및 TensorFlow 1.x의 tf.saved_model.Builder가 포함됩니다.

saved_model_cli show --dir /tmp/mobilenet/1 --tag_set serve
The given SavedModel MetaGraphDef contains SignatureDefs with the following keys:
SignatureDef key: "__saved_model_init_op"
SignatureDef key: "serving_default"

variables 디렉토리에는 일반적인 훈련 체크포인트 파일이 있습니다(훈련 체크포인트 가이드 참조).

ls /tmp/mobilenet/1/variables
variables.data-00000-of-00002  variables.data-00001-of-00002  variables.index

assets 디렉토리에는 텐서플로 그래프(TensorFlow graph)에서 사용되는 파일들, 예를 들어 상수 테이블을 초기화하는 데 사용되는 텍스트 파일들이 있습니다. 이번 예제에서는 사용되지 않습니다.

SavedModel은 텐서플로 그래프에서 사용되지 않는 파일을 위해 assets.extra 디렉토리를 가질 수 있는데, 예를 들면 사용자가 SavedModel과 함께 사용할 파일입니다. 텐서플로 자체는 이 디렉토리를 사용하지 않습니다.

사용자 정의 모델 내보내기

첫 번째 섹션에서는, tf.saved_model.savetf.keras.Model 객체에 대한 시그니처를 자동으로 결정했습니다. 이는 케라스의 Model 객체가 내보내기 위한 명시적 메서드와 입력 크기를 가지기 때문에 작동했습니다. tf.saved_model.save는 저수준(low-level) 모델 설계 API와도 잘 작동하지만, 모델을 텐서플로 서빙에 배포할 계획이라면 시그니처로 사용할 함수를 지정해야 합니다.

class CustomModule(tf.Module):

  def __init__(self):
    super(CustomModule, self).__init__()
    self.v = tf.Variable(1.)

  @tf.function
  def __call__(self, 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()

이 모듈은 tf.function 데코레이터가 적용된 두 메서드를 가지고 있습니다. 이 함수들은 SavedModel에 포함되어 있으므로 tf.saved_model.load 함수를 사용하여 파이썬 프로그램에 함께 로드됩니다. 하지만 명시적 선언 없이는 텐서플로 서빙과 같은 시그니처 배포 도구와 saved_model_cli가 접근할 수 없습니다.

module.mutateinput_signature를 가지고 있어서 계산 그래프를 SavedModel에 저장하기 위한 정보가 이미 충분히 있습니다. __call__은 시그니처가 없기에 저장하기 전 이 메서드를 호출해야 합니다.

module(tf.constant(0.))
tf.saved_model.save(module, "/tmp/module_no_signatures")
INFO:tensorflow:Assets written to: /tmp/module_no_signatures/assets

input_signature가 없는 함수의 경우, 저장 전에 사용된 입력의 크기는 함수가 불려진 이후에 사용될 것입니다. 스칼라값으로 __call__을 호출했으므로 스칼라값만 받아들일 것입니다

imported = tf.saved_model.load("/tmp/module_no_signatures")
assert 3. == imported(tf.constant(3.)).numpy()
imported.mutate(tf.constant(2.))
assert 6. == imported(tf.constant(3.)).numpy()

함수는 벡터와 같은 새로운 형식을 수용하지 않습니다.

imported(tf.constant([3.]))
ValueError: Could not find matching function to call for canonicalized inputs ((,), {}). Only existing signatures are [((TensorSpec(shape=(), dtype=tf.float32, name=u'x'),), {})].

get_concrete_function을 사용해 입력 크기를 함수 호출 없이 추가할 수 있습니다. 이 함수는 매개변수 값으로 Tensor 대신 입력 크기와 데이터 타입을 나타내는 tf.TensorSpec 객체를 받습니다. 크기가 None이면 모든 크기가 수용 가능합니다. 또는 각 축의 크기(axis size)를 담은 리스트일 수도 있습니다. 축 크기가 'None'이면 그 축에 대해 임의의 크기를 사용할 수 있습니다. 또한 tf.TensorSpecs는 이름을 가질 수 있는데, 기본값은 함수의 매개변수 키워드(여기서는 "x")입니다.

module.__call__.get_concrete_function(x=tf.TensorSpec([None], tf.float32))
tf.saved_model.save(module, "/tmp/module_no_signatures")
imported = tf.saved_model.load("/tmp/module_no_signatures")
assert [3.] == imported(tf.constant([3.])).numpy()
INFO:tensorflow:Assets written to: /tmp/module_no_signatures/assets

tf.keras.Modeltf.Module과 같은 객체에 포함된 함수와 변수는 가져올 때 사용할 수 있지만 많은 파이썬의 타입과 속성은 잃어버립니다. 파이썬 프로그램 자체는 SavedModel에 저장되지 않습니다.

내보낼 함수를 시그니처로 지정하지 못했기에 시그니처는 없습니다.

saved_model_cli show --dir /tmp/module_no_signatures --tag_set serve
The given SavedModel MetaGraphDef contains SignatureDefs with the following keys:
SignatureDef key: "__saved_model_init_op"

내보낼 시그니처 지정하기

어떤 함수가 시그니처라는 것을 나타내려면 저장할 때 signatures 매개변수를 지정합니다.

call = module.__call__.get_concrete_function(tf.TensorSpec(None, tf.float32))
tf.saved_model.save(module, "/tmp/module_with_signature", signatures=call)
INFO:tensorflow:Assets written to: /tmp/module_with_signature/assets

먼저 tf.function 객체를 get_concrete_function 메서드를 사용해 ConcreteFunction 객체로 바꾸었습니다. 이것은 함수가 고정된 input_signature 없이 만들어지고 함수와 연관된 명시적인 Tensor 입력이 없었으므로 필수적입니다.

saved_model_cli show --dir /tmp/module_with_signature --tag_set serve --signature_def serving_default
The given SavedModel SignatureDef contains the following input(s):
  inputs['x'] tensor_info:
      dtype: DT_FLOAT
      shape: unknown_rank
      name: serving_default_x:0
The given SavedModel SignatureDef contains the following output(s):
  outputs['output_0'] tensor_info:
      dtype: DT_FLOAT
      shape: unknown_rank
      name: StatefulPartitionedCall:0
Method name is: tensorflow/serving/predict

imported = tf.saved_model.load("/tmp/module_with_signature")
signature = imported.signatures["serving_default"]
assert [3.] == signature(x=tf.constant([3.]))["output_0"].numpy()
imported.mutate(tf.constant(2.))
assert [6.] == signature(x=tf.constant([3.]))["output_0"].numpy()
assert 2. == imported.v.numpy()

하나의 시그니처를 내보냈고 키는 기본값인 "serving_default"가 됩니다. 여러 시그니처를 내보내려면 딕셔너리로 전달합니다.

@tf.function(input_signature=[tf.TensorSpec([], tf.string)])
def parse_string(string_input):
  return imported(tf.strings.to_number(string_input))

signatures = {"serving_default": parse_string,
              "from_float": imported.signatures["serving_default"]}

tf.saved_model.save(imported, "/tmp/module_with_multiple_signatures", signatures)
INFO:tensorflow:Assets written to: /tmp/module_with_multiple_signatures/assets

saved_model_cli show --dir /tmp/module_with_multiple_signatures --tag_set serve
The given SavedModel MetaGraphDef contains SignatureDefs with the following keys:
SignatureDef key: "__saved_model_init_op"
SignatureDef key: "from_float"
SignatureDef key: "serving_default"

saved_model_cli는 커맨드 라인에서 SavedModel을 직접 실행할 수도 있습니다.

saved_model_cli run --dir /tmp/module_with_multiple_signatures --tag_set serve --signature_def serving_default --input_exprs="string_input='3.'"
saved_model_cli run --dir /tmp/module_with_multiple_signatures --tag_set serve --signature_def from_float --input_exprs="x=3."
2020-06-26 20:11:17.998297: I tensorflow/stream_executor/platform/default/dso_loader.cc:44] Successfully opened dynamic library libcuda.so.1
2020-06-26 20:11:18.005148: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:981] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2020-06-26 20:11:18.005487: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1561] Found device 0 with properties: 
pciBusID: 0000:00:05.0 name: Tesla V100-SXM2-16GB computeCapability: 7.0
coreClock: 1.53GHz coreCount: 80 deviceMemorySize: 15.78GiB deviceMemoryBandwidth: 836.37GiB/s
2020-06-26 20:11:18.005699: I tensorflow/stream_executor/platform/default/dso_loader.cc:44] Successfully opened dynamic library libcudart.so.10.1
2020-06-26 20:11:18.007320: I tensorflow/stream_executor/platform/default/dso_loader.cc:44] Successfully opened dynamic library libcublas.so.10
2020-06-26 20:11:18.008954: I tensorflow/stream_executor/platform/default/dso_loader.cc:44] Successfully opened dynamic library libcufft.so.10
2020-06-26 20:11:18.009252: I tensorflow/stream_executor/platform/default/dso_loader.cc:44] Successfully opened dynamic library libcurand.so.10
2020-06-26 20:11:18.011009: I tensorflow/stream_executor/platform/default/dso_loader.cc:44] Successfully opened dynamic library libcusolver.so.10
2020-06-26 20:11:18.012042: I tensorflow/stream_executor/platform/default/dso_loader.cc:44] Successfully opened dynamic library libcusparse.so.10
2020-06-26 20:11:18.015805: I tensorflow/stream_executor/platform/default/dso_loader.cc:44] Successfully opened dynamic library libcudnn.so.7
2020-06-26 20:11:18.015918: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:981] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2020-06-26 20:11:18.016256: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:981] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2020-06-26 20:11:18.016537: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1703] Adding visible gpu devices: 0
2020-06-26 20:11:18.016792: I tensorflow/core/platform/cpu_feature_guard.cc:143] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2 AVX512F FMA
2020-06-26 20:11:18.023493: I tensorflow/core/platform/profile_utils/cpu_utils.cc:102] CPU Frequency: 2000160000 Hz
2020-06-26 20:11:18.023944: I tensorflow/compiler/xla/service/service.cc:168] XLA service 0x7f90b4000b20 initialized for platform Host (this does not guarantee that XLA will be used). Devices:
2020-06-26 20:11:18.023968: I tensorflow/compiler/xla/service/service.cc:176]   StreamExecutor device (0): Host, Default Version
2020-06-26 20:11:18.109693: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:981] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2020-06-26 20:11:18.110127: I tensorflow/compiler/xla/service/service.cc:168] XLA service 0x50a6aa0 initialized for platform CUDA (this does not guarantee that XLA will be used). Devices:
2020-06-26 20:11:18.110164: I tensorflow/compiler/xla/service/service.cc:176]   StreamExecutor device (0): Tesla V100-SXM2-16GB, Compute Capability 7.0
2020-06-26 20:11:18.110378: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:981] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2020-06-26 20:11:18.110754: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1561] Found device 0 with properties: 
pciBusID: 0000:00:05.0 name: Tesla V100-SXM2-16GB computeCapability: 7.0
coreClock: 1.53GHz coreCount: 80 deviceMemorySize: 15.78GiB deviceMemoryBandwidth: 836.37GiB/s
2020-06-26 20:11:18.110847: I tensorflow/stream_executor/platform/default/dso_loader.cc:44] Successfully opened dynamic library libcudart.so.10.1
2020-06-26 20:11:18.110880: I tensorflow/stream_executor/platform/default/dso_loader.cc:44] Successfully opened dynamic library libcublas.so.10
2020-06-26 20:11:18.110900: I tensorflow/stream_executor/platform/default/dso_loader.cc:44] Successfully opened dynamic library libcufft.so.10
2020-06-26 20:11:18.110915: I tensorflow/stream_executor/platform/default/dso_loader.cc:44] Successfully opened dynamic library libcurand.so.10
2020-06-26 20:11:18.110928: I tensorflow/stream_executor/platform/default/dso_loader.cc:44] Successfully opened dynamic library libcusolver.so.10
2020-06-26 20:11:18.110942: I tensorflow/stream_executor/platform/default/dso_loader.cc:44] Successfully opened dynamic library libcusparse.so.10
2020-06-26 20:11:18.110955: I tensorflow/stream_executor/platform/default/dso_loader.cc:44] Successfully opened dynamic library libcudnn.so.7
2020-06-26 20:11:18.111039: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:981] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2020-06-26 20:11:18.111447: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:981] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2020-06-26 20:11:18.111778: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1703] Adding visible gpu devices: 0
2020-06-26 20:11:18.111863: I tensorflow/stream_executor/platform/default/dso_loader.cc:44] Successfully opened dynamic library libcudart.so.10.1
2020-06-26 20:11:18.112951: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1102] Device interconnect StreamExecutor with strength 1 edge matrix:
2020-06-26 20:11:18.112979: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1108]      0 
2020-06-26 20:11:18.112987: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1121] 0:   N 
2020-06-26 20:11:18.113130: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:981] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2020-06-26 20:11:18.113540: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:981] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2020-06-26 20:11:18.113914: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1247] Created TensorFlow device (/job:localhost/replica:0/task:0/device:GPU:0 with 69 MB memory) -> physical GPU (device: 0, name: Tesla V100-SXM2-16GB, pci bus id: 0000:00:05.0, compute capability: 7.0)
WARNING:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow/python/tools/saved_model_cli.py:443: load (from tensorflow.python.saved_model.loader_impl) is deprecated and will be removed in a future version.
Instructions for updating:
This function will only be available through the v1 compatibility library as tf.compat.v1.saved_model.loader.load or tf.compat.v1.saved_model.load. There will be a new function for importing SavedModels in Tensorflow 2.0.
INFO:tensorflow:Restoring parameters from /tmp/module_with_multiple_signatures/variables/variables
2020-06-26 20:11:18.143166: I tensorflow/stream_executor/cuda/cuda_driver.cc:763] failed to allocate 69.44M (72810496 bytes) from device: CUDA_ERROR_OUT_OF_MEMORY: out of memory
Result for output key output_0:
3.0
2020-06-26 20:11:20.049231: I tensorflow/stream_executor/platform/default/dso_loader.cc:44] Successfully opened dynamic library libcuda.so.1
2020-06-26 20:11:20.055872: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:981] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2020-06-26 20:11:20.056238: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1561] Found device 0 with properties: 
pciBusID: 0000:00:05.0 name: Tesla V100-SXM2-16GB computeCapability: 7.0
coreClock: 1.53GHz coreCount: 80 deviceMemorySize: 15.78GiB deviceMemoryBandwidth: 836.37GiB/s
2020-06-26 20:11:20.056453: I tensorflow/stream_executor/platform/default/dso_loader.cc:44] Successfully opened dynamic library libcudart.so.10.1
2020-06-26 20:11:20.058110: I tensorflow/stream_executor/platform/default/dso_loader.cc:44] Successfully opened dynamic library libcublas.so.10
2020-06-26 20:11:20.059838: I tensorflow/stream_executor/platform/default/dso_loader.cc:44] Successfully opened dynamic library libcufft.so.10
2020-06-26 20:11:20.060156: I tensorflow/stream_executor/platform/default/dso_loader.cc:44] Successfully opened dynamic library libcurand.so.10
2020-06-26 20:11:20.061948: I tensorflow/stream_executor/platform/default/dso_loader.cc:44] Successfully opened dynamic library libcusolver.so.10
2020-06-26 20:11:20.063004: I tensorflow/stream_executor/platform/default/dso_loader.cc:44] Successfully opened dynamic library libcusparse.so.10
2020-06-26 20:11:20.066778: I tensorflow/stream_executor/platform/default/dso_loader.cc:44] Successfully opened dynamic library libcudnn.so.7
2020-06-26 20:11:20.066890: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:981] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2020-06-26 20:11:20.067243: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:981] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2020-06-26 20:11:20.067515: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1703] Adding visible gpu devices: 0
2020-06-26 20:11:20.067763: I tensorflow/core/platform/cpu_feature_guard.cc:143] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2 AVX512F FMA
2020-06-26 20:11:20.074413: I tensorflow/core/platform/profile_utils/cpu_utils.cc:102] CPU Frequency: 2000160000 Hz
2020-06-26 20:11:20.074969: I tensorflow/compiler/xla/service/service.cc:168] XLA service 0x7f2210000b20 initialized for platform Host (this does not guarantee that XLA will be used). Devices:
2020-06-26 20:11:20.074994: I tensorflow/compiler/xla/service/service.cc:176]   StreamExecutor device (0): Host, Default Version
2020-06-26 20:11:20.159124: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:981] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2020-06-26 20:11:20.159554: I tensorflow/compiler/xla/service/service.cc:168] XLA service 0x546f610 initialized for platform CUDA (this does not guarantee that XLA will be used). Devices:
2020-06-26 20:11:20.159590: I tensorflow/compiler/xla/service/service.cc:176]   StreamExecutor device (0): Tesla V100-SXM2-16GB, Compute Capability 7.0
2020-06-26 20:11:20.159780: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:981] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2020-06-26 20:11:20.160101: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1561] Found device 0 with properties: 
pciBusID: 0000:00:05.0 name: Tesla V100-SXM2-16GB computeCapability: 7.0
coreClock: 1.53GHz coreCount: 80 deviceMemorySize: 15.78GiB deviceMemoryBandwidth: 836.37GiB/s
2020-06-26 20:11:20.160164: I tensorflow/stream_executor/platform/default/dso_loader.cc:44] Successfully opened dynamic library libcudart.so.10.1
2020-06-26 20:11:20.160183: I tensorflow/stream_executor/platform/default/dso_loader.cc:44] Successfully opened dynamic library libcublas.so.10
2020-06-26 20:11:20.160197: I tensorflow/stream_executor/platform/default/dso_loader.cc:44] Successfully opened dynamic library libcufft.so.10
2020-06-26 20:11:20.160212: I tensorflow/stream_executor/platform/default/dso_loader.cc:44] Successfully opened dynamic library libcurand.so.10
2020-06-26 20:11:20.160227: I tensorflow/stream_executor/platform/default/dso_loader.cc:44] Successfully opened dynamic library libcusolver.so.10
2020-06-26 20:11:20.160242: I tensorflow/stream_executor/platform/default/dso_loader.cc:44] Successfully opened dynamic library libcusparse.so.10
2020-06-26 20:11:20.160258: I tensorflow/stream_executor/platform/default/dso_loader.cc:44] Successfully opened dynamic library libcudnn.so.7
2020-06-26 20:11:20.160319: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:981] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2020-06-26 20:11:20.160635: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:981] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2020-06-26 20:11:20.160957: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1703] Adding visible gpu devices: 0
2020-06-26 20:11:20.161024: I tensorflow/stream_executor/platform/default/dso_loader.cc:44] Successfully opened dynamic library libcudart.so.10.1
2020-06-26 20:11:20.161997: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1102] Device interconnect StreamExecutor with strength 1 edge matrix:
2020-06-26 20:11:20.162021: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1108]      0 
2020-06-26 20:11:20.162029: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1121] 0:   N 
2020-06-26 20:11:20.162148: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:981] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2020-06-26 20:11:20.162477: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:981] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2020-06-26 20:11:20.162778: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1247] Created TensorFlow device (/job:localhost/replica:0/task:0/device:GPU:0 with 69 MB memory) -> physical GPU (device: 0, name: Tesla V100-SXM2-16GB, pci bus id: 0000:00:05.0, compute capability: 7.0)
WARNING:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow/python/tools/saved_model_cli.py:443: load (from tensorflow.python.saved_model.loader_impl) is deprecated and will be removed in a future version.
Instructions for updating:
This function will only be available through the v1 compatibility library as tf.compat.v1.saved_model.loader.load or tf.compat.v1.saved_model.load. There will be a new function for importing SavedModels in Tensorflow 2.0.
INFO:tensorflow:Restoring parameters from /tmp/module_with_multiple_signatures/variables/variables
2020-06-26 20:11:20.191890: I tensorflow/stream_executor/cuda/cuda_driver.cc:763] failed to allocate 69.44M (72810496 bytes) from device: CUDA_ERROR_OUT_OF_MEMORY: out of memory
Result for output key output_0:
3.0

가져온 모델 미세 튜닝하기

변수 객체가 사용 가능하므로 imported 함수를 통해 역전파할 수 있습니다.

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"는 5로 수렴, "loss"는 0으로 수렴
  print("loss={:.2f} v={:.2f}".format(train_step(), imported.v.numpy()))
loss=36.00 v=3.20
loss=12.96 v=3.92
loss=4.67 v=4.35
loss=1.68 v=4.61
loss=0.60 v=4.77
loss=0.22 v=4.86
loss=0.08 v=4.92
loss=0.03 v=4.95
loss=0.01 v=4.97
loss=0.00 v=4.98

SavedModel의 제어 흐름

tf.function에 들어갈 수 있는 것은 모두 SavedModel에 들어갈 수 있습니다. AutoGraph를 사용하면 Tensor에 의존하는 조건부 논리를 파이썬 제어 흐름으로 표현할 수 있습니다.

@tf.function(input_signature=[tf.TensorSpec([], tf.int32)])
def control_flow(x):
  if x < 0:
    tf.print("유효하지 않음!")
  else:
    tf.print(x % 3)

to_export = tf.Module()
to_export.control_flow = control_flow
tf.saved_model.save(to_export, "/tmp/control_flow")
INFO:tensorflow:Assets written to: /tmp/control_flow/assets

imported = tf.saved_model.load("/tmp/control_flow")
imported.control_flow(tf.constant(-1))  # 유효하지 않음!
imported.control_flow(tf.constant(2))   # 2
imported.control_flow(tf.constant(3))   # 0
유효하지 않음!
2
0

추정기(Estimator)의 SavedModel

추정기는 tf.Estimator.export_saved_model을 통해 SavedModel을 내보냅니다. 자세한 내용은 Estimator 가이드를 참조하십시오.

input_column = tf.feature_column.numeric_column("x")
estimator = tf.estimator.LinearClassifier(feature_columns=[input_column])

def input_fn():
  return tf.data.Dataset.from_tensor_slices(
    ({"x": [1., 2., 3., 4.]}, [1, 1, 0, 0])).repeat(200).shuffle(64).batch(16)
estimator.train(input_fn)

serving_input_fn = tf.estimator.export.build_parsing_serving_input_receiver_fn(
  tf.feature_column.make_parse_example_spec([input_column]))
export_path = estimator.export_saved_model(
  "/tmp/from_estimator/", serving_input_fn)
INFO:tensorflow:Using default config.
WARNING:tensorflow:Using temporary folder as model directory: /tmp/tmpqj83sz7g
INFO:tensorflow:Using config: {'_model_dir': '/tmp/tmpqj83sz7g', '_tf_random_seed': None, '_save_summary_steps': 100, '_save_checkpoints_steps': None, '_save_checkpoints_secs': 600, '_session_config': allow_soft_placement: true
graph_options {
  rewrite_options {
    meta_optimizer_iterations: ONE
  }
}
, '_keep_checkpoint_max': 5, '_keep_checkpoint_every_n_hours': 10000, '_log_step_count_steps': 100, '_train_distribute': None, '_device_fn': None, '_protocol': None, '_eval_distribute': None, '_experimental_distribute': None, '_experimental_max_worker_delay_secs': None, '_session_creation_timeout_secs': 7200, '_service': None, '_cluster_spec': ClusterSpec({}), '_task_type': 'worker', '_task_id': 0, '_global_id_in_cluster': 0, '_master': '', '_evaluation_master': '', '_is_chief': True, '_num_ps_replicas': 0, '_num_worker_replicas': 1}
WARNING:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow/python/training/training_util.py:236: Variable.initialized_value (from tensorflow.python.ops.variables) is deprecated and will be removed in a future version.
Instructions for updating:
Use Variable.read_value. Variables in 2.X are initialized automatically both in eager and graph (inside tf.defun) contexts.
INFO:tensorflow:Calling model_fn.
WARNING:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow/python/feature_column/feature_column_v2.py:540: Layer.add_variable (from tensorflow.python.keras.engine.base_layer_v1) is deprecated and will be removed in a future version.
Instructions for updating:
Please use `layer.add_weight` method instead.
WARNING:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow/python/keras/optimizer_v2/ftrl.py:144: calling Constant.__init__ (from tensorflow.python.ops.init_ops) with dtype is deprecated and will be removed in a future version.
Instructions for updating:
Call initializer instance with the dtype argument instead of passing it to the constructor
INFO:tensorflow:Done calling model_fn.
INFO:tensorflow:Create CheckpointSaverHook.
INFO:tensorflow:Graph was finalized.
INFO:tensorflow:Running local_init_op.
INFO:tensorflow:Done running local_init_op.
INFO:tensorflow:Calling checkpoint listeners before saving checkpoint 0...
INFO:tensorflow:Saving checkpoints for 0 into /tmp/tmpqj83sz7g/model.ckpt.
INFO:tensorflow:Calling checkpoint listeners after saving checkpoint 0...
INFO:tensorflow:loss = 0.6931472, step = 0
INFO:tensorflow:Calling checkpoint listeners before saving checkpoint 50...
INFO:tensorflow:Saving checkpoints for 50 into /tmp/tmpqj83sz7g/model.ckpt.
INFO:tensorflow:Calling checkpoint listeners after saving checkpoint 50...
INFO:tensorflow:Loss for final step: 0.39805028.
INFO:tensorflow:Calling model_fn.
INFO:tensorflow:Done calling model_fn.
WARNING:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow/python/saved_model/signature_def_utils_impl.py:145: build_tensor_info (from tensorflow.python.saved_model.utils_impl) is deprecated and will be removed in a future version.
Instructions for updating:
This function will only be available through the v1 compatibility library as tf.compat.v1.saved_model.utils.build_tensor_info or tf.compat.v1.saved_model.build_tensor_info.
INFO:tensorflow:Signatures INCLUDED in export for Classify: ['serving_default', 'classification']
INFO:tensorflow:Signatures INCLUDED in export for Regress: ['regression']
INFO:tensorflow:Signatures INCLUDED in export for Predict: ['predict']
INFO:tensorflow:Signatures INCLUDED in export for Train: None
INFO:tensorflow:Signatures INCLUDED in export for Eval: None
INFO:tensorflow:Restoring parameters from /tmp/tmpqj83sz7g/model.ckpt-50
INFO:tensorflow:Assets added to graph.
INFO:tensorflow:No assets to write.
INFO:tensorflow:SavedModel written to: /tmp/from_estimator/temp-1593202281/saved_model.pb

이 SavedModel은 텐서플로 서빙에 배포하는 데 유용한 직렬화된 tf.Example 프로토콜 버퍼를 사용합니다. 그러나 tf.saved_model.load로 불러오고 파이썬에서 실행할 수도 있습니다.

imported = tf.saved_model.load(export_path)

def predict(x):
  example = tf.train.Example()
  example.features.feature["x"].float_list.value.extend([x])
  return imported.signatures["predict"](
    examples=tf.constant([example.SerializeToString()]))
print(predict(1.5))
print(predict(3.5))
{'logits': <tf.Tensor: shape=(1, 1), dtype=float32, numpy=array([[0.32275462]], dtype=float32)>, 'class_ids': <tf.Tensor: shape=(1, 1), dtype=int64, numpy=array([[1]])>, 'classes': <tf.Tensor: shape=(1, 1), dtype=string, numpy=array([[b'1']], dtype=object)>, 'all_class_ids': <tf.Tensor: shape=(1, 2), dtype=int32, numpy=array([[0, 1]], dtype=int32)>, 'all_classes': <tf.Tensor: shape=(1, 2), dtype=string, numpy=array([[b'0', b'1']], dtype=object)>, 'logistic': <tf.Tensor: shape=(1, 1), dtype=float32, numpy=array([[0.57999545]], dtype=float32)>, 'probabilities': <tf.Tensor: shape=(1, 2), dtype=float32, numpy=array([[0.42000458, 0.57999545]], dtype=float32)>}
{'logits': <tf.Tensor: shape=(1, 1), dtype=float32, numpy=array([[-1.2967203]], dtype=float32)>, 'class_ids': <tf.Tensor: shape=(1, 1), dtype=int64, numpy=array([[0]])>, 'classes': <tf.Tensor: shape=(1, 1), dtype=string, numpy=array([[b'0']], dtype=object)>, 'all_class_ids': <tf.Tensor: shape=(1, 2), dtype=int32, numpy=array([[0, 1]], dtype=int32)>, 'all_classes': <tf.Tensor: shape=(1, 2), dtype=string, numpy=array([[b'0', b'1']], dtype=object)>, 'logistic': <tf.Tensor: shape=(1, 1), dtype=float32, numpy=array([[0.21471752]], dtype=float32)>, 'probabilities': <tf.Tensor: shape=(1, 2), dtype=float32, numpy=array([[0.78528255, 0.2147175 ]], dtype=float32)>}

tf.estimator.export.build_server_input_receiver_fn를 사용해 tf.train.Example이 아닌 원시 텐서를 가지는 입력 함수를 만들 수 있습니다.

C++에서 SavedModel 불러오기

SavedModel의 C++ 버전 loader는 SessionOptions 및 RunOptions을 허용하며 경로에서 SavedModel을 불러오는 API를 제공합니다. 불러 올 그래프와 연관된 태그를 지정해야합니다. 불러온 SavedModel의 버전은 SavedModelBundle이라고 하며 MetaGraphDef와 불러온 세션을 포함합니다.

const string export_dir = ...
SavedModelBundle bundle;
...
LoadSavedModel(session_options, run_options, export_dir, {kSavedModelTagTrain},
               &bundle);

SavedModel 커맨드 라인 인터페이스 세부 사항

SavedModel 커맨드 라인 인터페이스(CLI)를 사용하여 SavedModel을 검사하고 실행할 수 있습니다. 예를 들어, CLI를 사용하여 모델의 SignatureDef를 검사할 수 있습니다. CLI를 사용하면 입력 Tensor 크기 및 데이터 타입이 모델과 일치하는지 신속하게 확인할 수 있습니다. 또한 모델을 테스트하려는 경우 다양한 형식(예를 들어, 파이썬 표현식)의 샘플 입력을 전달하고 출력을 가져와 CLI를 사용하여 정확성 검사를 수행할 수 있습니다.

SavedModel CLI 설치하기

대체로 말하자면 다음 두 가지 방법 중 하나로 텐서플로를 설치할 수 있습니다:

  • 사전에 빌드된 텐서플로 바이너리로 설치
  • 소스 코드로 텐서플로 빌드

사전에 빌드된 텐서플로 바이너리를 통해 설치한 경우 SavedModel CLI가 이미 시스템 경로 bin\saved_model_cli에 설치되어 있습니다.

소스 코드에서 텐서플로를 빌드하는 경우 다음 추가 명령을 실행하여 saved_model_cli를 빌드해야 합니다:

$ bazel build tensorflow/python/tools:saved_model_cli

명령 개요

SavedModel CLI는 SavedModel의 MetaGraphDef에 대해 다음 두 명령어를 지원합니다:

  • SavedModel의 MetaGraphDef에 대한 계산을 보여주는 show
  • MetaGraphDef에 대한 계산을 실행하는 run

show 명령어

SavedModel은 태그 세트로 식별되는 하나 이상의 MetaGraphDef를 포함합니다. 모델을 텐서플로 서빙에 배포하려면, 각 모델에 어떤 종류의 SignatureDef가 있는지, 그리고 입력과 출력은 무엇인지 궁금할 수 있습니다. show 명령은 SavedModel의 내용을 계층적 순서로 검사합니다. 구문은 다음과 같습니다:

usage: saved_model_cli show [-h] --dir DIR [--all]
[--tag_set TAG_SET] [--signature_def SIGNATURE_DEF_KEY]

예를 들어, 다음 명령은 SavedModel에서 사용 가능한 모든 MetaGraphDef 태그 세트를 보여줍니다:

$ saved_model_cli show --dir /tmp/saved_model_dir
The given SavedModel contains the following tag-sets:
serve
serve, gpu

다음 명령은 MetaGraphDef에서 사용 가능한 모든 SignatureDef 키를 보여줍니다:

$ saved_model_cli show --dir /tmp/saved_model_dir --tag_set serve
The given SavedModel `MetaGraphDef` contains `SignatureDefs` with the
following keys:
SignatureDef key: "classify_x2_to_y3"
SignatureDef key: "classify_x_to_y"
SignatureDef key: "regress_x2_to_y3"
SignatureDef key: "regress_x_to_y"
SignatureDef key: "regress_x_to_y2"
SignatureDef key: "serving_default"

MetaGraphDef가 태그 세트에 여러 개의 태그를 가지고 있는 경우, 모든 태그를 지정해야 하며, 각 태그는 쉼표로 구분해야 합니다. 예를 들어:

$ saved_model_cli show --dir /tmp/saved_model_dir --tag_set serve,gpu

특정 SignatureDef에 대한 모든 입력 및 출력 텐서 정보(TensorInfo)를 표시하려면 SignatureDef 키를 signature_def 옵션으로 전달하십시오. 이것은 나중에 계산 그래프를 실행하기 위해 입력 텐서의 텐서 키 값, 크기 및 데이터 타입을 알고자 할 때 매우 유용합니다. 예를 들어:

$ saved_model_cli show --dir \
/tmp/saved_model_dir --tag_set serve --signature_def serving_default
The given SavedModel SignatureDef contains the following input(s):
  inputs['x'] tensor_info:
      dtype: DT_FLOAT
      shape: (-1, 1)
      name: x:0
The given SavedModel SignatureDef contains the following output(s):
  outputs['y'] tensor_info:
      dtype: DT_FLOAT
      shape: (-1, 1)
      name: y:0
Method name is: tensorflow/serving/predict

SavedModel에 사용 가능한 모든 정보를 표시하려면 --all 옵션을 사용하십시오. 예를 들어:

$ saved_model_cli show --dir /tmp/saved_model_dir --all
MetaGraphDef with tag-set: 'serve' contains the following SignatureDefs:

signature_def['classify_x2_to_y3']:
  The given SavedModel SignatureDef contains the following input(s):
    inputs['inputs'] tensor_info:
        dtype: DT_FLOAT
        shape: (-1, 1)
        name: x2:0
  The given SavedModel SignatureDef contains the following output(s):
    outputs['scores'] tensor_info:
        dtype: DT_FLOAT
        shape: (-1, 1)
        name: y3:0
  Method name is: tensorflow/serving/classify

...

signature_def['serving_default']:
  The given SavedModel SignatureDef contains the following input(s):
    inputs['x'] tensor_info:
        dtype: DT_FLOAT
        shape: (-1, 1)
        name: x:0
  The given SavedModel SignatureDef contains the following output(s):
    outputs['y'] tensor_info:
        dtype: DT_FLOAT
        shape: (-1, 1)
        name: y:0
  Method name is: tensorflow/serving/predict

run 명령어

run 명령을 호출하여 그래프 계산을 실행하고, 입력을 전달한 다음 출력을 표시(하고 선택적으로 저장)합니다. 구문은 다음과 같습니다:

usage: saved_model_cli run [-h] --dir DIR --tag_set TAG_SET --signature_def
                           SIGNATURE_DEF_KEY [--inputs INPUTS]
                           [--input_exprs INPUT_EXPRS]
                           [--input_examples INPUT_EXAMPLES] [--outdir OUTDIR]
                           [--overwrite] [--tf_debug]

run 명령은 입력을 모델에 전달하는 다음 세 가지 방법을 제공합니다:

  • --inputs 옵션을 사용하여 넘파이(numpy) ndarray를 파일에 전달할 수 있습니다.
  • --input_exprs 옵션을 사용하여 파이썬 표현식을 전달할 수 있습니다.
  • --input_examples 옵션을 사용하여 tf.train.Example을 전달할 수 있습니다.

--inputs

입력 데이터를 파일에 전달하려면, 다음과 같은 일반적인 형식을 가지는 --inputs 옵션을 지정합니다:

--inputs <INPUTS>

여기서 INPUTS는 다음 형식 중 하나입니다:

  • <input_key>=<filename>
  • <input_key>=<filename>[<variable_name>]

여러 개의 INPUTS를 전달할 수 있습니다. 여러 입력을 전달하는 경우 세미콜론을 사용하여 각 INPUTS를 구분하십시오.

saved_model_clinumpy.load를 사용하여 filename을 불러옵니다. filename은 다음 형식 중 하나일 수 있습니다:

  • .npy
  • .npz
  • 피클(pickle) 포맷

.npy 파일은 항상 넘파이 ndarray를 포함합니다. 그러므로 .npy 파일에서 불러올 때, 배열 내용이 지정된 입력 텐서에 직접 할당될 것입니다. 해당 .npy 파일과 함께 variable_name을 지정하면 variable_name이 무시되고 경고가 발생합니다.

.npz(zip) 파일에서 불러올 때, 입력 텐서 키로 불러올 zip 파일 내의 변수를 variable_name으로 선택적으로 지정할 수 있습니다. variable_name을 지정하지 않으면 SavedModel CLI는 zip 파일에 하나의 파일만 포함되어 있는지 확인하고 지정된 입력 텐서 키로 불러옵니다.

피클 파일에서 불러올 때, 대괄호 안에 variable_name이 지정되지 않았다면, 피클 파일 안에 있는 어떤 것이라도 지정된 입력 텐서 키로 전달될 것입니다. 그렇지 않으면, SavedModel CLI는 피클 파일에 딕셔너리가 저장되어 있다고 가정하고 variable_name에 해당하는 값이 사용됩니다.

--input_exprs

파이썬 표현식을 통해 입력을 전달하려면 --input_exprs 옵션을 지정하십시오. 이는 데이터 파일이 없어도 모델의 SignatureDef의 크기 및 데이터 타입과 일치하는 간단한 입력으로 모델의 정확성 검사를 하려는 경우 유용할 수 있습니다. 예를 들어:

`<input_key>=[[1],[2],[3]]`

파이썬 표현식 외에도 넘파이 함수를 전달할 수 있습니다. 예를 들어:

`<input_key>=np.ones((32,32,3))`

(numpy 모듈은 np로 이미 사용 가능하다고 가정합니다.)

--input_examples

tf.train.Example을 입력으로 전달하려면 --input_examples 옵션을 지정하십시오. 입력 키마다 딕셔너리의 리스트를 받습니다. 각 딕셔너리는 tf.train.Example의 인스턴스입니다. 딕셔너리 키는 기능이며 값은 각 기능의 값 리스트입니다. 예를 들어:

`<input_key>=[{"age":[22,24],"education":["BS","MS"]}]`

출력 저장

기본적으로, SavedModel CLI는 출력을 stdout에 기록합니다. --outdir 옵션으로 디렉토리를 전달하면, 지정된 디렉토리 안에 출력 텐서 키의 이름을 따라 .npy 파일로 출력이 저장됩니다.

기존 출력 파일을 덮어 쓰려면 --overwrite를 사용하십시오.