Skip to content

Commit bfc0b77

Browse files
authored
Merge branch 'main' into copilot/add-instrumentation-test-workflow
2 parents 4a15959 + ad52f61 commit bfc0b77

19 files changed

Lines changed: 648 additions & 412 deletions

File tree

.github/workflows/android-build.yml

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,15 @@ on:
1010
push:
1111
pull_request:
1212
branches: [main]
13+
schedule:
14+
# Run nightly at midnight UTC
15+
- cron: '0 0 * * *'
1316
workflow_dispatch:
17+
inputs:
18+
local_aar:
19+
description: 'URL to download a local AAR file. When set, the workflow will download the AAR and use it instead of the Maven dependency.'
20+
required: false
21+
type: string
1422

1523
permissions:
1624
contents: read
@@ -41,9 +49,20 @@ jobs:
4149
- name: Setup Gradle
4250
uses: gradle/actions/setup-gradle@v4
4351

52+
- name: Download local AAR
53+
if: ${{ inputs.local_aar && matrix.name == 'LlamaDemo' }}
54+
run: |
55+
mkdir -p ${{ matrix.path }}/app/libs
56+
curl -fL -o ${{ matrix.path }}/app/libs/executorch.aar "${{ inputs.local_aar }}"
57+
4458
- name: Build with Gradle
4559
working-directory: ${{ matrix.path }}
46-
run: ./gradlew build --no-daemon
60+
run: |
61+
if [ -n "${{ inputs.local_aar }}" ] && [ "${{ matrix.name }}" == "LlamaDemo" ]; then
62+
./gradlew build --no-daemon -PuseLocalAar=true
63+
else
64+
./gradlew build --no-daemon
65+
fi
4766
4867
- name: Upload build artifacts
4968
uses: actions/upload-artifact@v4
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# Copyright (c) Meta Platforms, Inc. and affiliates.
2+
# All rights reserved.
3+
#
4+
# This source code is licensed under the BSD-style license found in the
5+
# LICENSE file in the root directory of this source tree.
6+
7+
name: Export Models
8+
9+
on:
10+
schedule:
11+
# Run nightly at midnight UTC
12+
- cron: '0 0 * * *'
13+
workflow_dispatch:
14+
15+
permissions:
16+
contents: read
17+
18+
jobs:
19+
export:
20+
runs-on: ubuntu-latest
21+
strategy:
22+
fail-fast: false
23+
matrix:
24+
include:
25+
- name: dl3
26+
path: dl3/python
27+
artifact: dl3-xnnpack-fp32
28+
output: dl3/python/dl3_xnnpack_fp32.pte
29+
- name: mv2
30+
path: mv2/python
31+
artifact: mv2-xnnpack
32+
output: mv2/python/model_mv2_xnnpack.pte
33+
- name: mv3
34+
path: mv3/python
35+
artifact: mv3-models
36+
output: |
37+
mv3/python/mv3.pte
38+
mv3/python/mv3_coreml_all.pte
39+
mv3/python/mv3_mps_float16.pte
40+
mv3/python/mv3_xnnpack_fp32.pte
41+
42+
name: Export ${{ matrix.name }}
43+
44+
steps:
45+
- name: Checkout repository
46+
uses: actions/checkout@v4
47+
48+
- name: Set up Python
49+
uses: actions/setup-python@v5
50+
with:
51+
python-version: '3.11'
52+
53+
- name: Install dependencies
54+
run: |
55+
python -m pip install --upgrade pip
56+
pip install executorch torchvision
57+
58+
- name: Run export script
59+
working-directory: ${{ matrix.path }}
60+
run: python export.py
61+
62+
- name: Upload exported model
63+
uses: actions/upload-artifact@v4
64+
with:
65+
name: ${{ matrix.artifact }}
66+
path: ${{ matrix.output }}
67+
if-no-files-found: error
Binary file not shown.

llm/android/LlamaDemo/README.md

