-
Notifications
You must be signed in to change notification settings - Fork 2.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Android] Add ERNIE Tiny android support (#4342)
* [Android] init ERNIE Tiny android codes * [Android] init ERNIE Tiny android codes * [Android] init ERNIE Tiny android codes * [Android] init ERNIE Tiny JNI codes * [Android] init ERNIE Tiny JNI codes * [Android] Add ERNIE Tiny App codes * [Android] Add ERNIE Tiny App codes * [Android] remove UIE codes * [Android] Update perf_jni.h * [Android] Update AndroidManifest.xml * [Android] Update android/README.md * [Android] Update android/README.md * [Android] Update android/README.md * [Android] Update android/README.md * [Android] Update android/README.md * [Android] Update android/README.md * [Android] Update android/README.md * [Android] remove un-needed deps * [Android] remove un-needed c++ deps * [Android] fixed android/README.md typos * [Token] Add added_tokens_path to java & jni * [Token] Add added_tokens_path to java & jni * [Doc] fixed ERNIE 3.0 Tiny Android docs typos * [Doc] fixed ERNIE 3.0 Tiny Android docs typos
- Loading branch information
Showing
82 changed files
with
4,034 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
.DS_Store | ||
.idea | ||
.gradle | ||
.cxx | ||
cache | ||
build | ||
app/cache | ||
app/libs/* | ||
app/.cxx | ||
app/build | ||
app/src/main/assets/models/* | ||
app/.gradle | ||
app/.idea | ||
ernie_tiny/cache | ||
ernie_tiny/libs/fastdeploy* | ||
ernie_tiny/.cxx | ||
ernie_tiny/build | ||
ernie_tiny/src/main/assets/models/* | ||
ernie_tiny/.gradle | ||
ernie_tiny/.idea | ||
ui/build | ||
ui/.gradle | ||
ui/cache |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,240 @@ | ||
# FastDeploy ERNIE 3.0 Tiny 模型Android部署示例 | ||
|
||
本目录提供了快速完成在 Android 的车载语音场景下的口语理解(Spoken Language Understanding,SLU)任务的部署示例。 | ||
|
||
## 环境准备 | ||
|
||
1. 在本地环境安装好 Android Studio 工具,详细安装方法请见[Android Stuido 官网](https://developer.android.com/studio)。 | ||
2. 准备一部 Android 手机,并开启 USB 调试模式。开启方法: `手机设置 -> 查找开发者选项 -> 打开开发者选项和 USB 调试模式` | ||
|
||
## App示例编译和使用步骤 | ||
|
||
1. ERNIE 3.0 Tiny Android 部署示例位于`PaddleNLP/model_zoo/ernie-tiny/deploy/android`目录 | ||
2. 用 Android Studio 打开 ernie-tiny/deploy/android 工程 | ||
3. 手机连接电脑,打开 USB 调试和文件传输模式,并在 Android Studio 上连接自己的手机设备(手机需要开启允许从 USB 安装软件权限) | ||
|
||
<img width="1440" alt="image" src="https://user-images.githubusercontent.com/31974251/210742200-596f1585-9d4c-46e4-acae-5956a798c7ce.png"> | ||
|
||
|
||
工程内容说明: | ||
```bash | ||
. | ||
├── 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 插件](https://developer.android.com/studio/releases/gradle-plugin?hl=zh-cn#updating-plugin)章节,尝试更新Android Gradle plugin版本。 | ||
|
||
4. 点击 Run 按钮,自动编译 APP 并安装到手机。(该过程会自动下载预编译的 FastDeploy Android 库 以及 模型文件,需要联网) | ||
成功后效果如下,图一:APP 安装到手机;图二: APP 打开后的效果,输入文本后点击"开始分析意图"后即会自动进行意图识别和槽位分析;图三:APP设置选项,点击右上角的设置图片,可以设置不同选项进行体验。 | ||
|
||
| APP 效果 | APP 演示 | APP设置项 | | ||
| --- | --- | --- | | ||
| <img width="300" height="500" alt="image" src="https://user-images.githubusercontent.com/31974251/210737269-0fe175c9-7b87-40b3-8249-1c6378e4a5e9.jpg"> | <img width="300" height="500" alt="image" src="https://user-images.githubusercontent.com/31974251/210737041-0e79bd6b-90a8-42b0-8f66-97868386d9f3.gif"> | <img width="300" height="500" alt="image" src="https://user-images.githubusercontent.com/31974251/210774693-b199734c-442c-48ef-90ea-4d2e72ff7304.jpg"> | | ||
|
||
## ERNIE Tiny Java SDK 说明和使用 | ||
|
||
本工程除了可以直接编译 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`. | ||
|
||
<img width="1073" alt="image" src="https://user-images.githubusercontent.com/31974251/210746163-41d39478-8d5d-4138-9f76-75ff5c25c295.png"> | ||
|
||
在获取到`ernie_tiny-debug.aar`后,可将其拷贝到您自己的工程中进行使用。在 Android Studio 中的配置步骤如下: | ||
(1)首先,将`ernie_tiny-debug.aar`拷贝到您 Android 工程的libs目录下。 | ||
```bash | ||
├── build.gradle | ||
├── libs | ||
│ └── ernie_tiny-debug.aar | ||
├── proguard-rules.pro | ||
└── src | ||
``` | ||
(2)在您的 Android 工程中的 build.gradle 引入 ERNIE 3.0 Tiny SDK,如下 | ||
```groovy | ||
dependencies { | ||
implementation fileTree(include: ['ernie_tiny-debug.aar'], dir: 'libs') | ||
implementation 'com.android.support:appcompat-v7:28.0.0' | ||
// ... | ||
} | ||
``` | ||
|
||
### ERNIE 3.0 Tiny Java API说明如下 | ||
|
||
- 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 | ||
|
||
```java | ||
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 接口对输出的文本进行意图识别。 | ||
```java | ||
public IntentDetAndSlotFillResult[] predict(String[] texts); | ||
``` | ||
|
||
- ERNIE 3.0 Tiny Predictor 资源释放 API: 调用 release() API 可以释放模型资源,返回 true 表示释放成功,false 表示失败;调用 initialized() 可以判断 Predictor 是否初始化成功,true 表示初始化成功,false 表示失败。 | ||
```java | ||
public boolean release(); // 释放native资源 | ||
public boolean initialized(); // 检查Predictor是否初始化成功 | ||
``` | ||
|
||
- RuntimeOption设置说明 | ||
|
||
```java | ||
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`说明 | ||
|
||
```java | ||
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 推理示例 | ||
|
||
```java | ||
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 量化模型推理示例 | ||
|
||
```java | ||
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/src/main/java/com/baidu/paddle/paddlenlp/app/ernie_tiny/ERNIETinyMainActivity.java) 中的用法 | ||
|
||
## 替换 App 示例中的 ERNIE 3.0 Tiny 模型 | ||
|
||
替换 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` 中模型路径的默认值,如: | ||
|
||
```xml | ||
<!-- 将这个路径指修改成您的模型,如 models/ernie-tiny --> | ||
<string name="ERNIE_TINY_MODEL_DIR_DEFAULT">models/ernie-tiny</string> | ||
``` | ||
|
||
## 关于 ERNIE 3.0 Tiny JNI 的封装 | ||
|
||
如果您对 ERNIE 3.0 Tiny JNI 封装的实现感兴趣,可以参考 [ernie_tiny_jni/predictor_jni.cc](./ernie_tiny/src/main/cpp/ernie_tiny_jni/predictor_jni.cc), 关于如何使用 JNI 进行模型封装并和 Java 通信,可以参考 [FastDeploy/use_cpp_sdk_on_android.md](https://github.com/PaddlePaddle/FastDeploy/blob/develop/docs/cn/faq/use_cpp_sdk_on_android.md) 文档中的说明。 | ||
|
||
## 相关文档 | ||
|
||
[ERNIE 3.0 Tiny 模型详细介绍](../../README.md) | ||
|
||
[ERNIE 3.0 Tiny 模型C++部署方法](../cpp/README.md) | ||
|
||
[ERNIE 3.0 Tiny 模型Python部署方法](../python/README.md) | ||
|
||
[FastDeploy SDK 安装文档](https://github.com/PaddlePaddle/FastDeploy/blob/develop/docs/cn/build_and_install/download_prebuilt_libraries.md) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
apply plugin: 'com.android.application' | ||
|
||
android { | ||
compileSdk 28 | ||
|
||
defaultConfig { | ||
applicationId 'com.baidu.paddle.paddlenlp.app' | ||
minSdkVersion 15 | ||
//noinspection ExpiredTargetSdkVersion | ||
targetSdkVersion 28 | ||
versionCode 1 | ||
versionName "1.0" | ||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" | ||
} | ||
|
||
buildTypes { | ||
release { | ||
minifyEnabled false | ||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' | ||
} | ||
} | ||
} | ||
|
||
dependencies { | ||
implementation project(path: ':ernie_tiny') | ||
implementation project(path: ':ui') | ||
//noinspection GradleCompatible | ||
implementation 'com.android.support:appcompat-v7:28.0.0' | ||
//noinspection GradleDependency | ||
implementation 'com.android.support.constraint:constraint-layout:1.1.3' | ||
implementation 'com.android.support:design:28.0.0' | ||
implementation 'org.jetbrains:annotations:15.0' | ||
//noinspection GradleDependency | ||
testImplementation 'junit:junit:4.12' | ||
androidTestImplementation 'com.android.support.test:runner:1.0.2' | ||
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' | ||
} | ||
|
||
def FD_MODEL = [ | ||
[ | ||
'src' : 'https://bj.bcebos.com/paddlehub/fastdeploy/ernie-tiny.tgz', | ||
'dest': 'src/main/assets/models' | ||
], | ||
[ | ||
'src' : 'https://bj.bcebos.com/paddlehub/fastdeploy/ernie-tiny-clip.tgz', | ||
'dest': 'src/main/assets/models' | ||
], | ||
[ | ||
'src' : 'https://bj.bcebos.com/paddlehub/fastdeploy/ernie-tiny-clip-qat.tgz', | ||
'dest': 'src/main/assets/models' | ||
], | ||
[ | ||
'src' : 'https://bj.bcebos.com/paddlehub/fastdeploy/ernie-tiny-clip-qat-embedding-int8.tgz', | ||
'dest': 'src/main/assets/models' | ||
] | ||
|
||
] | ||
|
||
task downloadAndExtractModels(type: DefaultTask) { | ||
doFirst { | ||
println "[INFO] Downloading and extracting models ..." | ||
} | ||
doLast { | ||
String cachePath = "cache" | ||
if (!file("${cachePath}").exists()) { | ||
mkdir "${cachePath}" | ||
} | ||
FD_MODEL.eachWithIndex { model, index -> | ||
String[] modelPaths = model.src.split("/") | ||
String modelName = modelPaths[modelPaths.length - 1] | ||
String modelPrefix = modelName.substring(0, modelName.length() - 4) | ||
boolean copyFiles = false | ||
if (!file("${model.dest}/${modelPrefix}").exists()) { | ||
// Download the target model if not exists | ||
if (!file("${cachePath}/${modelName}").exists()) { | ||
println "[INFO] Downloading ${model.src} -> ${cachePath}/${modelName}" | ||
ant.get(src: model.src, dest: file("${cachePath}/${modelName}")) | ||
} | ||
copyFiles = true | ||
} | ||
if (copyFiles) { | ||
println "[INFO] Taring ${cachePath}/${modelName} -> ${model.dest}/${modelPrefix}" | ||
copy { from(tarTree("${cachePath}/${modelName}")) into("${model.dest}") } | ||
} else { | ||
println "[INFO] ${model.dest}/${modelPrefix} already exists!" | ||
} | ||
} | ||
} | ||
} | ||
|
||
preBuild.dependsOn downloadAndExtractModels |
21 changes: 21 additions & 0 deletions
21
model_zoo/ernie-tiny/deploy/android/app/proguard-rules.pro
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
# Add project specific ProGuard rules here. | ||
# You can control the set of applied configuration files using the | ||
# proguardFiles setting in build.gradle. | ||
# | ||
# For more details, see | ||
# http://developer.android.com/guide/developing/tools/proguard.html | ||
|
||
# If your project uses WebView with JS, uncomment the following | ||
# and specify the fully qualified class name to the JavaScript interface | ||
# class: | ||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview { | ||
# public *; | ||
#} | ||
|
||
# Uncomment this to preserve the line number information for | ||
# debugging stack traces. | ||
#-keepattributes SourceFile,LineNumberTable | ||
|
||
# If you keep the line number information, uncomment this to | ||
# hide the original source file name. | ||
#-renamesourcefileattribute SourceFile |
Oops, something went wrong.