def quantize_weight_by_dtype(
    weight: np.ndarray,
    axes: Union[int, Tuple[int, ...]],
    dtype: types,
    quantization_mode: str,
) -> Tuple[np.ndarray, np.ndarray, Optional[np.ndarray]]:
    """Similar to `quantize_weight, but use `dtype` to specify quant dtype."""
    if not np.issubdtype(weight.dtype, np.floating):
        # In principle, all dtypes are quantizable, e.g. int can be cast to float then quantize
        # In practise, Core ML constexpr dequantization ops return float,
        # so such constexpr can only replace float const
        raise ValueError("Only floating numpy arrays are supported.")

    val_min = np.amin(weight, axis=axes, keepdims=True)
    val_max = np.amax(weight, axis=axes, keepdims=True)
    q_val_min, q_val_max = get_quant_range_by_dtype(dtype, quantization_mode)
    zero_point = None

    if quantization_mode == "LINEAR_SYMMETRIC":
        # For the linear_symmetric quantization_mode, the range is symmetrical to 0
        max_abs = np.maximum(np.abs(val_min), np.abs(val_max))
        val_min = -max_abs
        val_max = max_abs
    else:
        assert quantization_mode == "LINEAR"
        # For the linear quantization_mode, we need to make sure the data range contains `0`
        val_min = np.minimum(0.0, val_min)
        val_max = np.maximum(0.0, val_max)

    scale = (val_max - val_min) / (q_val_max - q_val_min)
    quantized_data = np.round(weight / scale)

    if types.is_int(dtype):
        if quantization_mode == "LINEAR_SYMMETRIC" and dtype.is_unsigned():
            zero_point_shift = q_val_max // 2
            zero_point = zero_point_shift * np.ones(val_min.shape)
        elif quantization_mode == "LINEAR":
            zero_point = (q_val_min * val_max - q_val_max * val_min) / (val_max - val_min)
            zero_point = np.round(zero_point)
            zero_point = np.clip(zero_point, q_val_min, q_val_max)

    if zero_point is not None:
        quantized_data += zero_point
        zero_point = zero_point.squeeze()
    quantized_data = np.clip(quantized_data, q_val_min, q_val_max)
    scale = scale.astype(weight.dtype).squeeze()

    return quantized_data, scale, zero_point
Similar to `quantize_weight, but use `dtype` to specify quant dtype.
coremltools/optimize/_utils.py