前言
“分割一切,大家一起失业!”——近期,这样一句话在社交媒体上大火!这讲的就是 segment anything model(简称 “sam” )。sam 到底是什么?它具备哪些功能?它真的有这么强大吗?让我们一起通过本文了解详情!
sam 是一个由 meta ai 实验室推出的强大人工智能图像分割应用,可以自动识别哪些图像像素属于一个对象,并且对图像中各个对象进行自动风格处理,可广泛用于分析科学图像、编辑照片等。
sam 的完整应用由一个图片编码器模型(encoder)以及掩码解码(mask decoder) + 提示编码模型(prompt encoder)构成,这两部分都可以被解析为独立的静态模型。其中大部分的算力负载和推理延时都集中在图片编码器任务,因此如果进一步提升图片编码器部分的执行效率,就成为了 sam 应用的主要优化方向之一。
图:sam 模型任务pipeline
本次分享讲重点演示如何通过 openvino 的 nncf 模型压缩工具实现对 sam 编码器部分的量化压缩,实现在 cpu 侧的性能提升。
一、量化介绍
在正式开始实战之前,我们不得不提一下量化的概念,量化是指在不改变模型结构的情况下,将模型参数的表达区间从 fp32 映射到 int8 或是 int4 范围,用更小数值位宽来表示相同的信息,实现对于模型体积的压缩,降低内存消耗,同时在模型网络的执行过程中,系统会自动调用硬件平台专门针对低比特数据优化的指令集或 kernel 函数,提升性能。
图:不同精度数据的表示位宽
intel avx512 vnni 扩展指令集实现了将原本需要3个时钟周期才能完成的int8矩阵点乘与加法运算压缩到一个时钟周期,而在最新的 amx 指令集更是将多个 vnni 模块进行堆叠实现了单周期内成倍的性能提升。
图:int8 矩阵点乘与加法运算指令集优化
二、nncf 训练后量化模式
nncf 工具的全称是 neural network compression framework,是 openvino 工具链中专门用于模型压缩加速的方案实现,包含 量化,剪枝,二值化 等多种模型压缩算法,调用方式又可以分化为训练后量化 (ptq) 和 训练时压缩 (qat) 两种模式,训练时压缩要需要引入原始的训练脚本和数据集,而训练后量化则可以直接针对训练生成模型文件进行压缩,无需额外的训练脚本和标注数据集参与,这也是 nncf 在 openvino 2023.0 正式发布的新功能特性, 而这个模式也仅仅需要以下两步便可实现:
1. 准备校验数据集
这里的校验数据仅用作量化过程中对数据表示范围与分布的计算,因此不需要额外的标签数据,例如在图像识别任务中,我们仅需要送入200-300张左右的图片文件即可。此外我们还需要定义 dataloader 对象与 transform_fn 数据转换函数, dataloader 用于读取校验数据集中的每一个元素,transform_fn 用于将读取的元素转化为 openvino 模型推理的直接输入数据。
import nncfcalibration_loader = torch.utils.data.dataloader(...)def transform_fn(data_item): images, _ = data_item return imagescalibration_dataset = nncf.dataset(calibration_loader, transform_fn)
2. 运行模型量化
首先需要导入模型对象,然后通过 nncf.quantize() 接口,将模型对象与校验数据集绑定开启量化任务, nncf 工具可以支持多种模型对象类型,包含openvino.runtime.model, torch.nn.module, onnx.modelproto以及 tensorflow.module
model = ... #openvino/onnx/pytorch/tf objectquantized_model = nncf.quantize(model, calibration_dataset)
3.(可选)准确性控制模式
如果发现 nncf 在默认模式下的导出的模型准确性下降超过预期,我们也可以使用准确性控制模式(accuracy control)完成训练后量化,此时我们需要加入带标签的测试集数据,用来评估模型在量化过程中哪些 layer 对模型准确性损失的影响(敏感度)比较大,并作为排序依据,依次将这些 layer 回退至原始精度,直到模型符合预期准确性表现。通过这个模式,我们可以在保证模型准确性的情况下,尽可能压缩模型体积,实现性能和准确性之间的平衡。具体方法可以参考以下链接:
https://docs.openvino.ai/nightly/quantization_w_accuracy_control.html
三、 segment anything + nncf实战
接下来让我们具体一步步看下如何使用 nncf 的 ptq 模式完成 sam encoder 的量化。
项目地址:https://github.com/openvinotoolkit/openvino_notebooks/blob/main/notebooks/237-segment-anything/237-segment-anything.ipynb
1. 定义数据加载器
本示例使用 coco128 作为校验数据集,其中包含 128 张 .jpg 格式的图片。由于在量化 onnx 或 ir 静态模型的情况下,数据加载器必须是一个 torch 的 dataloader 类,因此这里我们需要继承 torch.utils.data.dataset 并重新构建一个数据集类,其中必须包含__getitem__方法,用于遍历数据集中的每一个对象,__len__用于获取数据集的对象数量,最后再通过 torch.utils.data.dataloader 方法生成数据加载器。
class cocoloader(data.dataset): def __init__(self, images_path): self.images = list(path(images_path).iterdir()) def __getitem__(self, index): image_path = self.images[index] image = cv2.imread(str(image_path)) image = cv2.cvtcolor(image, cv2.color_bgr2rgb) return image def __len__(self): return len(self.images) coco_dataset = cocoloader(out_dir / 'coco128/images/train2017')calibration_loader = torch.utils.data.dataloader(coco_dataset)
2. 定义数据格式转化模块
下一步是定义数据转化模块,我们可以调用之前定义 preprocess_image 函数完成数据的预处理,值得注意的是由于 calibration_loader 模块返回的单个数据对象为 torch tensor 类型 ,而 openvino 的 python 接口不支持该类型数据,我们需要先将其强制转化为 numpy 格式。
def transform_fn(image_data): image = image_data.numpy() processed_image = preprocess_image(np.squeeze(image)) return processed_imagecalibration_dataset = nncf.dataset(calibration_loader, transform_fn)
3. 运行 nncf 量化
为了确保量化后的模型准确性,这里我们使用原始的 fp32 onnx 格式模型作为输入对象,而不是 fp16 的 ir 格式模型,然后再将该对象送入 nncf.quantize 接口执行量化,该函数接口中有几个比较重要的额外参数:
# load fp32 onnx modelmodel = core.read_model(onnx_encoder_path)quantized_model = nncf.quantize(model, calibration_dataset, model_type=nncf.parameters.modeltype.transformer, preset=nncf.common.quantization.structs.quantizationpreset.mixed)ov_encoder_path_int8 = sam_image_encoder_int8.xmlserialize(quantized_model, ov_encoder_path_int8)
· model_type:模型类别,用于开启特殊的量化策略,例如在类 transformer 模型中,我们需要优先保证模型的准确性。
· preset:量化模式,默认为 performance,使用对卷积的权重和偏置均采用对称量化算法,有助于提升模型性能,此处为了提升模型准确性,我们采用 mixed 模式,采用权重对称量化,偏置非对称量化的方法,适合模型中包含非 relu 或者非对称的激活层。
由于 sam encoder 模型的网络结构比较复杂,而量化过程中我们需要多次遍历模型每一个 layer 的参数,所以量化耗时相对会长一些,请大家耐心等待。这边建议使用 32g 以上内存的硬件设备,如果遇到内存不够的情况,可以通过 subset_size=100 参数,适当降低校验数据数量。
4.模型准确性比较
接下来我们比较下 int8 和 fp16 模型的推理结果:
可以看到在 prompt 和 auto 模式下,int8 模型的准确性相较 fp16 模型,几乎没有任何变化。
注:auto 模式下,mask 将使用随机生成的颜色。
5. 性能比较
最后我们通过 openvino 自带的 benchmark_app 工具比较下性能指标:
[ info ] execution devices:['cpu'][ info ] count: 60 iterations[ info ] duration: 75716.93 ms[ info ] latency:[ info ] median: 14832.33 ms[ info ] average: 14780.77 ms[ info ] min: 10398.47 ms[ info ] max: 16725.65 ms[ info ] throughput: 0.79 fps
benchmark结果(fp16)
[ info ] execution devices:['cpu'][ info ] count: 72 iterations[ info ] duration: 68936.14 ms[ info ] latency:[ info ] median: 11281.87 ms[ info ] average: 11162.87 ms[ info ] min: 6736.09 ms[ info ] max: 12547.48 ms[ info ] throughput: 1.04 fps
benchmark 结果 (int8)
可以看到在 cpu 端,int8 模型相较 fp16 提升了大约 30%, 体积从原本的 350mb 压缩到了 100mb 不到。
四、总结
鉴于 sam 出色的自动化分割能力,相信未来会有越来越多应用场景会部署这项技术,而在产业化落地的过程中,开发者往往最关注的就是性能和准确性之间的平衡,以此获取成本更优的方案。openvino nncf 工具通过对 segment anything encoder 部分的量化压缩,在几乎没有影响模型准确性的情况下,显著提升模型的运行效率,降低模型占用空间。
关于AURIX开发板使用心得分享
沈义人再爆 OPPO Reno 10倍混合变焦版的详细规格
LTE简介和标准进展
CES2012:LG展出超薄4毫米液晶电视
看D类放大器如何实现高效率
SAM 到底是什么
敏感电阻的种类介绍
融合创新助“5G+安全生产”试点成效显著,建议体系化推广
德力西电气P*606E系列数显表闪亮登场
智能传感器不仅仅是在制造行业中发展,物流行业也需要智能传感器的加入
爱立信携手软银在日本市场合作开发和部署5G技术
国内首家,长鑫存储推出多款 LPDDR5产品
盘点十大“无所不能”的5G智慧终端
手机电池充电的误区有哪些,如何正确充电
陶瓷电容MLCC失效分析案例
使用超声波清洗电路板会对晶振造成什么影响?
开源大数据OLAP的演化过程和最佳实践
ExpertControl的CANbus(控制器局域网)专用
5G有哪些应用新场景
等离子弧焊的种类