def _max_pool2d_out_shape(
    imgshape, ws, stride, pad, ndim,
):
    """Return the shape of max_pool2d output.

    Adapted from Theano (2020/11/08):
    https://github.com/Theano/Theano/blob/master/theano/tensor/signal/pool.py

    Parameters
    ----------
    imgshape : tuple, list, or similar of integer or scalar Theano variable
        The shape of a tensor of images. The last N elements are
        interpreted as the number of rows, and the number of cols.
    ws : list or tuple of N ints
        Downsample factor over rows and column.
        ws indicates the pool region size.
    stride : list or tuple of N ints
        Stride size, which is the number of shifts over rows/cols/slices to get the
        next pool region.
    pad : tuple of N ints
        For each downsampling dimension, this specifies the number of zeros to
        add as padding on both sides. For 2D and (pad_h, pad_w), pad_h specifies the
        size of the top and bottom margins, pad_w specifies the size of the left and
        right margins.
    ndim : int
        The number of pooling dimensions N.
        The default is 2.

    Returns
    -------
    list
        The shape of the output from this op, for input of given shape.
    """

    assert ndim > 0
    assert (
        len(imgshape) >= ndim
    ), "imgshape must have at least {} dimensions".format(ndim)

    # Compute output shape based on formula on Torch page (2020/11/16):
    # https://pytorch.org/docs/stable/generated/torch.nn.MaxPool2d.html#torch.nn.MaxPool2d
    h_in, w_in = imgshape[-ndim:]
    h_out = int((h_in + 2 * pad[0] - (ws[0] - 1) - 1) // stride[0] + 1)
    w_out = int((w_in + 2 * pad[1] - (ws[1] - 1) - 1) // stride[1] + 1)

    rval = list(imgshape[:-ndim]) + [h_out, w_out]
    return rval