ONNX模型的量化

我们都希望从代码中榨取更多的性能,对吧?

在现代,充斥着需要大量计算资源的复杂机器学习算法,因此,榨取每一点性能至关重要。

传统上,机器学习算法是在具有支持大量并行计算能力的 GPU 上进行训练的。但是,当部署我们训练过的模型进行推理时,将所有东西都部署在能够访问这种高端 GPU 的机器上是不切实际的

NSDT工具推荐: Three.js AI纹理开发包 - YOLO合成数据生成器 - GLTF/GLB在线编辑 - 3D模型格式在线转换 - 可编程3D场景编辑器 - REVIT导出3D模型插件 - 3D模型语义搜索引擎 - Three.js虚拟轴心开发包 - 3D模型在线减面 - STL模型在线切割 

1、实际示例

让我们举一个例子来更好地理解我们正在解决的问题。

假设我们正在为神经机器翻译做一个机器学习组件。虽然你可以用任何机器学习模型来做到这一点,但我们以谷歌的 T5模型为例。

这是一个文本到文本的转换模型,在大型语料库上进行训练以完成多项任务。

Google T5 多任务图

执行此任务的示例代码如下所示:

from transformers import T5Tokenizer, T5ForConditionalGeneration, pipeline

tokenizer = T5Tokenizer.from_pretrained("t5-small")
model = T5ForConditionalGeneration.from_pretrained("t5-small")
pipe = pipeline(
	task='text2text-generation', 
    model=model, 
    tokenizer = tokenizer)
print(pipe('Translate English to French: Hi, How are you ?')) 

# Output: [{'generated_text': 'Bonjour, Comment êtes-vous ?'}]
  • 首先,我们从 transformers 包中导入所有必要的类和函数
  • 然后我们实例化 tokenizer 和模型
  • 我们将 tokenizer 和模型传递给管道辅助函数,
  • 从高层次上讲,transformer 架构可以分为两半:编码器和解码器。
  • 我们将文本输入句子转换为各自的 token 表示,并将这些 token 提供给 T5 模型的编码器部分,然后这些输出被提供给解码器部分,最后我们使用相同的 tokenizer 将输出 token 转换回其文本表示。
  • 所有上述复杂性都很好地包装在我们上面使用的管道函数中

现在,让我们来测量此代码的性能:

from transformers import T5Tokenizer, T5ForConditionalGeneration, pipeline
from timeit import timeit

tokenizer = T5Tokenizer.from_pretrained("t5-small")
model = T5ForConditionalGeneration.from_pretrained("t5-small")
pipe = pipeline(task='text2text-generation', model=model, tokenizer = tokenizer)

globals = dict(map(
    lambda x: (x, eval(x)),
    dir()
))

time_taken = timeit(
    globals = globals,
    number = 5,
    stmt="pipe('Translate English to French: Hi, How are you ?')",
)

print(f"It took about {time_taken} seconds")

我们使用 Python 内置的 time-it 模块来测量代码翻译所需的时间,并重复 5 次以获得平均估计值。

因为我们没有使用任何 GPU 进行推理,所以这些数字肯定取决于机器的原始 CPU 能力。但是我们仍然可以提取相对测量值。

(venv-meta) tarun@Taruns-MacBook-Pro ML % /Users/tarun/ML/venv-meta/bin/python /Users/tarun/ML/
t5_torch.py
It took about 0.4970941249999996 seconds

大约需要 0.5 秒

现在让我们检查一下内存使用情况

from memory_profiler import profile

from transformers import T5Tokenizer, T5ForConditionalGeneration, pipeline
from timeit import timeit

tokenizer = T5Tokenizer.from_pretrained("t5-small")
model = T5ForConditionalGeneration.from_pretrained("t5-small")
pipe = pipeline(task='text2text-generation', model=model, tokenizer = tokenizer)

@profile
def perform_inference():
    return pipe('Translate English to French: Hi, How are you ?')

if __name__ == '__main__':
    perform_inference()

运行脚本我们会发现以下结果:

(venv-meta) tarun@Taruns-MacBook-Pro ML % python -m memory_profiler t5_torch_memory_profile.py
Filename: t5_torch_memory_profile.py
Line #    Mem usage    Increment  Occurrences   Line Contents
=============================================================
    10    847.9 MiB    847.9 MiB           1   @profile
    11                                         def perform_inference():
    12    859.2 MiB     11.3 MiB           1       return pipe('Translate English to French: Hi, How are you ?')

我们可以看到,推理任务需要大约 11MB 的内存

虽然这些数字在功能强大的计算机上还不错,但在低功耗移动设备上可能会更加昂贵,如果有一种方法可以让这些模型的部署成本降低很多计算要求,并且执行速度更快,同时基本保持其准确性,那会怎样呢?

2、了解 ONNX

ONNX 代表开放神经网络交换,它是一种由微软研究院开发的开源技术,用于帮助加速跨框架和语言的机器学习推理。

ONNX 的好处在于它是跨平台和跨语言的。

这意味着你可以将机器学习导出为 ONNX 格式,并且可以用你喜欢的任何语言使用它们。

除此之外,ONNX 还具有许多内置优化功能,可以利用现代硬件级功能来加速推理。

让我们从将模型导出到 ONNX 表示开始。

将 transformer 模型导出为 ONNX 运行时等效项的官方方法是使用optimum

运行以下命令执行导出:

(venv-meta) tarun@Taruns-MacBook-Pro ML % optimum-cli export onnx \
--model t5-small \
--optimize O3 \
t5_small_onnx

在上面的命令中,我们使用 optimum-cli ,它是 optimal 库的命令行包装器。

