Skip to content

Commit 8f0ba25

Browse files
kirklandsignfacebook-github-bot
authored andcommitted
Allow switching between two backends
Summary: Now we can handle both XNNPACK and HTP (if built) Also update tutorial, and handle different input sizes https://pxl.cl/3wxXr Reviewed By: shoumikhin Differential Revision: D49969848 fbshipit-source-id: bae5ce2a7016336589b4c664dddd039eb8e0f727
1 parent 07aaad4 commit 8f0ba25

File tree

7 files changed

+104
-17
lines changed

7 files changed

+104
-17
lines changed

examples/demo-apps/android/ExecuTorchDemo/README.md

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,10 @@ cd ../../..
5858

5959
Configure the libraries for Android:
6060

61+
1. Configure a library with XNNPACK backend only
62+
63+
Note: This demo app and tutorial is only validated with arm64-v8a [ABI](https://developer.android.com/ndk/guides/abis).
64+
6165
```bash
6266
rm -rf cmake-out && mkdir cmake-out && cd cmake-out
6367
cmake .. \
@@ -71,6 +75,23 @@ cmake .. \
7175
-DEXECUTORCH_BUILD_EXTENSION_DATA_LOADER=ON
7276
```
7377

78+
2. Configure a library with XNNPACK and Qualcomm HTP backend
79+
80+
```bash
81+
rm -rf cmake-out && mkdir cmake-out && cd cmake-out
82+
cmake .. \
83+
-DCMAKE_TOOLCHAIN_FILE=/path/to/ndk/build/cmake/android.toolchain.cmake \
84+
-DANDROID_ABI=arm64-v8a \
85+
-DBUCK2=/tmp/buck2 \
86+
-DFLATC_EXECUTABLE=$(realpath ../third-party/flatbuffers/cmake-out/flatc) \
87+
-DEXECUTORCH_BUILD_ANDROID_DEMO_APP_JNI=ON \
88+
-DEXECUTORCH_BUILD_XNNPACK=ON \
89+
-DEXECUTORCH_BUILD_FLATC=OFF \
90+
-DEXECUTORCH_BUILD_QNN=ON \
91+
-DQNN_SDK_ROOT=/path/to/qnn/sdk \
92+
-DEXECUTORCH_BUILD_EXTENSION_DATA_LOADER=ON
93+
```
94+
7495
## Building and Copying Libraries
7596

7697
1. Build the libraries:
@@ -104,6 +125,8 @@ cd ..
104125

105126
## Model Download and Bundling
106127

128+
Note: Please refer to [XNNPACK backend](../../../backend/README.md) and [Qualcomm backend](../../../../backends/qualcomm/README.md) for the full export tutorial on backends.
129+
107130
1. Export a DeepLab v3 model and Inception v4 model backed with XNNPACK delegate and bundle it with
108131
the app:
109132

@@ -118,4 +141,4 @@ cp dl3_xnnpack_fp32.pte ic4_xnnpack_fp32.pte examples/android_demo_apps/ExecuTor
118141

119142
1. Open the project `examples/android_demo_apps/ExecuTorchDemo` with Android Studio.
120143

121-
2. Run the app (^R)
144+
2. [Run](https://developer.android.com/studio/run) the app (^R)

examples/demo-apps/android/ExecuTorchDemo/app/src/main/java/com/example/executorchdemo/ClassificationActivity.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ private void populateBitmap(String file) {
3333
Bitmap bitmap = null;
3434
try {
3535
bitmap = BitmapFactory.decodeStream(getAssets().open(file));
36-
bitmap = Bitmap.createScaledBitmap(bitmap, 224, 224, true);
36+
bitmap = Bitmap.createScaledBitmap(bitmap, 299, 299, true);
3737
} catch (IOException e) {
3838
Log.e("Classification", "Error reading assets", e);
3939
finish();
@@ -50,8 +50,8 @@ public void run() {
5050
Module module = null;
5151
try {
5252
bitmap = BitmapFactory.decodeStream(getAssets().open("corgi2.jpg"));
53-
bitmap = Bitmap.createScaledBitmap(bitmap, 224, 224, true);
54-
module = Module.load(MainActivity.assetFilePath(this, "ic3_xnnpack_fp32.pte"));
53+
bitmap = Bitmap.createScaledBitmap(bitmap, 299, 299, true);
54+
module = Module.load(MainActivity.assetFilePath(this, "ic4_qnn.pte"));
5555
} catch (IOException e) {
5656
Log.e("PytorchHelloWorld", "Error reading assets", e);
5757
finish();

examples/demo-apps/android/ExecuTorchDemo/app/src/main/java/com/example/executorchdemo/MainActivity.java

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import android.widget.Button;
2323
import android.widget.ImageView;
2424
import android.widget.ProgressBar;
25+
import android.widget.Toast;
2526
import com.example.executorchdemo.executor.EValue;
2627
import com.example.executorchdemo.executor.Module;
2728
import com.example.executorchdemo.executor.Tensor;
@@ -39,6 +40,7 @@ public class MainActivity extends Activity implements Runnable {
3940
private ProgressBar mProgressBar;
4041
private Bitmap mBitmap = null;
4142
private Module mModule = null;
43+
private String mBackend = "xnnpack";
4244
private String mImagename = "corgi.jpeg";
4345

4446
// see http://host.robots.ox.ac.uk:8080/pascal/VOC/voc2007/segexamples/index.html for the list of
@@ -99,8 +101,13 @@ protected void onCreate(Bundle savedInstanceState) {
99101
buttonRestart.setOnClickListener(
100102
new View.OnClickListener() {
101103
public void onClick(View v) {
102-
if (Objects.equals(mImagename, "corgi.jpeg")) mImagename = "dog.jpg";
103-
else mImagename = "deeplab.jpg";
104+
if (Objects.equals(mImagename, "corgi.jpeg")) {
105+
mImagename = "dog.jpg";
106+
} else if (Objects.equals(mImagename, "dog.jpg")) {
107+
mImagename = "deeplab.jpg";
108+
} else {
109+
mImagename = "corgi.jpeg";
110+
}
104111
try {
105112
mBitmap = BitmapFactory.decodeStream(getAssets().open(mImagename));
106113
mBitmap = Bitmap.createScaledBitmap(mBitmap, 224, 224, true);
@@ -112,6 +119,39 @@ public void onClick(View v) {
112119
}
113120
});
114121

122+
final Button buttonSwitchBackend = findViewById(R.id.switchBackendButton);
123+
buttonSwitchBackend.setText("Use Qualcomm backend");
124+
buttonSwitchBackend.setOnClickListener(
125+
new View.OnClickListener() {
126+
public void onClick(View v) {
127+
try {
128+
if (Objects.equals(mBackend, "xnnpack")) {
129+
mBackend = "qnn";
130+
mModule.destroy();
131+
mModule =
132+
Module.load(
133+
MainActivity.assetFilePath(getApplicationContext(), "dlv3_qnn.pte"));
134+
buttonSwitchBackend.setText("Use XNNPACK backend");
135+
} else {
136+
mBackend = "xnnpack";
137+
mModule.destroy();
138+
mModule =
139+
Module.load(
140+
MainActivity.assetFilePath(
141+
getApplicationContext(), "dl3_xnnpack_fp32.pte"));
142+
buttonSwitchBackend.setText("Use Qualcomm backend");
143+
}
144+
} catch (IOException e) {
145+
Log.e("ImageSegmentation", "Error reading assets", e);
146+
finish();
147+
}
148+
Toast toast =
149+
Toast.makeText(getApplicationContext(), "Using: " + mBackend, Toast.LENGTH_SHORT);
150+
toast.setMargin(50, 50);
151+
toast.show();
152+
}
153+
});
154+
115155
final Button classificationDemoButton = findViewById(R.id.classificationDemoButton);
116156
classificationDemoButton.setOnClickListener(
117157
new View.OnClickListener() {
@@ -203,6 +243,14 @@ public void run() {
203243
mButtonSegment.setEnabled(true);
204244
mButtonSegment.setText("segment");
205245
mProgressBar.setVisibility(ProgressBar.INVISIBLE);
246+
247+
Toast toast =
248+
Toast.makeText(
249+
getApplicationContext(),
250+
"Inference time (ms): " + inferenceTime,
251+
Toast.LENGTH_SHORT);
252+
toast.setMargin(50, 50);
253+
toast.show();
206254
}
207255
});
208256
}

examples/demo-apps/android/ExecuTorchDemo/app/src/main/res/layout/activity_main.xml

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
android:id="@+id/imageView"
1111
android:layout_width="388dp"
1212
android:layout_height="405dp"
13-
android:layout_marginTop="60dp"
13+
android:layout_marginTop="30dp"
1414
android:contentDescription="@string/image_view"
1515
app:layout_constraintDimensionRatio="1:1"
1616
app:layout_constraintEnd_toEndOf="parent"
@@ -34,7 +34,7 @@
3434
<ProgressBar
3535
android:id="@+id/progressBar"
3636
android:visibility="invisible"
37-
android:layout_marginTop="20dp"
37+
android:layout_marginTop="10dp"
3838
android:layout_width="wrap_content"
3939
android:layout_height="wrap_content"
4040
app:layout_constraintEnd_toEndOf="parent"
@@ -46,25 +46,37 @@
4646
android:id="@+id/restartButton"
4747
android:layout_width="wrap_content"
4848
android:layout_height="wrap_content"
49-
android:layout_marginTop="20dp"
49+
android:layout_marginTop="10dp"
5050
android:text="@string/restart"
5151
android:textAllCaps="false"
5252
app:layout_constraintEnd_toEndOf="parent"
5353
app:layout_constraintHorizontal_bias="0.498"
5454
app:layout_constraintStart_toStartOf="parent"
5555
app:layout_constraintTop_toBottomOf="@+id/segmentButton" />
5656

57+
<Button
58+
android:id="@+id/switchBackendButton"
59+
android:layout_width="wrap_content"
60+
android:layout_height="wrap_content"
61+
android:layout_marginTop="10dp"
62+
android:text="@string/switch_backend"
63+
android:textAllCaps="false"
64+
app:layout_constraintEnd_toEndOf="parent"
65+
app:layout_constraintHorizontal_bias="0.498"
66+
app:layout_constraintStart_toStartOf="parent"
67+
app:layout_constraintTop_toBottomOf="@+id/restartButton" />
68+
5769
<Button
5870
android:id="@+id/classificationDemoButton"
5971
android:layout_width="wrap_content"
6072
android:layout_height="wrap_content"
61-
android:layout_marginTop="20dp"
73+
android:layout_marginTop="10dp"
6274
android:text="@string/classification_demo"
6375
android:textAllCaps="false"
6476
app:layout_constraintEnd_toEndOf="parent"
6577
app:layout_constraintHorizontal_bias="0.498"
6678
app:layout_constraintStart_toStartOf="parent"
67-
app:layout_constraintTop_toBottomOf="@+id/restartButton" />
79+
app:layout_constraintTop_toBottomOf="@+id/switchBackendButton" />
6880

6981

7082
</androidx.constraintlayout.widget.ConstraintLayout>

examples/demo-apps/android/ExecuTorchDemo/app/src/main/res/values/strings.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,5 @@
88
<string name="live">Live</string>
99
<string name="classification_demo">Classification demo</string>
1010
<string name="segmentation_demo">Segmentation Demo</string>
11+
<string name="switch_backend">Switch backend</string>
1112
</resources>

examples/demo-apps/android/jni/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,8 @@ add_subdirectory(third-party/fbjni)
1212
if(NOT CMAKE_TOOLCHAIN_FILE MATCHES ".*ios\.toolchain\.cmake$")
1313
add_library(executorchdemo SHARED jni_layer.cpp)
1414
target_link_libraries(executorchdemo xnn_executor_runner_lib fbjni)
15+
if(EXECUTORCH_BUILD_QNN)
16+
target_link_libraries(executorchdemo qnn_executorch_backend)
17+
endif()
1518
target_compile_options(executorchdemo PUBLIC ${_common_compile_options})
1619
endif()

examples/demo-apps/android/jni/jni_layer.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,9 @@ class JEValue : public facebook::jni::JavaClass<JEValue> {
185185
auto numel = 1;
186186
for (int i = 0; i < rank; i++) {
187187
shapeVec.push_back(shapeArr[i]);
188+
}
189+
for (int i = rank - 1; i >= 0; --i) {
190+
strides[i] = numel;
188191
numel *= shapeArr[i];
189192
}
190193
JNIEnv* jni = facebook::jni::Environment::current();
@@ -318,15 +321,12 @@ class ExecuTorchJni : public facebook::jni::HybridClass<ExecuTorchJni> {
318321
jinputs) {
319322
size_t n = jinputs->size();
320323
auto kDimOrder = std::vector<uint8_t>({0, 1, 2, 3});
321-
constexpr int32_t kChannels = 3;
322-
constexpr int32_t kHeight = 224;
323-
constexpr int32_t kWidth = 224;
324-
auto kStrides = std::vector<int32_t>(
325-
{kChannels * kHeight * kWidth, kHeight * kWidth, kWidth, 1});
324+
// strides will be filled by JEValueToTensorImpl
325+
auto strides = std::vector<int32_t>({1, 1, 1, 1});
326326
std::vector<exec_aten::SizesType> shapeVec;
327327
// TODO: Inline the function
328328
auto tensor_impl = JEValue::JEValueToTensorImpl(
329-
jinputs->getElement(0), shapeVec, kDimOrder, kStrides);
329+
jinputs->getElement(0), shapeVec, kDimOrder, strides);
330330
EValue atEValue = EValue(exec_aten::Tensor(&tensor_impl));
331331
Error set_input_status = method_->set_input(atEValue, 0);
332332
ET_CHECK(set_input_status == Error::Ok);

0 commit comments

Comments
 (0)