← All courses ← Course home

Lesson 07 of 07

End-to-end Android checklist

Run the full path again: Mac training, LiteRT conversion, then the APK. Confirm that a real emulator or device shows the expected clothing label.

Agent brief (llms.md)

Environment setup

For the final run, have these ready: the Mac training project, a Linux conversion environment, Android Studio with its JDK and SDK, and an emulator or a USB-debuggable device. Use the same pinned dependencies from lessons 02–04. Start from a clean debug build.

# Mac: retrain or verify the source artifact.
uv run python train.py
# Linux conversion host: create clothing.tflite.
uv run python convert.py
# Android project: build and install.
./gradlew :app:assembleDebug
adb install -r app/build/outputs/apk/debug/app-debug.apk

This is a short acceptance checklist, not a new code path. The full snippets in the earlier lessons are the source of truth.

From empty Mac to on-device label

  1. Environment: install Python 3.11+, uv, PyTorch, and torchvision on the Mac. Confirm MPS if it is available. CPU is the fallback, and CUDA is not needed.
  2. Train: run train.py with ToTensor(), the shared ClothingCNN, three or more epochs as you like, and save CPU weights to clothing.pt.
  3. Contract: check input [1, 1, 28, 28] float32 and output [1, 10] float32 logits. Keep the ten-label order.
  4. Convert: on Linux, install litert-torch in a Python 3.11 uv environment and run litert_torch.convert(model, (torch.zeros(1, 1, 28, 28),)). Export clothing.tflite.
  5. Inspect: confirm the file is not empty and the model input and output sizes match the contract. Do not change NCHW to NHWC in only one place.
  6. Android project: create a Kotlin app with min SDK 23, add com.google.ai.edge.litert:litert:2.1.5 (or a newer verified published stable version), and put the model in app/src/main/assets.
  7. Runtime: copy the asset to a readable file, create one LiteRT CompiledModel, allocate buffers once, write one NCHW float array, run, and read ten logits.
  8. UI: resize or draw the image to 28×28, convert to grayscale 0–1, softmax logits for a confidence, and map argmax through the fixed labels.
  9. Verify: compare a fixed sample with Python, check Logcat for finite ten-value output, then measure cold versus warm latency on a real device.

Release check

[ ] clothing.pt exists and reloads with the same ClothingCNN definition
[ ] clothing.tflite was created by litert-torch on the documented Linux host
[ ] Input is float32 [1, 1, 28, 28] in both Python and Kotlin
[ ] Output is float32 [1, 10] logits; softmax is display-only
[ ] Ten labels have identical order in Python and Kotlin
[ ] APK Analyzer shows assets/clothing.tflite
[ ] CompiledModel and its buffers are created once, not per tap
[ ] CPU sample produces a stable, sensible label
[ ] Cold and warm latency are logged separately
[ ] Optional GPU/NPU tests fall back cleanly to CPU
Apple comparison. For the other deploy target, see the PyTorch to Core AI in Xcode course. The training contract is the same idea. That course ends with a .aimodel file and a SwiftUI app. This course ends with .tflite, LiteRT, and Kotlin.

Keep the boundary explicit

The important part is the contract. How you prepare the image, the layout, the data type, what the output means, and the labels are all part of the model. Once you test those at each step, the Android UI is ordinary app code around a small portable graph.

Key concepts

  • Full path: Mac uv training, Linux litert-torch conversion, Android CompiledModel.
  • The contract is preprocessing, layout, dtype, logits, and the ten labels at every step.
  • The APK must package assets/clothing.tflite. Buffers are allocated once.
  • This lesson is acceptance. It is not a new code path.

Takeaways

  • You can rebuild the published Android path from the earlier lessons without guessing.
  • Same training idea as the Core AI course. This one ends in .tflite, LiteRT, and Kotlin.
  • A stable CPU label plus cold and warm logs is the release bar.