【无标题】

NXP eIQ 机器学习 — 2

第四章 ARM计算库
Arm Compute Library (ACL)是为Arm CPU和GPU架构优化的底层函数集合,主要用于图像处理、计算机视觉和机器学习。
Arm计算库被设计为Arm NN框架的计算引擎,因此建议使用Arm NN,除非需要更优化的运行时。
源代码可以在https://source.codeaurora.org/external/imx/arm-computelibrary-imx上找到。
特点:
Arm计算库21.08
在Cortex-A CPU核上使用Arm Neon SIMD指令加速的多线程计算
c++ API
对计算的低级控制
请注意:
i.MX 8设备不支持GPU OpenCL后端。

4.1.1使用图API运行AlexNet
2012年,AlexNet赢得了ImageNet大规模视觉识别挑战赛(ILSVRC),这是一个旨在评估目标检测和图像分类算法的年度挑战赛。AlexNet由8个可训练层组成:5个卷积层和3个全连接层。所有可训练层之后都有一个ReLu激活函数,除了最后一个完全连接的层,其中使用了Softmax函数。
使用图形API的c++ AlexNet示例实现的位置在这个文件夹中:/usr/bin/arm-compute-library-21.08/examples
演示说明:
将归档文件(compute_library_alexnet.zip)下载到示例位置文件夹。
创建一个新的子文件夹并解压缩文件:

$ mkdir assets_alexnet
$ unzip compute_library_alexnet.zip -d assets_alexnet

设置执行的环境变量:

$ export PATH_ASSETS=/usr/bin/arm-compute-library-21.08/examples/assets_alexnet/

使用以下命令行参数运行示例:

$ ./graph_alexnet --data=$PATH_ASSETS --image=$PATH_ASSETS/go_kart.ppm --labels=$PATH_ASSETS/labels.txt --target=neon --type=f32 --threads=4

分类的输出应该如下所示:

---------- Top 5 predictions ----------
0.9736 - [id = 573], n03444034 go-kart
0.0108 - [id = 751], n04037443 racer, race car, racing car
0.0118 - [id = 518], n03127747 crash helmet
0.0022 - [id = 817], n04285008 sports car, sport car
0.0006 - [id = 670], n03791053 motor scooter, scooter
Test passed

