code: def test_ctc_loss(in_length, out_length, ctc_type):
      if ctc_type == "builtin" or ctc_type == "cudnnctc":
          _ctcloss_sum = torch.nn.CTCLoss(reduction="sum")
  
          def torch_ctcloss(th_pred, th_target, th_ilen, th_olen):
              th_pred = th_pred.log_softmax(2)
              loss = _ctcloss_sum(th_pred, th_target, th_ilen, th_olen)
              # Batch-size average
              loss = loss / th_pred.size(1)
              return loss
  
      elif ctc_type == "gtnctc":
          pytest.importorskip("gtn")
          from espnet.nets.pytorch_backend.gtn_ctc import (
              GTNCTCLossFunction,
          )
  
          _ctcloss_sum = GTNCTCLossFunction.apply
  
          def torch_ctcloss(th_pred, th_target, th_ilen, th_olen):
              targets = [t.tolist() for t in th_target]
              log_probs = torch.nn.functional.log_softmax(
                  th_pred, dim=2
              )
              loss = _ctcloss_sum(
                  log_probs, targets, th_ilen, 0, "none"
              )
              return loss
  
      n_out = 7
      input_length = numpy.array(in_length, dtype=numpy.int32)
      label_length = numpy.array(out_length, dtype=numpy.int32)
      np_pred = [
          numpy.random.rand(il, n_out).astype(numpy.float32)
          for il in input_length
      ]
      np_target = [
          numpy.random.randint(0, n_out, size=ol, dtype=numpy.int32)
          for ol in label_length
      ]
  
      # NOTE: np_pred[i] seems to be transposed and used axis=-1 in e2e_asr.py
      ch_pred = F.separate(F.pad_sequence(np_pred), axis=-2)
      ch_target = F.pad_sequence(np_target, padding=-1)
      ch_loss = F.connectionist_temporal_classification(
          ch_pred, ch_target, 0, input_length, label_length
      ).data
  
      th_pred = pad_list(
          [torch.from_numpy(x) for x in np_pred], 0.0
      ).transpose(0, 1)
      if ctc_type == "gtnctc":
          # gtn implementation expects targets as list
          th_target = np_target
          # keep as B x T x H for gtn
          th_pred = th_pred.transpose(0, 1)
      else:
          th_target = torch.from_numpy(numpy.concatenate(np_target))
      th_ilen = torch.from_numpy(input_length)
      th_olen = torch.from_numpy(label_length)
      th_loss = torch_ctcloss(
          th_pred, th_target, th_ilen, th_olen
      ).numpy()
  
      numpy.testing.assert_allclose(th_loss, ch_loss, 0.05)
  
file_path: espnet/test/test_loss.py
imports: import chainer.functions
  import numpy
  import pytest
  import torch
  from espnet.nets.pytorch_backend.e2e_asr import pad_list
  from espnet.nets.pytorch_backend.nets_utils import th_accuracy
label_desc: Use image node_id 1 for calling a global function with example usage: test_ctc_loss(in_length, out_length, ctc_type) and returns: loss, loss