mirror of
https://github.com/pytorch/pytorch.git
synced 2025-10-20 21:14:14 +08:00
Test application for profiling, CMake params for debug symbols (#28406)
Summary: Reason: To have one-step build for test android application based on the current code state that is ready for profiling with simpleperf, systrace etc. to profile performance inside the application. ## Parameters to control debug symbols stripping Introducing /CMakeLists parameter `ANDROID_DEBUG_SYMBOLS` to be able not to strip symbols for pytorch (not add linker flag `-s`) which is checked in `scripts/build_android.sh` On gradle side stripping happens by default, and to prevent it we have to specify ``` android { packagingOptions { doNotStrip "**/*.so" } } ``` which is now controlled by new gradle property `nativeLibsDoNotStrip ` ## Test_App `android/test_app` - android app with one MainActivity that does inference in cycle `android/build_test_app.sh` - script to build libtorch with debug symbols for specified android abis and adds `NDK_DEBUG=1` and `-PnativeLibsDoNotStrip=true` to keep all debug symbols for profiling. Script assembles all debug flavors: ``` └─ $ find . -type f -name *apk ./test_app/app/build/outputs/apk/mobilenetQuant/debug/test_app-mobilenetQuant-debug.apk ./test_app/app/build/outputs/apk/resnet/debug/test_app-resnet-debug.apk ``` ## Different build configurations Module for inference can be set in `android/test_app/app/build.gradle` as a BuildConfig parameters: ``` productFlavors { mobilenetQuant { dimension "model" applicationIdSuffix ".mobilenetQuant" buildConfigField ("String", "MODULE_ASSET_NAME", buildConfigProps('MODULE_ASSET_NAME_MOBILENET_QUANT')) addManifestPlaceholders([APP_NAME: "PyMobileNetQuant"]) buildConfigField ("String", "LOGCAT_TAG", "\"pytorch-mobilenet\"") } resnet { dimension "model" applicationIdSuffix ".resnet" buildConfigField ("String", "MODULE_ASSET_NAME", buildConfigProps('MODULE_ASSET_NAME_RESNET18')) addManifestPlaceholders([APP_NAME: "PyResnet"]) buildConfigField ("String", "LOGCAT_TAG", "\"pytorch-resnet\"") } ``` In that case we can setup several apps on the same device for comparison, to separate packages `applicationIdSuffix`: 'org.pytorch.testapp.mobilenetQuant' and different application names and logcat tags as `manifestPlaceholder` and another BuildConfig parameter: ``` ─ $ adb shell pm list packages | grep pytorch package:org.pytorch.testapp.mobilenetQuant package:org.pytorch.testapp.resnet ``` In future we can add another BuildConfig params e.g. single/multi threads and other configuration for profiling. At the moment 2 flavors - for resnet18 and for mobilenetQuantized which can be installed on connected device: ``` cd android ``` ``` gradle test_app:installMobilenetQuantDebug ``` ``` gradle test_app:installResnetDebug ``` ## Testing: ``` cd android sh build_test_app.sh adb install -r test_app/app/build/outputs/apk/mobilenetQuant/debug/test_app-mobilenetQuant-debug.apk ``` ``` cd $ANDROID_NDK python simpleperf/run_simpleperf_on_device.py record --app org.pytorch.testapp.mobilenetQuant -g --duration 10 -o /data/local/tmp/perf.data adb pull /data/local/tmp/perf.data python simpleperf/report_html.py ``` Simpleperf report has all symbols:  Pull Request resolved: https://github.com/pytorch/pytorch/pull/28406 Differential Revision: D18386622 Pulled By: IvanKobzarev fbshipit-source-id: 3a751192bbc4bc3c6d7f126b0b55086b4d586e7a
This commit is contained in:
committed by
Facebook Github Bot
parent
52456b2eba
commit
92b9de1428
@ -495,7 +495,7 @@ if(CMAKE_COMPILER_IS_GNUCXX AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 7.0.0
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-stringop-overflow")
|
||||
endif()
|
||||
|
||||
if(ANDROID)
|
||||
if(ANDROID AND (NOT ANDROID_DEBUG_SYMBOLS))
|
||||
if(CMAKE_COMPILER_IS_GNUCXX)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -s")
|
||||
else()
|
||||
|
10
android/.gitignore
vendored
10
android/.gitignore
vendored
@ -6,11 +6,5 @@ gradle/wrapper
|
||||
.idea/*
|
||||
.externalNativeBuild
|
||||
build
|
||||
pytorch_android/src/main/cpp/libtorch_include/x86/**
|
||||
pytorch_android/src/main/cpp/libtorch_include/x86_64/**
|
||||
pytorch_android/src/main/cpp/libtorch_include/armeabi-v7a/**
|
||||
pytorch_android/src/main/cpp/libtorch_include/arm64-v8a/**
|
||||
pytorch_android/src/main/jniLibs/x86/**
|
||||
pytorch_android/src/main/jniLibs/x86_64/**
|
||||
pytorch_android/src/main/jniLibs/armeabi-v7a/**
|
||||
pytorch_android/src/main/jniLibs/arm64-v8a/**
|
||||
pytorch_android/src/main/cpp/libtorch_include/**
|
||||
pytorch_android/src/main/jniLibs/**
|
||||
|
100
android/build_test_app.sh
Executable file
100
android/build_test_app.sh
Executable file
@ -0,0 +1,100 @@
|
||||
#!/bin/bash
|
||||
set -eux
|
||||
|
||||
PYTORCH_DIR="$(cd $(dirname $0)/..; pwd -P)"
|
||||
|
||||
PYTORCH_ANDROID_DIR=$PYTORCH_DIR/android
|
||||
WORK_DIR=$PYTORCH_DIR
|
||||
|
||||
echo "PYTORCH_DIR:$PYTORCH_DIR"
|
||||
echo "WORK_DIR:$WORK_DIR"
|
||||
|
||||
echo "ANDROID_HOME:$ANDROID_HOME"
|
||||
if [ ! -z "$ANDROID_HOME" ]; then
|
||||
echo "ANDROID_HOME not set; please set it to Android sdk directory"
|
||||
fi
|
||||
|
||||
if [ ! -d $ANDROID_HOME ]; then
|
||||
echo "ANDROID_HOME not a directory; did you install it under $ANDROID_HOME?"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
GRADLE_PATH=gradle
|
||||
GRADLE_NOT_FOUND_MSG="Unable to find gradle, please add it to PATH or set GRADLE_HOME"
|
||||
|
||||
if [ ! -x "$(command -v gradle)" ]; then
|
||||
if [ -z "$GRADLE_HOME" ]; then
|
||||
echo GRADLE_NOT_FOUND_MSG
|
||||
exit 1
|
||||
fi
|
||||
GRADLE_PATH=$GRADLE_HOME/bin/gradle
|
||||
if [ ! -f "$GRADLE_PATH" ]; then
|
||||
echo GRADLE_NOT_FOUND_MSG
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
echo "GRADLE_PATH:$GRADLE_PATH"
|
||||
|
||||
ABIS_LIST="armeabi-v7a,arm64-v8a,x86,x86_64"
|
||||
CUSTOM_ABIS_LIST=false
|
||||
if [ $# -gt 0 ]; then
|
||||
ABIS_LIST=$1
|
||||
CUSTOM_ABIS_LIST=true
|
||||
fi
|
||||
|
||||
echo "ABIS_LIST:$ABIS_LIST"
|
||||
|
||||
LIB_DIR=$PYTORCH_ANDROID_DIR/pytorch_android/src/main/jniLibs
|
||||
INCLUDE_DIR=$PYTORCH_ANDROID_DIR/pytorch_android/src/main/cpp/libtorch_include
|
||||
mkdir -p $LIB_DIR
|
||||
rm $LIB_DIR/*
|
||||
mkdir -p $INCLUDE_DIR
|
||||
|
||||
for abi in $(echo $ABIS_LIST | tr ',' '\n')
|
||||
do
|
||||
echo "abi:$abi"
|
||||
|
||||
OUT_DIR=$WORK_DIR/build_android_$abi
|
||||
|
||||
rm -rf $OUT_DIR
|
||||
mkdir -p $OUT_DIR
|
||||
|
||||
pushd $PYTORCH_DIR
|
||||
python $PYTORCH_DIR/setup.py clean
|
||||
|
||||
ANDROID_ABI=$abi BUILD_PYTORCH_MOBILE=1 VERBOSE=1 ANDROID_DEBUG_SYMBOLS=1 $PYTORCH_DIR/scripts/build_android.sh -DANDROID_CCACHE=$(which ccache)
|
||||
|
||||
cp -R $PYTORCH_DIR/build_android/install/lib $OUT_DIR/
|
||||
cp -R $PYTORCH_DIR/build_android/install/include $OUT_DIR/
|
||||
|
||||
echo "$abi build output lib,include copied to $OUT_DIR"
|
||||
|
||||
LIB_LINK_PATH=$LIB_DIR/$abi
|
||||
INCLUDE_LINK_PATH=$INCLUDE_DIR/$abi
|
||||
|
||||
rm -f $LIB_LINK_PATH
|
||||
rm -f $INCLUDE_LINK_PATH
|
||||
|
||||
ln -s $OUT_DIR/lib $LIB_LINK_PATH
|
||||
ln -s $OUT_DIR/include $INCLUDE_LINK_PATH
|
||||
|
||||
done
|
||||
|
||||
# To set proxy for gradle add following lines to ./gradle/gradle.properties:
|
||||
# systemProp.http.proxyHost=...
|
||||
# systemProp.http.proxyPort=8080
|
||||
# systemProp.https.proxyHost=...
|
||||
# systemProp.https.proxyPort=8080
|
||||
|
||||
if [ "$CUSTOM_ABIS_LIST" = true ]; then
|
||||
NDK_DEBUG=1 $GRADLE_PATH -PnativeLibsDoNotStrip=true -PABI_FILTERS=$ABIS_LIST -p $PYTORCH_ANDROID_DIR clean test_app:assembleDebug
|
||||
else
|
||||
NDK_DEBUG=1 $GRADLE_PATH -PnativeLibsDoNotStrip=true -p $PYTORCH_ANDROID_DIR clean test_app:assembleDebug
|
||||
fi
|
||||
|
||||
find $PYTORCH_ANDROID_DIR -type f -name *apk
|
||||
|
||||
find $PYTORCH_ANDROID_DIR -type f -name *apk | xargs echo "To install apk run: $ANDROID_HOME/platform-tools/adb install -r "
|
||||
|
||||
popd
|
||||
|
@ -22,3 +22,8 @@ ANDROID_MAVEN_GRADLE_PLUGIN_VERSION=2.1
|
||||
# Gradle internals
|
||||
org.gradle.internal.repository.max.retries=1
|
||||
org.gradle.jvmargs=-XX:MaxMetaspaceSize=1024m
|
||||
|
||||
android.useAndroidX=true
|
||||
android.enableJetifier=true
|
||||
|
||||
nativeLibsDoNotStrip=false
|
||||
|
@ -42,6 +42,9 @@ android {
|
||||
} else {
|
||||
pickFirst '**/libfbjni.so'
|
||||
}
|
||||
if (nativeLibsDoNotStrip) {
|
||||
doNotStrip "**/*.so"
|
||||
}
|
||||
}
|
||||
|
||||
useLibrary 'android.test.runner'
|
||||
|
@ -1,6 +1,8 @@
|
||||
include ':app', ':pytorch_android', ':fbjni', ':pytorch_android_torchvision', ':pytorch_host'
|
||||
include ':app', ':pytorch_android', ':fbjni', ':pytorch_android_torchvision', ':pytorch_host', ':test_app'
|
||||
|
||||
project(':fbjni').projectDir = file('libs/fbjni_local')
|
||||
project(':pytorch_android_torchvision').projectDir = file('pytorch_android_torchvision')
|
||||
|
||||
project(':pytorch_host').projectDir = file('pytorch_android/host')
|
||||
project(':test_app').projectDir = file('test_app/app')
|
||||
|
||||
|
9
android/test_app/.gitignore
vendored
Normal file
9
android/test_app/.gitignore
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
local.properties
|
||||
**/*.iml
|
||||
.gradle
|
||||
gradlew*
|
||||
gradle/wrapper
|
||||
.idea/*
|
||||
.DS_Store
|
||||
build
|
||||
.externalNativeBuild
|
61
android/test_app/app/build.gradle
Normal file
61
android/test_app/app/build.gradle
Normal file
@ -0,0 +1,61 @@
|
||||
apply plugin: 'com.android.application'
|
||||
|
||||
repositories {
|
||||
jcenter()
|
||||
}
|
||||
|
||||
def props = new Properties()
|
||||
file("../gradle.properties").withInputStream { props.load(it) }
|
||||
|
||||
def buildConfigProps = { k -> "\"${props.get(k)}\"" }
|
||||
|
||||
android {
|
||||
compileSdkVersion 28
|
||||
buildToolsVersion "29.0.2"
|
||||
defaultConfig {
|
||||
applicationId "org.pytorch.testapp"
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 28
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
ndk {
|
||||
abiFilters ABI_FILTERS.split(",")
|
||||
}
|
||||
buildConfigField ("String", "MODULE_ASSET_NAME", buildConfigProps('MODULE_ASSET_NAME'))
|
||||
buildConfigField ("String", "LOGCAT_TAG", "@string/app_name")
|
||||
addManifestPlaceholders([APP_NAME: "@string/app_name"])
|
||||
}
|
||||
buildTypes {
|
||||
debug {
|
||||
minifyEnabled false
|
||||
}
|
||||
}
|
||||
flavorDimensions "model"
|
||||
productFlavors {
|
||||
mobNet2Quant {
|
||||
dimension "model"
|
||||
applicationIdSuffix ".mobNet2Quant"
|
||||
buildConfigField ("String", "MODULE_ASSET_NAME", buildConfigProps('MODULE_ASSET_NAME_MOBNET2_QUANT'))
|
||||
addManifestPlaceholders([APP_NAME: "PyMobNet2Quant"])
|
||||
buildConfigField ("String", "LOGCAT_TAG", "\"pytorch-mobnet2q\"")
|
||||
}
|
||||
resnet18 {
|
||||
dimension "model"
|
||||
applicationIdSuffix ".resneti18"
|
||||
buildConfigField ("String", "MODULE_ASSET_NAME", buildConfigProps('MODULE_ASSET_NAME_RESNET18'))
|
||||
addManifestPlaceholders([APP_NAME: "PyResNet18"])
|
||||
buildConfigField ("String", "LOGCAT_TAG", "\"pytorch-resnet18\"")
|
||||
}
|
||||
}
|
||||
packagingOptions {
|
||||
pickFirst '**/libfbjni.so'
|
||||
doNotStrip '**.so'
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'androidx.appcompat:appcompat:1.1.0'
|
||||
|
||||
implementation project(':pytorch_android')
|
||||
implementation project(':pytorch_android_torchvision')
|
||||
}
|
19
android/test_app/app/src/main/AndroidManifest.xml
Normal file
19
android/test_app/app/src/main/AndroidManifest.xml
Normal file
@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="org.pytorch.testapp">
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:label="${APP_NAME}"
|
||||
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>
|
3
android/test_app/app/src/main/assets/.gitignore
vendored
Normal file
3
android/test_app/app/src/main/assets/.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
*
|
||||
*/
|
||||
!.gitignore
|
@ -0,0 +1,155 @@
|
||||
package org.pytorch.testapp;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.HandlerThread;
|
||||
import android.os.SystemClock;
|
||||
import android.util.Log;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.pytorch.IValue;
|
||||
import org.pytorch.Module;
|
||||
import org.pytorch.Tensor;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.FloatBuffer;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.UiThread;
|
||||
import androidx.annotation.WorkerThread;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
public class MainActivity extends AppCompatActivity {
|
||||
|
||||
private static final String TAG = BuildConfig.LOGCAT_TAG;
|
||||
private static final int TEXT_TRIM_SIZE = 4096;
|
||||
|
||||
private TextView mTextView;
|
||||
|
||||
protected HandlerThread mBackgroundThread;
|
||||
protected Handler mBackgroundHandler;
|
||||
private Module mModule;
|
||||
private FloatBuffer mInputTensorBuffer;
|
||||
private Tensor mInputTensor;
|
||||
private StringBuilder mTextViewStringBuilder = new StringBuilder();
|
||||
|
||||
private final Runnable mModuleForwardRunnable = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
final Result result = doModuleForward();
|
||||
runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
handleResult(result);
|
||||
if (mBackgroundHandler != null) {
|
||||
mBackgroundHandler.post(mModuleForwardRunnable);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_main);
|
||||
mTextView = findViewById(R.id.text);
|
||||
startBackgroundThread();
|
||||
mBackgroundHandler.post(mModuleForwardRunnable);
|
||||
}
|
||||
|
||||
protected void startBackgroundThread() {
|
||||
mBackgroundThread = new HandlerThread(TAG + "_bg");
|
||||
mBackgroundThread.start();
|
||||
mBackgroundHandler = new Handler(mBackgroundThread.getLooper());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
stopBackgroundThread();
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
protected void stopBackgroundThread() {
|
||||
mBackgroundThread.quitSafely();
|
||||
try {
|
||||
mBackgroundThread.join();
|
||||
mBackgroundThread = null;
|
||||
mBackgroundHandler = null;
|
||||
} catch (InterruptedException e) {
|
||||
Log.e(TAG, "Error stopping background thread", e);
|
||||
}
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
@Nullable
|
||||
protected Result doModuleForward() {
|
||||
if (mModule == null) {
|
||||
final String moduleFileAbsoluteFilePath = new File(
|
||||
assetFilePath(this, BuildConfig.MODULE_ASSET_NAME)).getAbsolutePath();
|
||||
mModule = Module.load(moduleFileAbsoluteFilePath);
|
||||
mInputTensorBuffer = Tensor.allocateFloatBuffer(3 * 224 * 224);
|
||||
mInputTensor = Tensor.fromBlob(mInputTensorBuffer, new long[]{1, 3, 224, 224});
|
||||
}
|
||||
|
||||
final long startTime = SystemClock.elapsedRealtime();
|
||||
final long moduleForwardStartTime = SystemClock.elapsedRealtime();
|
||||
final Tensor outputTensor = mModule.forward(IValue.from(mInputTensor)).toTensor();
|
||||
final long moduleForwardDuration = SystemClock.elapsedRealtime() - moduleForwardStartTime;
|
||||
final float[] scores = outputTensor.getDataAsFloatArray();
|
||||
final long analysisDuration = SystemClock.elapsedRealtime() - startTime;
|
||||
|
||||
return new Result(scores, moduleForwardDuration, analysisDuration);
|
||||
}
|
||||
|
||||
public static String assetFilePath(Context context, String assetName) {
|
||||
File file = new File(context.getFilesDir(), assetName);
|
||||
if (file.exists() && file.length() > 0) {
|
||||
return file.getAbsolutePath();
|
||||
}
|
||||
|
||||
try (InputStream is = context.getAssets().open(assetName)) {
|
||||
try (OutputStream os = new FileOutputStream(file)) {
|
||||
byte[] buffer = new byte[4 * 1024];
|
||||
int read;
|
||||
while ((read = is.read(buffer)) != -1) {
|
||||
os.write(buffer, 0, read);
|
||||
}
|
||||
os.flush();
|
||||
}
|
||||
return file.getAbsolutePath();
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "Error process asset " + assetName + " to file path");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static class Result {
|
||||
|
||||
private final float[] scores;
|
||||
private final long totalDuration;
|
||||
private final long moduleForwardDuration;
|
||||
|
||||
public Result(float[] scores, long moduleForwardDuration, long totalDuration) {
|
||||
this.scores = scores;
|
||||
this.moduleForwardDuration = moduleForwardDuration;
|
||||
this.totalDuration = totalDuration;
|
||||
}
|
||||
}
|
||||
|
||||
@UiThread
|
||||
protected void handleResult(Result result) {
|
||||
String message = String.format("forwardDuration:%d", result.moduleForwardDuration);
|
||||
Log.i(TAG, message);
|
||||
mTextViewStringBuilder.insert(0, '\n').insert(0, message);
|
||||
if (mTextViewStringBuilder.length() > TEXT_TRIM_SIZE) {
|
||||
mTextViewStringBuilder.delete(TEXT_TRIM_SIZE, mTextViewStringBuilder.length());
|
||||
}
|
||||
mTextView.setText(mTextViewStringBuilder.toString());
|
||||
}
|
||||
}
|
17
android/test_app/app/src/main/res/layout/activity_main.xml
Normal file
17
android/test_app/app/src/main/res/layout/activity_main.xml
Normal file
@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
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"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="top"
|
||||
android:textSize="14sp"
|
||||
android:background="@android:color/black"
|
||||
android:textColor="@android:color/white" />
|
||||
|
||||
</FrameLayout>
|
BIN
android/test_app/app/src/main/res/mipmap-mdpi/ic_launcher.png
Normal file
BIN
android/test_app/app/src/main/res/mipmap-mdpi/ic_launcher.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.0 KiB |
Binary file not shown.
After Width: | Height: | Size: 2.7 KiB |
6
android/test_app/app/src/main/res/values/colors.xml
Normal file
6
android/test_app/app/src/main/res/values/colors.xml
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="colorPrimary">#008577</color>
|
||||
<color name="colorPrimaryDark">#00574B</color>
|
||||
<color name="colorAccent">#D81B60</color>
|
||||
</resources>
|
3
android/test_app/app/src/main/res/values/strings.xml
Normal file
3
android/test_app/app/src/main/res/values/strings.xml
Normal file
@ -0,0 +1,3 @@
|
||||
<resources>
|
||||
<string name="app_name">PyTest</string>
|
||||
</resources>
|
11
android/test_app/app/src/main/res/values/styles.xml
Normal file
11
android/test_app/app/src/main/res/values/styles.xml
Normal file
@ -0,0 +1,11 @@
|
||||
<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>
|
7
android/test_app/gradle.properties
Normal file
7
android/test_app/gradle.properties
Normal file
@ -0,0 +1,7 @@
|
||||
android.useAndroidX=true
|
||||
android.enableJetifier=true
|
||||
|
||||
MODULE_ASSET_NAME_DEFAULT=mobilenet2q.pt
|
||||
MODULE_ASSET_NAME_MOBNET2_QUANT=mobilenet2q.pt
|
||||
MODULE_ASSET_NAME_RESNET18=resnet18.pt
|
||||
|
16
android/test_app/make_assets.py
Normal file
16
android/test_app/make_assets.py
Normal file
@ -0,0 +1,16 @@
|
||||
import torch
|
||||
import torchvision
|
||||
|
||||
print(torch.version.__version__)
|
||||
|
||||
resnet18 = torchvision.models.resnet18(pretrained=True)
|
||||
resnet18.eval()
|
||||
resnet18_traced = torch.jit.trace(resnet18, torch.rand(1, 3, 224, 224)).save("app/src/main/assets/resnet18.pt")
|
||||
|
||||
resnet50 = torchvision.models.resnet50(pretrained=True)
|
||||
resnet50.eval()
|
||||
torch.jit.trace(resnet50, torch.rand(1, 3, 224, 224)).save("app/src/main/assets/resnet50.pt")
|
||||
|
||||
mobilenet2q = torchvision.models.quantization.mobilenet_v2(pretrained=True, quantize=True)
|
||||
mobilenet2q.eval()
|
||||
torch.jit.trace(mobilenet2q, torch.rand(1, 3, 224, 224)).save("app/src/main/assets/mobilenet2q.pt")
|
@ -106,6 +106,10 @@ CMAKE_ARGS+=("-DANDROID_ABI=$ANDROID_ABI")
|
||||
CMAKE_ARGS+=("-DANDROID_NATIVE_API_LEVEL=$ANDROID_NATIVE_API_LEVEL")
|
||||
CMAKE_ARGS+=("-DANDROID_CPP_FEATURES=rtti exceptions")
|
||||
|
||||
if [ "${ANDROID_DEBUG_SYMBOLS:-}" == '1' ]; then
|
||||
CMAKE_ARGS+=("-DANDROID_DEBUG_SYMBOLS=1")
|
||||
fi
|
||||
|
||||
# Use-specified CMake arguments go last to allow overridding defaults
|
||||
CMAKE_ARGS+=($@)
|
||||
|
||||
|
Reference in New Issue
Block a user