检查点和导出的最佳模型之间有什么区别?
检查点至少是一个文件,其中包含在 特定时间点 获取 的特定图 的所有变量 的 值
。通过特定的图,我的意思是,当加载回检查点时,TensorFlow的作用是循环遍历图中定义的所有变量(
session正在运行的变量)并在检查点文件
中 搜索 与以下名称相同 的变量 图中的一个 。对于继续训练,这是理想的选择,因为您的图形在每次重新启动之间始终看起来相同。
导出的模型有不同的用途。导出模型的想法是,完成训练后,您希望获得一些可用于推理的内容,其中不包含所有特定于训练的(繁重)部分(一些示例:梯度计算,全局步骤变量,输入管道…)。而且,他的要点是关键,通常
,您向推理模型提供输入的方式与您用于训练的方式不同。
为了进行培训,您有一个输入管道,可将数据加载,预处理并将数据馈入网络。此输入管道不是模型本身的一部分,可能必须进行更改以进行推断。这是使用
Estimators进行操作时的关键点。
为什么需要服务输入接收器功能?
为了回答这个问题,我将首先退后一步。 为什么我们在所有广告中都需要输入函数,它们是什么?
TF
Estimator虽然可能不如其他模型网络直观,但它具有很大的优势:它们通过输入函数和模型函数将 模型 逻辑和 输入处理 逻辑明确分开。
模型分为三个不同阶段:训练,评估和推理。对于最常见的用例(或至少我目前能想到的所有用例),在TF中运行的 图
在所有这些阶段中都会有所不同。该图是输入预处理,模型以及在当前阶段运行模型所需的所有机械的组合。
希望有一些示例可以进一步阐明:训练时,您需要渐变以更新权重,运行训练步骤的优化器,监视事情进展的各种指标,从训练集中获取数据的输入管道等。
。评估时,您不需要渐变,而需要其他输入函数。当进行推理时,您所需要的只是模型的 前
部,输入函数也会有所不同(没有任何
tf.data.*东西,但通常只是一个占位符)。
Estimators中的每个阶段都有其自己的输入功能。您熟悉培训和评估的知识,推论只是您的
serving inputreceiver功能。在TF术语中,“服务”是打包训练后的模型并将其用于推理的过程(有一个完整的TensorFlow服务系统可用于大规模操作,但这超出了这个问题,您很可能根本就不需要它)。
是时候引用有关该主题的TF指南了:
在训练期间,input_fn()会摄取数据并准备将其供模型使用。同样,在服务时,a
serving_input_receiver_fn()
接受推理请求并为模型做好准备。此功能具有以下目的:
- 要将占位符添加到服务系统将随推理请求一起提供的图上。
- 添加将数据从输入格式转换为模型所需的特征张量所需的任何其他操作。
现在,服务输入功能规范取决于您计划将输入发送到图形的方式。
如果要将数据打包到(序列化的) tf.Example
(类似于TFRecord文件中的记录之一)中,则您的服务输入函数将具有字符串占位符(用于示例中的序列化字节),并且需要有关如何解释示例的规范,以便提取其数据。如果这是您想要的方式,我邀请您看一下上面链接的指南中的示例,它本质上显示了如何设置如何解释示例并解析示例以获取输入数据的规范。
相反,如果你在规划 直接将输入到网络的第一层 ,你 还
需要定义一个服务输入功能,但这次将只包含将被直接插入到网络的占位符。TF提供的功能可以做到这一点:
tf.estimator.export.build_raw_serving_input_receiver_fn。
那么, 您实际上是否需要编写自己的输入函数?
如果您需要的是占位符,否。只需使用
build_raw_serving_input_receiver_fn适当的参数即可。如果需要更高级的预处理,那么可以,您可能需要编写自己的预处理程序。在这种情况下,它将看起来像这样:
def serving_input_receiver_fn(): """For the sake of the example, let's assume your input to the network will be a 28x28 grayscale image that you'll then preprocess as needed""" input_images = tf.placeholder(dtype=tf.uint8, shape=[None, 28, 28, 1], name='input_images') # here you do all the operations you need on the images before they can be fed to the net (e.g., normalizing, reshaping, etc). Let's assume "images" is the resulting tensor. features = {'input_data' : images} # this is the dict that is then passed as "features" parameter to your model_fn receiver_tensors = {'input_data': input_images} # As far as I understand this is needed to map the input to a name you can retrieve later return tf.estimator.export.ServingInputReceiver(features, receiver_tensors)如何训练估算器,保存最佳模型,然后再加载?
您
model_fn采用
mode参数以便您有条件地构建模型。例如,在您的合作实验室中,您总是有一个优化器。这是错误的,因为它只应存在
mode ==tf.estimator.ModeKeys.TRAIN。
其次,您
build_fn的“输出”参数毫无意义。此函数应表示您的推理图,仅将您将在推理中馈入的张量作为输入,并返回logit
/预测。因此,我假设
outputs参数不存在,因为
build_fn签名应该存在
def build_fn(inputs, params)。
此外,您可以在定义
model_fn采取
features的张量。尽管可以做到这一点,但它既限制了您只能输入一个字符,又使serving_fn的事情变得复杂(您不能使用罐头形式,
build_raw_...而需要编写自己的形式并返回一个
TensorServingInputReceiver)。我将选择更通用的解决方案,并假设您的
model_fn情况如下(为简洁起见,我省略了变量范围,请根据需要添加):
def model_fn(features, labels, mode, params): my_input = features["input_data"] my_input.set_shape(I_SHAPE(params['batch_size'])) # output of the network onet = build_fn(features, params) predicted_labels = tf.nn.sigmoid(onet) predictions = {'labels': predicted_labels, 'logits': onet} export_outputs = { # see EstimatorSpec's docs to understand what this is and why it's necessary. 'labels': tf.estimator.export.PredictOutput(predicted_labels), 'logits': tf.estimator.export.PredictOutput(onet) } # NOTE: export_outputs can also be used to save models as "SavedModel"s during evaluation. # HERE is where the common part of the graph between training, inference and evaluation stops. if mode == tf.estimator.ModeKeys.PREDICT: # return early and avoid adding the rest of the graph that has nothing to do with inference. return tf.estimator.EstimatorSpec(mode=mode, predictions=predictions, export_outputs=export_outputs) labels.set_shape(O_SHAPE(params['batch_size'])) # calculate loss loss = loss_fn(onet, labels) # add optimizer only if we're training if mode == tf.estimator.ModeKeys.TRAIN: optimizer = tf.train.AdagradOptimizer(learning_rate=params['learning_rate']) # some metrics used both in training and eval mae = tf.metrics.mean_absolute_error(labels=labels, predictions=predicted_labels, name='mea_op') mse = tf.metrics.mean_squared_error(labels=labels, predictions=predicted_labels, name='mse_op') metrics = {'mae': mae, 'mse': mse} tf.summary.scalar('mae', mae[1]) tf.summary.scalar('mse', mse[1]) if mode == tf.estimator.ModeKeys.eval: return tf.estimator.EstimatorSpec(mode, loss=loss, eval_metric_ops=metrics, predictions=predictions, export_outputs=export_outputs) if mode == tf.estimator.ModeKeys.TRAIN: train_op = optimizer.minimize(loss, global_step=tf.train.get_global_step()) return tf.estimator.EstimatorSpec(mode, loss=loss, train_op=train_op, eval_metric_ops=metrics, predictions=predictions, export_outputs=export_outputs)现在,在调用
train_and_evaluate完成后,要设置导出部分:
1)定义您的服务输入功能:
serving_fn = tf.estimator.export.build_raw_serving_input_receiver_fn( {'input_data':tf.placeholder(tf.float32, [None,#YOUR_INPUT_SHAPE_HERE (without batch size)#])})2)将模型导出到某个文件夹
est.export_savedmodel('my_directory_for_saved_models', serving_fn)这会将估算器的 当前 状态保存到您指定的任何位置。如果需要特定的检查点,请在调用之前加载它
export_savedmodel。这将在“
my_directory_for_saved_models”中保存一个 预测 图,其中包含调用导出函数时估算器具有的训练参数。
最后,您可能不希望冻结图形(查找
freeze_graph.py)并对其进行优化以进行推理(查找
optimize_for_inference.py和/或
transform_graph),以获得冻结的
*.pb文件,然后可以根据需要加载并用于推理。
编辑:在更新中为新问题添加答案
边注:
我的“目标”(促使我提出这个问题)是尝试建立一个可重用的培训网络框架,以便我可以通过一个不同的build_fn并继续(加上具有导出模型的生活质量,提早停止等)。
。
如果可以的话,请务必将其发布在GitHub上的某个地方并将其链接到我。我一直在尝试使同一件事开始并运行一段时间,结果并不像我希望的那样好。
问题1:
换句话说,我的理解(可能是错误的)是,tf Example / SequenceExample的要点是存储一个随时可用的完整奇异数据实体-
除了从TFRecord文件读取以外,不需要其他处理。
实际上,通常不是这种情况(尽管 从理论上讲
,您的方法也完全可以)。您可以将TFRecords视为一种(详细记录的方式)以紧凑的方式存储数据集。例如,对于图像数据集,记录通常包含 压缩的
图像数据(如组成jpeg /
png文件的字节),其标签和一些元信息。然后,输入管道读取一条记录,对其进行解码,根据需要对其进行预处理,然后将其馈送到网络。当然,您可以在生成TFRecord数据集之前移动解码和预处理,并在示例中存储随时可提供的数据,但是数据集的规模将非常庞大。
特定的预处理管道是一个在阶段之间进行更改的示例(例如,您可以在训练管道中进行数据扩充,而在其他管道中则没有)。当然,在某些情况下,这些管道是相同的,但总的来说,这是不正确的。
关于一旁:
“评估时,您不需要渐变,而需要其他输入函数。”,唯一的区别(至少就我而言)是您读取的文件?
在您的情况下可能是这样。但是,再次假设您使用的是数据增强:您需要在eval期间将其禁用(或者更好的是完全不使用它),这会改变您的管道。
问题2:如果我使用记录训练模型并只想推断密集的张量怎么办?
这就是为什么您将管道与模型分开的原因。该模型将张量作为输入并对其进行操作。张量是占位符,还是将子图从Example转换为张量的子图的输出,这是属于框架的细节,而不是模型本身。
分割点是模型输入。该模型期望张量(或更普遍的情况下是
name:tensor项目的决定)作为输入,并使用它来构建其计算图。输入的来源由输入函数决定,但是只要所有输入函数的输出具有相同的接口,就可以根据需要交换输入,并且该模型将简单地获取并使用它。
因此,回顾一下,假设您使用“示例”进行训练/评估并使用密集张量进行预测,那么您的“训练”和“评估”输入函数将建立一个管道,该管道从某处读取示例,将其解码为张量,然后将其返回给模型以用作输入。另一方面,您的预测输入函数只是为模型的每个输入设置一个占位符,然后将它们返回给模型,因为它假定您将把准备好要馈送到网络的数据放入占位符中。
问题3:
您将占位符作为的参数传递
build_raw_serving_input_receiver_fn,因此选择其名称:
tf.estimator.export.build_raw_serving_input_receiver_fn( {'images':tf.placeholder(tf.float32, [None,28,28,1], name='input_images')})问题4:
代码中有一个错误(我混淆了两行),字典的键应该是
input_data(我修改了上面的代码)。在字典的关键必须是
您用来检索从张的关键
features在你的
model_fn。在
model_fn第一行是:
my_input = features["input_data"]
因此关键是
'input_data'。根据输入的内容
receiver_tensor,我仍然不确定自己所扮演的角色,所以我的建议是尝试设置与输入不同的名称,
features然后检查该名称在何处显示。
问题5:
我不确定自己是否了解,我将在澄清后对其进行编辑



