class_docstr: PipelineHelper assists with implementing pipelining in model parallelism.
  
  For a tutorial on model parallelism, as it's implemented in parts of ParlAI,
  see https://pytorch.org/tutorials/intermediate/model_parallel_tutorial.html.
  
  Usage:
  >>> my_model = PipelineHelper().make_parallel(my_model)
  
  Note that you will need to manually implement logic which handles the
  moved layers.
class_docstr_tok: ["PipelineHelper","assists","with","implementing","pipelining","in","model","parallelism",".","For","a","tutorial","on","model","parallelism",",","as","it","'s","implemented","in","parts","of","ParlAI",",","see","https",":","\/\/pytorch.org\/tutorials\/intermediate\/model_parallel_tutorial.html",".","Usage",":",">",">",">","my_model","=","PipelineHelper","(",")",".make_parallel","(","my_model",")","Note","that","you","will","need","to","manually","implement","logic","which","handles","the","moved","layers","."]
docstr: Split a tensor or group of tensors into smaller chunks of the same type.
  
  :param item:
      The item being split. May be a Tensor, a tuple of Tensors, or a
      dictionary mapping str -> Tensor.
  :param split_size:
      The maximum size of each output chunk. If None, we will guess using
      heuristics
  :param dim:
      The dimension to split along.
docstr_tok: ["Split","a","tensor","or","group","of","tensors","into","smaller","chunks","of","the","same","type",".",":","param","item",":","The","item","being","split",".","May","be","a","Tensor",",","a","tuple","of","Tensors",",","or","a","dictionary","mapping","str","-",">","Tensor",".",":","param","split_size",":","The","maximum","size","of","each","output","chunk",".","If","None",",","we","will","guess","using","heuristics",":","param","dim",":","The","dimension","to","split","along","."]
code: def split(
      item: Chunk, split_size: Optional[int] = None, dim=0
  ) -> List[Chunk]:
      """
      Split a tensor or group of tensors into smaller chunks of the same type.
  
      :param item:
          The item being split. May be a Tensor, a tuple of Tensors, or a
          dictionary mapping str -> Tensor.
      :param split_size:
          The maximum size of each output chunk. If None, we will guess using
          heuristics
      :param dim:
          The dimension to split along.
      """
      if split_size is None:
          split_size = PipelineHelper.guess_split_size(item)
  
      if isinstance(item, torch.Tensor):
          # base case, just split the tensor
          return list(torch.split(item, split_size, dim))
      elif isinstance(item, tuple):
          # We start with Tuple[Tensor] and we return List[Tuple[Tensor]]
          return list(
              zip(
                  *(
                      PipelineHelper.split(i, split_size, dim)
                      for i in item
                  )
              )
          )
      elif isinstance(item, dict):
          if item == {}:
              # Terrible edge case: the empty dict. We handle by returning an
              # infinite list of empty dicts and we'll figure out its correct
              # size later. This happens for the incremental_state in
              # MultiheadAttention.
              return itertools.repeat({})  # type: ignore
  
          # we can't handle dicts with empty objects in them, due to how we handle
          # the case above.  awkward syntax because pytorch 1.3 doesn't like
          # comparing tensors to dicts.
          if {} in [x for x in item.values() if isinstance(x, dict)]:
              raise ValueError(
                  "Cannot handle a dictionary with an empty dictionary inside."
              )
          if () in [x for x in item.values() if isinstance(x, tuple)]:
              raise ValueError(
                  "Cannot handle a dictionary with an empty tuple inside."
              )
  
          # we start with Dict[key,tensor]
          # we map it to d: Dict[key, List[Tensor]], where we have split each mapping
          d = {
              k: PipelineHelper.split(v, split_size, dim)
              for k, v in item.items()
          }
          # now we transpose it and return List[Dict[key, Tensor]]
          return [
              dict(zip(d.keys(), values))  # type: ignore
              for values in zip(*(d[k] for k in d.keys()))
          ]
      else:
          raise TypeError(f"Cannot split type {type(item)}")
  
imports: import os
  from typing import Union, Optional, Tuple, Any, List, Sized, TypeVar
  import itertools
  from collections import namedtuple
  import parlai.utils.logging
  import parlai.utils.io
  import torch.optim
label_desc: Use image node_id 7 for calling the PipelineHelper obj's underlying member method code with example usage: obj.split(item, split_size, dim) and returns: list, list, unknown, itertools