code: def images(self, tag, images, step=None, rows=None, cols=None):
      
      images = onp.array(images)
      if step is None:
        step = self._step
      else:
        self._step = step
      n_images = onp.shape(images)[0]
      if rows is None and cols is None:
        rows = 1
        cols = n_images
      elif rows is None:
        rows = n_images // cols
      elif cols is None:
        cols = n_images // rows
      tiled_images = _pack_images(images, rows, cols)
      self.image(tag, tiled_images, step=step)
docs: Saves (rows, cols) tiled images from onp.ndarray.
  
      If either rows or cols aren't given, they are determined automatically
      from the size of the image batch, if neither are given a long column
      of images is produced. This truncates the image batch rather than padding
      if it doesn't fill the final row.
  
      Args:
        tag: str: label for this data
        images: ndarray: [N,H,W,1] or [N,H,W,3] to tile in 2d
        step: int: training step
        rows: int: number of rows in tile
        cols: int: number of columns in tile