This is an implementation for [RFC: Supporting Sub-Channel Quantization in MLIR](https://discourse.llvm.org/t/rfc-supporting-sub-channel-quantization-in-mlir/82694). In order to make the review process easier, the PR has been divided into the following commit labels: 1. **Add implementation for sub-channel type:** Includes the class design for `UniformQuantizedSubChannelType`, printer/parser and bytecode read/write support. The existing types (per-tensor and per-axis) are unaltered. 2. **Add implementation for sub-channel type:** Lowering of `quant.qcast` and `quant.dcast` operations to Linalg operations. 3. **Adding C/Python Apis:** We first define he C-APIs and build the Python-APIs on top of those. 4. **Add pass to normalize generic ....:** This pass normalizes sub-channel quantized types to per-tensor per-axis types, if possible. A design note: - **Explicitly storing the `quantized_dimensions`, even when they can be derived for ranked tensor.** While it's possible to infer quantized dimensions from the static shape of the scales (or zero-points) tensor for ranked data tensors ([ref](https://discourse.llvm.org/t/rfc-supporting-sub-channel-quantization-in-mlir/82694/3) for background), there are cases where this can lead to ambiguity and issues with round-tripping. ``` Consider the example: tensor<2x4x!quant.uniform<i8:f32:{0:2, 0:2}, {{s00:z00, s01:z01}}>> ``` The shape of the scales tensor is [1, 2], which might suggest that only axis 1 is quantized. While this inference is technically correct, as the block size for axis 0 is a degenerate case (equal to the dimension size), it can cause problems with round-tripping. Therefore, even for ranked tensors, we are explicitly storing the quantized dimensions. Suggestions welcome! PS: I understand that the upcoming holidays may impact your schedule, so please take your time with the review. There's no rush.
240 lines
10 KiB
C
240 lines
10 KiB
C
//===-- mlir-c/Dialect/Quant.h - C API for LLVM -------------------*- C -*-===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM
|
|
// Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef MLIR_C_DIALECT_QUANT_H
|
|
#define MLIR_C_DIALECT_QUANT_H
|
|
|
|
#include "mlir-c/IR.h"
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
MLIR_DECLARE_CAPI_DIALECT_REGISTRATION(quant, quant);
|
|
|
|
//===---------------------------------------------------------------------===//
|
|
// QuantizedType
|
|
//===---------------------------------------------------------------------===//
|
|
|
|
/// Returns `true` if the given type is a quantization dialect type.
|
|
MLIR_CAPI_EXPORTED bool mlirTypeIsAQuantizedType(MlirType type);
|
|
|
|
/// Returns the bit flag used to indicate signedness of a quantized type.
|
|
MLIR_CAPI_EXPORTED unsigned mlirQuantizedTypeGetSignedFlag(void);
|
|
|
|
/// Returns the minimum possible value stored by a quantized type.
|
|
MLIR_CAPI_EXPORTED int64_t mlirQuantizedTypeGetDefaultMinimumForInteger(
|
|
bool isSigned, unsigned integralWidth);
|
|
|
|
/// Returns the maximum possible value stored by a quantized type.
|
|
MLIR_CAPI_EXPORTED int64_t mlirQuantizedTypeGetDefaultMaximumForInteger(
|
|
bool isSigned, unsigned integralWidth);
|
|
|
|
/// Gets the original type approximated by the given quantized type.
|
|
MLIR_CAPI_EXPORTED MlirType mlirQuantizedTypeGetExpressedType(MlirType type);
|
|
|
|
/// Gets the flags associated with the given quantized type.
|
|
MLIR_CAPI_EXPORTED unsigned mlirQuantizedTypeGetFlags(MlirType type);
|
|
|
|
/// Returns `true` if the given type is signed, `false` otherwise.
|
|
MLIR_CAPI_EXPORTED bool mlirQuantizedTypeIsSigned(MlirType type);
|
|
|
|
/// Returns the underlying type used to store the values.
|
|
MLIR_CAPI_EXPORTED MlirType mlirQuantizedTypeGetStorageType(MlirType type);
|
|
|
|
/// Returns the minimum value that the storage type of the given quantized type
|
|
/// can take.
|
|
MLIR_CAPI_EXPORTED int64_t mlirQuantizedTypeGetStorageTypeMin(MlirType type);
|
|
|
|
/// Returns the maximum value that the storage type of the given quantized type
|
|
/// can take.
|
|
MLIR_CAPI_EXPORTED int64_t mlirQuantizedTypeGetStorageTypeMax(MlirType type);
|
|
|
|
/// Returns the integral bitwidth that the storage type of the given quantized
|
|
/// type can represent exactly.
|
|
MLIR_CAPI_EXPORTED unsigned
|
|
mlirQuantizedTypeGetStorageTypeIntegralWidth(MlirType type);
|
|
|
|
/// Returns `true` if the `candidate` type is compatible with the given
|
|
/// quantized `type`.
|
|
MLIR_CAPI_EXPORTED bool
|
|
mlirQuantizedTypeIsCompatibleExpressedType(MlirType type, MlirType candidate);
|
|
|
|
/// Returns the element type of the given quantized type as another quantized
|
|
/// type.
|
|
MLIR_CAPI_EXPORTED MlirType
|
|
mlirQuantizedTypeGetQuantizedElementType(MlirType type);
|
|
|
|
/// Casts from a type based on the storage type of the given type to a
|
|
/// corresponding type based on the given type. Returns a null type if the cast
|
|
/// is not valid.
|
|
MLIR_CAPI_EXPORTED MlirType
|
|
mlirQuantizedTypeCastFromStorageType(MlirType type, MlirType candidate);
|
|
|
|
/// Casts from a type based on a quantized type to a corresponding typed based
|
|
/// on the storage type. Returns a null type if the cast is not valid.
|
|
MLIR_CAPI_EXPORTED MlirType mlirQuantizedTypeCastToStorageType(MlirType type);
|
|
|
|
/// Casts from a type based on the expressed type of the given type to a
|
|
/// corresponding type based on the given type. Returns a null type if the cast
|
|
/// is not valid.
|
|
MLIR_CAPI_EXPORTED MlirType
|
|
mlirQuantizedTypeCastFromExpressedType(MlirType type, MlirType candidate);
|
|
|
|
/// Casts from a type based on a quantized type to a corresponding typed based
|
|
/// on the expressed type. Returns a null type if the cast is not valid.
|
|
MLIR_CAPI_EXPORTED MlirType mlirQuantizedTypeCastToExpressedType(MlirType type);
|
|
|
|
/// Casts from a type based on the expressed type of the given quantized type to
|
|
/// equivalent type based on storage type of the same quantized type.
|
|
MLIR_CAPI_EXPORTED MlirType
|
|
mlirQuantizedTypeCastExpressedToStorageType(MlirType type, MlirType candidate);
|
|
|
|
//===---------------------------------------------------------------------===//
|
|
// AnyQuantizedType
|
|
//===---------------------------------------------------------------------===//
|
|
|
|
/// Returns `true` if the given type is an AnyQuantizedType.
|
|
MLIR_CAPI_EXPORTED bool mlirTypeIsAAnyQuantizedType(MlirType type);
|
|
|
|
/// Creates an instance of AnyQuantizedType with the given parameters in the
|
|
/// same context as `storageType` and returns it. The instance is owned by the
|
|
/// context.
|
|
MLIR_CAPI_EXPORTED MlirType mlirAnyQuantizedTypeGet(unsigned flags,
|
|
MlirType storageType,
|
|
MlirType expressedType,
|
|
int64_t storageTypeMin,
|
|
int64_t storageTypeMax);
|
|
|
|
//===---------------------------------------------------------------------===//
|
|
// UniformQuantizedType
|
|
//===---------------------------------------------------------------------===//
|
|
|
|
/// Returns `true` if the given type is a UniformQuantizedType.
|
|
MLIR_CAPI_EXPORTED bool mlirTypeIsAUniformQuantizedType(MlirType type);
|
|
|
|
/// Creates an instance of UniformQuantizedType with the given parameters in the
|
|
/// same context as `storageType` and returns it. The instance is owned by the
|
|
/// context.
|
|
MLIR_CAPI_EXPORTED MlirType mlirUniformQuantizedTypeGet(
|
|
unsigned flags, MlirType storageType, MlirType expressedType, double scale,
|
|
int64_t zeroPoint, int64_t storageTypeMin, int64_t storageTypeMax);
|
|
|
|
/// Returns the scale of the given uniform quantized type.
|
|
MLIR_CAPI_EXPORTED double mlirUniformQuantizedTypeGetScale(MlirType type);
|
|
|
|
/// Returns the zero point of the given uniform quantized type.
|
|
MLIR_CAPI_EXPORTED int64_t mlirUniformQuantizedTypeGetZeroPoint(MlirType type);
|
|
|
|
/// Returns `true` if the given uniform quantized type is fixed-point.
|
|
MLIR_CAPI_EXPORTED bool mlirUniformQuantizedTypeIsFixedPoint(MlirType type);
|
|
|
|
//===---------------------------------------------------------------------===//
|
|
// UniformQuantizedPerAxisType
|
|
//===---------------------------------------------------------------------===//
|
|
|
|
/// Returns `true` if the given type is a UniformQuantizedPerAxisType.
|
|
MLIR_CAPI_EXPORTED bool mlirTypeIsAUniformQuantizedPerAxisType(MlirType type);
|
|
|
|
/// Creates an instance of UniformQuantizedPerAxisType with the given parameters
|
|
/// in the same context as `storageType` and returns it. `scales` and
|
|
/// `zeroPoints` point to `nDims` number of elements. The instance is owned
|
|
/// by the context.
|
|
MLIR_CAPI_EXPORTED MlirType mlirUniformQuantizedPerAxisTypeGet(
|
|
unsigned flags, MlirType storageType, MlirType expressedType,
|
|
intptr_t nDims, double *scales, int64_t *zeroPoints,
|
|
int32_t quantizedDimension, int64_t storageTypeMin, int64_t storageTypeMax);
|
|
|
|
/// Returns the number of axes in the given quantized per-axis type.
|
|
MLIR_CAPI_EXPORTED intptr_t
|
|
mlirUniformQuantizedPerAxisTypeGetNumDims(MlirType type);
|
|
|
|
/// Returns `pos`-th scale of the given quantized per-axis type.
|
|
MLIR_CAPI_EXPORTED double mlirUniformQuantizedPerAxisTypeGetScale(MlirType type,
|
|
intptr_t pos);
|
|
|
|
/// Returns `pos`-th zero point of the given quantized per-axis type.
|
|
MLIR_CAPI_EXPORTED int64_t
|
|
mlirUniformQuantizedPerAxisTypeGetZeroPoint(MlirType type, intptr_t pos);
|
|
|
|
/// Returns the index of the quantized dimension in the given quantized per-axis
|
|
/// type.
|
|
MLIR_CAPI_EXPORTED int32_t
|
|
mlirUniformQuantizedPerAxisTypeGetQuantizedDimension(MlirType type);
|
|
|
|
/// Returns `true` if the given uniform quantized per-axis type is fixed-point.
|
|
MLIR_CAPI_EXPORTED bool
|
|
mlirUniformQuantizedPerAxisTypeIsFixedPoint(MlirType type);
|
|
|
|
//===---------------------------------------------------------------------===//
|
|
// UniformQuantizedSubChannelType
|
|
//===---------------------------------------------------------------------===//
|
|
|
|
/// Returns `true` if the given type is a UniformQuantizedSubChannel.
|
|
MLIR_CAPI_EXPORTED bool
|
|
mlirTypeIsAUniformQuantizedSubChannelType(MlirType type);
|
|
|
|
/// Creates a UniformQuantizedSubChannelType with the given parameters.
|
|
///
|
|
/// The type is owned by the context. `scalesAttr` and `zeroPointsAttr` must be
|
|
/// DenseElementsAttrs. `quantizedDimensions` and `blockSizes`
|
|
/// point to `blockSizeInfoLength` number of elements, describing respectively
|
|
/// the quantization axis and corresponding block size.
|
|
MLIR_CAPI_EXPORTED MlirType mlirUniformQuantizedSubChannelTypeGet(
|
|
unsigned flags, MlirType storageType, MlirType expressedType,
|
|
MlirAttribute scalesAttr, MlirAttribute zeroPointsAttr,
|
|
intptr_t blockSizeInfoLength, int32_t *quantizedDimensions,
|
|
int64_t *blockSizes, int64_t storageTypeMin, int64_t storageTypeMax);
|
|
|
|
/// Returns the number of block sizes provided in type.
|
|
MLIR_CAPI_EXPORTED intptr_t
|
|
mlirUniformQuantizedSubChannelTypeGetNumBlockSizes(MlirType type);
|
|
|
|
/// Returns the quantized dimension at the given position.
|
|
MLIR_CAPI_EXPORTED int32_t
|
|
mlirUniformQuantizedSubChannelTypeGetQuantizedDimension(MlirType type,
|
|
intptr_t pos);
|
|
|
|
/// Returns the block size at the given position.
|
|
MLIR_CAPI_EXPORTED int64_t
|
|
mlirUniformQuantizedSubChannelTypeGetBlockSize(MlirType type, intptr_t pos);
|
|
|
|
/// Returns the scales of the quantized type.
|
|
MLIR_CAPI_EXPORTED MlirAttribute
|
|
mlirUniformQuantizedSubChannelTypeGetScales(MlirType type);
|
|
|
|
/// Returns the zero-points of the quantized type.
|
|
MLIR_CAPI_EXPORTED MlirAttribute
|
|
mlirUniformQuantizedSubChannelTypeGetZeroPoints(MlirType type);
|
|
|
|
//===---------------------------------------------------------------------===//
|
|
// CalibratedQuantizedType
|
|
//===---------------------------------------------------------------------===//
|
|
|
|
/// Returns `true` if the given type is a CalibratedQuantizedType.
|
|
MLIR_CAPI_EXPORTED bool mlirTypeIsACalibratedQuantizedType(MlirType type);
|
|
|
|
/// Creates an instance of CalibratedQuantizedType with the given parameters
|
|
/// in the same context as `expressedType` and returns it. The instance is owned
|
|
/// by the context.
|
|
MLIR_CAPI_EXPORTED MlirType
|
|
mlirCalibratedQuantizedTypeGet(MlirType expressedType, double min, double max);
|
|
|
|
/// Returns the min value of the given calibrated quantized type.
|
|
MLIR_CAPI_EXPORTED double mlirCalibratedQuantizedTypeGetMin(MlirType type);
|
|
|
|
/// Returns the max value of the given calibrated quantized type.
|
|
MLIR_CAPI_EXPORTED double mlirCalibratedQuantizedTypeGetMax(MlirType type);
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
#endif // MLIR_C_DIALECT_QUANT_H
|