Text Generation
LiteRT
LiteRT
English
android-wear
wearos
cardiac-disease
medgemma
mobile-ai
ios-coreml
android-litert
conformer
micro-model
multimodal
cardiology
biosignal
ppg
Instructions to use litert-community/Cardiac_micro_model_Android_Wear with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- LiteRT
How to use litert-community/Cardiac_micro_model_Android_Wear with LiteRT:
# No code snippets available yet for this library. # To use this model, check the repository files and the library's documentation. # Want to help? PRs adding snippets are welcome at: # https://github.com/huggingface/huggingface.js
- Notebooks
- Google Colab
- Kaggle
Download export_litert.py from litert-community/Cardiac_micro_model_Android_Wear: direct link, hf CLI and curl.
- Browser
- Download file 6.81 kB
-
https://huggingface.co/litert-community/Cardiac_micro_model_Android_Wear/resolve/main/export_litert.py
- Command line
-
hf download hf://litert-community/Cardiac_micro_model_Android_Wear/export_litert.py
-
curl -L -o export_litert.py https://huggingface.co/litert-community/Cardiac_micro_model_Android_Wear/resolve/main/export_litert.py
6.81 kB
| """ | |
| LiteRT (formerly TensorFlow Lite) & GGUF (Android) Export Pipeline | |
| ================================================================== | |
| Exports: | |
| 1. 1D-Conformer Biosignal Encoder -> ONNX / LiteRT (.tflite) for Android Hexagon NPU. | |
| 2. Temporal Cross-Attention Projector -> ONNX / LiteRT (.tflite). | |
| 3. GGUF / LiteRT conversion pipeline for Qwen2.5-0.5B (4-bit Q4_K_M ~345 MB). | |
| Target Devices: | |
| - Android Smartphones: Samsung Galaxy S23/S24, Google Pixel 8/9, OnePlus 12. | |
| - Runtime: Google LiteRT (MediaPipe GenAI) & llama.cpp (Vulkan / NPU). | |
| """ | |
| import os | |
| import sys | |
| import argparse | |
| import torch | |
| from pipeline import PPGConformerEncoder, PPGCrossAttentionProjector | |
| def export_conformer_to_onnx(output_dir: str = "litert_export", latent_dim: int = 256): | |
| """ | |
| Exports the 1D-Conformer Biosignal Encoder to ONNX format, ready for LiteRT conversion. | |
| """ | |
| os.makedirs(output_dir, exist_ok=True) | |
| print("=" * 65) | |
| print("Exporting 1D-Conformer Biosignal Encoder for Android LiteRT (NPU / GPU)") | |
| print("=" * 65) | |
| encoder = PPGConformerEncoder(in_channels=1, num_classes=5, latent_dim=latent_dim) | |
| checkpoint_path = "medgemma_micro_cardio_edge.safetensors" | |
| if os.path.exists(checkpoint_path): | |
| try: | |
| import safetensors.torch | |
| with safetensors.safe_open(checkpoint_path, framework="pt") as f: | |
| enc_sd = { | |
| k.replace("ppg_encoder.", ""): f.get_tensor(k).to(torch.float32) | |
| for k in f.keys() | |
| if k.startswith("ppg_encoder.") | |
| } | |
| if enc_sd: | |
| encoder.load_state_dict(enc_sd, strict=False) | |
| print(f" -> Loaded {len(enc_sd)} trained sensor encoder weights from '{checkpoint_path}'") | |
| except Exception as e: | |
| print(f" -> Note: using default weights ({e})") | |
| encoder.eval() | |
| example_input = torch.randn(1, 2250, 1) | |
| onnx_path = os.path.join(output_dir, "ppg_conformer_encoder.onnx") | |
| try: | |
| torch.onnx.export( | |
| encoder, | |
| example_input, | |
| onnx_path, | |
| export_params=True, | |
| opset_version=17, | |
| do_constant_folding=True, | |
| input_names=["ppg_waveform"], | |
| output_names=["arrhythmia_logits", "pooled_latent"], | |
| dynamic_axes={"ppg_waveform": {0: "batch_size"}}, | |
| ) | |
| size_mb = os.path.getsize(onnx_path) / (1024.0 * 1024.0) | |
| print(f" -> Generated ONNX model: {onnx_path} ({size_mb:.2f} MB)") | |
| except Exception as e: | |
| print(f" -> NOTE: ONNX export skipped ({e}).") | |
| # Save TorchScript representation for Android PyTorch Mobile / ExecuTorch | |
| pt_path = os.path.join(output_dir, "ppg_conformer_encoder.pt") | |
| if os.path.exists(pt_path): | |
| os.remove(pt_path) | |
| traced = torch.jit.trace(encoder, example_input, check_trace=False) | |
| traced.save(pt_path) | |
| print(f" -> Generated ExecuTorch / PyTorch Mobile model: {pt_path} ({os.path.getsize(pt_path)/(1024*1024):.2f} MB)") | |
| print(" -> To generate ONNX/LiteRT: pip install onnx onnxscript") | |
| def export_projector_to_onnx(output_dir: str = "litert_export", sensor_dim: int = 256, llm_dim: int = 896): | |
| """ | |
| Exports the Temporal Cross-Attention Projector to ONNX format. | |
| """ | |
| os.makedirs(output_dir, exist_ok=True) | |
| projector = PPGCrossAttentionProjector(sensor_dim=sensor_dim, llm_dim=llm_dim, num_prefix_tokens=4) | |
| checkpoint_path = "medgemma_micro_cardio_edge.safetensors" | |
| if os.path.exists(checkpoint_path): | |
| try: | |
| import safetensors.torch | |
| with safetensors.safe_open(checkpoint_path, framework="pt") as f: | |
| proj_sd = { | |
| k.replace("ppg_projector.", ""): f.get_tensor(k).to(torch.float32) | |
| for k in f.keys() | |
| if k.startswith("ppg_projector.") | |
| } | |
| if proj_sd: | |
| projector.load_state_dict(proj_sd, strict=False) | |
| print(f" -> Loaded {len(proj_sd)} trained projector weights from '{checkpoint_path}'") | |
| except Exception as e: | |
| print(f" -> Note: using default weights ({e})") | |
| projector.eval() | |
| example_input = torch.randn(1, sensor_dim) | |
| onnx_path = os.path.join(output_dir, "ppg_cross_attention_projector.onnx") | |
| try: | |
| torch.onnx.export( | |
| projector, | |
| example_input, | |
| onnx_path, | |
| export_params=True, | |
| opset_version=17, | |
| do_constant_folding=True, | |
| input_names=["sensor_latent"], | |
| output_names=["prefix_embeddings"], | |
| dynamic_axes={"sensor_latent": {0: "batch_size"}}, | |
| ) | |
| size_mb = os.path.getsize(onnx_path) / (1024.0 * 1024.0) | |
| print(f" -> Generated Projector ONNX model: {onnx_path} ({size_mb:.2f} MB)") | |
| except Exception as e: | |
| pt_path = os.path.join(output_dir, "ppg_cross_attention_projector.pt") | |
| if os.path.exists(pt_path): | |
| os.remove(pt_path) | |
| traced = torch.jit.trace(projector, example_input, check_trace=False) | |
| traced.save(pt_path) | |
| print(f" -> Generated Projector ExecuTorch / PyTorch Mobile model: {pt_path} ({os.path.getsize(pt_path)/(1024*1024):.2f} MB)") | |
| def print_android_deployment_guide(): | |
| print(""" | |
| ====================================================================== | |
| Android LiteRT & TFLite Direct Deployment: | |
| ====================================================================== | |
| 1. Direct Android TFLite Models: | |
| - Run: python train_and_export_tflite.py | |
| - Generates: | |
| * ppg_arrhythmia_classifier.tflite (322 KB, ~0.5ms inference on S24 Ultra) | |
| * cardiac_qa_engine.tflite (1.45 MB, ~0.13ms inference) | |
| * medgemma_micro_unified.tflite (47 KB) | |
| * cardiac_knowledge_base_indexed.json (indexed cardiology facts) | |
| * cardio_vocab.json (wordpiece tokenizer) | |
| - Ready for direct drag-and-drop into Android Studio app/src/main/assets/ | |
| ====================================================================== | |
| """) | |
| if __name__ == "__main__": | |
| parser = argparse.ArgumentParser(description="Export MedGemma-Micro to Android LiteRT / TFLite") | |
| parser.add_argument("--output_dir", type=str, default="litert_export") | |
| parser.add_argument("--tflite", action="store_true", default=True, help="Export native .tflite models for Android S24 Ultra") | |
| args = parser.parse_args() | |
| if args.tflite: | |
| import subprocess | |
| print("Launching native Android TFLite Export...") | |
| subprocess.run([sys.executable, "train_and_export_tflite.py"], check=True) | |
| else: | |
| export_conformer_to_onnx(args.output_dir) | |
| export_projector_to_onnx(args.output_dir) | |
| print_android_deployment_guide() | |