Невозможно использовать основной Estimator с Predictor - PullRequest
0 голосов
/ 01 мая 2018

Я пользуюсь стандартными оценщиками и борюсь с плохой прогнозируемой производительностью, поэтому я пытаюсь использовать tf.contrib.predictor для улучшения производительности вывода. Я сделал этот минималистичный пример, чтобы воспроизвести мои проблемы:

import tensorflow as tf
from tensorflow.contrib import predictor

def serving_input_fn():
  x = tf.placeholder(dtype=tf.string, shape=[1], name='x')
  inputs = {'x': x }
  return tf.estimator.export.ServingInputReceiver(inputs, inputs)

input_feature_column = tf.feature_column.numeric_column('x', shape=[1])
estimator = tf.estimator.DNNRegressor(
    feature_columns=[input_feature_column],
    hidden_units=[10, 20, 10],
    model_dir="model_dir\\predictor-test")

estimator_predictor = predictor.from_estimator(estimator, serving_input_fn)

estimator_predictor({"inputs": ["1.0"]})

Это приводит к следующему исключению:

UnimplementedError (see above for traceback): Cast string to float is not supported
[[Node: dnn/input_from_feature_columns/input_layer/x/ToFloat = Cast[DstT=DT_FLOAT, SrcT=DT_STRING, _device="/job:localhost/replica:0/task:0/device:CPU:0"](dnn/input_from_feature_columns/input_layer/x/ExpandDims)]]

Я попытался использовать tf.estimator.export.TensorServingInputReceiver вместо ServingInputReceiver в моем serving_input_fn(), чтобы я мог скормить свою модель числовым тензором, который мне нужен:

def serving_input_fn():
  x = tf.placeholder(dtype=tf.float32, shape=[1], name='x')
  return tf.estimator.export.TensorServingInputReceiver(x, x)

но затем я получаю следующее исключение в моем predictor.from_estimator() звонке:

ValueError: features should be a dictionary of Tensors. Given type: <class 'tensorflow.python.framework.ops.Tensor'>

Есть идеи?

Ответы [ 3 ]

0 голосов
/ 07 мая 2018

Мое понимание всего этого не совсем верно, но я все заработал и, учитывая размер сообщества, я постараюсь поделиться тем, что я сделал.

Во-первых, я запускаю двоичные файлы tenorflow 1.5 с этим патчем , примененным вручную.

Точный код, который я запускаю, таков:

def serving_input_fn():
    x = tf.placeholder(dtype=tf.float32, shape=[3500], name='x')
    inputs = {'x': x }

    return tf.estimator.export.ServingInputReceiver(inputs, inputs)

estimator = tf.estimator.Estimator(
    model_fn=model_fn,
    model_dir="{}/model_dir_{}/model.ckpt-103712".format(script_dir, 3))

estimator_predictor = tf.contrib.predictor.from_estimator(
                            estimator, serving_input_fn)

p = estimator_predictor(
        {"x": np.array(sample.normalized.input_data)})

Мой случай немного отличается от вашего примера, потому что я использую собственный оценщик, но в вашем случае, я думаю, вы должны попробовать что-то вроде этого:

def serving_input_fn():
  x = tf.placeholder(dtype=tf.float32, shape=[1], name='x')
  inputs = {'x': x }

  return tf.estimator.export.ServingInputReceiver(inputs, inputs)

estimator = ...

estimator_predictor = tf.contrib.predictor.from_estimator(
                            estimator, serving_input_fn)

estimator_predictor({"x": [1.0]})
0 голосов
/ 09 мая 2018

Поработав над этим пару дней, я хочу поделиться тем, что я сделал. Следующий код также доступен из https://github.com/dage/tensorflow-estimator-predictor-example

TL; DR: предиктор лучше всего работает с пользовательскими оценщиками, а увеличение производительности огромно.

import tensorflow as tf
import numpy as np
import datetime
import time

FEATURES_RANK = 3   # The number of inputs
LABELS_RANK = 2     # The number of outputs

# Returns a numpy array of rank LABELS_RANK based on the features argument.
# Can be used when creating a training dataset.
def features_to_labels(features):
    sum_column = features.sum(1).reshape(features.shape[0], 1)
    labels = np.hstack((sum_column*i for i in range(1, LABELS_RANK+1)))
    return labels

