code: def batchfy_by_frame(
      sorted_data,
      max_frames_in,
      max_frames_out,
      max_frames_inout,
      num_batches=0,
      min_batch_size=1,
      shortest_first=False,
      ikey="input",
      okey="output",
  ):
      """Make variable batch set, which maximizes the number of frames to max_batch_frame.
  
      :param Dict[str, Dict[str, Any]] sorteddata: dictionary loaded from data.json
      :param int max_frames_in: Maximum input frames of a batch
      :param int max_frames_out: Maximum output frames of a batch
      :param int max_frames_inout: Maximum input+output frames of a batch
      :param int num_batches: # number of batches to use (for debug)
      :param int min_batch_size: minimum batch size (for multi-gpu)
      :param int test: Return only every `test` batches
      :param bool shortest_first: Sort from batch with shortest samples
          to longest if true, otherwise reverse
  
      :param str ikey: key to access input (for ASR ikey="input", for TTS ikey="output".)
      :param str okey: key to access output (for ASR okey="output". for TTS okey="input".)
  
      :return: List[Tuple[str, Dict[str, List[Dict[str, Any]]]] list of batches
      """
      if (
          max_frames_in <= 0
          and max_frames_out <= 0
          and max_frames_inout <= 0
      ):
          raise ValueError(
              "At least, one of `--batch-frames-in`, `--batch-frames-out` or "
              "`--batch-frames-inout` should be > 0"
          )
      length = len(sorted_data)
      minibatches = []
      start = 0
      end = 0
      while end != length:
          # Dynamic batch size depending on size of samples
          b = 0
          max_olen = 0
          max_ilen = 0
          while (start + b) < length:
              ilen = int(sorted_data[start + b][1][ikey][0]["shape"][0])
              if ilen > max_frames_in and max_frames_in != 0:
                  raise ValueError(
                      f"Can't fit one sample in --batch-frames-in ({max_frames_in}): "
                      f"Please increase the value"
                  )
              olen = int(sorted_data[start + b][1][okey][0]["shape"][0])
              if olen > max_frames_out and max_frames_out != 0:
                  raise ValueError(
                      f"Can't fit one sample in --batch-frames-out ({max_frames_out}): "
                      f"Please increase the value"
                  )
              if (
                  ilen + olen > max_frames_inout
                  and max_frames_inout != 0
              ):
                  raise ValueError(
                      f"Can't fit one sample in --batch-frames-out ({max_frames_inout}): "
                      f"Please increase the value"
                  )
              max_olen = max(max_olen, olen)
              max_ilen = max(max_ilen, ilen)
              in_ok = (
                  max_ilen * (b + 1) <= max_frames_in
                  or max_frames_in == 0
              )
              out_ok = (
                  max_olen * (b + 1) <= max_frames_out
                  or max_frames_out == 0
              )
              inout_ok = (max_ilen + max_olen) * (
                  b + 1
              ) <= max_frames_inout or max_frames_inout == 0
              if in_ok and out_ok and inout_ok:
                  # add more seq in the minibatch
                  b += 1
              else:
                  # no more seq in the minibatch
                  break
          end = min(length, start + b)
          batch = sorted_data[start:end]
          if shortest_first:
              batch.reverse()
          minibatches.append(batch)
          # Check for min_batch_size and fixes the batches if needed
          i = -1
          while len(minibatches[i]) < min_batch_size:
              missing = min_batch_size - len(minibatches[i])
              if -i == len(minibatches):
                  minibatches[i + 1].extend(minibatches[i])
                  minibatches = minibatches[1:]
                  break
              else:
                  minibatches[i].extend(minibatches[i - 1][:missing])
                  minibatches[i - 1] = minibatches[i - 1][missing:]
                  i -= 1
          start = end
      if num_batches > 0:
          minibatches = minibatches[:num_batches]
      lengths = [len(x) for x in minibatches]
      logging.info(
          str(len(minibatches))
          + " batches containing from "
          + str(min(lengths))
          + " to "
          + str(max(lengths))
          + " samples"
          + "(avg "
          + str(int(np.mean(lengths)))
          + " samples)."
      )
  
      return minibatches
  
imports: import itertools
  import logging
  import numpy
label_desc: Use image node_id 3 for calling a global function with example usage: batchfy_by_frame(sorted_data, max_frames_in, max_frames_out, max_frames_inout, num_batches, min_batch_size, shortest_first, ikey, okey) and returns: minibatches