我们首先指定要导出的模型,然后指定 ONNX 应该进行的优化级别。

但我们还没有完成,我们可以做得更好!

3、量化ONNX模型

如果我说我对某个结果的确定性为 85.90123456789%,而对同一结果的确定性为 85.88%,这里的小数精度会有所不同吗?

可能不会,这就是量化对机器学习模型的作用。

当我们训练这些模型时,我们通常使用更高的精度来训练它们,例如使用高达 64 位的浮点精度。

但在实践中,我们可以根据我们的偏好将这个精度降低到 32 位、16 位甚至 8 位。

量化是降低权重、偏差和激活的精度的过程,这样它们消耗的内存更少,运行速度更快!

为了量化我们新导出的模型,让我们再次运行 optimal-cli:

(venv-meta) tarun@Taruns-MacBook-Pro ML % optimum-cli onnxruntime \
quantize \
--onnx_model t5_onnx_small \
--arm64 \
--output t5_onnx_small_quantized

...

Saving quantized model at: t5_onnx_small_quantized (external data format: False)
Configuration saved in t5_onnx_small_quantized/ort_config.json
Special tokens have been added in the vocabulary, make sure the associated word embeddings are fine-tuned or trained.
Special tokens have been added in the vocabulary, make sure the associated word embeddings are fine-tuned or trained.

现在我们已经准备好了量化模型。让我们再次检查一下时间消耗:

from optimum.pipelines import pipeline
from transformers import T5Tokenizer
from optimum.onnxruntime import ORTModelForSeq2SeqLM
from timeit import timeit

model = ORTModelForSeq2SeqLM.from_pretrained('t5_onnx_small_quantized')
tokenizer = T5Tokenizer.from_pretrained('t5-small')
pipe = pipeline(task='text2text-generation',model=model, tokenizer=tokenizer)

globals = dict(map(
    lambda x: (x, eval(x)),
    dir()
))

time_taken = timeit(
    globals = globals,
    number = 5,
    stmt="pipe('Translate English to French: Hi, How are you ?')",
)

print(f"It took about {time_taken} seconds")

我们可以看到,我们的逻辑大部分保持不变,唯一的变化是,我们不再加载由 PyTorch 支持的 hugging face transformers T5 模型,而是加载来自 optimal.onnxruntime 的 ONNX 等效模型。

(venv-meta) tarun@Taruns-MacBook-Pro ML % /Users/tarun/ML/venv-meta/bin/python /Users/tarun/ML/
t5_onnx.py
It took about 0.09925400000000018 seconds

只需很少的代码改动,性能就能提升 5 倍。

同样,让我们​​看看内存方面的表现如何:

from memory_profiler import profile
from optimum.pipelines import pipeline
from transformers import T5Tokenizer
from optimum.onnxruntime import ORTModelForSeq2SeqLM

model = ORTModelForSeq2SeqLM.from_pretrained('t5_onnx_small_quantized')
tokenizer = T5Tokenizer.from_pretrained('t5-small')
pipe = pipeline(task='text2text-generation',model=model, tokenizer=tokenizer)

@profile
def perform_inference():
    return pipe('Translate English to French: Hi, How are you ?')

if __name__ == '__main__':
    perform_inference()

除模型初始化部分外,代码再次看起来大致相似:

(venv-meta) tarun@Taruns-MacBook-Pro ML % python -m memory_profiler t5_onnx_quantized_memory_profile.py
Line #    Mem usage    Increment  Occurrences   Line Contents
=============================================================
    10    933.9 MiB    933.9 MiB           1   @profile
    11                                         def perform_inference():
    12    938.7 MiB      4.9 MiB           1       return pipe('Translate English to French: Hi, How are you ?')

我们可以清楚地看到,我们最终消耗的内存少了很多。事实上,它的内存消耗比以前少了近 2.2 倍。正如一位聪明的程序员曾经说过的:

“当谈到扩展时,优化就是游戏的名称”😎

这个故事的所有代码示例都可以在我的 github 页面上找到。


原文链接:ONNX 模型的量化 - BimAnt

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ONNX模型量化是指将已经训练好的ONNX模型进行压缩和优化,以降低模型的存储空间和计算资源需求,同时保持模型的精度和性能。量化可以通过减少浮点数的位数来实现,例如将浮点数转换为整数或低精度浮点数。 根据引用,可以使用基于Python的TensorRT库进行ONNX模型量化。TensorRT是英伟达推出的用于高性能深度学习推理的库,它支持使用INT8量化技术对ONNX模型进行压缩和加速。 具体步骤如下: 1. 下载并解压缩ONNX模型文件。 2. 使用TensorRT的量化工具,将ONNX模型转换为INT8量化格式。 3. 保存量化后的ONNX模型。 引用中提供了一个使用PaddlePaddle框架和Paddle2ONNX工具进行ONNX模型量化的示例。在示例中,先下载并解压缩MobileNetV1模型文件,然后使用Paddle2ONNX工具将模型转换为ONNX格式,并指定opset_version为12,最后实现动态量化。 综上所述,ONNX模型量化是通过压缩和优化已经训练好的ONNX模型,以降低存储空间和计算资源需求的技术。可以使用TensorRT等库和工具来实现ONNX模型量化。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [ONNX模型优化与量化细节](https://blog.csdn.net/sunny0660/article/details/120405998)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [基于python的tensorrt int8 量化yolov5 onnx模型实现](https://download.csdn.net/download/weixin_42848583/85041103)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [模型量化(3):ONNX 模型的静态量化和动态量化](https://blog.csdn.net/m0_63642362/article/details/124741589)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值