我能够训练我的模型并使用ML Engine进行预测,但我的结果不包含任何识别信息。这在一次提交一行进行预测时工作正常但在提交多行时我无法将预测连接回原始输入数据。 GCP documentation讨论了使用实例密钥,但我找不到任何使用实例密钥训练和预测的示例代码。采用GCP人口普查示例如何更新输入函数以通过图表传递唯一ID并在训练期间忽略它并返回带预测的唯一ID?或者,如果有人知道已经使用了有用的键的另一个例子,那么。
def serving_input_fn():
feature_placeholders = {
column.name: tf.placeholder(column.dtype, [None])
for column in INPUT_COLUMNS
}
features = {
key: tf.expand_dims(tensor, -1)
for key, tensor in feature_placeholders.items()
}
return input_fn_utils.InputFnOps(
features,
None,
feature_placeholders
)
def generate_input_fn(filenames,
num_epochs=None,
shuffle=True,
skip_header_lines=0,
batch_size=40):
def _input_fn():
files = tf.concat([
tf.train.match_filenames_once(filename)
for filename in filenames
], axis=0)
filename_queue = tf.train.string_input_producer(
files, num_epochs=num_epochs, shuffle=shuffle)
reader = tf.TextLineReader(skip_header_lines=skip_header_lines)
_, rows = reader.read_up_to(filename_queue, num_records=batch_size)
row_columns = tf.expand_dims(rows, -1)
columns = tf.decode_csv(row_columns, record_defaults=CSV_COLUMN_DEFAULTS)
features = dict(zip(CSV_COLUMNS, columns))
# Remove unused columns
for col in UNUSED_COLUMNS:
features.pop(col)
if shuffle:
features = tf.train.shuffle_batch(
features,
batch_size,
capacity=batch_size * 10,
min_after_dequeue=batch_size*2 + 1,
num_threads=multiprocessing.cpu_count(),
enqueue_many=True,
allow_smaller_final_batch=True
)
label_tensor = parse_label_column(features.pop(LABEL_COLUMN))
return features, label_tensor
return _input_fn
更新 我能够使用来自this answer below的建议代码我只需要稍微改变它来更新model_fn_ops中的输出备选,而不仅仅是预测字典。但是,这仅在我的服务输入函数针对类似于this的json输入进行编码时才有效。我的服务输入功能以前是在Census Core Sample中的CSV服务输入功能之后建模的。
我认为我的问题来自build_standardized_signature_def函数,甚至更多来自它所调用的is_classification_problem函数。使用csv服务函数的输入字典长度是1,所以这个逻辑最终使用classification_signature_def,它最终显示得分(结果实际上是probabilities)而输入字典长度更大使用json服务输入函数而不是1,而是使用包含所有输出的predict_signature_def。
答案 0 :(得分:8)
更新:在版本1.3中,贡献估计器(例如tf.contrib.learn.DNNClassifier)被更改为继承自核心估计器类tf.estimator.Estimator,与之前的版本不同,它将模型函数隐藏为私有类会员,因此您需要使用estimator.model_fn
替换下面解决方案中的estimator._model_fn
。
Josh的答案指向了Flowers示例,如果您想使用自定义估算器,这是一个很好的解决方案。如果您想坚持使用预设估算器(例如tf.contrib.learn.DNNClassifiers
),您可以将其包装在自定义估算器中,以增加对密钥的支持。 (注意:我认为罐装估算器在进入核心时可能会获得关键支持。)
KEY = 'key'
def key_model_fn_gen(estimator):
def _model_fn(features, labels, mode, params):
key = features.pop(KEY, None)
model_fn_ops = estimator.model_fn(
features=features, labels=labels, mode=mode, params=params)
if key:
model_fn_ops.predictions[KEY] = key
# This line makes it so the exported SavedModel will also require a key
model_fn_ops.output_alternatives[None][1][KEY] = key
return model_fn_ops
return _model_fn
my_key_estimator = tf.contrib.learn.Estimator(
model_fn=key_model_fn_gen(
tf.contrib.learn.DNNClassifier(model_dir=model_dir...)
),
model_dir=model_dir
)
然后可以使用 my_key_estimator
,就像使用DNNClassifier
一样,除了它会期望来自input_fns(预测,评估和培训)的名称为'key'
的功能。
EDIT2: 您还需要将相应的输入张量添加到您选择的预测输入函数中。例如,新的JSON服务输入fn将如下所示:
def json_serving_input_fn():
inputs = # ... input_dict as before
inputs[KEY] = tf.placeholder([None], dtype=tf.int64)
features = # .. feature dict made from input_dict as before
tf.contrib.learn.InputFnOps(features, None, inputs)
(在1.2和1.3之间略有不同,因为tf.contrib.learn.InputFnOps
被替换为tf.estimator.export.ServingInputReceiver
,并且在1.3)中不再需要填充张量为2级
然后ML Engine将发送一个名为“key”的张量,其中包含您的预测请求,该张量将传递给您的模型,并通过您的预测。
EDIT3:修改key_model_fn_gen
以支持忽略缺少的键值。
EDIT4:添加了预测键
答案 1 :(得分:4)
好问题。 Cloud ML Engine flowers sample通过使用tf.identity操作将字符串直接从输入传递到输出来执行此操作。以下是graph construction期间的相关行。
keys_placeholder = tf.placeholder(tf.string, shape=[None])
inputs = {
'key': keys_placeholder,
'image_bytes': tensors.input_jpeg
}
# To extract the id, we need to add the identity function.
keys = tf.identity(keys_placeholder)
outputs = {
'key': keys,
'prediction': tensors.predictions[0],
'scores': tensors.predictions[1]
}
对于批量预测,您需要在实例记录中插入“key”:“some_key_value”。对于在线预测,您可以使用JSON请求query上面的图形,如:
{'instances' : [
{'key': 'first_key', 'image_bytes' : {'b64': ...}},
{'key': 'second_key', 'image_bytes': {'b64': ...}}
]
}