第五章 Arm NN
Arm NN是由利纳罗人工智能计划(Linaro Artificial Intelligence Initiative)开发的一个开源推理引擎框架,NXP是该计划的一部分。它不会自己执行计算,而是将来自多种模型格式(如TensorFlow Lite或ONNX)的输入委托给专门的计算引擎。
源代码可以在https://source.codeaurora.org/external/imx/armnn-imx上找到。
特点:
Arm NN 21.08
在ACL Neon后端提供的Cortex-A内核上使用Arm Neon SIMD指令进行加速的多线程计算
使用VSI NPU后端提供的GPU/NPU硬件加速(在着色器或卷积单元上)并行计算
c++和Python API(支持Python版本3)
支持多种输入格式(TensorFlow Lite, ONNX)
用于序列化、反序列化和量化的脱机工具(必须从源代码构建)
请注意:Arm NN推理引擎已弃用,未来将移除。
5.1 Arm NN软件栈
Arm NN软件栈如下图所示。Arm NN支持以下硬件单元的计算:
CPU Arm Cortex-A内核
GPU/NPU硬件加速器使用VSI NPU后端,它可以运行在GPU和NPU上,具体取决于哪一个可用
关于GPU/NPU加速器在各个硬件平台上的支持情况,请参见软件栈介绍
在这里插入图片描述
5.2计算后端
Arm NN本身并不擅长实现计算操作。在CPU上运行的只有c++引用后端,它没有进行性能优化,应该用于测试、检查结果、创建原型,或者在其他后端都不支持特定层的情况下作为最终的回退。其他后端将计算操作委托给其他更专门的库,如Arm compute Library (ACL)。
对于CPU:有NEON后端,它使用Arm计算库和Arm NEON SIMD扩展。
对于gpu和NPU: NXP提供VSI NPU后端,充分利用了使用OpenVX的i.MX 8的gpu /NPU的全部能力,提供了很大的性能提升。ACL OpenCL后端,你可能会注意到在源代码中,不支持由于Arm NN OpenCL要求没有被i.MX 8 gpu满足。
要在运行下面几节中描述的示例时激活所选择的后端,请添加以下参数。用户可以为示例应用程序提供多个后端。模型中的一层将由第一个后端执行,它支持该层:
<example_binary> --compute=arg
其中arg可以是:
CpuRef: Arm NN c++后端(没有SIMD指令);一组CPU上没有加速的参考实现,用于测试、原型或作为最终的回退。它非常慢。
CpuAcc: ACL NEON后端(运行在CPU上,使用NEON指令= SIMD)
VsiNpu:对于gpu和NPU, NXP提供VSI NPU后端,充分利用了i.MX 8 gpu的全部功能。
要开发自己的应用程序,请确保将选择的后端(CpuAcc、VsiNpu或CpuRef)传递给Optimize函数进行推断。
请注意
VsiNpu后端将执行委托给OpenVX驱动程序。工作负载是在NPU上执行还是在GPU上执行取决于驱动程序。
5.3运行Arm NN测试
Arm NN SDK提供了一组测试,也可以认为是演示Arm NN做什么和如何使用它。它们加载各种格式的神经网络模型(TensorFlow Lite, ONNX),对指定的输入数据运行推断,并输出推断结果。当构建Yocto映像时,默认构建Arm NN测试,并安装在/usr/bin/armnn-21.08。注意,输入数据、模型配置和模型权重不随Arm NN分布。用户必须分别下载它们,并在运行测试之前确保它们在设备上可用。然而,Arm NN测试没有附带文档。输入文件名是硬编码的,因此研究代码以找出期望的输入文件名。
为了帮助开始使用Arm NN,以下部分提供了关于如何准备输入数据和如何运行Arm NN测试的详细信息。所有这些都使用了众所周知的神经网络模型。因此,除了少数例外,这种预先训练的网络可以在Internet上免费获得。输入图像、模型、格式及其内容通过代码分析进行推导。然而,这对于所有的测试都是不可能的,因为要么模型不是公开可用的,要么不能清楚地推断出应用程序需要什么输入文件。一般的工作流程是先在主机上准备数据,然后将数据部署到板子上,在板子上运行实际的Arm NN测试。
下面几节假设神经网络模型文件存储在名为models的文件夹中,输入图像文件存储在名为data的文件夹中。使用以下命令在较大的分区上创建这个文件夹结构:

$ cd /usr/bin/armnn-21.08 
$ mkdir data 
$ mkdir models

5.3.1 TensorFlow Lite测试
Arm NN SDK为TensorFlow Lite模型提供以下测试:

/usr/bin/armnn-21.08/TfLiteInceptionV3Quantized-Armnn 
/usr/bin/armnn-21.08/TfLiteInceptionV4Quantized-Armnn 
/usr/bin/armnn-21.08/TfLiteMnasNet-Armnn 
/usr/bin/armnn-21.08/TfLiteMobileNetSsd-Armnn 
/usr/bin/armnn-21.08/TfLiteMobilenetQuantized-Armnn 
/usr/bin/armnn-21.08/TfLiteMobilenetV2Quantized-Armnn 
/usr/bin/armnn-21.08/TfLiteResNetV2-Armnn
/usr/bin/armnn-21.08/TfLiteVGG16Quantized-Armnn 
/usr/bin/armnn-21.08/TfLiteResNetV2-50-Quantized-Armnn 
/usr/bin/armnn-21.08/TfLiteMobileNetQuantizedSoftmax-Armnn 
/usr/bin/armnn-21.08/TfLiteYoloV3Big-Armnn

请注意
有关支持的操作符的完整列表,请参阅对TensorFlow Lite的支持。
下表提供了每个Arm NN TensorFlow Lite二进制示例的所有依赖项列表。
表1 Arm NN TensorFlow Lite示例依赖项
在这里插入图片描述
请注意
有些模型或输入文件不是公开可用的。
执行以下步骤来运行上面的每个例子:

  1. 下载模型(表格第2列)并复制到设备的模型文件夹中。
  2. 下载输入数据(表格第3列),复制到设备的data文件夹中。根据预期输入重命名所有JPG图像(shark.jpg, Dog.jpg, Cat.jpg)。所有这些名称都是区分大小写的。
    3.运行测试:
$ cd /usr/bin/armnn-21.08 
$ ./<armnn_binary> --data-dir=data --model-dir=models

5.3.2 ONNX测试
Arm NN为ONNX模型提供了以下一组测试:

/usr/bin/armnn-21.08/OnnxMnist-Armnn 
/usr/bin/armnn-21.08/OnnxMobileNet-Armnn

请注意
有关支持的操作符的完整列表,请参阅ONNX支持。
下表提供了每个Arm NN ONNX二进制示例的所有依赖项列表。
表2 Arm NN ONNX示例依赖项
在这里插入图片描述
执行以下步骤来运行上面的每个例子:
1.下载模型(表的第2列)。
2. 将原来的模型名称重命名为新的模型名称(表的第4列),并将其复制到设备上的models文件夹中。
3.下载输入数据(表格第3列),复制到设备的data文件夹中。
4.根据预期输入重命名所有JPG图像(shark.jpg, Dog.jpg, Cat.jpg)。所有这些名称都是区分大小写的。
5. 运行测试:

$ cd /usr/bin/armnn-21.08 
$ ./<armnn_binary> --data-dir=data --model-dir=models

5.4在自定义C/ c++应用中使用Arm NN
您可以使用Arm NN功能为i.MX 8系列设备创建自己的C/ c++应用程序。这需要使用Arm NNAPI编写代码,设置构建依赖关系,为aarch64架构交叉编译代码,并部署应用程序。下面是每个步骤的详细描述:
1.编写的代码。
了解如何在自己的应用程序中使用Arm NNAPI的一个很好的起点是阅读Arm提供的"How-to guides"。这包括一个演示如何加载和运行MNIST TensorFlow模型推断的应用程序。
2.准备和安装SDK。
从软件开发人员的角度来看,Arm NN是一个库。因此,要创建和构建一个使用Arm NN的应用程序,您需要头文件和匹配库。关于如何构建Yocto SDK,请参阅i.MX Yocto项目用户指南(IMXLXYOCTOUG)。默认情况下,不添加头文件和库。要确保SDK包含头文件和库,请将以下内容添加到local.conf中。
TOOLCHAIN_TARGET_TASK_append += " armnn-dev"
3.构建代码。
要构建Arm提供的“armnn-mnist”示例,你需要做一些修改,使其在Yocto交叉编译环境下工作:
从Makefile中删除ARMNN_INC的定义和它的所有用法。默认的include目录中已经有Arm NN头。
从Makefile中删除ARMNN_LIB的定义和它的所有用法。Arm NN库已经在默认链接器搜索路径中可用。
在Makefile中将“g++”替换为“${CXX}”。
构建示例:

$ source <Yocto_SDK_install_folder>/environment-setup-aarch64-poky-linux

运行make:

$ make

4.将构建的应用程序复制到板上。
输入数据在“How-to guides”中有描述。如果您在板上使用的映像与您为其构建SDK的映像相同,那么板上应该可以使用运行应用程序所需的所有运行时动态库。

5.5 python接口到ArmNN (PyArmNN)
PyArmNN是ArmNN SDK的Python扩展。PyArmNN提供类似于ArmNN c++ API的接口。它仅支持Python 3.x而不是Python 2.x。
完整的API文档请参考NXPmicro GitHub: https://github.com/NXPmicro/pyarmnn-release
5.5.1开始
开始使用PyArmNN最简单的方法是使用解析器。我们将在下面演示如何使用它们:
安装的依赖

pip3 install imageio

创建一个解析器对象并加载模型文件。

import pyarmnn as annimport imageio
# ONNX parser also exist.
parser = ann.ITfLiteParser()
network = parser.CreateNetworkFromBinaryFile('./model.tflite')

通过使用输入层的名称获取输入绑定信息。

input_binding_info = parser.GetNetworkInputBindingInfo(0, 'input_layer_name')
# Create a runtime object that will perform inference.
options = ann.CreationOptions()
runtime = ann.IRuntime(options)

选择执行的首选后端并优化网络。

列表中较早的后端选项的值较高

# Backend choices earlier in the list have higher 
preference.preferredBackends = [ann.BackendId('CpuAcc'), ann.BackendId('CpuRef')]opt_network, messages = ann.Optimize(network, preferredBackends, runtime.GetDeviceSpec(), ann.OptimizerOptions())
# Load the optimized network into the runtime.
net_id, _ = runtime.LoadNetwork(opt_network)

使用输入和输出绑定信息创建工作负载张量。

# Load an image and create an inputTensor for inference.
# img must have the same size as the input layer; PIL or skimage might be used for resizing if img has a different size
img = imageio.imread('./image.png')
input_tensors = ann.make_input_tensors([input_binding_info], [img])
# Get output binding information for an output layer by using the layer name.
output_binding_info = parser.GetNetworkOutputBindingInfo(0, 'output_layer_name')
output_tensors = ann.make_output_tensors([outputs_binding_info])

执行推断并将结果返回到numpy数组中。

runtime.EnqueueWorkload(0, input_tensors, output_tensors)
results = ann.workload_tensors_to_ndarray(output_tensors)
print(results)

5.5.2 运行示例
为了获得更完整的Arm NN体验,在/usr/bin/armnn-21.08/pyarmnn/中有几个示例,它们需要请求、PIL,可能还需要一些其他Python3模块,这取决于您的映像。您可以使用pip3包安装程序安装缺失的模块。例如,对于图像分类演示:

$ cd /usr/bin/armnn-21.08/pyarmnn/image_classification 
$ pip3 install -r requirements.txt

要运行这些示例,请使用Python3解释器执行它们。没有参数,资源由脚本下载。例如,对于图像分类演示:

$ python3 tflite_mobilenetv1_quantized.py

输出应该类似如下:

Downloading 'mobilenet_v1_1.0_224_quant_and_labels.zip' from 'https://storage.googleapis.com/download.tensorflow.org/models/tflite/mobilenet_v1_1.0_224_quant_and_labels.zip' ...
Finished.Downloading 'kitten.jpg' from 'https://s3.amazonaws.com/model-server/inputs/kitten.jpg' ...Finished.
Running inference on 'kitten.jpg' ...
class=tabby ; value=99
class=Egyptian cat ; value=84
class=tiger cat ; value=71
class=cricket ; value=0
class=zebra ; value=0

请注意:Example_utils.py是一个包含其他脚本通用函数的文件,它自己不执行任何东西。
5.6 Arm NN delegate for TensorFlow Lite
Arm NN Delegate是一个独立的软件,可以与TensorFlow Lite框架一起使用来加载TensorFlow Lite模型,并将工作负载委托给Arm NN库。
请注意:在5.10.52-2.1.0 Yocto版本中,只支持TensorFlow Lite c++ API。Python TensorFlow Lite API不支持加载动态委托。
5.6.1 Arm NN委托c++项目集成
下面的例子演示了一个使用TensorFlow Lite解释器将工作负载委托给Arm NN框架的示例项目。
1.在你的主机上激活Yocto SDK环境进行交叉编译(确保tensorflow-lite-dev和armn -dev包安装在SDK中,它们应该在构建SDK时默认存在),例如:<yocto_sdk_install_dir>/environment-setup-cortexa53-crypto-poky-linux
2. 源代码应该在aarch64 sysroot目录下,例如:/sysroot /cortexa53-crypto-poky-linux/usr/bin/armnn-21.08/delegate。交叉编译使用:$CXX -o armnn_delegate_example armnn_delegate_example.cpp -larmnn -larmnnDelegate -ltensorflow-lite
3.复制armnn_delegate_example到你的板上并运行它。输出应该如下所示:

$ ./armnn_delegate_example
INFO: TfLiteArmnnDelegate: Created TfLite ArmNN delegate.
Warm-up time: 4662.1 ms
Inference time: 2.809 ms
TOP 1: 412

现在让我们看看armnn_delegate_example.cpp中的代码:
1.首先,我们需要加载一个模型,创建TensorFlow Lite解释器,并分配适当大小的输入张量。你可以在你自己的项目中使用不同的tflite模型:

std::unique_ptr<tflite::FlatBufferModel> model = tflite::FlatBufferModel::BuildFromFile("/usr/bin/tensorflow-lite-2.6.0/examples/mobilenet_v1_1.0_224_quant.tflite"); 
auto interpreter = std::make_unique<Interpreter>(); 
tflite::ops::builtin::BuiltinOpResolver resolver; 
tflite::InterpreterBuilder(*model, resolver)(&interpreter); 
if (interpreter->AllocateTensors() != kTfLiteOk) 
{ 
std::cout << "Failed to allocate tensors!" << std::endl; 
return 0; 
} 

2.然后我们需要用一些数据填充这个张量。您可以从文件加载数据,或者简单地用随机数填充缓冲区。注意,在我们的例子中,我们使用的是量化模型,因此输入应该在< 0,255 >范围内,输入张量有3个通道和224x224输入:

srand (time(NULL));
uint8_t* input = interpreter->typed_input_tensor<uint8_t>(0); 
for (int i = 0; i < (3 * 224 * 224); ++i) { 
input[i] = rand() % 256;
} 

3.要配置Arm NN后端,我们必须指定委托选项。后端根据图层支持从左到右分配给各个图层:

std::vector<armnn::BackendId> backends = { armnn::Compute::VsiNpu, armnn::Compute::CpuAcc, armnn::Compute::CpuRef };armnnDelegate::DelegateOptions delegateOptions(backends);std::unique_ptr<TfLiteDelegate, decltype(&armnnDelegate::TfLiteArmnnDelegateDelete)> theArmnnDelegate(armnnDelegate::TfLiteArmnnDelegateCreate(delegateOptions), armnnDelegate::TfLiteArmnnDelegateDelete);
  1. 现在我们必须将委托应用到图中。这将把图划分为子图,这些子图将在可能的情况下使用Arm NN委托执行。剩下的将退回到CPU的TensorFlow Lite内置内核:
if (interpreter->ModifyGraphWithDelegate(theArmnnDelegate.get()) != kTfLiteOk)
{ 
std::cout << "Failed to modify graph!" << std::endl; 
return EXIT_FAILURE;
} 

5.然后,我们可以运行推断,检索结果,并处理它。来自mobilenet模型的输出是一个softmax数组,因此,例如要检索顶级标签,我们必须应用一个argmax函数。注意,在本例中,我们运行了2次推断。这是由于VsiNpu后台的使用,它有很长的预热时间:

if (interpreter->Invoke() != kTfLiteOk)
{ std::cout << "Failed to run second inference!" << std::endl; 
return EXIT_FAILURE;
}
...
uint8_t* output = interpreter->typed_output_tensor<uint8_t>(0); 
  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值