code: def forward_pre_hook(self, module, input):
      data = input[0]
      feats = input[1] if len(input) > 1 else None
      nan_mask = input[2] if len(input) > 2 else None
      length = input[3] if len(input) > 3 else None
      if not nan_mask.any().item():
          nan_mask = None
      if (length is None) and (nan_mask is None):
          scale = data.std(dim=1, unbiased=False, keepdim=True)
          offset = data.mean(dim=1, keepdim=True)
      else:
          if nan_mask is None:
              count = length.unsqueeze(dim=1).float()
              tensor = data
          else:
              tensor = data.masked_fill(nan_mask.unsqueeze(dim=-1), 0.0)
              if length is None:
                  count = (
                      nan_mask.logical_not()
                      .float()
                      .sum(dim=1, keepdim=True)
                  )
              else:
                  count = length.unsqueeze(
                      dim=1
                  ).float() - nan_mask.float().sum(dim=1, keepdim=True)
          offset = tensor.sum(dim=1).div(count)
          offset = offset.unsqueeze(dim=1)
          scale = tensor.pow(2).sum(dim=1).div(count)
          scale = scale.unsqueeze(dim=1)
          scale = scale.sub(offset.pow(2))
          scale = scale.sqrt()
      scale = scale + self.eps
      data = data.sub(offset).div(scale)
      self._buffers["offset"] = offset
      self._buffers["scale"] = scale
  
      return data, feats, nan_mask, length
  
imports: from typing import TYPE_CHECKING, Optional
  import torch
  from torch import Tensor, BoolTensor
  from torch.nn import functional
label_desc: Use image node_id 2 for calling the ZScoreNormalizer obj's underlying member method code with example usage: obj.forward_pre_hook(module, input) and returns: data,  feats,  nan_mask,  length