Я столкнулся с проблемой при попытке сохранить сводную информацию и показатели оценки, которые расположены слишком близко друг к другу в распределенном параметре.
Я пытался больше узнать о том, как сводки сохраняются при обучении и оценке модели распределенным способом. Определенно, есть вещи, которые я еще не обернул должным образом, но, насколько я понимаю, только мастер записывает резюме в указанный model_dir, и я думаю, что я понял, что проблема в том, что мастер запускает другую контрольную точку и прогон оценки, пока он еще выполняет предыдущую оценку?
Я видел упомянутое что-то, что может быть связано с документами tf.estimator.RunConfig API , поэтому я установил keep_checkpoint_max
на более высокое значение, но это не имело никакого значения ,
Когда я отправляю задание на gcloud ml-engine со следующими параметрами:
- 2 пс (n1-highmem-8)
- 2 рабочих (n1-highmem-8)
keep_checkpoint_max=10
save_checkpoint_steps=50
save_summary_steps=20
Мой train_and_eval()
код,
def train_and_eval(self, feature_provider, steps):
self._send_dist_data_to_comet(feature_provider, ["train", "test"])
self._initialize_estimator(feature_provider)
train_spec = tf.estimator.TrainSpec(
input_fn=lambda: self.train_input_fn(
tfrecords=feature_provider.train_tfrecords, params=self.params
),
max_steps=steps,
)
eval_spec = tf.estimator.EvalSpec(
input_fn=lambda: self.eval_input_fn(
tfrecords=feature_provider.test_tfrecords, params=self.params
),
steps=None,
throttle_secs=0,
)
tf.estimator.train_and_evaluate(
estimator=self._estimator,
train_spec=train_spec,
eval_spec=eval_spec,
)
Я установил throttle_secs=0
, чтобы убедиться, что никакие оценки не пропущены, я установил steps=400
, мои сводки по тензорной доске:
Таким образом, я полагаю, что он правильно начинает регистрировать сводки тренировок каждые 20 шагов (возможно, сводка на шаге 20 была перезаписана, так как первый - на шаге 40), но после первой контрольной точки практически ничего не записывается, пока тренировка не будет завершена и последний контрольный пункт и прогон оценки имеют место.
Код, который я использую для записи метрик на тензорную доску,
def scalars(model, features, labels, spec, params):
std_metrics = {
"accuracy": tf.metrics.accuracy(
labels=labels,
predictions=spec.predictions["class_ids"],
name="acc_op",
),
"mpc_accuracy": tf.metrics.mean_per_class_accuracy(
labels=labels,
predictions=spec.predictions["class_ids"],
num_classes=params["_n_out_classes"],
name="mpc_acc_op",
),
"auc": tf.metrics.auc(
labels=tf.one_hot(indices=labels, depth=params["_n_out_classes"]),
predictions=spec.predictions["probabilities"],
name="auc_op",
),
}
if spec.mode == ModeKeys.EVAL:
eval_metrics = spec.eval_metric_ops or {}
eval_metrics.update(std_metrics)
spec = spec._replace(eval_metric_ops=eval_metrics)
else:
tf.summary.scalar("loss", spec.loss)
tf.summary.scalar("accuracy", std_metrics["accuracy"][1])
tf.summary.scalar("auc", std_metrics["auc"][1])
return spec
Я работаю с несколькими моделями в своем проекте, поэтому я использую вышеописанную функцию вместе с декоратором для ввода кода в разные model_fns
.
Декоратор выглядит следующим образом (не уверен, насколько важен следующий код, но я решил, что для полноты картины его вставлю)
def attach(addons, modes=None, order="POST"):
def decorator(model_fn):
@wraps(model_fn)
def wrapper(self, features, labels, mode, params):
aux = self.aux_config # dict so i can enable/disable particular addons by name, in this case the addon would be 'scalars'
targets = modes or ["train", "eval", "predict"]
target_modes = [
{
"train": ModeKeys.TRAIN,
"eval": ModeKeys.EVAL,
"predict": ModeKeys.PREDICT,
}.get(trg_mode.lower())
for trg_mode in targets
]
applicable_addons = [
addon
for addon in addons
if mode in target_modes and aux.get(addon.__name__, True)
] # addons can be added for specific modes only, in this case I attach 'scalars' for "TRAIN" and "EVAL"
if order == "PRE": # this specifies whether to run the code in the addon before the model_fn or afterwards
for add_on in applicable_addons:
add_on(self, features, labels, mode, params)
spec = model_fn(self, features, labels, mode, params)
elif order == "POST": #in the case of 'scalars' I first run the model_fn then pass the spec through the 'scalars' fn above
spec = model_fn(self, features, labels, mode, params)
for add_on in applicable_addons:
spec = add_on(self, features, labels, spec, params)
return spec
return wrapper
return decorator
# I define a couple of partials based on the order of any functions i want to attach to a model_fn,
# this is just to make code more legible
prepare = partial(attach, order="PRE") # if it goes before the model_fn it's 'preparing' something
addon = partial(attach, order="POST") # if it goes after, it's an 'addon' to the model_fn
Наконец, в _model_fn()
в моем базовом классе абстрактной модели возвращается фактическое model_fn
для конкретной модели вместе с любыми аддонами, и это выглядит как
@addon([scalars], ["TRAIN", "EVAL"])
def _model_fn(self, features, labels, mode, params):
return self.model_fn(features, labels, mode, params)
Все вышеперечисленное прекрасно работает, когда я запускаю модели локально. Я не уверен, что это что-то, что я могу даже исправить, может быть, есть какой-то крючок или я могу заставить рабочих ждать, пока мастер закончит контрольную точку, прежде чем продолжить?
Буду очень признателен за любые идеи, я могу поделиться другими частями своего кода, если я пропустил что-либо относящееся к проблеме.
Заранее благодарен за любую помощь 10