code: def log_parameter_and_gradient_statistics(self, # pylint: disable=invalid-name
                                                model: Model,
                                                batch_grad_norm: float) -> None:
          
          if self._should_log_parameter_statistics:
              # Log parameter values to Tensorboard
              for name, param in model.named_parameters():
                  self.add_train_scalar("parameter_mean/" + name, param.data.mean())
                  self.add_train_scalar("parameter_std/" + name, param.data.std())
                  if param.grad is not None:
                      if param.grad.is_sparse:
                          # pylint: disable=protected-access
                          grad_data = param.grad.data._values()
                      else:
                          grad_data = param.grad.data
  
                      # skip empty gradients
                      if torch.prod(torch.tensor(grad_data.shape)).item() > 0: # pylint: disable=not-callable
                          self.add_train_scalar("gradient_mean/" + name, grad_data.mean())
                          self.add_train_scalar("gradient_std/" + name, grad_data.std())
                      else:
                          # no gradient for a parameter with sparse gradients
                          logger.info("No gradient for %s, skipping tensorboard logging.", name)
              # norm of gradients
              if batch_grad_norm is not None:
                  self.add_train_scalar("gradient_norm", batch_grad_norm)
docs: Send the mean and std of all parameters and gradients to tensorboard, as well
          as logging the average gradient norm.