提交 dbcc7450 编写于 作者: H Huihuang Zheng

Merge branch 'zhenghuihuang/jni-feature' into 'incubate/lite'

Add java demo

See merge request inference/paddlelite!86
......@@ -98,7 +98,7 @@ add_custom_target(lite_compile_deps COMMAND echo 1)
set(offline_lib_registry_file "${CMAKE_BINARY_DIR}/lite_libs.txt")
file(WRITE ${offline_lib_registry_file} "") # clean
set(__lite_cc_files "";"")
set(__lite_cc_files "" ; "")
set(__lite_cc_files "${CMAKE_BINARY_DIR}/lite_cc_files.txt")
file(WRITE ${__lite_cc_files} "") # clean
# cc_library with branch support.
......@@ -272,6 +272,8 @@ if (LITE_WITH_LIGHT_WEIGHT_FRAMEWORK)
#cc_library(inference_mobile_lib DEPS light_api_lite)
# copy cpp mobile_light demo/lib
add_custom_target(publish_inference_mobile_lib ${TARGET}
COMMAND mkdir -p "${INFER_LITE_PUBLISH_ROOT}/cxx/lib"
COMMAND mkdir -p "${INFER_LITE_PUBLISH_ROOT}/demo/cxx"
COMMAND cp "${CMAKE_BINARY_DIR}/libpaddle_api_light_bundled.a" "${INFER_LITE_PUBLISH_ROOT}/cxx/lib"
COMMAND cp -r "${CMAKE_SOURCE_DIR}/paddle/fluid/lite/demo/cxx/mobile_light" "${INFER_LITE_PUBLISH_ROOT}/demo/cxx"
)
......@@ -282,8 +284,30 @@ if (LITE_WITH_LIGHT_WEIGHT_FRAMEWORK)
# copy java mobile_light demo/lib
add_custom_target(publish_java_inference_mobile_lib ${TARGET}
COMMAND mkdir -p "${INFER_LITE_PUBLISH_ROOT}/java/so"
COMMAND mkdir -p "${INFER_LITE_PUBLISH_ROOT}/demo/java"
COMMAND cp "${CMAKE_BINARY_DIR}/paddle/fluid/lite/api/android/jni/libpaddle_lite_jni.so" "${INFER_LITE_PUBLISH_ROOT}/java/so"
COMMAND cp -r "${CMAKE_SOURCE_DIR}/paddle/fluid/lite/api/android/jni/src" "${INFER_LITE_PUBLISH_ROOT}/java"
COMMAND cp -r "${CMAKE_SOURCE_DIR}/paddle/fluid/lite/demo/java/android" "${INFER_LITE_PUBLISH_ROOT}/demo/java"
COMMAND cp -r "${CMAKE_BINARY_DIR}/third_party/install/inception_v4_simple"
"${INFER_LITE_PUBLISH_ROOT}/demo/java/android/PaddlePredictor/app/src/main/assets"
COMMAND cp -r "${CMAKE_BINARY_DIR}/third_party/install/lite_naive_model"
"${INFER_LITE_PUBLISH_ROOT}/demo/java/android/PaddlePredictor/app/src/main/assets"
COMMAND cp -r "${CMAKE_BINARY_DIR}/third_party/install/mobilenet_v1"
"${INFER_LITE_PUBLISH_ROOT}/demo/java/android/PaddlePredictor/app/src/main/assets"
COMMAND cp -r "${CMAKE_BINARY_DIR}/third_party/install/mobilenet_v2_relu"
"${INFER_LITE_PUBLISH_ROOT}/demo/java/android/PaddlePredictor/app/src/main/assets"
COMMAND cp -r "${CMAKE_BINARY_DIR}/third_party/install/resnet50"
"${INFER_LITE_PUBLISH_ROOT}/demo/java/android/PaddlePredictor/app/src/main/assets"
COMMAND cp "${CMAKE_BINARY_DIR}/paddle/fluid/lite/api/android/jni/libpaddle_lite_jni.so"
"${INFER_LITE_PUBLISH_ROOT}/demo/java/android/PaddlePredictor/app/src/main/jniLibs/arm7"
COMMAND cp "${CMAKE_BINARY_DIR}/paddle/fluid/lite/api/android/jni/libpaddle_lite_jni.so"
"${INFER_LITE_PUBLISH_ROOT}/demo/java/android/PaddlePredictor/app/src/main/jniLibs/arm8"
COMMAND cp "${CMAKE_BINARY_DIR}/paddle/fluid/lite/api/android/jni/libpaddle_lite_jni.so"
"${INFER_LITE_PUBLISH_ROOT}/demo/java/android/PaddlePredictor/app/src/main/jniLibs/arm64-v8a"
COMMAND cp "${CMAKE_BINARY_DIR}/paddle/fluid/lite/api/android/jni/libpaddle_lite_jni.so"
"${INFER_LITE_PUBLISH_ROOT}/demo/java/android/PaddlePredictor/app/src/main/jniLibs/armeabi-v7a"
COMMAND cp "${CMAKE_BINARY_DIR}/paddle/fluid/lite/api/android/jni/libpaddle_lite_jni.so"
"${INFER_LITE_PUBLISH_ROOT}/demo/java/android/PaddlePredictor/app/src/main/jniLibs/x86"
)
add_dependencies(publish_java_inference_mobile_lib paddle_lite_jni)
add_dependencies(publish_inference_lite publish_java_inference_mobile_lib)
......
# Java Android Demo
要编译和跑起 ./android 文件夹下的 Android demo 程序 PaddlePredictor,你需要准备:
1. 一台能运行安卓程序的安卓手机
2. 一台带有AndroidStudio的开发机
## 如果你使用我们的 cmake 生成 demo 程序,
可以直接把 `${INFER_LITE_PUBLISH_ROOT}/demo/java/android/PaddlePredictor` 载入你的AndroidStudio,
运行,查看本文末尾的程序运行显示结果。
## 手动编译(给测试人员需要更新 demo 模型或 .so 库可阅读)
###编译:
首先在PaddleLite的开发Docker镜像中,拉取最新PaddleLite代码,编译对应你手机架构的预测库,
下面我们以arm8 架构举例。进入paddlelite 目录,运行以下cmake 和make 命令:
```
mkdir -p build.lite.android.arm8.gcc
cd build.lite.android.arm8.gcc
cmake .. \
-DWITH_GPU=OFF \
-DWITH_MKL=OFF \
-DWITH_LITE=ON \
-DLITE_WITH_JAVA=ON \
-DLITE_WITH_CUDA=OFF \
-DLITE_WITH_X86=OFF \
-DLITE_WITH_ARM=ON \
-DLITE_WITH_LIGHT_WEIGHT_FRAMEWORK=ON \
-DWITH_TESTING=ON \
-DARM_TARGET_OS=android -DARM_TARGET_ARCH_ABI=armv8 -DARM_TARGET_LANG=gcc
make -j 4
```
Make完成后查看要存在`build.lite.android.arm8.gcc/paddle/fluid/lite/api/android/jni/libpaddle_lite_jni.so`
这个文件。该文件为PaddleLite c++ 动态链接库。接下来Android Java 代码会load 这个库来跑c++ 代码
### 把.so动态库拷贝进安卓demo程序:
把本文件夹下 demo/PaddlePredictor 载入到AndroidStudio。把上一步提到的`libpaddle_lite_jni.so`
拷贝进 `PaddlePredictor/app/src/main/jinLibs/所有架构文件夹下` 比如文件夹arm8里要包含该 .so文件:
### 把demo使用到的模型文件拷贝进安卓程序:
`build.lite.android.arm8.gcc/third_party/install` 文件夹下,把以下我们的模型文件夹拷贝进
`PaddlePredictor/app/src/main/assets` 这个文件夹
需要拷贝的模型文件:
inception_v4_simple
lite_naive_model
mobilenet_v1
mobilenet_v2_relu
resnet50
## 运行 Android 程序结果
以上准备工作完成,就可以开始Build ,安装,和跑安卓demo程序。当你运行PaddlePredictor 程序时,大概会等10秒,
然后看到类似以下字样:
lite_naive_model output: 50.213173, -28.872887
expected: 50.2132, -28.8729
inception_v4_simple test:true
time: 2078 ms
resnet50 test:true
time: 2078 ms
mobilenet_v1 test:true
time: 2078 ms
mobilenet_v2 test:true
time: 2078 ms
该 demo 程序跑我们的 5 个模型,第一个模型结果将真正的头两个数字输出,并在第二行附上期望的正确值。你应该要
看到他们的误差小于0.001。后面四个模型如果你看到 test:true 字样,说明模型输出通过了我们在 demo 程序里对其输出
的测试。time 代表该测试花费的时间。
*.iml
.gradle
/local.properties
/.idea/caches
/.idea/libraries
/.idea/modules.xml
/.idea/workspace.xml
/.idea/navEditor.xml
/.idea/assetWizardSettings.xml
.DS_Store
/build
/captures
.externalNativeBuild
# 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
package com.baidu.paddle.lite;
import android.content.Context;
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.*;
/**
* Instrumented test, which will execute on an Android device.
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {
@Test
public void useAppContext() {
// Context of the app under test.
Context appContext = InstrumentationRegistry.getTargetContext();
assertEquals("com.baidu.paddle.lite", appContext.getPackageName());
}
}
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.baidu.paddle.lite">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
\ No newline at end of file
After build PaddleLite in your build folder, copy following models in this directory:
inception_v4_simple
lite_naive_model
mobilenet_v1
mobilenet_v2_relu
resnet50
package com.baidu.paddle.lite;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Date;
import java.util.ArrayList;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
String textOutput = "";
ArrayList<float[]> output;
output = runNaiveModel("lite_naive_model");
textOutput += "lite_naive_model output: " + output.get(0)[0] + ", " + output.get(1)[1] + "\n";
textOutput += "expected: 50.2132, -28.8729\n";
Date start = new Date();
output = runImageModel("inception_v4_simple");
Date end = new Date();
textOutput += "\ninception_v4_simple test: " + testInceptionV4Simple(output) + "\n";
textOutput += "time: " + (end.getTime() - start.getTime()) + " ms\n";
start = new Date();
output = runImageModel("resnet50");
end = new Date();
textOutput += "\nresnet50 test: " + testResnet50(output) + "\n";
textOutput += "time: " + (end.getTime() - start.getTime()) + " ms\n";
start = new Date();
output = runImageModel("mobilenet_v1");
end = new Date();
textOutput += "\nmobilenet_v1 test: " + testMobileNetV1(output) + "\n";
textOutput += "time: " + (end.getTime() - start.getTime()) + " ms\n";
start = new Date();
output = runImageModel("mobilenet_v2_relu");
end = new Date();
textOutput += "\nmobilenet_v2 test: " + testMobileNetV2Relu(output) + "\n";
textOutput += "time: " + (end.getTime() - start.getTime()) + " ms\n";
TextView textView = findViewById(R.id.text_view);
textView.setText(textOutput);
}
public String copyFromAssetsToCache(String modelPath) {
String newPath = getCacheDir() + "/" + modelPath;
// String newPath = "/sdcard/" + modelPath;
File desDir = new File(newPath);
try {
if (!desDir.exists()) {
desDir.mkdir();
}
for (String fileName : this.getAssets().list(modelPath)) {
InputStream stream = getAssets().open(modelPath + "/" + fileName);
OutputStream output = new BufferedOutputStream(new FileOutputStream(newPath + "/" + fileName));
byte data[] = new byte[1024];
int count;
while ((count = stream.read(data)) != -1) {
output.write(data, 0, count);
}
output.flush();
output.close();
stream.close();
}
} catch (Exception e) {
throw new RuntimeException(e);
}
return desDir.getPath();
}
public ArrayList<float[]> runModel(String modelName, int[] dims, float[] inputBuffer) {
String modelPath = copyFromAssetsToCache(modelName);
// Cxx Model
Place[] validPlaces = new Place[2];
validPlaces[0] = new Place(Place.TargetType.X86, Place.PrecisionType.FLOAT);
validPlaces[1] = new Place(Place.TargetType.ARM, Place.PrecisionType.FLOAT);
Place preferredPlace = validPlaces[1];
PaddlePredictor.loadCxxModel(modelPath, preferredPlace, validPlaces);
PaddlePredictor.setInput(0, dims, inputBuffer);
PaddlePredictor.run();
float[] cxxOutput = PaddlePredictor.getFloatOutput(0);
String optimizedModelPath = modelPath + ".opt";
if (!new File(optimizedModelPath).exists()) {
PaddlePredictor.saveOptimizedModel(optimizedModelPath);
}
PaddlePredictor.clear();
// Mobile Model
PaddlePredictor.loadMobileModel(optimizedModelPath);
PaddlePredictor.setInput(0, dims, inputBuffer);
PaddlePredictor.run();
float[] mobileOutput = PaddlePredictor.getFloatOutput(0);
PaddlePredictor.clear();
ArrayList<float[]> result = new ArrayList<>();
result.add(cxxOutput);
result.add(mobileOutput);
return result;
}
public ArrayList<float[]> runNaiveModel(String modelName) {
int[] dims = {100, 100};
float[] inputBuffer = new float[10000];
for (int i = 0; i < 10000; ++i) {
inputBuffer[i] = i;
}
return runModel(modelName, dims, inputBuffer);
}
/**
* Input size is 3 * 224 * 224
*
* @param modelName
* @return
*/
public ArrayList<float[]> runImageModel(String modelName) {
int[] dims = {1, 3, 224, 224};
int item_size = 3 * 224 * 224;
float[] inputBuffer = new float[item_size];
for (int i = 0; i < item_size; ++i) {
inputBuffer[i] = 1;
}
return runModel(modelName, dims, inputBuffer);
}
public boolean equalsNear(float a, float b, float delta) {
return a >= b - delta && a <= b + delta;
}
public boolean expectedResult(float[] expected, ArrayList<float[]> result) {
if (result.size() != 2) {
return false;
}
if (expected.length != 20) {
return false;
}
float[] output = result.get(0);
float[] output1 = result.get(1);
if (output.length != output1.length || output.length != 1000) {
return false;
}
for (int i = 0; i < output.length; ++i) {
if (!equalsNear(output[i], output1[i], 1e-6f)) {
return false;
}
}
int step = 50;
for (int i = 0; i < expected.length; ++i) {
if (!equalsNear(output[i * step], expected[i], 1e-6f)) {
return false;
}
}
return true;
}
public boolean testInceptionV4Simple(ArrayList<float[]> output) {
float[] expected = {0.0011684548f, 0.0010390386f, 0.0011301535f, 0.0010133048f,
0.0010259597f, 0.0010982729f, 0.00093195855f, 0.0009141837f,
0.00096620916f, 0.00089982944f, 0.0010064574f, 0.0010474789f,
0.0009782845f, 0.0009230255f, 0.0010548076f, 0.0010974824f,
0.0010612885f, 0.00089107914f, 0.0010112736f, 0.00097655767f};
return expectedResult(expected, output);
}
public boolean testResnet50(ArrayList<float[]> output) {
float[] expected = {0.00024139918f, 0.00020566184f, 0.00022418296f, 0.00041731037f,
0.0005366107f, 0.00016948722f, 0.00028638865f, 0.0009257241f,
0.00072681636f, 8.531815e-05f, 0.0002129998f, 0.0021168243f,
0.006387163f, 0.0037145028f, 0.0012812682f, 0.00045948103f,
0.00013535398f, 0.0002483765f, 0.00076759676f, 0.0002773295f};
return expectedResult(expected, output);
}
public boolean testMobileNetV1(ArrayList<float[]> output) {
float[] expected = {0.00019130898f, 9.467885e-05f, 0.00015971427f, 0.0003650665f,
0.00026431272f, 0.00060884043f, 0.0002107942f, 0.0015819625f,
0.0010323516f, 0.00010079765f, 0.00011006987f, 0.0017364529f,
0.0048292773f, 0.0013995157f, 0.0018453331f, 0.0002428986f,
0.00020211363f, 0.00013668182f, 0.0005855956f, 0.00025901722f};
return expectedResult(expected, output);
}
public boolean testMobileNetV2Relu(ArrayList<float[]> output) {
float[] expected = {0.00017082224f, 5.699624e-05f, 0.000260885f, 0.00016412718f,
0.00034818667f, 0.00015230637f, 0.00032959113f, 0.0014772735f,
0.0009059976f, 9.5378724e-05f, 5.386537e-05f, 0.0006427285f,
0.0070957416f, 0.0016094646f, 0.0018807327f, 0.00010506048f,
6.823785e-05f, 0.00012269315f, 0.0007806194f, 0.00022354358f};
return expectedResult(expected, output);
}
}
/* Copyright (c) 2019 PaddlePaddle Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License. */
package com.baidu.paddle.lite;
/** Java Native Interface (JNI) class for Paddle Lite APIs */
public class PaddlePredictor {
/** name of C++ JNI lib */
private final static String JNI_LIB_NAME = "paddle_lite_jni";
/* load the C++ JNI lib */
static {
System.loadLibrary(JNI_LIB_NAME);
}
/**
* Loads mobile cxx model, which is the model before optimizing passes. The cxx
* model allow users to manage hardware place resources. Caller uses a place at
* Java to control Target, DataLayout, Precision, and Device ID. More details
* about the four fields see our Paddle-Mobile document.
*
*
* @param modelPath modelPath model file path
* @param preferredPlace preferred place to run Cxx Model
* @param validPlaces n * 4 int array, valid places to run Cxx Model
* @return true if load successfully
*/
public static native boolean loadCxxModel(String modelPath, Place preferredPlace, Place[] validPlaces);
/**
* Loads mobile lite model, which is the model after optimizing passes.
*
* @param modelPath model file path
* @return true if load successfully
*/
public static native boolean loadMobileModel(String modelPath);
/**
* Saves optimized model, which is the model can be used by
* {@link loadMobileModel}
*
* @param modelPath model file path
* @return true if save successfully
*/
public static native boolean saveOptimizedModel(String modelPath);
/**
* Clears the current loaded model.
*
* @return true if a loaded model has been cleared.
*/
public static native boolean clear();
/**
* Set input data on offset-th column of feed data
*
* @param offset the offset-th column of feed data will be set
* @param buf the input data
* @param dims dimension format of the input image
* @return true if set successfully
*/
public static native boolean setInput(int offset, int[] dims, float[] buf);
/**
* Set input data on offset-th column of feed data
*
* @param offset the offset-th column of feed data will be set
* @param buf the input data
* @param dims dimension format of the input image
* @return true if set successfully
*/
public static native boolean setInput(int offset, int[] dims, byte[] buf);
/**
* Run the predict model
*
* @return true if run successfully
*/
public static native boolean run();
/**
* Get offset-th column of output data as float
*
* @param offset the offset-th column of output data will be returned
* @return model predict output
*/
public static native float[] getFloatOutput(int offset);
/**
* Get offset-th column of output data as byte (int8 in C++ side)
*
* @param offset the offset-th column of output data will be returned
* @return model predict output
*/
public static native byte[] getByteOutput(int offset);
/**
* Fetches a Tensor's value as Float data
*
* @param name Tensor's name
* @return values of the Tensor
*/
public static native float[] fetchFloat(String name);
/**
* Fetches a Tensor's value as byte data (int8 at C++ side)
*
* @param name Tensor's name
* @return values of the Tensor
*/
public static native byte[] fetchByte(String name);
/**
* Main function for test
*/
public static void main(String[] args) {
System.out.println("Load native library successfully");
}
}
/* Copyright (c) 2019 PaddlePaddle Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License. */
package com.baidu.paddle.lite;
/**
* Place specifies the execution context of a Kernel or input/output for a
* kernel. It is used to make the analysis of the MIR more clear and accurate.
*/
public class Place {
public enum TargetType {
UNKNOWN(0), HOST(1), X86(2), CUDA(3), ARM(4), OpenCL(5), Any(6);
public final int value;
private TargetType(int value) {
this.value = value;
}
}
public enum PrecisionType {
UNKNOWN(0), FLOAT(1), INT8(2), INT32(3), ANY(4);
public final int value;
private PrecisionType(int value) {
this.value = value;
}
}
public enum DataLayoutType {
UNKNOWN(0), NCHW(1), ANY(2);
public final int value;
private DataLayoutType(int value) {
this.value = value;
}
}
public TargetType target;
public PrecisionType precision;
public DataLayoutType layout;
public int device;
public Place() {
target = TargetType.UNKNOWN;
precision = PrecisionType.UNKNOWN;
layout = DataLayoutType.UNKNOWN;
device = 0;
}
public Place(TargetType target) {
this(target, PrecisionType.FLOAT);
}
public Place(TargetType target, PrecisionType precision) {
this(target, precision, DataLayoutType.NCHW);
}
public Place(TargetType target, PrecisionType precision, DataLayoutType layout) {
this(target, precision, layout, 0);
}
public Place(TargetType target, PrecisionType precision, DataLayoutType layout, int device) {
this.target = target;
this.precision = precision;
this.layout = layout;
this.device = device;
}
public boolean isValid() {
return target != TargetType.UNKNOWN && precision != PrecisionType.UNKNOWN && layout != DataLayoutType.UNKNOWN;
}
public int getTargetInt() {
return target.value;
}
public int getPrecisionInt() {
return precision.value;
}
public int getDataLayoutInt() {
return layout.value;
}
public int getDevice() {
return device;
}
}
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path
android:fillType="evenOdd"
android:pathData="M32,64C32,64 38.39,52.99 44.13,50.95C51.37,48.37 70.14,49.57 70.14,49.57L108.26,87.69L108,109.01L75.97,107.97L32,64Z"
android:strokeWidth="1"
android:strokeColor="#00000000">
<aapt:attr name="android:fillColor">
<gradient
android:endX="78.5885"
android:endY="90.9159"
android:startX="48.7653"
android:startY="61.0927"
android:type="linear">
<item
android:color="#44000000"
android:offset="0.0" />
<item
android:color="#00000000"
android:offset="1.0" />
</gradient>
</aapt:attr>
</path>
<path
android:fillColor="#FFFFFF"
android:fillType="nonZero"
android:pathData="M66.94,46.02L66.94,46.02C72.44,50.07 76,56.61 76,64L32,64C32,56.61 35.56,50.11 40.98,46.06L36.18,41.19C35.45,40.45 35.45,39.3 36.18,38.56C36.91,37.81 38.05,37.81 38.78,38.56L44.25,44.05C47.18,42.57 50.48,41.71 54,41.71C57.48,41.71 60.78,42.57 63.68,44.05L69.11,38.56C69.84,37.81 70.98,37.81 71.71,38.56C72.44,39.3 72.44,40.45 71.71,41.19L66.94,46.02ZM62.94,56.92C64.08,56.92 65,56.01 65,54.88C65,53.76 64.08,52.85 62.94,52.85C61.8,52.85 60.88,53.76 60.88,54.88C60.88,56.01 61.8,56.92 62.94,56.92ZM45.06,56.92C46.2,56.92 47.13,56.01 47.13,54.88C47.13,53.76 46.2,52.85 45.06,52.85C43.92,52.85 43,53.76 43,54.88C43,56.01 43.92,56.92 45.06,56.92Z"
android:strokeWidth="1"
android:strokeColor="#00000000" />
</vector>
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path
android:fillColor="#008577"
android:pathData="M0,0h108v108h-108z" />
<path
android:fillColor="#00000000"
android:pathData="M9,0L9,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,0L19,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,0L29,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,0L39,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,0L49,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,0L59,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,0L69,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,0L79,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M89,0L89,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M99,0L99,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,9L108,9"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,19L108,19"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,29L108,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,39L108,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,49L108,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,59L108,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,69L108,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,79L108,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,89L108,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,99L108,99"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,29L89,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,39L89,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,49L89,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,59L89,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,69L89,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,79L89,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,19L29,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,19L39,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,19L49,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,19L59,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,19L69,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,19L79,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
</vector>
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:id="@+id/text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#008577</color>
<color name="colorPrimaryDark">#00574B</color>
<color name="colorAccent">#D81B60</color>
</resources>
<resources>
<string name="app_name">PaddlePredictor</string>
</resources>
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>
</resources>
package com.baidu.paddle.lite;
import org.junit.Test;
import static org.junit.Assert.*;
/**
* Example local unit test, which will execute on the development machine (host).
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
public class ExampleUnitTest {
@Test
public void addition_isCorrect() {
assertEquals(4, 2 + 2);
}
}
\ No newline at end of file
# Project-wide Gradle settings.
# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
org.gradle.jvmargs=-Xmx1536m
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
#Wed Jun 26 10:57:21 CST 2019
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip
#!/usr/bin/env sh
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn () {
echo "$*"
}
die () {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=$(save "$@")
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
cd "$(dirname "$0")"
fi
exec "$JAVACMD" "$@"
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega
## This file must *NOT* be checked into Version Control Systems,
# as it contains information specific to your local configuration.
#
# Location of the SDK. This is only used by Gradle.
# For customization when using a Version Control System, please read the
# header note.
#Wed Jun 26 10:57:21 CST 2019
ndk.dir=/Users/zhenghuihuang/Library/Android/sdk/ndk-bundle
sdk.dir=/Users/zhenghuihuang/Library/Android/sdk
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册