class_docstr: :class:`~opacus.optimizers.optimizer.DPOptimizer` that implements
  per layer clipping strategy and is compatible with distributed data parallel
class_docstr_tok: [":","class",":","`","~opacus.optimizers.optimizer.DPOptimizer","`","that","implements","per","layer","clipping","strategy","and","is","compatible","with","distributed","data","parallel"]
code: def _register_hooks(self):
      for p, max_grad_norm in zip(self.params, self.max_grad_norms):
          if not p.requires_grad:
              continue
  
          if not hasattr(p, "ddp_hooks"):
              p.ddp_hooks = []
  
          p.ddp_hooks.append(
              p.register_hook(
                  partial(self._ddp_per_layer_hook, p, max_grad_norm)
              )
          )
  
imports: from __future__ import annotations
  from functools import partial
  from typing import Callable, List, Optional
  import torch
  from opt_einsum import contract
  from torch import nn
  from torch.optim import Optimizer
  from .ddpoptimizer import DistributedDPOptimizer
  from .optimizer import DPOptimizer, _generate_noise
  from .perlayeroptimizer import DPPerLayerOptimizer
label_desc: Use image node_id 9 for calling the DistributedPerLayerOptimizer obj's underlying member method code with example usage: obj._register_hooks() without return types