code: def make_grid(
      tensor: Union[torch.Tensor, List[torch.Tensor]],
      nrow: int = 8,
      padding: int = 2,
      normalize: bool = False,
      value_range: Optional[Tuple[int, int]] = None,
      scale_each: bool = False,
      pad_value: float = 0.0,
  ) -> torch.Tensor:
      """
      Make a grid of images.
  
      Args:
          tensor (Tensor or list): 4D mini-batch Tensor of shape (B x C x H x W)
              or a list of images all of the same size.
          nrow (int, optional): Number of images displayed in each row of the grid.
              The final grid size is ``(B / nrow, nrow)``. Default: ``8``.
          padding (int, optional): amount of padding. Default: ``2``.
          normalize (bool, optional): If True, shift the image to the range (0, 1),
              by the min and max values specified by ``value_range``. Default: ``False``.
          value_range (tuple, optional): tuple (min, max) where min and max are numbers,
              then these numbers are used to normalize the image. By default, min and max
              are computed from the tensor.
          scale_each (bool, optional): If ``True``, scale each image in the batch of
              images separately rather than the (min, max) over all images. Default: ``False``.
          pad_value (float, optional): Value for the padded pixels. Default: ``0``.
  
      Returns:
          grid (Tensor): the tensor containing grid of images.
      """
      if not torch.jit.is_scripting() and not torch.jit.is_tracing():
          _log_api_usage_once(make_grid)
      if not torch.is_tensor(tensor):
          if isinstance(tensor, list):
              for t in tensor:
                  if not torch.is_tensor(t):
                      raise TypeError(
                          f"tensor or list of tensors expected, got a list containing {type(t)}"
                      )
          else:
              raise TypeError(
                  f"tensor or list of tensors expected, got {type(tensor)}"
              )
  
      # if list of tensors, convert to a 4D mini-batch Tensor
      if isinstance(tensor, list):
          tensor = torch.stack(tensor, dim=0)
  
      if tensor.dim() == 2:  # single image H x W
          tensor = tensor.unsqueeze(0)
      if tensor.dim() == 3:  # single image
          if (
              tensor.size(0) == 1
          ):  # if single-channel, convert to 3-channel
              tensor = torch.cat((tensor, tensor, tensor), 0)
          tensor = tensor.unsqueeze(0)
  
      if (
          tensor.dim() == 4 and tensor.size(1) == 1
      ):  # single-channel images
          tensor = torch.cat((tensor, tensor, tensor), 1)
  
      if normalize is True:
          tensor = tensor.clone()  # avoid modifying tensor in-place
          if value_range is not None and not isinstance(
              value_range, tuple
          ):
              raise TypeError(
                  "value_range has to be a tuple (min, max) if specified. min and max are numbers"
              )
  
          def norm_ip(img, low, high):
              img.clamp_(min=low, max=high)
              img.sub_(low).div_(max(high - low, 1e-5))
  
          def norm_range(t, value_range):
              if value_range is not None:
                  norm_ip(t, value_range[0], value_range[1])
              else:
                  norm_ip(t, float(t.min()), float(t.max()))
  
          if scale_each is True:
              for t in tensor:  # loop over mini-batch dimension
                  norm_range(t, value_range)
          else:
              norm_range(tensor, value_range)
  
      if not isinstance(tensor, torch.Tensor):
          raise TypeError("tensor should be of type torch.Tensor")
      if tensor.size(0) == 1:
          return tensor.squeeze(0)
  
      # make the mini-batch of images into a grid
      nmaps = tensor.size(0)
      xmaps = min(nrow, nmaps)
      ymaps = int(math.ceil(float(nmaps) / xmaps))
      height, width = int(tensor.size(2) + padding), int(
          tensor.size(3) + padding
      )
      num_channels = tensor.size(1)
      grid = tensor.new_full(
          (
              num_channels,
              height * ymaps + padding,
              width * xmaps + padding,
          ),
          pad_value,
      )
      k = 0
      for y in range(ymaps):
          for x in range(xmaps):
              if k >= nmaps:
                  break
              # Tensor.copy_() is a valid method but seems to be missing from the stubs
              # https://pytorch.org/docs/stable/tensors.html#torch.Tensor.copy_
              grid.narrow(1, y * height + padding, height - padding).narrow(  # type: ignore[attr-defined]
                  2, x * width + padding, width - padding
              ).copy_(
                  tensor[k]
              )
              k = k + 1
      return grid
  
imports: import collections
  import math
  import pathlib
  import warnings
  from itertools import repeat
  from types import FunctionType
  from typing import Any, BinaryIO, List, Optional, Tuple, Union
  import numpy
  import torch
  from PIL import Image, ImageColor, ImageDraw, ImageFont
label_desc: Use image node_id 1 for calling a global function with example usage: make_grid(tensor, nrow, padding, normalize, value_range, scale_each, pad_value) and returns: grid, tensor