我有一个自定义估算工具,我正在尝试在评估期间使用一些自定义指标。但是,每当我将这些指标添加到评估中时,通过eval_metric_ops,评估变得非常慢(比实际计算相同指标的培训慢得多)。如果我没有在那里添加指标,那么我只能在Tensorboard中查看培训而非评估的指标。
为自定义估算工具添加自定义指标的正确方法是什么,以便在评估期间保存。
这就是我所拥有的:
def compute_accuracy(preds, labels):
total = tf.shape(labels.values)[0]
preds = tf.sparse_to_dense(preds.indices, preds.dense_shape, preds.values, default_value=-1)
labels = tf.sparse_to_dense(labels.indices, labels.dense_shape, labels.values, default_value=-2)
r = tf.shape(labels)[0]
c = tf.minimum(tf.shape(labels)[1], tf.shape(preds)[1])
preds = tf.slice(preds, [0,0], [r,c])
labels = tf.slice(labels, [0,0], [r,c])
preds = tf.cast(preds, tf.int32)
labels = tf.cast(labels, tf.int32)
correct = tf.reduce_sum(tf.cast(tf.equal(preds, labels), tf.int32))
accuracy = tf.divide(correct, total)
return accuracy
In model_fn
edit_dist = tf.reduce_mean(tf.edit_distance(tf.cast(predicted_label[0], tf.int32), labels))
accuracy = compute_accuracy(predicted_label[0], labels)
tf.summary.scalar('edit_dist', edit_dist)
tf.summary.scalar('accuracy', accuracy)
metrics = {
'accuracy': tf.metrics.mean(accuracy),
'edit_dist':tf.metrics.mean(edit_dist),
}
if mode == tf.estimator.ModeKeys.EVAL:
return tf.estimator.EstimatorSpec(mode, loss=loss, eval_metric_ops=metrics)
根据要求,这是完整的模型和TfRecord Writer代码:
def crnn_model(features, labels, mode, params):
inputs = features['image']
print("INPUTS SHAPE", inputs.shape)
if mode == tf.estimator.ModeKeys.TRAIN:
batch_size = params['batch_size']
lr_initial = params['lr']
lr = tf.train.exponential_decay(lr_initial, global_step=tf.train.get_global_step(),
decay_steps=params['lr_decay_steps'], decay_rate=params['lr_decay_rate'],
staircase=True)
tf.summary.scalar('lr', lr)
else:
batch_size = params['test_batch_size']
with tf.variable_scope('crnn', reuse=False):
rnn_output, predicted_label, logits = CRNN(inputs, hidden_size=params['hidden_size'], batch_size=batch_size)
if mode == tf.estimator.ModeKeys.PREDICT:
predictions = {
'predicted_label': predicted_label,
'logits': logits,
}
return tf.estimator.EstimatorSpec(mode, predictions=predictions)
loss = tf.reduce_mean(tf.nn.ctc_loss(labels=labels, inputs=rnn_output,
sequence_length=23 * np.ones(batch_size),
ignore_longer_outputs_than_inputs=True))
edit_dist = tf.reduce_mean(tf.edit_distance(tf.cast(predicted_label[0], tf.int32), labels))
accuracy = compute_accuracy(predicted_label[0], labels)
metrics = {
'accuracy': tf.metrics.mean(accuracy),
'edit_dist':tf.metrics.mean(edit_dist),
}
tf.summary.scalar('loss', loss)
tf.summary.scalar('edit_dist', edit_dist)
tf.summary.scalar('accuracy', accuracy)
if mode == tf.estimator.ModeKeys.EVAL:
return tf.estimator.EstimatorSpec(mode, loss=loss, eval_metric_ops=metrics)
assert mode == tf.estimator.ModeKeys.TRAIN
update_ops = tf.get_collection(tf.GraphKeys.UPDATE_OPS)
with tf.control_dependencies(update_ops):
optimizer = tf.train.AdadeltaOptimizer(learning_rate=lr)
train_op = optimizer.minimize(loss=loss, global_step=tf.train.get_global_step())
return tf.estimator.EstimatorSpec(mode, loss=loss, train_op=train_op)
Tf Record Writer code
def _write_fn(self, out_file, image_list, label_list, mode):
writer = tf.python_io.TFRecordWriter(out_file)
N = len(image_list)
for i in range(N):
if (i % 1000) == 0:
print('%s Data: %d/%d records saved' % (mode, i,N))
sys.stdout.flush()
try:
#print('Try image: ', image_list[i])
image = load_image(image_list[i])
except (ValueError, AttributeError):
print('Ignoring image: ', image_list[i])
continue
label = label_list[i]
feature = {
'label': _int64_feature(label),
'image': _byte_feature(tf.compat.as_bytes(image.tostring()))
}
example = tf.train.Example(features=tf.train.Features(feature=feature))
writer.write(example.SerializeToString())
writer.close()
答案 0 :(得分:1)
在Estimator框架中,所有内容都发生在model_fn
,即您的crnn_model(features, labels, mode, params)
。这就是为什么这个函数有这么复杂的签名。
mode
参数表示是否要求进行培训,评估或预测。因此,如果您想在评估期间将其他摘要记录到tensorboard,您可以在if mode == tf.estimator.ModeKeys.EVAL
部分或if
中的任何model_fn
之外添加摘要。
我认为您的评估速度要慢得多,因为您的列车/评估的批量大小不同,并且评估批量可能会更小。 你表示情况并非如此。
仔细查看您的代码,并体验过相似的模型之后,我认为评估需要更长时间才能使用指标,因为其中一个指标是edit_distance()
,它是在CPU上按顺序实现的。在培训期间,此op
不是必需的,因此不会运行。
我的建议是,您使用相同的train()
和evaluate()
在不同的程序中运行model_fn()
和model_dir
。这样,train
无需等待evaluate
。并且evaluate
仅在必要时运行,即model_dir
中有新检查点时。如果您没有2个GPU,则可以在两个进程之间拆分GPU内存(使用带有gpu_memory_fraction=0.75
的自定义run-config进行训练)或者隐藏来自{{1}的GPU } evaluate()
环境变量