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

def images(self, tag, images, step=None, rows=None, cols=None):
    """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
    """
    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)