def get_reduce_out_shape(in_shape, axis=None, keepdims=False):
    """
    Computes ouput shape in reduction operators.

    Args:
        in_shape : input shape
        axis (Union[int, list, tuple]): The reduction axis. Default value is None, in this case,
            all dimensions will be reduced.
        keepdims (bool): If True, retains reduced dimensions with length 1, default value is False.

    Returns:
        output shape.
    """

    dims = len(in_shape)
    if axis is None:
        axis = list(range(dims))
    if not isinstance(axis, (int, list, tuple)):
        raise ValueError("axis must be of the following type: int, list, tuple.")
    if isinstance(axis, int):
        axis = [axis]
    axis = list(axis)
    for i, axis_val in enumerate(axis):
        if axis_val < 0:
            axis[i] = axis_val + dims
        if axis_val >= dims:
            raise ValueError("axis[{}] is {}, which exceeds max dimension {}".format(i, axis[i], dims))
    remaining_axis = []
    for i in range(dims):
        if i not in axis:
            remaining_axis.append(i)
    out_shape = []
    for i in range(dims):
        if i in remaining_axis:
            out_shape.append(in_shape[i])
        else:
            if keepdims:
                out_shape.append(1)
    if not out_shape:
        out_shape.append(1)
    return out_shape