code: def __call__(self, preds, batch, **kwargs):
      for k, v in kwargs.items():
          epoch_reset = v
          if epoch_reset:
              self.epoch_reset()
      word_probs = preds
      word_label, word_label_mask = batch
      line_right = 0
      if word_probs is not None:
          word_pred = word_probs.argmax(2)
      word_pred = word_pred.cpu().detach().numpy()
      word_scores = [
          SequenceMatcher(
              None,
              s1[: int(np.sum(s3))],
              s2[: int(np.sum(s3))],
              autojunk=False,
          ).ratio()
          * (len(s1[: int(np.sum(s3))]) + len(s2[: int(np.sum(s3))]))
          / len(s1[: int(np.sum(s3))])
          / 2
          for s1, s2, s3 in zip(word_label, word_pred, word_label_mask)
      ]
      batch_size = len(word_scores)
      for i in range(batch_size):
          if word_scores[i] == 1:
              line_right += 1
      self.word_rate = np.mean(word_scores)  # float
      self.exp_rate = line_right / batch_size  # float
      exp_length, word_length = word_label.shape[:2]
      self.word_right.append(self.word_rate * word_length)
      self.exp_right.append(self.exp_rate * exp_length)
      self.word_total_length = self.word_total_length + word_length
      self.exp_total_num = self.exp_total_num + exp_length
  
imports: from rapidfuzz.distance import Levenshtein
  from difflib import SequenceMatcher
  import numpy
  import string
label_desc: Use image node_id 2 for calling the CANMetric obj's underlying member method code with example usage: obj.__call__(preds, batch) without return types