def serving_input_fn():
    x = tf.placeholder(dtype=tf.float32, shape=[None, FEATURES_RANK], name='x')     # match dtype in input_fn
    inputs = {'x': x }
    return tf.estimator.export.ServingInputReceiver(inputs, inputs)

def model_fn(features, labels, mode):
    net = features["x"]         # input
    for units in [4, 8, 4]:     # hidden units
        net = tf.layers.dense(net, units=units, activation=tf.nn.relu)
        net = tf.layers.dropout(net, rate=0.1)
    output = tf.layers.dense(net, LABELS_RANK, activation=None)

    if mode == tf.estimator.ModeKeys.PREDICT:
        return tf.estimator.EstimatorSpec(mode, predictions=output, export_outputs={"out": tf.estimator.export.PredictOutput(output)})

    loss = tf.losses.mean_squared_error(labels, output)

    if mode == tf.estimator.ModeKeys.EVAL:
        return tf.estimator.EstimatorSpec(mode, loss=loss)

    optimizer = tf.train.AdagradOptimizer(learning_rate=0.1)
    train_op = optimizer.minimize(loss, global_step=tf.train.get_global_step())
    return tf.estimator.EstimatorSpec(mode, loss=loss, train_op=train_op)

# expecting a numpy array of shape (1, FEATURE_RANK) for constant_feature argument
def input_fn(num_samples, constant_feature = None, is_infinite = True):
    feature_values = np.full((num_samples, FEATURES_RANK), constant_feature) if isinstance(constant_feature, np.ndarray) else np.random.rand(num_samples, FEATURES_RANK)
    feature_values = np.float32(feature_values) # match dtype in serving_input_fn
    labels = features_to_labels(feature_values)
    dataset = tf.data.Dataset.from_tensors(({"x": feature_values}, labels))
    if is_infinite:
        dataset = dataset.repeat()
    return dataset.make_one_shot_iterator().get_next()

estimator = tf.estimator.Estimator(
    model_fn=model_fn,  
    model_dir="model_dir\\estimator-predictor-test-{date:%Y-%m-%d %H.%M.%S}".format(date=datetime.datetime.now()))

train = estimator.train(input_fn=lambda : input_fn(50), steps=500)
evaluate = estimator.evaluate(input_fn=lambda : input_fn(20), steps=1)

predictor = tf.contrib.predictor.from_estimator(estimator, serving_input_fn)

consistency_check_features = np.random.rand(1, FEATURES_RANK)
consistency_check_labels = features_to_labels(consistency_check_features)

num_calls_predictor = 100
predictor_input = {"x": consistency_check_features}
start_time_predictor = time.clock()
for i in range(num_calls_predictor):
    predictor_prediction = predictor(predictor_input)
delta_time_predictor = 1./num_calls_predictor*(time.clock() - start_time_predictor)

num_calls_estimator_predict = 10
estimator_input = lambda : input_fn(1, consistency_check_features, False)
start_time_estimator_predict = time.clock()
for i in range(num_calls_estimator_predict):
    estimator_prediction = list(estimator.predict(input_fn=estimator_input))
delta_time_estimator = 1./num_calls_estimator_predict*(time.clock() - start_time_estimator_predict)

print("{} --> {}\n  predictor={}\n  estimator={}.\n".format(consistency_check_features, consistency_check_labels, predictor_prediction, estimator_prediction))
print("Time used per estimator.predict() call: {:.5f}s, predictor(): {:.5f}s ==> predictor is {:.0f}x faster!".format(delta_time_estimator, delta_time_predictor, delta_time_estimator/delta_time_predictor))

На моем ноутбуке я получаю следующие результаты:

[[0.55424854 0.98057611 0.98604857]] --> [[2.52087322 5.04174644]]
  predictor={'output': array([[2.5221248, 5.049496 ]], dtype=float32)}
  estimator=[array([2.5221248, 5.049496 ], dtype=float32)].

Time used per estimator.predict() call: 0.30071s, predictor(): 0.00057s ==> predictor is 530x faster!
0 голосов
/ 01 мая 2018

ошибка в следующей строке:

estimator_predictor({"inputs": ["1.0"]})

пожалуйста, поставьте 1,0 из кавычек. В настоящее время это строка.

...