Lines changed: 34 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,17 @@ The goal is for you to see the type of support ExecuTorch provides and feel comf
1515

1616
## Supporting Models
1717
As a whole, the models that this app supports are (varies by delegate):
18-
* Llama 3.2 Quantized 1B/3B
19-
* Llama 3.2 1B/3B in BF16
20-
* Llama Guard 3 1B
21-
* Llama 3.1 8B
22-
* Llama 3 8B
23-
* Llama 2 7B
24-
* LLaVA-1.5 vision model (only XNNPACK)
25-
* Qwen 3 0.6B, 1.7B, and 4B
26-
* Voxtral Mini 3B
27-
* Gemma 3 4B
18+
* [Llama](https://github.com/pytorch/executorch/tree/main/examples/models/llama)
19+
* Llama 3.2 Quantized 1B/3B
20+
* Llama 3.2 1B/3B in BF16
21+
* Llama Guard 3 1B
22+
* Llama 3.1 8B
23+
* Llama 3 8B
24+
* Llama 2 7B
25+
* [LLaVA-1.5 vision model (only XNNPACK)](https://github.com/pytorch/executorch/tree/main/examples/models/llava)
26+
* [Qwen 3 0.6B, 1.7B, and 4B](https://github.com/pytorch/executorch/tree/main/examples/models/qwen3)
27+
* [Voxtral Mini 3B](https://github.com/pytorch/executorch/tree/main/examples/models/voxtral)
28+
* [Gemma 3 4B](https://github.com/pytorch/executorch/tree/main/examples/models/gemma3)
2829

2930
## Building the APK
3031
First it’s important to note that by default, the app depends on [ExecuTorch library](https://central.sonatype.com/artifact/org.pytorch/executorch-android) on Maven Central. It uses the latest `org.pytorch:executorch-android` package, which comes with all the default kernel libraries (portable, quantized, optimized), LLM customized libraries, and XNNPACK backend.
@@ -64,6 +65,18 @@ Select the settings widget to get started with picking a model, its parameters a
6465

6566

6667

68+
### Push Model and Tokenizer Files to Device
69+
70+
Before selecting a model and tokenizer in the app, you need to push these files to your Android device. Use the following commands to copy the model (`.pte`) and tokenizer files to the device:
71+
72+
```sh
73+
adb shell mkdir -p /data/local/tmp/llama
74+
adb push <your_model>.pte /data/local/tmp/llama
75+
adb push <your_tokenizer> /data/local/tmp/llama
76+
```
77+
78+
Replace `<your_model>.pte` with your exported model file and `<your_tokenizer>` with your tokenizer file (e.g., `tokenizer.bin` or `tokenizer.model`).
79+
6780
### Select Models and Parameters
6881

6982
Once you've selected the model, tokenizer, and model type you are ready to click on "Load Model" to have the app load the model and go back to the main Chat activity.
@@ -91,15 +104,15 @@ mModule = new LlmModule(
91104
int loadResult = mModule.load();
92105
```
93106

94-
* `modelCategory`: Indicate whether it’s a text-only or vision model
95-
* `modePath`: path to the .pte file
96-
* `tokenizerPath`: path to the tokenizer file
97-
* `temperature`: model parameter to adjust the randomness of the model’s output
98-
* `dataPath`: path to one or a list of .ptd files
107+
* `modelCategory`: Indicates whether it’s a text-only or vision model
108+
* `modelPath`: Path to the .pte file
109+
* `tokenizerPath`: Path to the tokenizer file
110+
* `temperature`: Model parameter to adjust the randomness of the model’s output
111+
* `dataPath`: Path to one or a list of .ptd files
99112

100113

101114
### User Prompt
102-
Once model is successfully loaded then enter any prompt and click the send (i.e. generate) button to send it to the model.
115+
Once the model is successfully loaded, enter any prompt and click the send (i.e., generate) button to send it to the model.
103116
<p align="center">
104117
<img src="https://raw.githubusercontent.com/pytorch/executorch/refs/heads/main/docs/source/_static/img/load_complete_and_start_prompt.png" style="width:300px">
105118
</p>
@@ -112,11 +125,11 @@ You can provide it more follow-up questions as well.
112125
#### ExecuTorch App API
113126

114127
```java
115-
mModule.generate(prompt,sequence_length, MainActivity.this);
128+
mModule.generate(prompt, sequence_length, MainActivity.this);
116129
```
117-
* `prompt`: User formatted prompt
130+
* `prompt`: User-formatted prompt
118131
* `sequence_length`: Number of tokens to generate in response to a prompt
119-
* `MainActivity.this`: Indicate that the callback functions (OnResult(), OnStats()) are present in this class.
132+
* `MainActivity.this`: Indicates that the callback functions (`onResult()`, `onStats()`) are present in this class.
120133

121134
[*LLaVA-1.5: Only for XNNPACK delegate*]
122135

@@ -177,7 +190,7 @@ Ensure you have the following functions in your callback class that you provided
177190
```
178191

179192
## Instrumentation Test
180-
You can run the instrumentation test for sanity check. The test loads a model pte file and tokenizer.bin file
193+
You can run the instrumentation test for a sanity check. The test loads a model .pte file and tokenizer.bin file
181194
under `/data/local/tmp/llama`.
182195

183196
### Model preparation
@@ -204,4 +217,4 @@ adb push tokenizer.bin /data/local/tmp/llama
204217
```
205218

206219
## Reporting Issues
207-
If you encountered any bugs or issues following this tutorial please file a bug/issue here on [Github](https://github.com/pytorch/executorch/issues/new), or join our discord [here](https://lnkd.in/gWCM4ViK).
220+
If you encountered any bugs or issues following this tutorial, please file a bug/issue here on [GitHub](https://github.com/pytorch/executorch/issues/new), or join our Discord [here](https://lnkd.in/gWCM4ViK).

llm/android/LlamaDemo/SDK-quick-setup-guide.md

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
# Guide to set up Java/SDK/NDK for Android
1+
# Guide to Set Up Java/SDK/NDK for Android
22

3-
Follow this doc if you haven't set up Java/SDK/NDK for Android development
3+
Follow this guide if you haven't set up Java/SDK/NDK for Android development
44
already.
5-
This doc provides a CLI tutorial to set them up. Otherwise, you can do the same
6-
thing with Android Studio GUI.
5+
This guide provides a CLI tutorial to set them up. Alternatively, you can do the same
6+
thing with the Android Studio GUI.
77

8-
## Set up Java 17
9-
1. Download the archive from Oracle website.
8+
## Set Up Java 17
9+
1. Download the archive from the Oracle website.
1010
Make sure you have read and agree with the terms and conditions from the website before downloading.
1111
```bash
1212
export DEV_HOME=<path-to-dev>
@@ -40,14 +40,14 @@ export PATH="$JAVA_HOME/bin:$PATH"
4040
Note: Oracle has tutorials for installing Java on
4141
[Linux](https://docs.oracle.com/en/java/javase/17/install/installation-jdk-linux-platforms.html#GUID-4A6BD592-1840-4BB4-A758-4CD49E9EE88B)
4242
and [macOS](https://docs.oracle.com/en/java/javase/17/install/installation-jdk-macos.html#GUID-E8A251B6-D9A9-4276-ABC8-CC0DAD62EA33).
43-
Some Linux distributions has JDK package in package manager. For example, Debian users can install
44-
openjdk-17-jdk package.
43+
Some Linux distributions have a JDK package in the package manager. For example, Debian users can install
44+
the openjdk-17-jdk package.
4545

46-
## Set up Android SDK/NDK
47-
Android has a command line tool [sdkmanager](https://developer.android.com/tools/sdkmanager) which
48-
helps users managing SDK and other tools related to Android development.
46+
## Set Up Android SDK/NDK
47+
Android has a command-line tool [sdkmanager](https://developer.android.com/tools/sdkmanager) which
48+
helps users manage SDK and other tools related to Android development.
4949

50-
1. Go to https://developer.android.com/studio and download the archive from "Command line tools
50+
1. Go to https://developer.android.com/studio and download the archive from the "Command line tools
5151
only" section. Make sure you have read and agree with the terms and conditions from the website.
5252

5353
Linux:
@@ -58,7 +58,7 @@ macOS:
5858
```bash
5959
curl https://dl.google.com/android/repository/commandlinetools-mac-11076708_latest.zip -o commandlinetools.zip
6060
```
61-
2. Unzip.
61+
2. Unzip:
6262
```bash
6363
unzip commandlinetools.zip
6464
```
@@ -80,7 +80,7 @@ If you want to use Android Studio and never set up Java/SDK/NDK before, or if
8080
you use the newly installed ones, follow these steps to set Android Studio to use
8181
them.
8282

83-
Copy these output paths to be used by Android Studio
83+
Copy these output paths to be used by Android Studio:
8484
```bash
8585
echo $ANDROID_HOME
8686
echo $ANDROID_NDK

llm/android/LlamaDemo/app/src/main/java/com/example/executorchllamademo/MainActivity.java

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -381,11 +381,20 @@ protected void onResume() {
381381
// If users change the model file, but not pressing loadModelButton, we won't load the new
382382
// model
383383
checkForUpdateAndReloadModel(updatedSettingsFields);
384-
} else {
384+
} else if (mModule == null) {
385+
// Only ask user to select model if no model is currently loaded
386+
askUserToSelectModel();
387+
}
388+
} else {
389+
// Settings not updated, but still check if model/tokenizer is not selected
390+
String modelPath = updatedSettingsFields.getModelFilePath();
391+
String tokenizerPath = updatedSettingsFields.getTokenizerFilePath();
392+
if (modelPath.isEmpty() || tokenizerPath.isEmpty()) {
385393
askUserToSelectModel();
386394
}
387395
}
388-
} else {
396+
} else if (mModule == null) {
397+
// Only ask user to select model if no model is currently loaded
389398
askUserToSelectModel();
390399
}
391400
}
@@ -452,8 +461,16 @@ private void askUserToSelectModel() {
452461
ETLogging.getInstance().log(askLoadModel);
453462
runOnUiThread(
454463
() -> {
455-
mMessageAdapter.add(askLoadModelMessage);
456-
mMessageAdapter.notifyDataSetChanged();
464+
if (!mMessageAdapter.isDuplicateSystemMessage(askLoadModel)) {
465+
mMessageAdapter.add(askLoadModelMessage);
466+
mMessageAdapter.notifyDataSetChanged();
467+
}
468+
new AlertDialog.Builder(this)
469+
.setTitle("Please Select a Model")
470+
.setMessage(
471+
"Please select a model and tokenizer from the settings (top right corner) to get started.")
472+
.setPositiveButton(android.R.string.ok, null)
473+
.show();
457474
});
458475
}
459476

llm/android/LlamaDemo/app/src/main/java/com/example/executorchllamademo/MessageAdapter.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,4 +132,21 @@ public int getMaxPromptID() {
132132
}
133133
return maxPromptID;
134134
}
135+
136+
/**
137+
* Checks if the last message is a duplicate system message with the given text.
138+
*
139+
* @param text The text to check against the last message
140+
* @return true if the last message is a system message with matching text, false otherwise
141+
*/
142+
boolean isDuplicateSystemMessage(String text) {
143+
int count = getCount();
144+
if (count == 0) {
145+
return false;
146+
}
147+
Message lastMessage = getItem(count - 1);
148+
return lastMessage != null
149+
&& lastMessage.getMessageType() == MessageType.SYSTEM
150+
&& text.equals(lastMessage.getText());
151+
}
135152
}

0 commit comments

Comments
 (0)