Maison  >  Article  >  développement back-end  >  Maîtrisez rapidement la fonction Hook en Python

Maîtrisez rapidement la fonction Hook en Python

coldplay.xixi
coldplay.xixiavant
2020-12-11 17:11:218294parcourir

Tutoriel PythonLa colonne présente la fonction Hook en Python

Maîtrisez rapidement la fonction Hook en Python

De nombreuses recommandations d'apprentissage gratuites, alors s'il vous plaît, visitez le tutoriel Python(vidéo)

1. 🎜>

J'entends souvent le concept de fonction hook. Récemment, je regardais le framework open source de détection de cible mmdetection, et il contient également de nombreuses méthodes de programmation Hook. qu'est-ce qu'un crochet exactement ? Quelle est la fonction du crochet ?

  • qu'est-ce que le crochet ? Le crochet, comme son nom l'indique, peut être compris comme un crochet, qui sert à accrocher quelque chose lorsque cela est nécessaire. L'explication spécifique est la suivante : la fonction hook consiste à accrocher notre propre fonction hook implémentée au point de montage cible à un certain moment.

  • Le rôle de la fonction hook. Par exemple, le concept de hook est très courant dans le développement de logiciels de bureau Windows, en particulier le mécanisme de divers déclencheurs d'événements, par exemple dans un MFC C++ ; programme, la souris doit être surveillée. Lorsque le bouton gauche est enfoncé, MFC fournit une fonction de hook onLeftKeyDown. Évidemment, le framework MFC n'implémente pas l'opération spécifique de onLeftKeyDown pour nous, mais nous fournit uniquement un hook Lorsque nous avons besoin de le traiter, il nous suffit de réécrire cette fonction et de monter l'opération dont nous avons besoin dans ce hook. ne faites pas de montage, le mécanisme de déclenchement d'événements MFC effectue des opérations vides.

