NNCF

NNCF 基础认识

什么是 NNCF(Neural Network Compression Framework)?

  • OpenVINO 提供的对神经网络进行压缩,以加速其推理速度,支持 PyTorchTensorFlowONNX 和 OpenVINO IR 格式的模型,提供 以下优化:
  • (1)Weight Compression 权重压缩:一种易于使用的减少大语言模型的空间占用和加速推理的方法
  • (2)Post-training Quantization 训练后量化:旨在通过应用 8 位整数量化来优化深度学习模型,不需要重新训练或微调,但可能会导致准确性下降(使用校准数据集)
  • (3)Training-time Optimization 训练时量化:涉及一套例如结构化或非结构化裁剪的高级方法,也叫量化感知训练,这种方法需要使用模型的原始框架,对于 NNCF,它要么是 PyTorch,要么是 TensorFlow

在 openVINO 上如何使用 NNCF 的量化?

  • 训练后量化:有三种思路:(1) 直接对 openvino 模型进行权重压缩;(2)直接对 openvino 模型进行量化后训练;(3)先对 pytorch、onnx 等模型进行训练后量化,再转换为 openvino 模型
  • 训练时量化:在 Pytorch 或者 tensorflow 中使用 nncf 进行量化感知训练,然后转换为 openvino 模型

可以将 NNCF 压缩模型与 OpenVINO 推理引擎以外的运行时一起使用吗?

  • 可以,请注意,NNCF 不是 OpenVINO 软件包的一部分,因此需要单独安装

NNCF 压缩后的模型必须和 OpenVINO 或 Intel CPU 绑定执行吗?

  • 不是必需的。 大多数 NNCF 后端都可以运行压缩并生成压缩的模型对象,而无需 OpenVINO 或机器上的 Intel CPU

NNCF 可以在 GPU 上运行吗?

  • 目前,所有 NNCF 支持的后端都允许在仅 CPU 模式下运行,NNCF 不会干扰这一点
  • 但请注意,与 GPU 驱动的执行相比,训练感知压缩在大多数 CPU 上的运行速度自然要慢得多

如何使用 NNCF 进行权重压缩 (Weight Compression)?

  • 和量化不同,权重压缩的目标是模型权重,而量化的目标是模型权重与激活,换句话说,模型压缩允许激活保持浮点数
    1
    2
    3
    from nncf import compress_weights
    from nncf import CompressWeightsMode
    compressed_model = compress_weights(model, mode=CompressWeightsMode.INT4_ASYM)
  • NNCF 的权重压缩支持 8 位、4 位整数的权重压缩,即以下模式:
    Memory ReductionLatency ImprovementAccuracy Loss
    INT8 AsymmetricLowMedium
    INT4 SymmetricHighHigh
    INT4 AsymmetricHighMedium

如何使用 NNCF 对 openVINO 进行 INT8 量化?

  • 一种不需要重新训练的模型压缩方法,但是提供两种思路确保精度:即 Basic quantization (simple)Accuracy-aware Quantization (advanced),前者要求提供校准数据集,后者要求提供校准数据集 + 指标函数
  • Basic quantization (simple):创建校准数据集类实例和转换函数,转换函数的目的是从数据集类中的 data tensor 和 label tensor 取出前者
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    import nncf
    import torch
    calibration_loader = torch.utils.data.DataLoader(...)
    def transform_fn(data_item):
    images, _ = data_item
    return images.numpy()
    calibration_dataset = nncf.Dataset(calibration_loader, transform_fn)
    #量化模型
    import openvino as ov
    model = ov.Core().read_model("model_path")
    quantized_model = nncf.quantize(model, calibration_dataset)
  • Accuracy-aware Quantization (advanced):除了校准数据集之外,还需要验证数据集来计算准确度指标
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    import nncf
    import torch
    calibration_loader = torch.utils.data.DataLoader(...)
    def transform_fn(data_item):
    images, _ = data_item
    return images.numpy()
    calibration_dataset = nncf.Dataset(calibration_loader, transform_fn)
    validation_dataset = nncf.Dataset(calibration_loader, transform_fn)
    #定义评估函数
    import numpy as np
    import torch
    from sklearn.metrics import accuracy_score
    import openvino
    def validate(model: openvino.CompiledModel,
    validation_loader: torch.utils.data.DataLoader) -> float:
    predictions = []
    references = []
    output = model.outputs[0]
    for images, target in validation_loader:
    pred = model(images)[output]
    predictions.append(np.argmax(pred, axis=1))
    references.append(target)
    predictions = np.concatenate(predictions, axis=0)
    references = np.concatenate(references, axis=0)
    return accuracy_score(predictions, references)
    #量化模型
    model = ... # openvino.Model object
    quantized_model = nncf.quantize_with_accuracy_control(
    model,
    calibration_dataset=calibration_dataset,
    validation_dataset=validation_dataset,
    validation_fn=validate,
    max_drop=0.01,
    drop_type=nncf.DropType.ABSOLUTE,
    )

如何使用 NNCF 进行量化感知训练?

  • NNCF 支持在 pytorch、tensorflow 训练模型时量化模型,还支持过滤无效的卷积层
  • 量化感知训练:在 Pytorch 中使用量化感知训练
    1
    2
    3
    4
    5
    6
    7
    #使用Post Training Quantization方法量化模型
    model = TorchModel() # instance of torch.nn.Module
    model = nncf.quantize(model, ...)
    # tune quantized model for 5 epochs as the baseline
    for epoch in range(0, 5):
    for i, data in enumerate(train_loader):
    ... # training loop body
  • 过滤无效卷积层:一种高级优化方法,它允许通过删除 来自模型卷积运算的冗余或不重要的过滤器。此删除分两个步骤完成:1. 不重要的过滤器通过微调的 NNCF 优化归零;2. 在导出到 OpenVINO 中间表示期间,将从模型中删除零滤波器
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    import torch
    import nncf # Important - should be imported right after torch
    from nncf import NNCFConfig
    from nncf.torch import create_compressed_model, register_default_init_args
    #Create NNCF configuration
    nncf_config_dict = {
    "input_info": {"sample_size": [1, 3, 224, 224]}, # input shape required for model tracing
    "compression": [
    {
    "algorithm": "filter_pruning",
    "pruning_init": 0.1,
    "params": {
    "pruning_target": 0.4,
    "pruning_steps": 15
    }
    },
    {
    "algorithm": "quantization", # 8-bit quantization with default settings
    },
    ]
    }
    nncf_config = NNCFConfig.from_dict(nncf_config_dict)
    nncf_config = register_default_init_args(nncf_config, train_loader) # train_loader is an instance of torch.utils.data.DataLoader
    #Apply optimization methods
    model = TorchModel() # instance of torch.nn.Module
    compression_ctrl, model = create_compressed_model(model, nncf_config)
    #Fine-tune the model
    # tune quantized model for 50 epochs as the baseline
    for epoch in range(0, 50):
    compression_ctrl.scheduler.epoch_step() # Epoch control API
    for i, data in enumerate(train_loader):
    compression_ctrl.scheduler.step() # Training iteration control API
    ... # training loop body
    #Export quantized model
    compression_ctrl.export_model("compressed_model.onnx")

参考:

  1. Model Optimization - NNCF — OpenVINO™ documentationCopy to clipboardCopy to clipboard — Version(2024)