NNCF
NNCF 基础认识
什么是 NNCF(Neural Network Compression Framework)?
- OpenVINO 提供的对神经网络进行压缩,以加速其推理速度,支持 PyTorch、TensorFlow、ONNX 和 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
3from nncf import compress_weights
from nncf import CompressWeightsMode
compressed_model = compress_weights(model, mode=CompressWeightsMode.INT4_ASYM) - NNCF 的权重压缩支持 8 位、4 位整数的权重压缩,即以下模式:
Memory Reduction Latency Improvement Accuracy Loss INT8 Asymmetric Low Medium INT4 Symmetric High High INT4 Asymmetric High Medium
如何使用 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
11import 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
35import 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
35import 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")
参考: