Android 应用程序
在 Android 中,除了 NN API 外,应用程序还可以直接访问 SyNAP。直接访问 SyNAP 的主要优势是零拷贝输入/输出以及执行使用 SyNAP 工具包提前编译的优化模型。
可以通过使用 synapnb 库的自定义 JNI C++ 代码访问 SyNAP。该库可以正常使用,唯一的限制是使用 Synap 分配器,可以通过 synap_allocator() 获取。
另一种选择是使用 synap_device 库的自定义 JNI C 代码。在这种情况下没有限制。该库允许使用 synap_allocate_io_buffer 函数创建新的 I/O 缓冲区。也可以使用从 gralloc 等获取的现有 DMABUF 句柄,使用 synap_create_io_buffer 创建。DMABUF 可以使用标准的 Linux DMABUF API(即 mmap/munmap/ioctls)访问。
SyNAP 提供了一个示例 JNI 库,展示了如何在 Java 应用程序中使用 synap_device 库。代码位于 java 目录中,可以通过在应用程序的 settings.gradle 中添加以下行来包含在现有的 Android 应用程序中:
include ':synap'
project(':synap').projectDir = file("[absolute path to synap]/java")
然后可以按如下方式使用代码:
package com.synaptics.synap;
public class InferenceEngine {
/**
* 使用传入的模型数据执行推理
*
* @param model EBG 模型
* @param inputs 包含模型输入数据的数组,每个网络输入一个字节数组,
* 大小为网络期望的大小
* @param outputs 用于存储网络输出的数组,每个网络输出一个字节数组,
* 大小为网络期望的大小
*/
public static void infer(byte[] model, byte[][] inputs, byte[][] outputs) {
Synap synap = Synap.getInstance();
// 加载网络
Network network = synap.createNetwork(model);
// 创建输入缓冲区并将其附加到网络
IoBuffer[] inputBuffers = new IoBuffer[inputs.length];
Attachment[] inputAttachments = new Attachment[inputs.length];
for (int i = 0; i < inputs.length; i++) {
// 创建所需长度的输入缓冲区
inputBuffers[i] = synap.createIoBuffer(inputs[i].length);
// 将缓冲区附加到网络(确保保持对附件的引用以避免被垃圾回收和销毁)
inputAttachments[i] = network.attachIoBuffer(inputBuffers[i]);
// 将缓冲区设置为网络的第 i 个输入
inputAttachments[i].useAsInput(i);
// 将输入数据复制到缓冲区
inputBuffers[i].copyFromBuffer(inputs[i], 0, 0, inputs[i].length);
}
// 创建输出缓冲区并将其附加到网络
IoBuffer[] outputBuffers = new IoBuffer[outputs.length];
Attachment[] outputAttachments = new Attachment[inputs.length];
for (int i = 0; i < outputs.length; i++) {
// 创建所需长度的输出缓冲区
outputBuffers[i] = synap.createIoBuffer(outputs[i].length);
// 将缓冲区附加到网络(确保保持对附件的引用以避免被垃圾回收和销毁)
outputAttachments[i] = network.attachIoBuffer(outputBuffers[i]);
// 将缓冲区设置为网络的第 i 个输出
outputAttachments[i].useAsOutput(i);
}
// 运行网络
network.run();
// 将结果数据复制到输出缓冲区
for (int i = 0; i < outputs.length; i++) {
outputBuffers[i].copyToBuffer(outputs[i], 0, 0, outputs[i].length);
}
// 释放资源(当对象被垃圾回收时会自动完成,但这可能需要一些时间,
// 所以最好尽快显式释放它们)
network.release(); // 这将自动释放附件
for (int i = 0 ; i < inputs.length; i++) {
inputBuffers[i].release();
}
for (int i = 0 ; i < outputs.length; i++) {
outputBuffers[i].release();
}
}
}
备注
为了简化应用程序开发,默认情况下,VSSDK 允许不受信任的应用程序(如从 Google Play 商店侧载或下载的应用程序)使用 SyNAP API。由于 API 使用有限的硬件资源,这可能导致第三方应用程序干扰平台进程的情况。要将 SyNAP 的访问限制为仅平台应用程序,请删除文件 vendor/vsi/sepolicy/synap_device/untrusted_app.te。