部署神经网络时计算图的优化方法

news/2024/11/15 15:05:06/

部署神经网络时计算图的优化方法

部署神经网络时,各路框架基本都会把神经网络的计算建模为一个(有向无环的)计算图,之后再对这个计算图进行优化,包括硬件相关的优化和硬件无关的优化。本文介绍几种部署神经网络时计算图的优化方法,帮助读者在部署神经网络时理解部署工具都干了些什么。

算子融合

最关键的优化计算图的方式就是算子融合了,算子融合指的是将多个神经网络算子(例如卷积、池化、归一化等)组合在一起,以提高计算效率和性能。

输入卷积层与归一化融合

卷积神经网络中,输入的图像往往要做一个Normalization,比如ImageNet上训练的神经网络经常需要进行下面这个操作:

std = [0.229, 0.224, 0.225]
mean = [0.485, 0.456, 0.406]
x = (x/255 - mean) / std

而YoloV5这样的模型则更简单,mean是0,std是1:

x = x / 255

在第一层卷积时,我们会将卷积核在图像上进行滑动,用卷积核的参数乘以对应位置的像素(然后加上偏置),即

y = wx+b

我们把Normalization的过程代入上面这个式子并化简:

y = w(x/255-mean)/std + b
# 化简后
y = (w/255/std)x + (b-w*mean/255/std)

这个过程中,我们发现式子可以看作一个新的y=wx+b,新的w是w/255/std,新的b则是b-w*mean/255/std。所以,我们可以提前对卷积核参数进行变化,从而将两个算子合并为一个算子。

这是一个最简单的例子,其它的算子融合和上述操作的原理是类似的。

矩阵乘法操作 + 激活函数 融合

神经网络里最常见的还有矩阵乘法操作 + 激活函数的组合,比如卷积层后面紧跟着一个ReLU,或者Transformer的FFN中Linear跟着一个GeLU等。 激活函数可以在计算矩阵乘法的同时计算,下面是用c++写的一个伪代码的例子:

