Как избежать того, чтобы резюме тензорной доски перезаписывались при запуске train_and_eval () в распределенных настройках и сохранении нескольких контрольных точек? - PullRequest
0 голосов
/ 27 октября 2018

Я столкнулся с проблемой при попытке сохранить сводную информацию и показатели оценки, которые расположены слишком близко друг к другу в распределенном параметре.

Я пытался больше узнать о том, как сводки сохраняются при обучении и оценке модели распределенным способом. Определенно, есть вещи, которые я еще не обернул должным образом, но, насколько я понимаю, только мастер записывает резюме в указанный 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, мои сводки по тензорной доске:

Resulting summaries from tensorboard

Таким образом, я полагаю, что он правильно начинает регистрировать сводки тренировок каждые 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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...