Comme on peut le voir ci-dessus, la fonction

  • hook est une fonction prédéfinie dans le programme. Cette fonction est dans le programme d'origine. flow (exposant un hook out)

  • Nous devons implémenter un détail spécifique dans le bloc fonctionnel défini par le hook dans le processus. Nous devons hooker ou enregistrer notre implémentation dans le hook. , rendre la fonction hook disponible pour la cible

  • le hook est un mécanisme de programmation et n'a aucune relation directe avec le langage spécifique

  • Si du mode conception Il semble que le mode hook soit une extension de la méthode modèle

  • Le hook ne sera utilisé que lorsqu'il est enregistré, donc dans le processus du programme d'origine, lorsqu'il n'y a pas d'enregistrement ou de montage , l'exécution Vide (c'est-à-dire qu'aucune opération n'est effectuée)

Cet article utilise python pour expliquer l'implémentation des hooks et montre des cas d'application de hooks dans des projets open source. La fonction de la fonction hook est similaire à un autre nom que l'on entend souvent : fonction de rappel (callback function), et peut être comprise selon le même modèle.

Maîtrisez rapidement la fonction Hook en Python

2. Exemple d'implémentation de Hook

Pour autant que je sache, la fonction hook est la plus couramment utilisée dans certains types de traitement de processus. Ce processus comporte souvent de nombreuses étapes. Les fonctions de crochet sont souvent montées dans ces étapes pour offrir une flexibilité permettant d'ajouter des opérations supplémentaires.

Ce qui suit est un exemple simple. Le but de cet exemple est d'implémenter une fonction universelle d'insertion de contenu dans la file d'attente. Il y a 2 étapes de processus

  • Les données doivent être filtrées avant d'être insérées dans la file d'attente

    input_filter_fn

  • Insérer dans la file d'attente

    insert_queue

  • class ContentStash(object):
        """
        content stash for online operation
        pipeline is
        1. input_filter: filter some contents, no use to user
        2. insert_queue(redis or other broker): insert useful content to queue
        """
    
        def __init__(self):
            self.input_filter_fn = None
            self.broker = []
    
        def register_input_filter_hook(self, input_filter_fn):
            """
            register input filter function, parameter is content dict
            Args:
                input_filter_fn: input filter function
    
            Returns:
    
            """
            self.input_filter_fn = input_filter_fn
    
        def insert_queue(self, content):
            """
            insert content to queue
            Args:
                content: dict
    
            Returns:
    
            """
            self.broker.append(content)
    
        def input_pipeline(self, content, use=False):
            """
            pipeline of input for content stash
            Args:
                use: is use, defaul False
                content: dict
    
            Returns:
    
            """
            if not use:
                return
    
            # input filter
            if self.input_filter_fn:
                _filter = self.input_filter_fn(content)
                
            # insert to queue
            if not _filter:
                self.insert_queue(content)
    
    
    
    # test
    ## 实现一个你所需要的钩子实现:比如如果content 包含time就过滤掉,否则插入队列
    def input_filter_hook(content):
        """
        test input filter hook
        Args:
            content: dict
    
        Returns: None or content
    
        """
        if content.get('time') is None:
            return
        else:
            return content
    
    
    # 原有程序
    content = {'filename': 'test.jpg', 'b64_file': "#test", 'data': {"result": "cat", "probility": 0.9}}
    content_stash = ContentStash('audit', work_dir='')
    
    # 挂上钩子函数, 可以有各种不同钩子函数的实现,但是要主要函数输入输出必须保持原有程序中一致,比如这里是content
    content_stash.register_input_filter_hook(input_filter_hook)
    
    # 执行流程
    content_stash.input_pipeline(content)
3. Application des hooks dans les frameworks open source

3.1 keras

Dans le processus de formation en apprentissage profond, la fonction hook se reflète le plus clairement .

Un processus de formation (à l'exclusion de la préparation des données) interrogera l'ensemble de formation plusieurs fois, chaque fois est appelée une époque, et chaque époque est divisée en plusieurs lots pour la formation. Le processus se décompose en :

  • Démarrer l'entraînement

  • Avant d'entraîner une époque

  • S'entraîner un Avant lot

  • Après entraînement d'un lot

  • Après entraînement une époque

  • Évaluer la validation set

  • Fin de la formation

Ces étapes sont intercalées dans le processus de formation de données par lots. Celles-ci peuvent être comprises comme des fonctions de hook. besoin Ces fonctions de hook implémentent certaines choses personnalisées, telles que l'enregistrement du modèle formé dans

, l'utilisation du meilleur modèle pour effectuer l'effet d'ensemble de test dans 训练一个epoch后, etc. 结束训练

La fonction hook est implémentée dans keras via diverses fonctions de rappel. Placez une classe parent de rappel ici. Lors de la personnalisation, il vous suffit d'hériter de cette classe parent et d'implémenter les hooks qui vous préoccupent.

@keras_export('keras.callbacks.Callback')
class Callback(object):
  """Abstract base class used to build new callbacks.

  Attributes:
      params: Dict. Training parameters
          (eg. verbosity, batch size, number of epochs...).
      model: Instance of `keras.models.Model`.
          Reference of the model being trained.

  The `logs` dictionary that callback methods
  take as argument will contain keys for quantities relevant to
  the current batch or epoch (see method-specific docstrings).
  """

  def __init__(self):
    self.validation_data = None  # pylint: disable=g-missing-from-attributes
    self.model = None
    # Whether this Callback should only run on the chief worker in a
    # Multi-Worker setting.
    # TODO(omalleyt): Make this attr public once solution is stable.
    self._chief_worker_only = None
    self._supports_tf_logs = False

  def set_params(self, params):
    self.params = params

  def set_model(self, model):
    self.model = model

  @doc_controls.for_subclass_implementers
  @generic_utils.default
  def on_batch_begin(self, batch, logs=None):
    """A backwards compatibility alias for `on_train_batch_begin`."""

  @doc_controls.for_subclass_implementers
  @generic_utils.default
  def on_batch_end(self, batch, logs=None):
    """A backwards compatibility alias for `on_train_batch_end`."""

  @doc_controls.for_subclass_implementers
  def on_epoch_begin(self, epoch, logs=None):
    """Called at the start of an epoch.

    Subclasses should override for any actions to run. This function should only
    be called during TRAIN mode.

    Arguments:
        epoch: Integer, index of epoch.
        logs: Dict. Currently no data is passed to this argument for this method
          but that may change in the future.
    """

  @doc_controls.for_subclass_implementers
  def on_epoch_end(self, epoch, logs=None):
    """Called at the end of an epoch.

    Subclasses should override for any actions to run. This function should only
    be called during TRAIN mode.

    Arguments:
        epoch: Integer, index of epoch.
        logs: Dict, metric results for this training epoch, and for the
          validation epoch if validation is performed. Validation result keys
          are prefixed with `val_`.
    """

  @doc_controls.for_subclass_implementers
  @generic_utils.default
  def on_train_batch_begin(self, batch, logs=None):
    """Called at the beginning of a training batch in `fit` methods.

    Subclasses should override for any actions to run.

    Arguments:
        batch: Integer, index of batch within the current epoch.
        logs: Dict, contains the return value of `model.train_step`. Typically,
          the values of the `Model`'s metrics are returned.  Example:
          `{'loss': 0.2, 'accuracy': 0.7}`.
    """
    # For backwards compatibility.
    self.on_batch_begin(batch, logs=logs)

  @doc_controls.for_subclass_implementers
  @generic_utils.default
  def on_train_batch_end(self, batch, logs=None):
    """Called at the end of a training batch in `fit` methods.

    Subclasses should override for any actions to run.

    Arguments:
        batch: Integer, index of batch within the current epoch.
        logs: Dict. Aggregated metric results up until this batch.
    """
    # For backwards compatibility.
    self.on_batch_end(batch, logs=logs)

  @doc_controls.for_subclass_implementers
  @generic_utils.default
  def on_test_batch_begin(self, batch, logs=None):
    """Called at the beginning of a batch in `evaluate` methods.

    Also called at the beginning of a validation batch in the `fit`
    methods, if validation data is provided.

    Subclasses should override for any actions to run.

    Arguments:
        batch: Integer, index of batch within the current epoch.
        logs: Dict, contains the return value of `model.test_step`. Typically,
          the values of the `Model`'s metrics are returned.  Example:
          `{'loss': 0.2, 'accuracy': 0.7}`.
    """

  @doc_controls.for_subclass_implementers
  @generic_utils.default
  def on_test_batch_end(self, batch, logs=None):
    """Called at the end of a batch in `evaluate` methods.

    Also called at the end of a validation batch in the `fit`
    methods, if validation data is provided.

    Subclasses should override for any actions to run.

    Arguments:
        batch: Integer, index of batch within the current epoch.
        logs: Dict. Aggregated metric results up until this batch.
    """

  @doc_controls.for_subclass_implementers
  @generic_utils.default
  def on_predict_batch_begin(self, batch, logs=None):
    """Called at the beginning of a batch in `predict` methods.

    Subclasses should override for any actions to run.

    Arguments:
        batch: Integer, index of batch within the current epoch.
        logs: Dict, contains the return value of `model.predict_step`,
          it typically returns a dict with a key 'outputs' containing
          the model's outputs.
    """

  @doc_controls.for_subclass_implementers
  @generic_utils.default
  def on_predict_batch_end(self, batch, logs=None):
    """Called at the end of a batch in `predict` methods.

    Subclasses should override for any actions to run.

    Arguments:
        batch: Integer, index of batch within the current epoch.
        logs: Dict. Aggregated metric results up until this batch.
    """

  @doc_controls.for_subclass_implementers
  def on_train_begin(self, logs=None):
    """Called at the beginning of training.

    Subclasses should override for any actions to run.

    Arguments:
        logs: Dict. Currently no data is passed to this argument for this method
          but that may change in the future.
    """

  @doc_controls.for_subclass_implementers
  def on_train_end(self, logs=None):
    """Called at the end of training.

    Subclasses should override for any actions to run.

    Arguments:
        logs: Dict. Currently the output of the last call to `on_epoch_end()`
          is passed to this argument for this method but that may change in
          the future.
    """

  @doc_controls.for_subclass_implementers
  def on_test_begin(self, logs=None):
    """Called at the beginning of evaluation or validation.

    Subclasses should override for any actions to run.

    Arguments:
        logs: Dict. Currently no data is passed to this argument for this method
          but that may change in the future.
    """

  @doc_controls.for_subclass_implementers
  def on_test_end(self, logs=None):
    """Called at the end of evaluation or validation.

    Subclasses should override for any actions to run.

    Arguments:
        logs: Dict. Currently the output of the last call to
          `on_test_batch_end()` is passed to this argument for this method
          but that may change in the future.
    """

  @doc_controls.for_subclass_implementers
  def on_predict_begin(self, logs=None):
    """Called at the beginning of prediction.

    Subclasses should override for any actions to run.

    Arguments:
        logs: Dict. Currently no data is passed to this argument for this method
          but that may change in the future.
    """

  @doc_controls.for_subclass_implementers
  def on_predict_end(self, logs=None):
    """Called at the end of prediction.

    Subclasses should override for any actions to run.

    Arguments:
        logs: Dict. Currently no data is passed to this argument for this method
          but that may change in the future.
    """

  def _implements_train_batch_hooks(self):
    """Determines if this Callback should be called for each train batch."""
    return (not generic_utils.is_default(self.on_batch_begin) or
            not generic_utils.is_default(self.on_batch_end) or
            not generic_utils.is_default(self.on_train_batch_begin) or
            not generic_utils.is_default(self.on_train_batch_end))

Les programmes originaux de ces hooks sont en cours de formation du modèle

emplacement du code source de Keras : tensorflowpythonkerasenginetraining.py

Une partie de l'extrait est comme suit (## I am hook) :

# Container that configures and calls `tf.keras.Callback`s.
      if not isinstance(callbacks, callbacks_module.CallbackList):
        callbacks = callbacks_module.CallbackList(
            callbacks,
            add_history=True,
            add_progbar=verbose != 0,
            model=self,
            verbose=verbose,
            epochs=epochs,
            steps=data_handler.inferred_steps)

      ## I am hook
      callbacks.on_train_begin()
      training_logs = None
      # Handle fault-tolerance for multi-worker.
      # TODO(omalleyt): Fix the ordering issues that mean this has to
      # happen after `callbacks.on_train_begin`.
      data_handler._initial_epoch = (  # pylint: disable=protected-access
          self._maybe_load_initial_epoch_from_ckpt(initial_epoch))
      for epoch, iterator in data_handler.enumerate_epochs():
        self.reset_metrics()
        callbacks.on_epoch_begin(epoch)
        with data_handler.catch_stop_iteration():
          for step in data_handler.steps():
            with trace.Trace(
                'TraceContext',
                graph_type='train',
                epoch_num=epoch,
                step_num=step,
                batch_size=batch_size):
              ## I am hook
              callbacks.on_train_batch_begin(step)
              tmp_logs = train_function(iterator)
              if data_handler.should_sync:
                context.async_wait()
              logs = tmp_logs  # No error, now safe to assign to logs.
              end_step = step + data_handler.step_increment
              callbacks.on_train_batch_end(end_step, logs)
        epoch_logs = copy.copy(logs)

        # Run validation.

        ## I am hook
        callbacks.on_epoch_end(epoch, epoch_logs)

3,2 mmdetection

mmdetection est un framework open source pour la détection de cibles qui intègre de nombreux algorithmes d'apprentissage en profondeur de détection de cibles différents (version pytorch), tels que plus rapide-rcnn, fpn, retian et al. Les hooks sont également largement utilisés pour exposer des parties spécifiques du processus de mise en œuvre de l’application.

Voir

https://github.com/open-mmlab/mmdetection pour plus de détails

这里看一个训练的调用例子(摘录)(https://github.com/open-mmlab/mmdetection/blob/5d592154cca589c5113e8aadc8798bbc73630d98/mmdet/apis/train.py

def train_detector(model,
                   dataset,
                   cfg,
                   distributed=False,
                   validate=False,
                   timestamp=None,
                   meta=None):
    logger = get_root_logger(cfg.log_level)

    # prepare data loaders

    # put model on gpus

    # build runner
    optimizer = build_optimizer(model, cfg.optimizer)
    runner = EpochBasedRunner(
        model,
        optimizer=optimizer,
        work_dir=cfg.work_dir,
        logger=logger,
        meta=meta)
    # an ugly workaround to make .log and .log.json filenames the same
    runner.timestamp = timestamp

    # fp16 setting
    # register hooks
    runner.register_training_hooks(cfg.lr_config, optimizer_config,
                                   cfg.checkpoint_config, cfg.log_config,
                                   cfg.get('momentum_config', None))
    if distributed:
        runner.register_hook(DistSamplerSeedHook())

    # register eval hooks
    if validate:
        # Support batch_size > 1 in validation
        eval_cfg = cfg.get('evaluation', {})
        eval_hook = DistEvalHook if distributed else EvalHook
        runner.register_hook(eval_hook(val_dataloader, **eval_cfg))

    # user-defined hooks
    if cfg.get('custom_hooks', None):
        custom_hooks = cfg.custom_hooks
        assert isinstance(custom_hooks, list), \
            f'custom_hooks expect list type, but got {type(custom_hooks)}'
        for hook_cfg in cfg.custom_hooks:
            assert isinstance(hook_cfg, dict), \
                'Each item in custom_hooks expects dict type, but got ' \
                f'{type(hook_cfg)}'
            hook_cfg = hook_cfg.copy()
            priority = hook_cfg.pop('priority', 'NORMAL')
            hook = build_from_cfg(hook_cfg, HOOKS)
            runner.register_hook(hook, priority=priority)

4. 总结

本文介绍了hook的概念和应用,并给出了python的实现细则。希望对比有帮助。总结如下:

  • hook函数是流程中预定义好的一个步骤,没有实现

  • 挂载或者注册时, 流程执行就会执行这个钩子函数

  • 回调函数和hook函数功能上是一致的

  • hook设计方式带来灵活性,如果流程中有一个步骤,你想让调用方来实现,你可以用hook函数

相关免费学习推荐:php编程(视频)

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer