跳到主要内容

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