def compute_qparams_by_dtype(
    weight: np.ndarray,
    dtype: types,
    quantization_mode: str,
    block_sizes: List[int],
) -> Optional[Tuple[np.ndarray, np.ndarray, Optional[np.ndarray]]]:
    """
    Similar to `compute_qparams`, ut use `dtype` to specify quant dtype.
    """
    if not isinstance(weight, np.ndarray):
        raise ValueError(f"Only numpy arrays are supported, but got weight type {type(weight)}")

    if len(block_sizes) != len(weight.shape):
        raise AssertionError(
            "Each axis should have a block size, which means len(block_sizes) must be "
            f"equal to weight's rank, but got {len(block_sizes)} vs {len(weight.shape)}"
        )

    new_shape, scale_shape, axes_to_skip = [], [], []
    for axis, (dim_size, block_size) in enumerate(zip(weight.shape, block_sizes)):
        if block_size > 0:
            if dim_size % block_size != 0:
                _logger.warning(
                    f"Invalid block_sizes; On {axis}th axis, the dim size {dim_size} is "
                    f"not divisible by block size {block_size}. Unable to perform "
                    "structured quantization."
                )
                return None

            # Skip this axis while computing min & max
            axes_to_skip.append(len(new_shape))

            # channel dim now will be (num_blocks, block_size)
            num_blocks = dim_size // block_size
            new_shape.extend([num_blocks, block_size])
            scale_shape.append(num_blocks)
        else:
            new_shape.append(dim_size)
            scale_shape.append(1)

    # Axes to reduce while compute min & max values
    axes = tuple(filter(lambda x: x not in axes_to_skip, range(len(new_shape))))

    quantized_data, scale, zero_point = quantize_weight_by_dtype(
        weight.reshape(new_shape), axes, dtype, quantization_mode
    )

    np_dtype = types.nptype_from_builtin(dtype)
    quantized_data = quantized_data.reshape(weight.shape).astype(np_dtype)
    scale = scale.reshape(scale_shape)
    if zero_point is not None:
        zero_point = zero_point.reshape(scale_shape).astype(np_dtype)

    return quantized_data, scale, zero_point

    Similar to `compute_qparams`, ut use `dtype` to specify quant dtype.
    
coremltools/optimize/_utils.py