// 矩阵乘法 + ReLU的融合
void MatMul(input, weight, bias, output, num_of_elements) {for (int i = 0; i < num_of_elements; i++){for (int j = 0; j < num_of_elements; j++){int accumulator = 0;for (int k = 0; k < num_of_elements; k++){accumulator += input[i][k] * weight[k][j];}// reluoutput[i][j] = accumulator + bias[j] > 0 ? accumulator + bias[j]: 0;}}
}

矩阵乘法就是不断计算向量的点积,即一系列数字相乘后求和,而激活函数基本是对数字进行一个非线性的变换,所以非线性变换的过程可以求和得到结果之后马上进行,而不是进行完所有的矩阵乘法之后,再读一遍矩阵进行非线性的变换。

线性变换 + BatchNorm 融合

线性变换+BN也是一个常见的组合,比如YoloV5中就有很多的CBS(Conv+BN+SiLU)的组合(这里把Conv就是局部的线性变换)。

这种融合可以通过简化合并公式的方式进行:
Y = W x + B Y ′ = γ Y − m e a n v a r + β Y ′ = γ W x + B − m e a n v a r + β Y ′ = γ v a r W x + γ v a r ( B − m e a n ) + β Y=Wx+B \quad Y^\prime=\gamma\frac{Y-mean}{var}+\beta \\ Y^\prime = \gamma\frac{Wx+B-mean}{var}+\beta \\ Y^\prime = \frac{\gamma}{var}Wx + \frac{\gamma}{var}(B-mean) + \beta Y=Wx+BY=γvarYmean+βY=γvarWx+Bmean+βY=varγWx+varγ(Bmean)+β

常量折叠

这个是在代码编译领域也常用的优化方法,举个最简单的例子,当我们写python的时候,我们想让某个程序暂停两个小时,则一般会写time.sleep(2*60*60),这个时候假如让程序在运行时再计算2*60*60就会略显繁琐,所以编译器会提前把2*60*607200代替。

更复杂的例子涉及到多个变量,比如a=5;b=a+3;c=b+a,这个时候优化的方式就是提前计算出b,c的值。

公共子表达式消除

公共表达式是传统编程语言编译器常用的优化的一种,在程序中计算表达式时,有时会出现公共的子表达式,重复计算这些子表达式会增加计算开销。

比如下面这个例子:

temp = b * c
a = b * c + g
d = b * c + e

计算a和d的时候会重复计算b*c,假如我们只计算一次temp = b * c,然后计算a=temp+g, d=temp+e,就能提高效率。

到了神经网络领域,可能会出现下图左边这个情况,此时需要合并成右边这种情况,从而简化计算图。

在这里插入图片描述

死代码消除

这也是传统编程语言编译器中的一种优化方式,比如下面这个代码,return之后的代码是unreachable的,所以编译后应该完全消除这部分。

def test(flag):print("Flag is False.")returnprint("This code is unreachable.")

到了神经网络上,在计算图上其实能比较直观地发现没有用的节点或者不可达的节点。比如有一个节点孤立在计算图外面;或者某个节点有输入没输出且不是输出节点;或者某个节点有输出没输入且不是输入节点。

总结

神经网络编译器和传统编程语言编译器非常相似,其许多优化技术都是从编程语言编译器中沿用而来,但是神经网络编译器也有它的特点,有新的例如算子融合的优化方法可以用。这些优化方式能够对神经网络的部署起到关键的作用。

总结

神经网络编译器和传统编程语言编译器非常相似,其许多优化技术都是从编程语言编译器中沿用而来,但是神经网络编译器也有它的特点,有新的例如算子融合的优化方法可以用。这些优化方式能够对神经网络的部署起到关键的作用。


http://www.ppmy.cn/news/1547225.html

相关文章

【热门主题】000049 人工智能学习框架:开启智能未来的钥匙

前言&#xff1a;哈喽&#xff0c;大家好&#xff0c;今天给大家分享一篇文章&#xff01;并提供具体代码帮助大家深入理解&#xff0c;彻底掌握&#xff01;创作不易&#xff0c;如果能帮助到大家或者给大家一些灵感和启发&#xff0c;欢迎收藏关注哦 &#x1f495; 目录 【热…

云时代基础设施模型:可变与不可变之析

在基础设施管理的领域中&#xff0c;存在两种起着主导作用的方法&#xff0c;也就是可变基础设施与不可变基础设施。它们决定着资源的部署以及维护的模式&#xff0c;对更新的实施途径、基础设施的演进方向&#xff0c;还有不同环境之间的一致性保障起着关键的作用。 可变基础设…

梧桐数据库分区表提高查询效率的策略分析

梧桐数据库分区表提高查询效率的策略分析 概述 在大数据时代&#xff0c;数据库的性能优化成为了一个重要议题。分区表作为一种有效的数据库优化手段&#xff0c;通过将大型表分割成多个小的、可管理的分区&#xff0c;可以显著提高查询效率和数据管理的便利性。本文将详细探…

Unity6 + Android Studio 开发环境搭建【备忘】

目录 版本兼容异常 软件下载 SDK与NDK下载 配置路径 打包APK 版本兼容异常 背景&#xff1a;本机有段时间没使用过Unity开发项目了&#xff0c;本机安装有Android Studio老版本。 尝鲜Unity6新版本&#xff0c;选择Mobile模板工程&#xff0c;切换至Android平台&#xff…

计算机网络-网络编程

一、客户端和服务器 学习传输层给应用层提供的api&#xff0c;可以写代码把数据交给传输层&#xff0c;进一步通过层层封装就可以把数据通过网卡发送出去了 网络中主动发起请求的一方被称为客户端&#xff0c;被动接收的一方被称为服务器 客户端和服务器之间的交互有很多模式…

开源模型应用落地-qwen模型小试-Qwen2.5-7B-Instruct-tool usage入门-集成心知天气(二)

一、前言 Qwen-Agent 是一个利用开源语言模型Qwen的工具使用、规划和记忆功能的框架。其模块化设计允许开发人员创建具有特定功能的定制代理,为各种应用程序提供了坚实的基础。同时,开发者可以利用 Qwen-Agent 的原子组件构建智能代理,以理解和响应用户查询。 本篇将介绍如何…

.NET 中的虚拟内存

在 .Net 中&#xff0c;虚拟内存是由操作系统管理的地址空间&#xff0c;允许应用程序在可用物理内存&#xff08;RAM&#xff09;之上分配和使用更多的内存。C# 程序&#xff08;或 .NET 程序&#xff09;运行在 .NET 公共语言运行时&#xff08;CLR&#xff09;上&#xff0c…

SQL,力扣题目1126,查询活跃业务

一、力扣链接 LeetCode_1126 二、题目描述 事件表&#xff1a;Events ------------------------ | Column Name | Type | ------------------------ | business_id | int | | event_type | varchar | | occurrences | int | ------------------------…