J'ai essayé de rechercher un bon exemple de base, mais il semble que la documentation et les exemples soient un peu dispersés pour ce sujet. Commençons donc avec un exemple de base: le tf.estimator .
Cet exemple particulier ne fait pas exporter un modèle, donc nous allons le faire (pas besoin pour le cas 1):
def serving_input_receiver_fn():
"""Build the serving inputs."""
# The outer dimension (None) allows us to batch up inputs for
# efficiency. However, it also means that if we want a prediction
# for a single instance, we'll need to wrap it in an outer list.
inputs = {"x": tf.placeholder(shape=[None, 4], dtype=tf.float32)}
return tf.estimator.export.ServingInputReceiver(inputs, inputs)
export_dir = classifier.export_savedmodel(
export_dir_base="/path/to/model",
serving_input_receiver_fn=serving_input_receiver_fn)
astérisque énorme sur ce code: il semble y avoir un bug dans TensorFlow 1.3 qui ne vous permet pas de faire l'exportation ci-dessus sur un estimateur "en conserve" (tel que DNNClassifier). Pour une solution de contournement, consultez la section «Annexe: solution de contournement».
Le code ci-dessous les références export_dir
(valeur de retour de l'étape d'exportation) à souligner qu'il est pas «/chemin/vers/modèle », mais plutôt un sous-répertoire de ce répertoire dont le nom est un horodatage.
Cas d'utilisation 1: Effectuer la prédiction dans le même processus que la formation
C'est une science-kit apprendre type d'expérience, et est déjà illustrée par l'échantillon. Par souci d'exhaustivité, vous appelez simplement predict
sur le modèle formé:
classifier.train(input_fn=train_input_fn, steps=2000)
# [...snip...]
predictions = list(classifier.predict(input_fn=predict_input_fn))
predicted_classes = [p["classes"] for p in predictions]
Cas d'utilisation 2: Charger un SavedModel en Python/Java/C++ et effectuer des prévisions
Python client
Peut-être la chose la plus facile à utiliser si vous voulez faire une prédiction en Python est SavedModelPredictor. Dans le programme Python qui utilisera le SavedModel
, nous avons besoin de code comme ceci:
from tensorflow.contrib import predictor
predict_fn = predictor.from_saved_model(export_dir)
predictions = predict_fn(
{"x": [[6.4, 3.2, 4.5, 1.5],
[5.8, 3.1, 5.0, 1.7]]})
print(predictions['scores'])
Client Java
package dummy;
import java.nio.FloatBuffer;
import java.util.Arrays;
import java.util.List;
import org.tensorflow.SavedModelBundle;
import org.tensorflow.Session;
import org.tensorflow.Tensor;
public class Client {
public static void main(String[] args) {
Session session = SavedModelBundle.load(args[0], "serve").session();
Tensor x =
Tensor.create(
new long[] {2, 4},
FloatBuffer.wrap(
new float[] {
6.4f, 3.2f, 4.5f, 1.5f,
5.8f, 3.1f, 5.0f, 1.7f
}));
// Doesn't look like Java has a good way to convert the
// input/output name ("x", "scores") to their underlying tensor,
// so we hard code them ("Placeholder:0", ...).
// You can inspect them on the command-line with saved_model_cli:
//
// $ saved_model_cli show --dir $EXPORT_DIR --tag_set serve --signature_def serving_default
final String xName = "Placeholder:0";
final String scoresName = "dnn/head/predictions/probabilities:0";
List<Tensor> outputs = session.runner()
.feed(xName, x)
.fetch(scoresName)
.run();
// Outer dimension is batch size; inner dimension is number of classes
float[][] scores = new float[2][3];
outputs.get(0).copyTo(scores);
System.out.println(Arrays.deepToString(scores));
}
}
C++ client
Vous voudrez probablement utiliser tensorflow::LoadSavedModel
avec Session
.
#include <unordered_set>
#include <utility>
#include <vector>
#include "tensorflow/cc/saved_model/loader.h"
#include "tensorflow/core/framework/tensor.h"
#include "tensorflow/core/public/session.h"
namespace tf = tensorflow;
int main(int argc, char** argv) {
const string export_dir = argv[1];
tf::SavedModelBundle bundle;
tf::Status load_status = tf::LoadSavedModel(
tf::SessionOptions(), tf::RunOptions(), export_dir, {"serve"}, &bundle);
if (!load_status.ok()) {
std::cout << "Error loading model: " << load_status << std::endl;
return -1;
}
// We should get the signature out of MetaGraphDef, but that's a bit
// involved. We'll take a shortcut like we did in the Java example.
const string x_name = "Placeholder:0";
const string scores_name = "dnn/head/predictions/probabilities:0";
auto x = tf::Tensor(tf::DT_FLOAT, tf::TensorShape({2, 4}));
auto matrix = x.matrix<float>();
matrix(0, 0) = 6.4;
matrix(0, 1) = 3.2;
matrix(0, 2) = 4.5;
matrix(0, 3) = 1.5;
matrix(0, 1) = 5.8;
matrix(0, 2) = 3.1;
matrix(0, 3) = 5.0;
matrix(0, 4) = 1.7;
std::vector<std::pair<string, tf::Tensor>> inputs = {{x_name, x}};
std::vector<tf::Tensor> outputs;
tf::Status run_status =
bundle.session->Run(inputs, {scores_name}, {}, &outputs);
if (!run_status.ok()) {
cout << "Error running session: " << run_status << std::endl;
return -1;
}
for (const auto& tensor : outputs) {
std::cout << tensor.matrix<float>() << std::endl;
}
}
Cas d'utilisation 3: Servir un modèle en utilisant tensorflow service
Exportation de modèles d'une manière prête à servir une Classification model exige que l'entrée soit un objet tf.Example
.Voici comment nous pourrions exporter un modèle pour tensorflow service:
def serving_input_receiver_fn():
"""Build the serving inputs."""
# The outer dimension (None) allows us to batch up inputs for
# efficiency. However, it also means that if we want a prediction
# for a single instance, we'll need to wrap it in an outer list.
example_bytestring = tf.placeholder(
shape=[None],
dtype=tf.string,
)
features = tf.parse_example(
example_bytestring,
tf.feature_column.make_parse_example_spec(feature_columns)
)
return tf.estimator.export.ServingInputReceiver(
features, {'examples': example_bytestring})
export_dir = classifier.export_savedmodel(
export_dir_base="/path/to/model",
serving_input_receiver_fn=serving_input_receiver_fn)
Le lecteur est renvoyé à tensorflow Au service de documentation pour plus d'instructions sur la façon de configurer tensorflow service, donc je vais seulement fournir le code client ici:
# Omitting a bunch of connection/initialization code...
# But at some point we end up with a stub whose lifecycle
# is generally longer than that of a single request.
stub = create_stub(...)
# The actual values for prediction. We have two examples in this
# case, each consisting of a single, multi-dimensional feature `x`.
# This data here is the equivalent of the map passed to the
# `predict_fn` in use case #2.
examples = [
tf.train.Example(
features=tf.train.Features(
feature={"x": tf.train.Feature(
float_list=tf.train.FloatList(value=[6.4, 3.2, 4.5, 1.5]))})),
tf.train.Example(
features=tf.train.Features(
feature={"x": tf.train.Feature(
float_list=tf.train.FloatList(value=[5.8, 3.1, 5.0, 1.7]))})),
]
# Build the RPC request.
predict_request = predict_pb2.PredictRequest()
predict_request.model_spec.name = "default"
predict_request.inputs["examples"].CopyFrom(
tensor_util.make_tensor_proto(examples, tf.float32))
# Perform the actual prediction.
stub.Predict(request, PREDICT_DEADLINE_SECS)
Notez que la clé, examples
, qui est référencé dans le predict_request.inputs
doit correspondre à la clé utilisée dans le serving_input_receiver_fn
au moment de l'exportation (voir le constructeur à ServingInputReceiver
dans ce code).
Annexe: Contourner Les exportations de modèles en conserve dans TF 1.3
Il semble y avoir un bug dans tensorflow 1.3 où les modèles en boîte n'exportent pas correctement pour le cas 2 (le problème n'existe pas pour " "estimateurs personnalisés"). Voici une solution de contournement qui enveloppe un DNNClassifier pour faire fonctionner les choses, en particulier pour l'exemple Iris:
# Build 3 layer DNN with 10, 20, 10 units respectively.
class Wrapper(tf.estimator.Estimator):
def __init__(self, **kwargs):
dnn = tf.estimator.DNNClassifier(**kwargs)
def model_fn(mode, features, labels):
spec = dnn._call_model_fn(features, labels, mode)
export_outputs = None
if spec.export_outputs:
export_outputs = {
"serving_default": tf.estimator.export.PredictOutput(
{"scores": spec.export_outputs["serving_default"].scores,
"classes": spec.export_outputs["serving_default"].classes})}
# Replace the 3rd argument (export_outputs)
copy = list(spec)
copy[4] = export_outputs
return tf.estimator.EstimatorSpec(mode, *copy)
super(Wrapper, self).__init__(model_fn, kwargs["model_dir"], dnn.config)
classifier = Wrapper(feature_columns=feature_columns,
hidden_units=[10, 20, 10],
n_classes=3,
model_dir="/tmp/iris_model")
Pouvez-vous commenter un peu plus sur l'environnement dans lequel vous souhaitez effectuer des prédictions? Voulez-vous juste écrire une application Python qui charge le modèle dans le même processus et effectue une prédiction? Voulez-vous exécuter votre propre service de production pour servir votre modèle? Voulez-vous utiliser un service géré dans le cloud? – rhaertel80
Maintenant, j'essaye d'écrire un script python pour charger le modèle et effectuer la prédiction. – nayan
[Exemple de fonction export_savedmodel] (https://stackoverflow.com/a/48329456/4268517) –