You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: _mobile/android.md
+73-72Lines changed: 73 additions & 72 deletions
Original file line number
Diff line number
Diff line change
@@ -10,12 +10,12 @@ published: true
10
10
11
11
# Android
12
12
13
-
## Quick start with a HelloWorld example
13
+
## Quickstart with a HelloWorld Example
14
14
15
-
[HelloWorld](https://github.com/pytorch/android-demo-app/tree/master/HelloWorldApp) is a simple image classification application that demonstrates how to use PyTorch android api.
15
+
[HelloWorld](https://github.com/pytorch/android-demo-app/tree/master/HelloWorldApp) is a simple image classification application that demonstrates how to use PyTorch Android API.
16
16
This application runs TorchScript serialized TorchVision pretrained resnet18 model on static image which is packaged inside the app as android asset.
17
17
18
-
#### 1. Model preparation
18
+
#### 1. Model Preparation
19
19
20
20
Let’s start with model preparation. If you are familiar with PyTorch, you probably should already know how to train and save your model. In case you don’t, we are going to use a pre-trained image classification model(Resnet18), which is packaged in [TorchVision](https://pytorch.org/docs/stable/torchvision/index.html).
21
21
To install it, run the command below:
@@ -44,13 +44,13 @@ More details about TorchScript you can find in [tutorials on pytorch.org](https:
Where `org.pytorch:pytorch_android` is the main dependency with pytorch android api, including libtorch native library for all 4 android abis (armeabi-v7a, arm64-v8a, x86, x86_64).
69
+
Where `org.pytorch:pytorch_android` is the main dependency with PyTorch Android API, including libtorch native library for all 4 android abis (armeabi-v7a, arm64-v8a, x86, x86_64).
70
70
Further in this doc you can find how to rebuild it only for specific list of android abis.
71
71
72
72
`org.pytorch:pytorch_android_torchvision` - additional library with utility functions for converting `android.media.Image` and `android.graphics.Bitmap` to tensors.
73
73
74
-
#### 4. Reading static image from android asset
74
+
#### 4. Reading image from Android Asset
75
75
76
-
All logic happens in [org.pytorch.helloworld.MainActivity](https://github.com/pytorch/android-demo-app/blob/master/HelloWorldApp/app/src/main/java/org/pytorch/helloworld/MainActivity.java#L31-L69).
77
-
As a first step we read `image.jpg` to `android.graphics.Bitmap` using standard android api.
76
+
All the logic happens in [`org.pytorch.helloworld.MainActivity`](https://github.com/pytorch/android-demo-app/blob/master/HelloWorldApp/app/src/main/java/org/pytorch/helloworld/MainActivity.java#L31-L69).
77
+
As a first step we read `image.jpg` to `android.graphics.Bitmap` using the standard Android API.
`org.pytorch.Module` represents `torch::jit::script::Module` that can be loaded with `load` method specifying file path to the serialized to file model.
`org.pytorch.torchvision.TensorImageUtils` is part of 'org.pytorch:pytorch_android_torchvision' library.
94
-
`TensorImageUtils#bitmapToFloat32Tensor` method creates tensor in [torch vision format](https://pytorch.org/docs/stable/torchvision/models.html) using `android.graphics.Bitmap` as a source.
93
+
`org.pytorch.torchvision.TensorImageUtils` is part of `org.pytorch:pytorch_android_torchvision` library.
94
+
The `TensorImageUtils#bitmapToFloat32Tensor` method creates tensors in the [torchvision format](https://pytorch.org/docs/stable/torchvision/models.html) using `android.graphics.Bitmap` as a source.
95
95
96
96
> All pre-trained models expect input images normalized in the same way, i.e. mini-batches of 3-channel RGB images of shape (3 x H x W), where H and W are expected to be at least 224.
97
-
> The images have to be loaded in to a range of [0, 1] and then normalized using mean = [0.485, 0.456, 0.406] and std = [0.229, 0.224, 0.225]
97
+
> The images have to be loaded in to a range of `[0, 1]` and then normalized using `mean = [0.485, 0.456, 0.406]` and `std = [0.229, 0.224, 0.225]`
98
98
99
-
`inputTensor`'s shape is 1x3xHxW, where H and W are bitmap height and width appropriately.
99
+
`inputTensor`'s shape is `1x3xHxW`, where `H` and `W` are bitmap height and width appropriately.
`org.pytorch.Module.forward` method runs loaded module's `forward` method and gets result as `org.pytorch.Tensor` outputTensor with shape `1x1000`.
109
109
110
110
#### 8. Processing results
111
-
It's content is retrieved using `org.pytorch.Tensor.getDataAsFloatArray()` method that returns java array of floats with scores for every image net class.
111
+
Its content is retrieved using `org.pytorch.Tensor.getDataAsFloatArray()` method that returns java array of floats with scores for every image net class.
112
112
113
113
After that we just find index with maximum score and retrieve predicted class name from `ImageNetClasses.IMAGENET_CLASSES` array that contains all ImageNet classes.
114
114
@@ -124,14 +124,16 @@ for (int i = 0; i < scores.length; i++) {
In the following sections you can find detailed explanation of pytorch android api, code walk through for bigger [demo application](https://github.com/pytorch/android-demo-app/tree/master/PyTorchDemoApp), implementation details of api and how to customize and build it from the source.
127
+
In the following sections you can find detailed explanations of PyTorch Android API, code walk through for a bigger [demo application](https://github.com/pytorch/android-demo-app/tree/master/PyTorchDemoApp),
128
+
implementation details of the API, how to customize and build it from source.
128
129
129
-
## Pytorch demo app
130
+
## PyTorch Demo Application
130
131
131
-
Bigger example of application that does image classification from android camera output and text classification you can find in the [same github repo](https://github.com/pytorch/android-demo-app/tree/master/PyTorchDemoApp).
132
+
We have also created another more complex PyTorch Android demo application that does image classification from camera output and text classification in the [same github repo](https://github.com/pytorch/android-demo-app/tree/master/PyTorchDemoApp).
132
133
133
-
To get device camera output in it uses [android cameraX api](https://developer.android.com/training/camerax
134
-
). All the logic that works with CameraX is separated to [`org.pytorch.demo.vision.AbstractCameraXActivity`](https://github.com/pytorch/android-demo-app/blob/master/PyTorchDemoApp/app/src/main/java/org/pytorch/demo/vision/AbstractCameraXActivity.java) class.
134
+
To get device camera output it uses [Android CameraX API](https://developer.android.com/training/camerax
135
+
).
136
+
All the logic that works with CameraX is separated to [`org.pytorch.demo.vision.AbstractCameraXActivity`](https://github.com/pytorch/android-demo-app/blob/master/PyTorchDemoApp/app/src/main/java/org/pytorch/demo/vision/AbstractCameraXActivity.java) class.
135
137
136
138
137
139
```
@@ -158,13 +160,13 @@ void setupCameraX() {
158
160
void analyzeImage(android.media.Image, int rotationDegrees)
159
161
```
160
162
161
-
Where `analyzeImage` method processes camera output, `android.media.Image`.
163
+
Where the `analyzeImage` method process the camera output, `android.media.Image`.
162
164
163
-
It uses aforementioned [`TensorImageUtils.imageYUV420CenterCropToFloat32Tensor`](https://github.com/pytorch/pytorch/blob/master/android/pytorch_android_torchvision/src/main/java/org/pytorch/torchvision/TensorImageUtils.java#L90) method to convert `android.media.Image` in `YUV420` format to input tensor.
165
+
It uses the aforementioned [`TensorImageUtils.imageYUV420CenterCropToFloat32Tensor`](https://github.com/pytorch/pytorch/blob/master/android/pytorch_android_torchvision/src/main/java/org/pytorch/torchvision/TensorImageUtils.java#L90) method to convert `android.media.Image` in `YUV420` format to input tensor.
164
166
165
-
After getting predicted scores from the model it [finds top K classes](https://github.com/pytorch/android-demo-app/blob/master/PyTorchDemoApp/app/src/main/java/org/pytorch/demo/vision/ImageClassificationActivity.java#L153-L161) with the highest scores and shows on the UI.
167
+
After getting predicted scores from the model it finds top K classes with the highest scores and shows on the UI.
166
168
167
-
## Building pytorch android from source
169
+
## Building PyTorch Android from Source
168
170
169
171
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.
170
172
@@ -175,19 +177,22 @@ cd pytorch
175
177
sh ./scripts/build_pytorch_android.sh
176
178
```
177
179
178
-
Its workflow contains several steps:
179
-
1. Builds libtorch for android for all 4 android abis (armeabi-v7a, arm64-v8a, x86, x86_64)
180
-
2. Creates symbolic links to the results of those builds:
180
+
The workflow contains several steps:
181
+
182
+
1\. Build libtorch for android for all 4 android abis (armeabi-v7a, arm64-v8a, x86, x86_64)
183
+
184
+
2\. Create symbolic links to the results of those builds:
181
185
`android/pytorch_android/src/main/jniLibs/${abi}` to the directory with output libraries
182
-
`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.
183
-
3. And finally runs `gradle` in `android/pytorch_android` directory with task `assembleRelease`
186
+
`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.
187
+
188
+
3\. And finally run `gradle` in `android/pytorch_android` directory with task `assembleRelease`
184
189
185
-
Script requires that android sdk, android ndk and gradle are installed.
190
+
Script requires that Android SDK, Android NDK and gradle are installed.
186
191
They are specified as environment variables:
187
192
188
-
`ANDROID_HOME` - path to [android sdk](https://developer.android.com/studio/command-line/sdkmanager.html)
193
+
`ANDROID_HOME` - path to [Android SDK](https://developer.android.com/studio/command-line/sdkmanager.html)
189
194
190
-
`ANDROID_NDK` - path to [android ndk](https://developer.android.com/studio/projects/install-ndk)
195
+
`ANDROID_NDK` - path to [Android NDK](https://developer.android.com/studio/projects/install-ndk)
191
196
192
197
`GRADLE_HOME` - path to [gradle](https://gradle.org/releases/)
193
198
@@ -226,7 +231,7 @@ dependencies {
226
231
}
227
232
```
228
233
229
-
At the moment for the case of using aar files directly we need additional configuration due to packaging specific (libfbjni.so is packaged in both pytorch_android_fbjni.aar and pytorch_android.aar).
234
+
At the moment for the case of using aar files directly we need additional configuration due to packaging specific (`libfbjni.so` is packaged in both `pytorch_android_fbjni.aar` and `pytorch_android.aar`).
230
235
```
231
236
packagingOptions {
232
237
pickFirst "**/libfbjni.so"
@@ -235,52 +240,49 @@ packagingOptions {
235
240
236
241
## API Details
237
242
238
-
Main part of java api includes 3 classes:
243
+
Main part of java API includes 3 classes:
239
244
```
240
245
org.pytorch.Module
241
246
org.pytorch.IValue
242
247
org.pytorch.Tensor
243
248
```
244
249
245
-
If the reader is familiar with pytorch python api, we can think that org.pytorch.Tensor represents torch.tensor, org.pytorch.Moduletorch.Module<?>, while org.pytorch.IValue represents value of TorchScript variable, supporting all its types. ( https://pytorch.org/docs/stable/jit.html#types )
250
+
If the reader is familiar with PyTorch Python API, we can think of `org.pytorch.Tensor` representing `torch.tensor`, `org.pytorch.Module` representing `torch.Module`, and `org.pytorch.IValue` representing the value of the TorchScript variable, supporting all its [types](https://pytorch.org/docs/stable/jit.html#types).
Where the first parameter `long[] shape` is shape of the Tensor as array of longs.
276
278
277
-
Content of the Tensor can be provided either as (a) java array or (b) as java.nio.DirectByteBuffer of proper type with native bit order.
279
+
Content of the Tensor can be provided either as (a) java array or (b) as `java.nio.DirectByteBuffer` of proper type with native bit order.
278
280
279
-
In case of (a) proper DirectByteBuffer will be created internally. (b) case has an advantage that user can keep the reference to DirectByteBuffer and change its content in future for the next run, avoiding allocation of DirectByteBuffer for repeated runs.
281
+
In case of (a) proper `DirectByteBuffer` will be created internally. (b) case has an advantage that user can keep the reference to DirectByteBuffer and change its content in future for the next run, avoiding allocation of DirectByteBuffer for repeated runs.
280
282
281
-
Java’s primitive type byte is signed and java does not have unsigned 8 bit type. For dtype=uint8 api uses byte that will be reinterpretted as uint8 on native side. On java side unsigned value of byte can be read as (byte & 0xFF).
283
+
Java’s primitive type byte is signed and java does not have unsigned 8 bit type. For dtype=uint8 java API uses java primitive `byte` that will be reinterpreted as uint8 on native side. On java side unsigned value of byte can be read as `byte & 0xFF`.
282
284
283
-
#### Tensor content layout
285
+
#### Tensor Content Layout
284
286
285
287
Tensor content is represented as a one dimensional array (buffer),
286
288
where the first element has all zero indexes T\[0, ... 0\].
@@ -293,17 +295,17 @@ Tensor has methods to check its dtype:
293
295
```
294
296
int dtype()
295
297
```
296
-
That returns one of the dtype codes:
298
+
That returns one of the `DType` enum element:
297
299
```
298
-
Tensor.DTYPE_UINT8
299
-
Tensor.DTYPE_INT8
300
-
Tensor.DTYPE_INT32
301
-
Tensor.DTYPE_FLOAT32
302
-
Tensor.DTYPE_INT64
303
-
Tensor.DTYPE_FLOAT64
300
+
DType.UINT8
301
+
DType.INT8
302
+
DType.INT32
303
+
DType.FLOAT32
304
+
DType.INT64
305
+
DType.FLOAT64
304
306
```
305
307
306
-
The data of Tensor can be read as java array:
308
+
The data of Tensor can be read as a java array:
307
309
```
308
310
byte[] getDataAsUnsignedByteArray()
309
311
byte[] getDataAsByteArray()
@@ -312,18 +314,17 @@ long[] getDataAsLongArray()
312
314
float[] getDataAsFloatArray()
313
315
double[] getDataAsDoubleArray()
314
316
```
315
-
These methods throw IllegalStateException if called for inappropriate dtype.
317
+
These methods throw `IllegalStateException` if called for inappropriate dtype.
IValue represents a TorchScript variable that can be one of the supported (by torchscript) types ( https://pytorch.org/docs/stable/jit.html#types ). IValue is a tagged union. For every supported type it has a factory method, method to check the type and a getter method to retrieve a value.
321
-
Getters throw IllegalStateException if called for inappropriate type.
321
+
IValue represents a TorchScript variable that can be one of the supported (by TorchScript) [types](https://pytorch.org/docs/stable/jit.html#types).
322
+
`IValue` is a tagged union. For every supported type it has a factory method, method to check the type and a getter method to retrieve a value.
323
+
Getters throw `IllegalStateException` if called for inappropriate type.
Module is a wrapper of torch.jit.ScriptModule (`torch::jit::script::Module` in pytorch c++ api) which can be constructed with factory method load providing absolute path to the file with serialized TorchScript.
327
+
Module is a wrapper of torch.jit.ScriptModule (`torch::jit::script::Module` in PyTorch C++ API) which can be constructed with the factory method `load` providing absolute path to the file with serialized TorchScript.
0 commit comments