|
1 |
| -# Android Demo App |
| 1 | +# Android |
2 | 2 |
|
3 |
| -Please refer to [pytorch-labs/executorch-examples](https://github.com/pytorch-labs/executorch-examples/tree/main/dl3/android/DeepLabV3Demo) for the Android demo app based on [ExecuTorch](https://github.com/pytorch/executorch). |
| 3 | +## Demo applications and tutorials |
4 | 4 |
|
5 |
| -Please join our [Discord](https://discord.com/channels/1334270993966825602/1349854760299270284) for any questions. |
| 5 | +Demo applications with code walk-through can be find in [this github repo](https://github.com/pytorch/android-demo-app). |
| 6 | + |
| 7 | +## Publishing |
| 8 | + |
| 9 | +##### Release |
| 10 | +Release artifacts are published to jcenter: |
| 11 | + |
| 12 | +```groovy |
| 13 | +repositories { |
| 14 | + jcenter() |
| 15 | +} |
| 16 | +
|
| 17 | +# lite interpreter build |
| 18 | +dependencies { |
| 19 | + implementation 'org.pytorch:pytorch_android_lite:1.10.0' |
| 20 | + implementation 'org.pytorch:pytorch_android_torchvision_lite:1.10.0' |
| 21 | +} |
| 22 | +
|
| 23 | +# full jit build |
| 24 | +dependencies { |
| 25 | + implementation 'org.pytorch:pytorch_android:1.10.0' |
| 26 | + implementation 'org.pytorch:pytorch_android_torchvision:1.10.0' |
| 27 | +} |
| 28 | +``` |
| 29 | + |
| 30 | +##### Nightly |
| 31 | + |
| 32 | +Nightly(snapshots) builds are published every night from `master` branch to [nexus sonatype snapshots repository](https://oss.sonatype.org/#nexus-search;quick~pytorch_android) |
| 33 | + |
| 34 | +To use them repository must be specified explicitly: |
| 35 | +```groovy |
| 36 | +repositories { |
| 37 | + maven { |
| 38 | + url "https://oss.sonatype.org/content/repositories/snapshots" |
| 39 | + } |
| 40 | +} |
| 41 | +
|
| 42 | +# lite interpreter build |
| 43 | +dependencies { |
| 44 | + ... |
| 45 | + implementation 'org.pytorch:pytorch_android_lite:1.12.0-SNAPSHOT' |
| 46 | + implementation 'org.pytorch:pytorch_android_torchvision_lite:1.12.0-SNAPSHOT' |
| 47 | + ... |
| 48 | +} |
| 49 | +
|
| 50 | +# full jit build |
| 51 | +dependencies { |
| 52 | + ... |
| 53 | + implementation 'org.pytorch:pytorch_android:1.12.0-SNAPSHOT' |
| 54 | + implementation 'org.pytorch:pytorch_android_torchvision:1.12.0-SNAPSHOT' |
| 55 | + ... |
| 56 | +} |
| 57 | +``` |
| 58 | +The current nightly(snapshots) version is the value of `VERSION_NAME` in `gradle.properties` in current folder, at this moment it is `1.8.0-SNAPSHOT`. |
| 59 | + |
| 60 | +## Building PyTorch Android from Source |
| 61 | + |
| 62 | +In some cases you might want to use a local build of pytorch android, for example you may build custom libtorch binary with another set of operators or to make local changes. |
| 63 | + |
| 64 | +For this you can use `./scripts/build_pytorch_android.sh` script. |
| 65 | +```bash |
| 66 | +git clone https://github.com/pytorch/pytorch.git |
| 67 | +cd pytorch |
| 68 | +git submodule update --init --recursive |
| 69 | +bash ./scripts/build_pytorch_android.sh |
| 70 | +``` |
| 71 | + |
| 72 | +The workflow contains several steps: |
| 73 | + |
| 74 | +1\. Build libtorch for android for all 4 android abis (armeabi-v7a, arm64-v8a, x86, x86_64) |
| 75 | + |
| 76 | +2\. Create symbolic links to the results of those builds: |
| 77 | +`android/pytorch_android/src/main/jniLibs/${abi}` to the directory with output libraries |
| 78 | +`android/pytorch_android/src/main/cpp/libtorch_include/${abi}` to the directory with headers. These directories are used to build `libpytorch.so` library that will be loaded on android device. |
| 79 | + |
| 80 | +3\. And finally run `gradle` in `android/pytorch_android` directory with task `assembleRelease` |
| 81 | + |
| 82 | +Script requires that Android SDK, Android NDK and gradle are installed. |
| 83 | +They are specified as environment variables: |
| 84 | + |
| 85 | +`ANDROID_HOME` - path to [Android SDK](https://developer.android.com/studio/command-line/sdkmanager.html) |
| 86 | + |
| 87 | +`ANDROID_NDK` - path to [Android NDK](https://developer.android.com/studio/projects/install-ndk). It's recommended to use NDK 21.x. |
| 88 | + |
| 89 | +`GRADLE_HOME` - path to [gradle](https://gradle.org/releases/) |
| 90 | + |
| 91 | + |
| 92 | +After successful build you should see the result as aar file: |
| 93 | + |
| 94 | +```bash |
| 95 | +$ find pytorch_android/build/ -type f -name *aar |
| 96 | +pytorch_android/build/outputs/aar/pytorch_android.aar |
| 97 | +pytorch_android_torchvision/build/outputs/aar/pytorch_android.aar |
| 98 | +``` |
| 99 | + |
| 100 | +It can be used directly in android projects, as a gradle dependency: |
| 101 | +```groovy |
| 102 | +allprojects { |
| 103 | + repositories { |
| 104 | + flatDir { |
| 105 | + dirs 'libs' |
| 106 | + } |
| 107 | + } |
| 108 | +} |
| 109 | +
|
| 110 | +dependencies { |
| 111 | + implementation(name:'pytorch_android', ext:'aar') |
| 112 | + implementation(name:'pytorch_android_torchvision', ext:'aar') |
| 113 | + ... |
| 114 | + implementation 'com.facebook.soloader:nativeloader:0.10.5' |
| 115 | + implementation 'com.facebook.fbjni:fbjni-java-only:0.2.2' |
| 116 | +} |
| 117 | +``` |
| 118 | +We also have to add all transitive dependencies of our aars. |
| 119 | +As `pytorch_android` [depends](https://github.com/pytorch/pytorch/blob/master/android/pytorch_android/build.gradle#L76-L77) on `'com.facebook.soloader:nativeloader:0.10.5'` and `'com.facebook.fbjni:fbjni-java-only:0.2.2'`, we need to add them. |
| 120 | +(In case of using maven dependencies they are added automatically from `pom.xml`). |
| 121 | + |
| 122 | +You can check out [test app example](https://github.com/pytorch/pytorch/blob/master/android/test_app/app/build.gradle) that uses aars directly. |
| 123 | + |
| 124 | +## Linking to prebuilt libtorch library from gradle dependency |
| 125 | + |
| 126 | +In some cases, you may want to use libtorch from your android native build. |
| 127 | +You can do it without building libtorch android, using native libraries from PyTorch android gradle dependency. |
| 128 | +For that, you will need to add the next lines to your gradle build. |
| 129 | +```groovy |
| 130 | +android { |
| 131 | +... |
| 132 | + configurations { |
| 133 | + extractForNativeBuild |
| 134 | + } |
| 135 | +... |
| 136 | + compileOptions { |
| 137 | + externalNativeBuild { |
| 138 | + cmake { |
| 139 | + arguments "-DANDROID_STL=c++_shared" |
| 140 | + } |
| 141 | + } |
| 142 | + } |
| 143 | +... |
| 144 | + externalNativeBuild { |
| 145 | + cmake { |
| 146 | + path "CMakeLists.txt" |
| 147 | + } |
| 148 | + } |
| 149 | +} |
| 150 | +
|
| 151 | +dependencies { |
| 152 | + extractForNativeBuild('org.pytorch:pytorch_android:1.10.0') |
| 153 | +} |
| 154 | +
|
| 155 | +task extractAARForNativeBuild { |
| 156 | + doLast { |
| 157 | + configurations.extractForNativeBuild.files.each { |
| 158 | + def file = it.absoluteFile |
| 159 | + copy { |
| 160 | + from zipTree(file) |
| 161 | + into "$buildDir/$file.name" |
| 162 | + include "headers/**" |
| 163 | + include "jni/**" |
| 164 | + } |
| 165 | + } |
| 166 | + } |
| 167 | +} |
| 168 | +
|
| 169 | +tasks.whenTaskAdded { task -> |
| 170 | + if (task.name.contains('externalNativeBuild')) { |
| 171 | + task.dependsOn(extractAARForNativeBuild) |
| 172 | + } |
| 173 | +} |
| 174 | +``` |
| 175 | + |
| 176 | +pytorch_android aar contains headers to link in `headers` folder and native libraries in `jni/$ANDROID_ABI/`. |
| 177 | +As PyTorch native libraries use `ANDROID_STL` - we should use `ANDROID_STL=c++_shared` to have only one loaded binary of STL. |
| 178 | + |
| 179 | +The added task will unpack them to gradle build directory. |
| 180 | + |
| 181 | +In your native build you can link to them adding these lines to your CMakeLists.txt: |
| 182 | + |
| 183 | + |
| 184 | +```cmake |
| 185 | +# Relative path of gradle build directory to CMakeLists.txt |
| 186 | +set(build_DIR ${CMAKE_SOURCE_DIR}/build) |
| 187 | +
|
| 188 | +file(GLOB PYTORCH_INCLUDE_DIRS "${build_DIR}/pytorch_android*.aar/headers") |
| 189 | +file(GLOB PYTORCH_LINK_DIRS "${build_DIR}/pytorch_android*.aar/jni/${ANDROID_ABI}") |
| 190 | +
|
| 191 | +set(BUILD_SUBDIR ${ANDROID_ABI}) |
| 192 | +target_include_directories(${PROJECT_NAME} PRIVATE |
| 193 | + ${PYTORCH_INCLUDE_DIRS} |
| 194 | +) |
| 195 | +
|
| 196 | +find_library(PYTORCH_LIBRARY pytorch_jni |
| 197 | + PATHS ${PYTORCH_LINK_DIRS} |
| 198 | + NO_CMAKE_FIND_ROOT_PATH) |
| 199 | +
|
| 200 | +find_library(FBJNI_LIBRARY fbjni |
| 201 | + PATHS ${PYTORCH_LINK_DIRS} |
| 202 | + NO_CMAKE_FIND_ROOT_PATH) |
| 203 | +
|
| 204 | +target_link_libraries(${PROJECT_NAME} |
| 205 | + ${PYTORCH_LIBRARY}) |
| 206 | + ${FBJNI_LIBRARY}) |
| 207 | +
|
| 208 | +``` |
| 209 | +If your CMakeLists.txt file is located in the same directory as your build.gradle, `set(build_DIR ${CMAKE_SOURCE_DIR}/build)` should work for you. But if you have another location of it, you may need to change it. |
| 210 | + |
| 211 | +After that, you can use libtorch C++ API from your native code. |
| 212 | +```cpp |
| 213 | +#include <string> |
| 214 | +#include <ATen/NativeFunctions.h> |
| 215 | +#include <torch/script.h> |
| 216 | +namespace pytorch_testapp_jni { |
| 217 | +namespace { |
| 218 | + struct JITCallGuard { |
| 219 | + c10::InferenceMode guard; |
| 220 | + torch::jit::GraphOptimizerEnabledGuard no_optimizer_guard{false}; |
| 221 | + }; |
| 222 | +} |
| 223 | + |
| 224 | +void loadAndForwardModel(const std::string& modelPath) { |
| 225 | + JITCallGuard guard; |
| 226 | + torch::jit::Module module = torch::jit::load(modelPath); |
| 227 | + module.eval(); |
| 228 | + torch::Tensor t = torch::randn({1, 3, 224, 224}); |
| 229 | + c10::IValue t_out = module.forward({t}); |
| 230 | +} |
| 231 | +} |
| 232 | +``` |
| 233 | +
|
| 234 | +To load torchscript model for mobile we need some special setup which is placed in `struct JITCallGuard` in this example. It may change in future, you can track the latest changes keeping an eye in our [pytorch android jni code]([https://github.com/pytorch/pytorch/blob/master/android/pytorch_android/src/main/cpp/pytorch_jni_jit.cpp#L28) |
| 235 | +
|
| 236 | +[Example of linking to libtorch from aar](https://github.com/pytorch/pytorch/tree/master/android/test_app) |
| 237 | +
|
| 238 | +## PyTorch Android API Javadoc |
| 239 | +
|
| 240 | +You can find more details about the PyTorch Android API in the [Javadoc](https://pytorch.org/javadoc/). |
0 commit comments