README.md
1# TensorFlow Inference Model Format
2
3WARNING: SessionBundle has been deprecated and is no longer supported. Switch to
4[SavedModel](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/python/saved_model/README.md)
5immediately.
6
7[TOC]
8
9## Overview
10
11This document describes the data formats and layouts for exporting
12[TensorFlow](https://www.tensorflow.org/) models for inference.
13
14These exports have the following properties:
15
16* Recoverable
17 * given an export the graph can easily be initialized and run
18* Hermetic
19 * an export directory is self-contained to facilitate distribution
20
21The TensorFlow `Saver` writes **checkpoints** (graph variables) while training
22so it can recover if it crashes. A TensorFlow Serving **export** contains a
23checkpoint with the current state of the graph variables along with a MetaGraph
24definition that's needed for serving.
25
26## Directory Structure
27
28~~~
29# Directory overview
3000000000/
31 assets/
32 export.meta
33 export-?????-of-?????
34~~~
35
36* `00000000` -- Export version
37 * Format `%08d`
38* `assets` -- Asset file directory
39 * Holds auxiliary files for the graph (e.g., vocabularies)
40* `export.meta` -- MetaGraph Definition
41 * Binary [`tensorflow::MetaGraphDef`](https://github.com/tensorflow/tensorflow/tree/master/tensorflow/core/protobuf/meta_graph.proto)
42* `export-?????-of-?????`
43 * A checkpoint of the Graph Variables
44 * Outputs from Python [`Saver`](https://github.com/tensorflow/tensorflow/tree/master/tensorflow/python/training/saver.py)
45 with `sharded=True`.
46
47## Exporting (Python code)
48
49The [`Exporter`](https://github.com/tensorflow/tensorflow/tree/master/tensorflow/contrib/session_bundle/exporter.py)
50class can be used to export a model in the above format from a TensorFlow Python
51binary.
52
53### Exporting TF.learn models
54
55TF.learn uses an
56[Exporter wrapper](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/contrib/learn/python/learn/utils/export.py)
57that can be used for building signatures. Use the `BaseEstimator.export`
58function to export your Estimator with a signature.
59
60## Importing (C++ code)
61
62The [`LoadSessionBundleFromPath`](https://github.com/tensorflow/tensorflow/tree/master/tensorflow/contrib/session_bundle/session_bundle.h)
63function can be used to create a `tensorflow::Session` and initialize it from an
64export. This function takes session options and the path to the export as
65arguments and returns a bundle of export data including a `tensorflow::Session`
66which can be run.
67
68## Signatures
69
70Graphs used for inference tasks typically have set of inputs and outputs used at
71inference time. We call this a 'Signature'.
72
73### Standard Signatures (standard usage)
74
75Graphs used for standard inference tasks have standard sets of inputs and
76outputs. For example, a graph used for a regression task has an input tensor for
77the data and an output tensor for the regression values. The signature mechanism
78makes it easy to identify the relevant input and output tensors for common graph
79applications.
80
81The [`Manifest`](https://github.com/tensorflow/tensorflow/tree/master/tensorflow/contrib/session_bundle/manifest.proto)
82contains a `Signature` message which contains the task specific inputs and
83outputs.
84
85~~~proto
86// A Signature specifies the inputs and outputs of commonly used graphs.
87message Signature {
88 oneof type {
89 RegressionSignature regression_signature = 1;
90 ClassificationSignature classification_signature = 2;
91 GenericSignature generic_signature = 3;
92 }
93};
94~~~
95
96A Standard Signature can be set at export time using the `Exporter` API.
97
98~~~python
99# Run an export.
100signature = exporter.classification_signature(input_tensor=input,
101 classes_tensor=output)
102export = exporter.Exporter(saver)
103export.init(sess.graph.as_graph_def(), default_graph_signature=signature)
104export.export(export_path, global_step_tensor, sess)
105~~~
106
107#### TF.learn signatures
108
109TF.learn models can use the `BaseEstimator.export` function directly to export.
110To specify a Signature, use the [Exporter wrapper](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/contrib/learn/python/learn/utils/export.py)
111helpers (e.g. `classification_signature_fn`).
112
113~~~python
114estimator = tf.contrib.learn.Estimator(...)
115...
116# Other possible parameters omitted for the sake of brevity.
117estimator.export(
118 export_path,
119 signature_fn=tf.contrib.learn.utils.export.classification_signature_fn)
120~~~
121
122#### Recovering signatures
123
124These can be recovered at serving time using utilities in [`signature.h`](https://github.com/tensorflow/tensorflow/tree/master/tensorflow/contrib/session_bundle/signature.h)
125
126~~~c++
127// Get the classification signature.
128ClassificationSignature signature;
129TF_CHECK_OK(GetClassificationSignature(bundle->meta_graph_def, &signature));
130
131// Run the graph.
132Tensor input_tensor = GetInputTensor();
133Tensor classes_tensor;
134Tensor scores_tensor;
135TF_CHECK_OK(RunClassification(signature, input_tensor, session, &classes_tensor,
136 &scores_tensor));
137~~~
138
139### Generic Signatures (custom or advanced usage)
140
141Generic Signatures enable fully custom usage of the `tensorflow::Session` API.
142They are recommended for when the Standard Signatures do not satisfy a
143particular use-case. A general example of when to use these is for a model
144taking a single input and generating multiple outputs performing different
145inferences.
146
147~~~proto
148// GenericSignature specifies a map from logical name to Tensor name.
149// Typical application of GenericSignature is to use a single GenericSignature
150// that includes all of the Tensor nodes and target names that may be useful at
151// serving, analysis or debugging time. The recommended name for this signature
152// is "generic_bindings".
153message GenericSignature {
154 map<string, TensorBinding> map = 1;
155};
156~~~
157
158Generic Signatures can be used to compliment a Standard Signature, for example
159to support debugging. Here is an example that includes the Standard regression
160Signature and a Generic Signature.
161
162~~~python
163named_tensor_bindings = {"logical_input_A": v0,
164 "logical_input_B": v1}
165signatures = {
166 "regression": exporter.regression_signature(input_tensor=v0,
167 output_tensor=v1),
168 "generic": exporter.generic_signature(named_tensor_bindings)}
169export = exporter.Exporter(saver)
170export.init(sess.graph.as_graph_def(), named_graph_signatures=signatures)
171export.export(export_path, global_step_tensor, sess)
172~~~
173
174Generic Signature does not differentiate between input and output tensors. It
175provides full flexibility to specify the input and output tensors you need.
176The benefit is preserving a mapping between names that you specify at export
177time (we call these the logical names), and the actual graph node names that may
178be less stable and/or auto-generated by TensorFlow.
179
180In [`signature.h`](https://github.com/tensorflow/tensorflow/tree/master/tensorflow/contrib/session_bundle/signature.h)
181note that the generic signature methods `BindGenericInputs` and
182`BindGenericNames` are doing simple string to string mapping as a convenience.
183These methods map from the names used at training time to actual names in the
184graph.
185
186The bound results from those methods can be used as inputs to
187`tensorflow::Session->Run()`. Specifically, the bound result
188`vector<pair<string, Tensor>>` from `BindGenericInputs` can be supplied as the
189first parameter `inputs` to `tensorflow::Session->Run()`. Similarly, the bound
190result `vector<string>` from `BindGenericNames`, can be mapped to
191`output_tensor_names` in the `tensorflow::Session->Run()` arguments. The next
192parameter, `target_node_names` is typically null at inference time. The last
193parameter `outputs` is for the results, which share the same order as the
194supplied `output_tensor_names`.
195
196## Custom Initialization
197
198Some graphs many require custom initialization after the variables have been
199restored. Such initialization, done through an arbitrary Op, can be added using
200the `Exporter` API. If set, `LoadSessionBundleFromPath` will automatically run
201the Op when restoring a `Session` following the loading of variables.
202
203## Assets
204
205In many cases we have Ops which depend on external files for initialization
206(such as vocabularies). These "assets" are not stored in the graph and are
207needed for both training and inference.
208
209In order to create hermetic exports these asset files need to be:
210
2111. copied to each export directory, and
2122. read when recovering a session from an export base directory.
213
214Copying assets to the export directory is handled with a callback mechanism.
215The callback function receives two parameters:
216
2171. the dictionary of source files to desired basename, and
2182. the export directory.
219The default callback uses `gfile.Copy` to perform the copy.
220
221The tensor that contains the filepath to be copied is specified by passing the
222collection of asset filepath tensor, which is usually extracted from the graph
223by `tf.get_collection(tf.GraphKeys.ASSET_FILEPATHS)`.
224
225~~~python
226# Run an export.
227export = exporter.Exporter(save)
228export.init(
229 sess.graph.as_graph_def(),
230 asset_collection=tf.get_collection(tf.GraphKeys.ASSET_FILEPATHS))
231export.export(export_path, global_step_tensor, sess)
232~~~
233
234Users can use their own callbacks as shown in the following example, with the
235requirement to keep the basename of the original files:
236
237~~~python
238def my_custom_copy_callback(files_to_copy, export_dir_path):
239 # Copy all source files (keys) in files_to_copy to export_dir_path using the
240 # corresponding basename (value).
241 ...
242
243# Run an export.
244export = exporter.Exporter(save)
245export.init(
246 sess.graph.as_graph_def(),
247 asset_collection=tf.get_collection(tf.GraphKeys.ASSET_FILEPATHS),
248 asset_callback=my_custom_copy_callback)
249export.export(export_path, global_step_tensor, sess)
250~~~
251
252`AssetFile` binds the name of a tensor in the graph to the name of a file
253within the assets directory. `LoadSessionBundleFromPath` will handle the base
254path and asset directory swap/concatenation such that the tensor is set with
255the fully qualified filename upon return.
256
257# Exporter Usage
258
259The typical workflow of model exporting is:
260
2611. Build model graph G.
2622. Train variables or load trained variables from checkpoint in session S.
2633. [Optional] Build inference graph I.
2644. Export G.
265
266The Exporter should be used as follows:
267
2681. The Saver used in Exporter(saver) should be created within the context of G.
2692. Exporter.init() should be called within the context of G.
2703. Exporter.export() should be called using session S.
2714. If I is provided for Exporter.init(), an exact same Saver should be created
272 under I as the saver under G -- in the way that exact same Save/Restore ops
273 are created in both G and S.
274