本目录提供了快速完成在 Android 的车载语音场景下的口语理解(Spoken Language Understanding,SLU)任务的部署示例。
- 在本地环境安装好 Android Studio 工具,详细安装方法请见Android Stuido 官网。
- 准备一部 Android 手机,并开启 USB 调试模式。开启方法:
手机设置 -> 查找开发者选项 -> 打开开发者选项和 USB 调试模式
- ERNIE 3.0 Tiny Android 部署示例位于
PaddleNLP/model_zoo/ernie-tiny/deploy/android
目录 - 用 Android Studio 打开 ernie-tiny/deploy/android 工程
- 手机连接电脑,打开 USB 调试和文件传输模式,并在 Android Studio 上连接自己的手机设备(手机需要开启允许从 USB 安装软件权限)
工程内容说明:
.
├── README.md
├── app # App示例代码
├── build.gradle
├── ernie_tiny # ERNIE Tiny JNI & Java封装代码
# ... # 一些和gradle相关的工程配置文件
├── local.properties
└── ui # 一些辅助用的UI代码
注意:
如果您在导入项目、编译或者运行过程中遇到 NDK 配置错误的提示,请打开
File > Project Structure > SDK Location
,修改Andriod NDK location
为您本机配置的 NDK 所在路径。本工程默认使用的NDK版本为20. 如果您是通过 Android Studio 的 SDK Tools 下载的 NDK (见本章节"环境准备"),可以直接点击下拉框选择默认路径。 还有一种 NDK 配置方法,你可以在local.properties
文件中手动完成 NDK 路径配置,如下图所示 如果以上步骤仍旧无法解决 NDK 配置错误,请尝试根据 Android Studio 官方文档中的更新 Android Gradle 插件章节,尝试更新Android Gradle plugin版本。
- 点击 Run 按钮,自动编译 APP 并安装到手机。(该过程会自动下载预编译的 FastDeploy Android 库 以及 模型文件,需要联网) 成功后效果如下,图一:APP 安装到手机;图二: APP 打开后的效果,输入文本后点击"开始分析意图"后即会自动进行意图识别和槽位分析;图三:APP 设置选项,点击右上角的设置图片,可以设置不同选项进行体验。
APP 效果 | APP 演示 | APP设置项 |
---|---|---|
![]() |
![]() |
![]() |
如果您使用的是较旧版本的Android Studio时遇到gradle版本兼容的问题,可以修改build.gradle 中的gradle版本号为您当前使用的版本。
buildscript {
// ...
dependencies {
classpath 'com.android.tools.build:gradle:7.2.2' // 修改为您当前使用的版本
}
}
- 点击 APP 右上角的设置选项,可以跳转到设置页。在设置页,您可以选择不同的模型和不同的推理精度,即是否开启 FP16 和 Int8 推理,两种推理精度只能二选一。所有模型均支持FP32推理,当设置项中的 FP16 和 Int8 选项都为 false 或 不设置 时,即使用了FP32进行推理。各模型FP16和Int8推理的支持情况为:
模型选项 | 模型名称 | FP16 | Int8 |
---|---|---|---|
models/ernie-tiny | 原模型 | ✅ | - |
models/ernie-tiny-clip | 原模型+裁剪(词表+模型宽度) | ✅ | - |
models/ernie-tiny-clip-qat | 原模型+裁剪(词表+模型宽度)+量化(矩阵乘) | - | ✅ |
models/ernie-tiny-clip-qat-embedding-int8 | 原模型+裁剪(词表+模型宽度)+量化(矩阵乘+Embedding) | - | ✅ |
本工程除了可以直接编译 App 体验之外,还可以编译 ERNIE 3.0 Tiny 的Java SDK
,方便用户开箱即用。 如下图所示,编译 Java SDK 的步骤为:
- 先在 Android Studio 中打开
ernie_tiny/build.gradle
工程文件; - 选择 Build->Make Module 'android:ernietiny';
- 从
ernie_tiny/build/outputs/aar
目录中获取编译后得到的 SDK,即ernie_tiny-debug.aar
.
在获取到ernie_tiny-debug.aar
后,可将其拷贝到您自己的工程中进行使用。在 Android Studio 中的配置步骤如下:
(1)首先,将ernie_tiny-debug.aar
拷贝到您 Android 工程的libs目录下。
├── build.gradle
├── libs
│ └── ernie_tiny-debug.aar
├── proguard-rules.pro
└── src
(2)在您的 Android 工程中的 build.gradle 引入 ERNIE 3.0 Tiny SDK,如下
dependencies {
implementation fileTree(include: ['ernie_tiny-debug.aar'], dir: 'libs')
implementation 'com.android.support:appcompat-v7:28.0.0'
// ...
}
- ERNIE 3.0 Tiny
Predictor
初始化 API: 模型初始化 API 包含两种方式,方式一是通过构造函数直接初始化;方式二是,通过调用 init 函数,在合适的程序节点进行初始化。ERNIE 3.0 Tiny Predictor 初始化参数说明如下:- modelFile: String, paddle 格式的模型文件路径,如 infer_model.pdmodel
- paramFile: String, paddle 格式的参数文件路径,如 infer_model.pdiparams
- vocabFile: String, 词表文件,如 vocab.txt 每一行包含一个词
- slotLabelsFile: String, 槽位标签文件,如 slots_label.txt
- intentLabelsFile: String, 意图标签文件,如 intent_label.txt 每一行包含一个标签
- addedTokensFile: String, 额外词表文件,如 added_tokens.json,json文件
- runtimeOption: RuntimeOption,可选参数,模型初始化 option。如果不传入该参数则会使用默认的运行时选项。
- maxLength: 最大序列长度,默认为16
public Predictor(); // 空构造函数,之后可以调用init初始化
public Predictor(String modelFile, String paramsFile, String vocabFile, String slotLabelsFile, String intentLabelsFile, String addedTokensFile);
public Predictor(String modelFile, String paramsFile, String vocabFile, String slotLabelsFile, String intentLabelsFile, String addedTokensFile, RuntimeOption runtimeOption, int maxLength);
public boolean init(String modelFile, String paramsFile, String vocabFile, String slotLabelsFile, String intentLabelsFile, String addedTokensFile, RuntimeOption runtimeOption, int maxLength);
- ERNIE 3.0 Tiny
Predictor
预测 API:Predictor 提供 predict 接口对输出的文本进行意图识别。
public IntentDetAndSlotFillResult[] predict(String[] texts);
- ERNIE 3.0 Tiny Predictor 资源释放 API: 调用 release() API 可以释放模型资源,返回 true 表示释放成功,false 表示失败;调用 initialized() 可以判断 Predictor 是否初始化成功,true 表示初始化成功,false 表示失败。
public boolean release(); // 释放native资源
public boolean initialized(); // 检查Predictor是否初始化成功
- RuntimeOption设置说明
public class RuntimeOption {
public void enableLiteFp16(); // 开启fp16精度推理
public void disableLiteFP16(); // 关闭fp16精度推理(默认关闭)
public void enableLiteInt8(); // 开启int8精度推理(需要先准备好量化模型)
public void disableLiteInt8(); // 关闭int8精度推理(默认关闭)
public void setCpuThreadNum(int threadNum); // 设置线程数
public void setLitePowerMode(LitePowerMode mode); // 设置能耗模式
public void setLitePowerMode(String modeStr); // 通过字符串形式设置能耗模式
}
- 意图和槽位识别结果
IntentDetAndSlotFillResult
说明
public class IntentDetAndSlotFillResult {
public String mStr; // 可用于debug的字符串 拼接了意图识别和槽位识别的结果
public boolean mInitialized = false;
public IntentDetResult mIntentResult; // 意图识别结果
public SlotFillResult[] mSlotResult; // 槽位识别结果
static class IntentDetResult {
public String mIntentLabel; // 意图识别结果文本标签
public float mIntentConfidence; // 意图识别结果置信度
}
static class SlotFillResult {
public String mSlotLabel; // 槽位识别结果文本标签
public String mEntity; // 槽位识别的实体
public int[] mPos; // [2] // 在原始文本对应的位置 [start,end]
}
}
- ERNIE 3.0 Tiny
Predictor
FP32/FP16 推理示例
import com.baidu.paddle.paddlenlp.ernie_tiny.RuntimeOption;
import com.baidu.paddle.paddlenlp.ernie_tiny.Predictor;
import com.baidu.paddle.paddlenlp.ernie_tiny.IntentDetAndSlotFillResult;
import android.app.Activity;
// 以下为伪代码
class TestERNIETiny extends Activity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Predictor predictor = new Predictor();
// 设置模型文件和标签文件
String modelFile = "ernie-tiny/infer_model.pdmodel";
String paramsFile = "ernie-tiny/infer_model.pdiparams";
String vocabFile = "ernie-tiny/vocab.txt";
String slotLabelsFile = "ernie-tiny/slots_label.txt";
String intentLabelsFile = "ernie-tiny/intent_label.txt";
String addedTokensFile = "ernie-tiny/added_tokens.json";
// RuntimeOption 设置
RuntimeOption option = new RuntimeOption();
option.setCpuThreadNum(2); // 设置线程数
option.enableLiteFp16(); // 是否开启FP16精度推理
// Predictor初始化
predictor.init(modelFile, paramsFile, vocabFile, slotLabelsFile, intentLabelsFile, addedTokensFile, option, 16);
// 进行意图识别和槽位分析
String[] inputTexts = new String[]{"来一首周华健的花心", "播放我们都一样", "到信阳市汽车配件城"};
IntentDetAndSlotFillResult[] results = predictor.predict(inputTexts);
}
}
- ERNIE 3.0 Tiny
Predictor
Int8 量化模型推理示例
import com.baidu.paddle.paddlenlp.ernie_tiny.RuntimeOption;
import com.baidu.paddle.paddlenlp.ernie_tiny.Predictor;
import com.baidu.paddle.paddlenlp.ernie_tiny.IntentDetAndSlotFillResult;
import android.app.Activity;
// 以下为伪代码
class TestERNIETiny extends Activity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Predictor predictor = new Predictor();
// 设置模型文件和标签文件
String modelFile = "ernie-tiny-clip-qat-embedding-int8/infer_model.pdmodel";
String paramsFile = "ernie-tiny-clip-qat-embedding-int8/infer_model.pdiparams";
String vocabFile = "ernie-tiny-clip-qat-embedding-int8/vocab.txt";
String slotLabelsFile = "ernie-tiny-clip-qat-embedding-int8/slots_label.txt";
String intentLabelsFile = "ernie-tiny-clip-qat-embedding-int8/intent_label.txt";
String addedTokensFile = "ernie-tiny-clip-qat-embedding-int8/added_tokens.json";
// RuntimeOption 设置
RuntimeOption option = new RuntimeOption();
option.setCpuThreadNum(2); // 设置线程数
option.enableLiteInt8(); // 开启int8精度推理(需要先准备好量化模型)
// Predictor初始化
predictor.init(modelFile, paramsFile, vocabFile, slotLabelsFile, intentLabelsFile, addedTokensFile, option, 16);
// 进行意图识别和槽位分析
String[] inputTexts = new String[]{"来一首周华健的花心", "播放我们都一样", "到信阳市汽车配件城"};
IntentDetAndSlotFillResult[] results = predictor.predict(inputTexts);
}
}
更详细的用法请参考 ERNIETinyMainActivity 中的用法
替换 App 示例中的模型的步骤非常简单,模型所在的位置为 app/src/main/assets/models
。替换模型之前请确保您的模型目录中包含 vocab.txt、slots_label.txt、intent_label.txt 以及 added_token.json 等意图识别和槽位分析所需要的词表和标签文件。替换模型的步骤为:
- 将您的 ERNIE 3.0 Tiny 模型放在
app/src/main/assets/models
目录下; - 修改
app/src/main/res/values/strings.xml
中模型路径的默认值,如:
<!-- 将这个路径指修改成您的模型,如 models/ernie-tiny-clip-qat-embedding-int8 -->
<string name="ERNIE_TINY_MODEL_DIR_DEFAULT">models/ernie-tiny-clip-qat-embedding-int8</string>
如果您对 ERNIE 3.0 Tiny JNI 封装的实现感兴趣,可以参考 ernie_tiny_jni/predictor_jni.cc, 关于如何使用 JNI 进行模型封装并和 Java 通信,可以参考 FastDeploy/use_cpp_sdk_on_android.md 文档中的说明。