Skip to content

Commit

Permalink
[Reland] Add a workflow to release Android binaries (pytorch#110976)
Browse files Browse the repository at this point in the history
This adds 2 jobs to build PyTorch Android with and without lite interpreter:

* Keep the list of currently supported ABI armeabi-v7a, arm64-v8a, x86, x86_64
* Pass all the test on emulator
* Run an the test app on emulator and my Android phone `arm64-v8a` without any issue
![Screenshot_20231010-114453](https://github.com/pytorch/pytorch/assets/475357/57e12188-1675-44d2-a259-9f9577578590)
* Run on AWS https://us-west-2.console.aws.amazon.com/devicefarm/home#/mobile/projects/b531574a-fb82-40ae-b687-8f0b81341ae0/runs/5fce6818-628a-4099-9aab-23e91a212076
Pull Request resolved: pytorch#110976
Approved by: https://github.com/atalman
  • Loading branch information
huydhn authored and pytorchmergebot committed Oct 18, 2023
1 parent a771fde commit 53c1dca
Show file tree
Hide file tree
Showing 9 changed files with 131 additions and 12 deletions.
File renamed without changes.
20 changes: 15 additions & 5 deletions .github/workflows/_run_android_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,17 +41,25 @@ jobs:
strategy:
matrix: ${{ fromJSON(needs.filter.outputs.test-matrix) }}
fail-fast: false
# NB: This job can only run on GitHub Linux runner atm. This is an ok thing though
# because that runner is ephemeral and could access upload secrets
runs-on: ${{ matrix.runner }}
env:
# GitHub runner installs Android SDK on this path
ANDROID_ROOT: /usr/local/lib/android
ANDROID_NDK_VERSION: '21.4.7075529'
BUILD_LITE_INTERPRETER: ${{ matrix.use_lite_interpreter }}
# 4 of them are supported atm: armeabi-v7a, arm64-v8a, x86, x86_64
SUPPORT_ABI: '${{ matrix.support_abi }}'
steps:
# [see note: pytorch repo ref]
- name: Checkout PyTorch
uses: pytorch/pytorch/.github/actions/checkout-pytorch@main

- name: Setup miniconda
uses: pytorch/test-infra/.github/actions/setup-miniconda@main
with:
python-version: 3.8
environment-file: .github/requirements/conda-env-${{ runner.os }}-${{ runner.arch }}
environment-file: .github/requirements/conda-env-${{ runner.os }}-${{ runner.arch }}.txt

- name: Install NDK
uses: nick-fields/[email protected]
Expand All @@ -60,12 +68,12 @@ jobs:
max_attempts: 3
retry_wait_seconds: 90
command: |
set -eux
# Install NDK 21 after GitHub update
# https://github.com/actions/virtual-environments/issues/5595
ANDROID_ROOT="/usr/local/lib/android"
ANDROID_SDK_ROOT="${ANDROID_ROOT}/sdk"
ANDROID_NDK="${ANDROID_SDK_ROOT}/ndk-bundle"
ANDROID_NDK_VERSION="21.4.7075529"
SDKMANAGER="${ANDROID_SDK_ROOT}/cmdline-tools/latest/bin/sdkmanager"
# NB: This step downloads and installs NDK, thus it could be flaky.
Expand All @@ -86,8 +94,10 @@ jobs:
- name: Build PyTorch Android
run: |
set -eux
echo "CMAKE_PREFIX_PATH=${CONDA_PREFIX:-"$(dirname "$(which conda)")/../"}" >> "${GITHUB_ENV}"
${CONDA_RUN} ./scripts/build_pytorch_android.sh x86
${CONDA_RUN} ./scripts/build_pytorch_android.sh "${SUPPORT_ABI}"
- name: Run tests
uses: reactivecircus/android-emulator-runner@v2
Expand Down
48 changes: 48 additions & 0 deletions .github/workflows/build-android-binaries.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
name: Build Android binaries

on:
push:
branches:
- nightly
tags:
# NOTE: Binary build pipelines should only get triggered on release candidate builds
# Release candidate tags look like: v1.11.0-rc1
- v[0-9]+.[0-9]+.[0-9]+-rc[0-9]+
paths:
- .github/workflows/build-android-binaries.yml
- .github/workflows/_run_android_tests.yml
- android/**
pull_request:
paths:
- .github/workflows/build-android-binaries.yml
- .github/workflows/_run_android_tests.yml
- android/**
# NB: We can use this workflow dispatch to test and build the binaries manually
workflow_dispatch:

concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }}-${{ github.event_name == 'workflow_dispatch' }}
cancel-in-progress: true

jobs:
android-build-test:
name: android-build-test
uses: ./.github/workflows/_run_android_tests.yml
with:
test-matrix: |
{ include: [
{ config: 'default',
shard: 1,
num_shards: 1,
runner: 'ubuntu-20.04-16x',
use_lite_interpreter: 1,
support_abi: 'armeabi-v7a,arm64-v8a,x86,x86_64',
},
{ config: 'default',
shard: 1,
num_shards: 1,
runner: 'ubuntu-20.04-16x',
use_lite_interpreter: 0,
support_abi: 'armeabi-v7a,arm64-v8a,x86,x86_64',
},
]}
9 changes: 8 additions & 1 deletion .github/workflows/periodic.yml
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,14 @@ jobs:
with:
test-matrix: |
{ include: [
{ config: "default", shard: 1, num_shards: 1, runner: "ubuntu-20.04-16x" },
{ config: 'default',
shard: 1,
num_shards: 1,
runner: 'ubuntu-20.04-16x',
use_lite_interpreter: 1,
# Just set x86 for testing here
support_abi: 'x86',
},
]}
linux-vulkan-focal-py3_11-clang10-build:
Expand Down
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -365,3 +365,7 @@ venv/
# Log files
*.log
sweep/

# Android build artifacts
android/pytorch_android/.cxx
android/pytorch_android_torchvision/.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import java.util.HashMap;
import java.util.Map;
import org.junit.Test;
import org.junit.Ignore;

public abstract class PytorchTestBase {
private static final String TEST_MODULE_ASSET_NAME = "android_api_module.ptl";
Expand Down Expand Up @@ -413,7 +414,10 @@ public void testOtherMathOps() throws IOException {
}

@Test
@Ignore
public void testSpectralOps() throws IOException {
// NB: This model fails without lite interpreter. The error is as follows:
// RuntimeError: stft requires the return_complex parameter be given for real inputs
runModel("spectral_ops");
}

Expand Down
16 changes: 11 additions & 5 deletions android/test_app/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@ android {
buildConfigField("long[]", "INPUT_TENSOR_SHAPE", "new long[]{1, 3, 224, 224}")
buildConfigField("boolean", "NATIVE_BUILD", 'false')
buildConfigField("boolean", "USE_VULKAN_DEVICE", 'false')
buildConfigField(
"int",
"BUILD_LITE_INTERPRETER",
System.env.BUILD_LITE_INTERPRETER != null ? System.env.BUILD_LITE_INTERPRETER : "1"
)
addManifestPlaceholders([APP_NAME: "@string/app_name", MAIN_ACTIVITY: "org.pytorch.testapp.MainActivity"])
}
buildTypes {
Expand All @@ -63,22 +68,23 @@ android {
mnet {
dimension "model"
applicationIdSuffix ".mnet"
buildConfigField("String", "MODULE_ASSET_NAME", "\"mnet.pt\"")
buildConfigField("String", "MODULE_ASSET_NAME", "\"mobilenet_v2.ptl\"")
addManifestPlaceholders([APP_NAME: "MNET"])
buildConfigField("String", "LOGCAT_TAG", "\"pytorch-mnet\"")
}
// NB: This is not working atm https://github.com/pytorch/pytorch/issues/102966
mnetVulkan {
dimension "model"
applicationIdSuffix ".mnet_vulkan"
buildConfigField("String", "MODULE_ASSET_NAME", "\"mnet_vulkan.pt\"")
buildConfigField("String", "MODULE_ASSET_NAME", "\"mobilenet_v2_vulkan.ptl\"")
buildConfigField("boolean", "USE_VULKAN_DEVICE", 'true')
addManifestPlaceholders([APP_NAME: "MNET_VULKAN"])
buildConfigField("String", "LOGCAT_TAG", "\"pytorch-mnet-vulkan\"")
}
resnet18 {
dimension "model"
applicationIdSuffix ".resnet18"
buildConfigField("String", "MODULE_ASSET_NAME", "\"resnet18.pt\"")
buildConfigField("String", "MODULE_ASSET_NAME", "\"resnet18.ptl\"")
addManifestPlaceholders([APP_NAME: "RN18"])
buildConfigField("String", "LOGCAT_TAG", "\"pytorch-resnet18\"")
}
Expand Down Expand Up @@ -149,8 +155,8 @@ dependencies {
//nativeBuildImplementation(name: 'pytorch_android_torchvision-release', ext: 'aar')
//extractForNativeBuild(name: 'pytorch_android-release', ext: 'aar')

nightlyImplementation 'org.pytorch:pytorch_android:1.12.0-SNAPSHOT'
nightlyImplementation 'org.pytorch:pytorch_android_torchvision:1.12.0-SNAPSHOT'
nightlyImplementation 'org.pytorch:pytorch_android:2.2.0-SNAPSHOT'
nightlyImplementation 'org.pytorch:pytorch_android_torchvision:2.2.0-SNAPSHOT'

aarImplementation(name:'pytorch_android', ext:'aar')
aarImplementation(name:'pytorch_android_torchvision', ext:'aar')
Expand Down
8 changes: 7 additions & 1 deletion test/mobile/model_test/gen_test_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,11 @@
TensorViewOpsModule,
)
from torch.jit.mobile import _load_for_lite_interpreter
from torchvision_models import MobileNetV2Module
from torchvision_models import (
MobileNetV2Module,
MobileNetV2VulkanModule,
Resnet18Module,
)

test_path_ios = "ios/TestApp/models/"
test_path_android = "android/pytorch_android/src/androidTest/assets/"
Expand Down Expand Up @@ -98,6 +102,8 @@
"torchscript_collection_ops": TSCollectionOpsModule(),
# vision
"mobilenet_v2": MobileNetV2Module(),
"mobilenet_v2_vulkan": MobileNetV2VulkanModule(),
"resnet18": Resnet18Module(),
# android api module
"android_api_module": AndroidAPIModule(),
}
Expand Down
34 changes: 34 additions & 0 deletions test/mobile/model_test/torchvision_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,37 @@ def getModule(self):
)
optimized_module(example)
return optimized_module


class MobileNetV2VulkanModule:
def getModule(self):
model = torchvision.models.mobilenet_v2(pretrained=True)
model.eval()
example = torch.zeros(1, 3, 224, 224)
traced_script_module = torch.jit.trace(model, example)
optimized_module = optimize_for_mobile(traced_script_module, backend="vulkan")
augment_model_with_bundled_inputs(
optimized_module,
[
(example, ),
],
)
optimized_module(example)
return optimized_module


class Resnet18Module:
def getModule(self):
model = torchvision.models.resnet18(pretrained=True)
model.eval()
example = torch.zeros(1, 3, 224, 224)
traced_script_module = torch.jit.trace(model, example)
optimized_module = optimize_for_mobile(traced_script_module)
augment_model_with_bundled_inputs(
optimized_module,
[
(example, ),
],
)
optimized_module(example)
return optimized_module

0 comments on commit 53c1dca

Please sign in to comment.