简答题 4分×8个=32分
分析题 7分×4个=28分
设计题 40分 (1000~1200字)用什么算法,讲清楚
第1章 绪论
嵌入式系统(结构共性)
机器学习算法在嵌入式系统实现时所用的优化手段分层 (会画图,内容会描述)
第2章 嵌入式软件编程模式和优化
常见的嵌入式系统运行模式 P9-17
基于周期调用的运行模式 几个任务按顺序循环执行 基于中断的前后台运行模式 引入中断服务程序,使传感器数据输入间隔稳定 基于事件队列的运行模式 后台程序根据输入内容生成“事件”挂到全局的“事件队列”,前台程序不断检查事件队列,找到其中待处理的事件数据包,提取并执行 带时间信息的事件队列运行模式 系统根据当前时间检查事件队列,对于时间匹配的事件队列,执行队列中的所有事件,执行完删除该队列 计算图运行模式 根据各个运算之间的数据依赖关系制定执行顺序,即每个运算节点的所有输入数据都已经准备好之后才能执行。
2.2通用软件优化方法 P20
循环结构优化——针对具有多层嵌套的循环执行结构的优化
时间空间平衡——增加内存空间换取运算时间降低或者反过来的优化方法
运算精度和性能平衡——通过降低运算精度来提升运算速度并降低存储空间的方法
底层运算的快速实现算法——对于底层的乘除运算用等效的位操作提速
内存使用优化——通过调整运算次序或者复用内存,降低程序对嵌入式系统的最大内存需求
第3章 机器学习算法概述
3.3 SVM分类器 (知道怎么回事)P40
SVM(Support Vector Machine,支持向量机)是被广泛使用的分类算法,是神经网络热潮到来前应用最广泛的机器学习算法之一。SVM的数学描述一般是通过核空间的距离给出的,这里我们基于RBF(Radial Basis Function)核SVM的原理给出一个直觉上的解释,如果需要了解更加严格的理论分析,读者可以查阅本章参考文献。
SVM分类器根据物体的特征取值将其分为两类 ,图3-3给出了若干个物体样本在特征空间的位置,图中空心点和实心黑点分别表示两种不同的物体。
可以看出,空心点和实心黑点的分布位置具有一定的规律,从直觉上可以用图示虚线分离这两类点,在虚线上方的是第一类(空心点对应的类别),在虚线下方是第二类(实心黑点对应的类别)。SVM通过构建分类判别函数f(x)实现在两类物体的特征空间取不同的符号 ,比如在第一类物体特征空间(曲线上方)取值为正,在第二类物体特征空间(曲线下方)取值为负。在这个例子中, 代表特征空间的点的坐标。
3.6 神经网络
3.6.1 原理概述
2.卷积运算 (画图或会写伪代码)
神经网络中的卷积运算主要是二维卷积,它可以看成滑动窗口在需要卷积的特征数据上移动,在每个移动位置计算窗口内元素的加权和,如图3-10所示。
在很多神经网络软件框架中,卷积运算被转换成矩阵乘法实现,下面通过一个简单的例子说明。图3-11给出了一个二维卷积的例子。
图3-11中给出的4个卷积结果对应的运算为
上面的运算是线性运算,可以写成下面的矩阵形式:
伪代码 P209
折叠的 伪代码 P209
// 单通道卷积计算
void conv2d_f32(
float *din,
float *dout,
int din_hgt,
int din_wid,
const float *ker,
const int *shape)
{
int k_hgt = shape[0], k_wid = shape[1];
int dout_hgt = din_hgt - k_hgt + 1;
int dout_wid = dout_wid - k_wid + 1;
for (int h = 0; h < dout_hgt; h++)
{
for (int w = 0; w < dout_wid; w++)
{
for (int kh = 0; kh < k_hgt; kh++)
{
for (int kw = 0; kw < k_wid; kw++)
{
dout[h][w] += din[h + kh][w + kw] * ker[kh][kw];
}
}
}
}
}
// 二维卷积层计算
void conv2d_f32(float *dout, // 输出数据
float *din, // 输入数据
int din_hgt, // 输入数据(矩阵)高度
int din_wid, // 输入数据(矩阵)宽度
const float *ker, // 卷积核
const float *bias, // 偏置
const int *shape) // 卷积核形状
{
// 卷积核尺寸
int num_cout = shape[0], num_cin = shape[1];
int k_hgt = shape[2], k_wid = shape[3];
// 输出数据尺寸
int dout_hgt = (din_hgt - k_hgt + 1);
int dout_wid = (din_wid - k_wid + 1);
for (int cout = 0; cout < num_cout; cout++)
{
// 加上偏置
for (int n = 0; n < dout_hgt * dout_wid; n++)
dout[cout * dout_hgt * dout_wid + n] = bias[cout];
// 对每个输入通道计算二维卷积
for (int cin = 0; cin < num_cin; cin++)
{
// h和w是滑动窗位置
for (int h = 0; h < dout_hgt; h++)
{
for (int w = 0; w < dout_wid; w++)
{
// kh和kw是卷积核内的元素位置
for (int kh = 0; kh < k_hgt; kh++)
{
for (int kw = 0; kw < k_wid; kw++)
{
// dout[cout][h][w] +=
// din[cin][h+kh][w+kw] *
// ker[cout][cin][kh][kw]
dout[cout * dout_hgt * dout_wid + h * dout_wid + w] +=
din[cin * din_hgt * din_wid + (h + kh) * din_wid + (w + kw)] *
ker[cout * num_cin * k_hgt * k_wid + cin * k_hgt * k_wid + kh * k_wid + kw];
}
}
}
}
}
}
return;
}
3.6.2 模型训练和推理
神经网络结构(一定会画LeNet结构)P51
图3-15 手写数字识别神经网络的结构和各层数据尺寸
神经网络运算流程的描述如下:
1)第一个卷积层使用32个5×5的卷积核对28×28原始图片进行卷积,得到32个24×24的卷积结果,经过ReLU激活函数运算并池化后,得到32个12×12的特征图。
2)第二个卷积层使用32个32通道的5×5卷积核,作用于上一层数据得到32个8×8的特征图,经过ReLU和池化后得到32个4×4特征图。
3)第二卷积层处理结果被“拉直”成512维(512=32×4×4)的向量。
4)第一个全连接层,该层输出1024维的向量,输出同样经过ReLU函数运算。
5)第二个全连接层,该层输出10维向量,作为10个数字类型的匹配“得分”。其中“得分”最高的元素对应于原始图像对应的最可能的数字。
上述神经网络通过现成的神经网络框架能够高效地构建和训练。代码清单3-6所示是基于Pytorch的神经网络构建的代码。
折叠的 3-6 代码
##网络
class mnist_c(nn.Module):
def __init_(self):
super(mnist_c, self).__init__()
self.conv1 = nn.Conv2d(1, 32, 5, 1)
self.conv2 = nn.Conv2d(32, 32, 5, 1)
self.dropout = nn.Dropout2d(0.4)
self.fc1 = nn.Linear(512, 1024)
self.fc2 = nn.Linear(1024, 10)
# 浮点训练和推理
def forward(self, x):
x = self.conv1(x)
x = F.relu(x)
x = F.max_pool2d(x, 2)
x = self.conv2(x)
x = F.relu(x)
x = F.max_pool2d(x, 2)
x = torch.flatten(x, 1)
x = self.fc1(x)
x = F.relu(x)
x = self.dropout(x)
x = self.fc2(x)
return x
上面的代码中,函数forward定义了神经网络的具体运算,相比之前的图3-15,上面的代码多了一个dropout运算(倒数第三行),这一运算用于在训练过程中将部分运算结果置零,这样能够提高神经网络训练效果,在神经网络推理运算中,dropout层的运算被直接跳过。
第4章 数值的表示和运算
4.1 浮点数
4.1.1 单精度和双精度浮点数
P55 图4-1 32位单精度浮点数的具体存储结构
P55 图4-2 64位双精度浮点数的具体存储结构
存储的内容包括三部分:符号位S、指数位E和尾数位M。其中指数位E存储指数值的二进制编码,对于单精度浮点数,其对应指数值是,对于双精度浮点数,对应指数位为。尾数位M有两种格式——规范化格式和非规范化格式。这里主要讨论规范化格式,在这一格式下,M用于记录形如(1.xxxx)2的二进制数,小数点的左边固定为1,因此M中不需要额外保存这个1,只保存小数点之后的内容。对于规范化的普通浮点数,单精度数中E的取值范围是1~254,双精度数中E的取值范围是1~2046。从以上特点可以看到,对于规范化表示形式,浮点数的具体值如下。
这个127和1023是什么东西?答:是偏置。为什么要有偏置?答:使指数以无符号形式存储,便于浮点数加减运算时候对阶操作。 为什么是127和1023?答:E全0时,根据S为0或1表示+0和-0,;E全1时,根据M全0或非全0表示无穷或无效数。 [0,255]变成[1,254],[1,254] -127 得到 [-126,127]
下面给出一个具体的32位单精度浮点数的例子:
如上所示的32位数据对应:
于是,它对应的数值是
下面是双精度浮点数的例子,对应的数据是 。它在双精度浮点数格式中显示为
如上所示的64位数据对应:
它所表示的数值为
隐藏的 一些解释
单精度能够表示的数值范围是
,双精度能够表示的数值范围是
。单精度和双精度浮点数的取值范围足够大,几乎满足所有机器学习的运算需要。对于机器学习以及各种算法,除了表示数值的范围外,另一个重要的指标是动态范围,即对不同数值的分辨能力,这可以通过它们能够表示的(规范化格式)最小正数和最大正数来表示,即
在IEEE754标准中,还定义了几种特殊的浮点数二进制形式,它们对应的数值不能用之前给出的公式计算。比如:“正无穷大”INF,它对应的二进制形式中E部分的位全为1,对应的M部分的所有位都是零;“无效数”NAN,它对应的二进制形式中E部分的位全为1,对应的M部分的位非全零。
之前的讨论给出了从二进制计算浮点数值的公式,这个公式是针对“规范化”的浮点数的。在应用中,大多数浮点数属于“规范化”浮点数,并适用于之前给出的公式。但IEEE754标准还定义了一类“非规范化”的数,这类浮点数的指数部分E全零,计算“非规范化”浮点数对应的公式和之前不同,具体如下。
“非规范化”浮点数能够表示的最小正数小于“规范化”浮点数的。由于“非规范化”浮点数存储尾数的有效数字减小,因此这一简化过程会损失一些计算精度。
对于纯软件实现的浮点运算的嵌入式系统(不带有浮点协处理器的嵌入式处理器),标准数学运算函数库的API在运算过程中尽量使用“规范化”形式存储的浮点数,但这一过程会占用一定的运算时间,对于速度有严格要求的应用,为了进一步降低预算时间,允许部分浮点数的运算使用非规范化的表示形式。对于拥有硬件浮点运算单元的处理器,硬件往往被优化成只针对“规范化”浮点数运算,对于这类系统,使用非规范化的浮点数运算需要额外的软件协助,反而会降低运算速度。
4.3仿射映射量化
4.3.2 量化数据运算(乘法解释)P83-84
仿射映射变换使用下面的公式将量化符号q和它表示的实数d对应起来:
其中d是实数,q是整数,是实数d的量化表示,z是零点,代表实数0的量化表示,通常也用整数表示,s是量化步长,代表上述量化数能够表示的两个实数数值的最小间隔。对于任意给定的实数d,仿射映射量化过程就是根据(s,z)计算它的量化符号q,使得s(q-z)和d最接近,具体算法如下:
下面我们讨论使用仿射映射量化的数据的运算。讨论过程中使用记号(s,z,q)表示为量化中心为z、步长为s以及量化符号为q的仿射映射量化数据。考虑两个量化数
和
的相乘运算,它们的乘积用
表示。这3个数对应的浮点数值分别是
根据乘积关系c=ab可以得出
其中 使用整数乘法即可完成,不需要进行浮点运算。对于 的计算,通常需要用到浮点数运算,但我们可以使用整数乘法加上移位实现。这通过下面的例子说明。比如 ,我们希望计算它和整数x的乘积,首先可以将0.7近似表示为下面的形式:
于是
其中分子计算只需要进行整数乘法,而分母对应的除法只需要移位操作实现。类似算法的更多细节可以在4.4节找到。
第5章 卷积运算优化
5.2 快速卷积算法
5.2.1 一维循环卷积频域快速算法 (理解卷积怎么到频域)P114~
两个长度同为N的序列 x、h,分别进行离散傅里叶变换 ,相乘 ,再进行离散傅里叶反变换 ,得到x与h循环卷积的结果。
*卷积定理:卷积定理是傅立叶变换满足的一个重要性质。卷积定理指出,函数卷积的傅立叶变换是函数傅立叶变换的乘积。具体分为时域卷积定理和频域卷积定理,时域卷积定理即时域内的卷积对应频域内的乘积;频域卷积定理即频域内的卷积对应时域内的乘积,两者具有对偶关系。
折叠的 推导和代码、矩阵描述 P114-116
最常见的循环卷积优化是使用频域变换的方式实现的。前面介绍循环卷积时,提到可以用多项式表示循环卷积过程,基于频域变换的快速卷积算法可以通过多项式解释。考虑两个长度同为N的序列
和
,它们的循环卷积结果是多项式y(p)的系数:
其中:
令 ,于是有
式(5-19)表明x(p)和h(p)分别是序列
和
在频点nω的离散傅里叶变换。取ω=2π/N,“自动”满足
,得到
根据 y(p) 的多项式形式,可见此时 可以通过 x(p)h(p) 的离散傅里叶反变换得到。于是我们可以用两次离散傅里叶变换和一次离散傅里叶反变换实现循环卷积,如下面的Python代码所示。
import numpy as np
# 生成循环卷积的测试序列x和h
N = 20
x = np.random.randint(-10, 10, N).astype(float)
h = np.random.randint(-10, 10, N).astype(float)
fx = np.fft.fft(x) # 序列x的DFT
fh = np.fft.fft(h) # 序列h的DFT
fy = fx * fh
y = np.fft.ifft(fy) # 序列x和h的循环卷积结果
基于傅里叶变换的循环卷积可以写成下面的矩阵方程形式:
其中 W 是离散傅里叶变换矩阵(注意,该变换矩阵有几种不同的表示形式,相差一个比例因子N或者√N,本书使用定义使得W是酉矩阵):
上面公式中 代表W的共轭,符号⊙代表两个向量逐元素相乘,比如[1 2]⊙[10 100]=[10 200];(Wx)和(Wh)分别看成数据序列x 和h 的“频域”表示,而乘以 的运算代表频域到时域的反变换运算。这一变换过程如图5-5所示。
5.3 近似卷积算法 (几种近似卷计算法)
5.3.1 基于卷积核低秩分解的二维快速卷积
5.3.2 矩形卷积核近似卷积
5.3.3 分段线性卷积核近似
5.3.4 卷积核的分段近似
5.3.5 基于IIR滤波器的近似卷积
5.3.6 基于卷积核低秩近似的二维近似快速卷积
5.3.7 基于二维矩形卷积核的近似快速卷积
第8章 ARM平台上的机器学习编程
嵌入式处理器分类
FPGA:现场可编程逻辑门阵列
FPGA 器件属于专用集成电路中的一种半定制电路,是可编程的逻辑列阵 ,能够有效的解决原有的器件门电路数较少的问题。FPGA 的基本结构包括可编程输入输出单元,可配置逻辑块,数字时钟管理模块,嵌入式块RAM,布线资源,内嵌专用硬核,底层内嵌功能单元。由于FPGA具有布线资源丰富,可重复编程和集成度高,投资较低的特点 ,在数字电路设计领域得到了广泛的应用。FPGA的设计流程包括算法设计、代码仿真以及设计、板机调试,设计者以及实际需求建立算法架构,利用EDA建立设计方案或HD编写设计代码,通过代码仿真保证设计方案符合实际要求,最后进行板级调试,利用配置电路将相关文件下载至FPGA芯片中,验证实际运行效果。
MPU:嵌入式微处理器
嵌入式微处理器是由通用计算机 中的CPU演变而来的 。它的特征是具有32位以上的处理器,具有较高的性能 ,当然其价格也相应较高。但与计算机处理器 不同的是,在实际嵌入式应用中,只保留和嵌入式应用紧密相关的功能硬件,去除其他的冗余功能部分 ,这样就以最低的功耗和资源实现嵌入式应用的特殊要求
MPU是计算机的计算、判断或控制中心 ,有人称它为”计算机的心脏 ”。
MCU:嵌入式微控制器
微控制单元 (Microcontroller Unit) ,又称单片微型计算机 (Single Chip Microcomputer )或者单片机 。
是把中央处理器的频率与规格做适当缩减 ,并将 内存(memory)、计数器(Timer)、USB、A/D转换、UART、PLC、DMA等周边接口 ,甚至LCD驱动电路都整合在单一芯片上,形成芯片级的计算机,为不同的应用场合做不同组合控制 。诸如手机、PC外围、遥控器,至汽车电子、工业上的步进马达、机器手臂的控制等,都可见到MCU的身影。
DSP:嵌入式DSP处理器
嵌入式DSP处理器(Embedded Digital Signal Processor,EDSP)是一种非常擅长于高速实现各种数字信号处理运算(如数字滤波 、频谱分析等)的嵌入式处理器 。由于对DSP硬件结构和指令进行了特殊设计,使其能够高速完成各种数字信号处理算法。
SOC:嵌入式片上系统
SOC的定义多种多样,由于其内涵丰富、应用范围广,很难给出准确定义。一般说来, SOC称为系统级芯片 ,也有称片上系统 ,意指它是一个产品,是一个有专用目标的集成电路 ,其中包含完整系统并有嵌入软件的全部内容 。同时它又是一种技术,用以实现从确定系统功能开始,到软/硬件划分,并完成设计的整个过程 。
从狭义角度讲,它是信息系统核心的芯片集成,是将系统关键部件 集成在一块芯片上 ;从广义角度讲, SoC是一个微小型系统,如果说中央处理器 (CPU)是大脑,那么SoC就是包括大脑、心脏、眼睛和手的系统。国内外学术界一般倾向将SoC定义为将微处理器 、模拟IP(Intellectual Property)核、数字IP核和存储器 (或片外存储控制接口)集成在单一芯片上 ,它通常是客户定制的,或是面向特定用途的标准产品。
ARM处理器主要分三个系列:Cortex-A/M/R
Cortex-A
该系列处理器侧重复杂应用,能够运行类似Linux级别的操作系统。 在操作系统支持下运行多任务应用程序,提供丰富的人机交互功能。这一类处理器关注运算性能,功耗和速度相对较高,应用领域包括平板电脑和彩屏手机等。
Cortex-M
该系列处理器针对工业控制应用,在外围接口控制器和片内运算加速硬件的选择上根据工业应用需求进行优化,平衡外围电路复杂度、系统功耗、可靠性和成本 。Cortex-M系列处理器在片内存储和运算能力上低于Cortex-A系列处理器 ,但它在工业控制和消费类家电产品中得到广泛应用。 在大多数嵌入式应用系统中,Cortex-M处理器往往站在“幕后”,不直接参与用户界面操作,比如用于设备的电源控制、传感器芯片数据传输和接口管理等。
Cortex-R
这一系列处理器面向需要实时,快速响应的应用 ,对功耗、性能和封装形式进行了优化,使之适用于可靠性和容错要求更高的工业应用领域 。
8.1 CMSIS软件框架概述
会分层
CMSIS(Cortex Microcontroller Software Interface Standard)
P258 图8-1 CMSIS软件接口标准的模块构成
图8-1的左侧列出了CMSIS软件的三个分层:应用层、CMSIS层、硬件层,中间的CMSIS层包括了独立于具体的ARM处理器型号的软件模块,它们规定了和ARM处理器平台无关的通用接口规范。最下层硬件层是和ARM处理器型号以及外围控制器相关的定义。CMSIS框架的核心部分包括了多个子模块,下面简要列出这些子模块的功能说明。
折叠的 上图中每个部分的说明 P258-260
CMSIS-Core
CMSIS-Core提供ARM处理器启动时最初运行的代码、处理器内部单元的访问代码以及外设控制器部分代码。这些代码包括处理器、寄存器的基本配置,默认的中断服务程序的代码,时钟中断设置等。这部分代码为后续的软件执行提供一个最基本的运行环境。
CMSIS-DAP
CMSIS-DAP中的DAP来自英文Debug Access Port的首字母。它规定了ARM处理器和调试器的统一接口,包括调试控制命令、数据格式等信息。CMSIS-DAP同时包括了ARM处理器调试控制固件(firmware)的具体实现,它使得PC端的调试软件通过USB口和ARM处理器通信,并执行调试任务。利用CMSIS-DAP提供的固件可以快速实现一个Cortex处理器的仿真器硬件,如图8-2所示。关于CMSIS-DAP的细节,请参照https://arm-software.github.io/CMSIS_5,我们在这里不详细展开。
CMSIS-Zone
对于复杂的ARM处理器架构以及多核ARM处理器,不同软件模块运行在相互分离的不同“空间”。这里的“空间”就是英文单词Zone,它包括了软件模块运行的地址访问范围以及能够访问的外围控制器集合两部分。CMSIS-Zone定义了用于描述不同空间的文件格式,并提供图形化的界面生成这些描述文件。而这些描述文件能够进一步被自动代码生成工具使用,生成各种程序源代码,包括编译链接脚本文件、地址空间定义的头文件、CPU启动时刻的初始化代码、C/C++代码框架等。
CMSIS-RTOS
CMSIS-RTOS是实时操作系统(Real Time Operating System,RTOS)的接口API,它本身不是RTOS,需要和第三方提供的RTOS一起使用,但它为上层应用提供名称统一的API接口,通过这些API调用底层不同类型操作系统的服务。使用CMSIS-RTOS定义的API接口,使得运行在操作系统上的用户应用程序可以和底层操作系统的类型“无关”,方便应用程序移植到兼容CMSIS-RTOS的不同实时操作系统上。下图所示是基于CMSIS-RTOS架构的示意图。
CMSIS-NN
CMSIS-NN包括和神经网络相关的数学运算代码,其中一部分运算基于CMSIS-DSP实现。它具体包括了神经网络卷积层的卷积运算、激活函数运算、神经网络全连接层的计算、softmax运算等。
CMSIS-DSP
CMSIS-DSP包括一系列数学运算的实现代码,用于各类信号处理应用,内容包括快速算法、复数运算、矩阵运算、时域/频域变换运算、数据统计、插值等数学运算。它同时也包括和应用相关的滤波运算和电机控制代码。这些代码针对特定的处理器进行了手工优化,因此对于不同的ARM处理器类型有不同的版本,用户程序需要用“宏开关”来选择和所使用的处理器匹配的代码。
CMSIS-Driver
CMSIS-Driver定义了处理器内置的外部设备控制器的驱动程序API接口,包括描述不同设备操作函数API的头文件以及建议的设备操作流程。使用CMSIS-Driver定义的驱动程序API接口使得用户应用程序能够和设备的具体型号保持相对“独立”,便于软件在不同处理器上移植。需要注意的是,驱动程序API接口仅仅是头文件里的函数申明,而具体的代码实现细节还是需要第三方开发完成。由于CPU外围控制器的多样性,CMSIS-Driver定义的内容随着硬件产品更新而不断扩充。
CMSIS-SVD
CMSIS-SVD中的SVD是指System View Description,即“系统视图描述”,CMSIS-SVD定义了基于XML文本的处理器外设信息和参数格式,这一格式的文本能够清晰地描述每种Cortex-M处理器的特性,包括处理器型号、总线位宽、外围控制器特性、片内寄存器等。ARM的硬件调试器通过这些描述文件,在调试时为程序员提供处理器状态数据显示。下图给出了CMSIS-SVD定义的XML文件的层次化结构,它从高到低定义了ARM处理器的所有参数信息,包括了从器件级、处理器级、外围控制器级、存储器级、寄存器域级和每个位域取值的信息。
8.5.2 基于ONNX 格式的机器学习模型构建
:你要知道onnx这个格式
1.ONNX数据格式概述
ONNX是英文Open Neural Network Exchange的缩写,它是一种开放的神经网络数据格式 。不同的神经网络训练框架对应的数据模型可以转换成ONNX格式表示 ,目前已有的转换工具支持TensorFlow、Caffe,Pytorch,Microsoft Cognitive Toolkit,Apache MXNet等神经网络框架输出的模型数据文件和ONNX数据格式之间的相互转换。
ONNX除了用于描述神经网络模型之外,也能够用于描述其他机器学习算法模型,包括随机森林、SVM等常见的机器学习模型。现有的转换工具支持将Scikit-Learn软件包训练生成的机器学习模型转成ONNX格式。
ONNX文件格式有不同的版本,每个版本支持的神经网络或者机器学习的算子范围各不相同。ARM NN目前支持的ONNX的算子类型有限,一些复杂的ONNX模型数据还不能够直接被ARM NN解析,但ARM NN对ONNX的支持在不断扩展中。目前对ONNX所定义的算子支持比较全面的有微软的ONNX-Runtime,它分为x86和ARM版本,可以从GitHub下载编译得到ONNX的模型数据的执行环境。
通过ONNX格式“中转”可以实现不同神经网络框架生成的网络数据模型格式转换。下面列出部分ONNX格式转换软件包(Python下的软件包):
·sklearn-onnx——将Python下的Scikit-Learn训练得到的机器学习模型转成ONNX格式。
·tensorflow-onnx(tf2onnx)——将TensorFlow模型转成ONNX格式。
·keras2onnx——将Keras模型转成ONNX格式。
·ONNXMLTools——包括多个机器学习或者神经网络框架数据文件转成ONNX的工具,包括Keras、TensorFlow、Scikit-Learn、Apple Core ML、Spark ML、LightGBM、libsvm、XGBoost、H2O。