Upload README.md with huggingface_hub
Browse files
README.md
ADDED
|
@@ -0,0 +1,184 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
library_name: coreml
|
| 3 |
+
license: cc-by-4.0
|
| 4 |
+
tags:
|
| 5 |
+
- coreml
|
| 6 |
+
- asr
|
| 7 |
+
- speech-recognition
|
| 8 |
+
- streaming
|
| 9 |
+
- nemotron
|
| 10 |
+
- nvidia
|
| 11 |
+
- rnnt
|
| 12 |
+
- fastconformer
|
| 13 |
+
- apple-silicon
|
| 14 |
+
- neural-engine
|
| 15 |
+
language:
|
| 16 |
+
- en
|
| 17 |
+
base_model: nvidia/nemotron-speech-streaming-en-0.6b
|
| 18 |
+
pipeline_tag: automatic-speech-recognition
|
| 19 |
+
---
|
| 20 |
+
|
| 21 |
+
# Nemotron Speech 600M β CoreML (Streaming)
|
| 22 |
+
|
| 23 |
+
Native CoreML conversion of [nvidia/nemotron-speech-streaming-en-0.6b](https://huggingface.co/nvidia/nemotron-speech-streaming-en-0.6b), a 600M-parameter streaming ASR model using FastConformer encoder + RNNT decoder. Optimized for Apple Neural Engine (ANE) on Apple Silicon.
|
| 24 |
+
|
| 25 |
+
Converted directly from the original NeMo checkpoint via coremltools, with 3-level numerical validation against the PyTorch reference.
|
| 26 |
+
|
| 27 |
+
Sibling project: **[danielbodart/nemotron-speech-600m-onnx](https://huggingface.co/danielbodart/nemotron-speech-600m-onnx)** β ONNX Runtime version for Linux (CUDA + CPU).
|
| 28 |
+
|
| 29 |
+
## Performance
|
| 30 |
+
|
| 31 |
+
| Metric | Value |
|
| 32 |
+
|--------|-------|
|
| 33 |
+
| Encoder ANE utilization | **93%** (1486/1597 ops on Neural Engine) |
|
| 34 |
+
| Inference speed | **~15.5x realtime** on Apple Silicon |
|
| 35 |
+
| Encoder CPU ops | 7% (softmax, attention masking β see config.json for breakdown) |
|
| 36 |
+
| Decoder | 100% CPU (CPU_ONLY compute units) |
|
| 37 |
+
|
| 38 |
+
No manual ANE optimizations applied β coremltools compiler routes ops automatically.
|
| 39 |
+
|
| 40 |
+
## Available Precisions
|
| 41 |
+
|
| 42 |
+
| Variant | Encoder | Decoder | Total | Compute Units | Notes |
|
| 43 |
+
|---------|---------|---------|-------|---------------|-------|
|
| 44 |
+
| `fp16/` | 1.1 GB | 17 MB | ~1.1 GB | Encoder: CPU+ANE, Decoder: CPU | Recommended |
|
| 45 |
+
|
| 46 |
+
Future: INT8 quantization via coremltools (can halve encoder size on ANE).
|
| 47 |
+
|
| 48 |
+
## Model Architecture
|
| 49 |
+
|
| 50 |
+
Two CoreML models (decoder and joint network are fused into one):
|
| 51 |
+
|
| 52 |
+
| Model | Input | Output | Compute |
|
| 53 |
+
|-------|-------|--------|---------|
|
| 54 |
+
| **Encoder** | mel `[1, 128, 65]` + caches (FP32 in, FP16 out) | encoded `[1, 1024, 7]` + caches | CPU_AND_NE |
|
| 55 |
+
| **Fused Decoder+Joint** | enc_frame `[1, 1024, 1]` + token `[1, 1]` + LSTM h,c (FP32 in, FP16 out) | logits `[1, 1025]` + LSTM h,c | CPU_ONLY |
|
| 56 |
+
|
| 57 |
+
Mel spectrogram preprocessing runs on the host (not in CoreML).
|
| 58 |
+
|
| 59 |
+
### Important: ANE stride padding
|
| 60 |
+
|
| 61 |
+
CoreML output MLMultiArrays may have non-contiguous strides due to ANE alignment padding. For example, the encoder output `[1, 1024, 7]` may have physical strides `[32768, 32, 1]` instead of C-contiguous `[7168, 7, 1]`. **Callers must use stride-aware copy, not flat memcpy.**
|
| 62 |
+
|
| 63 |
+
## Runtime Configuration
|
| 64 |
+
|
| 65 |
+
All parameters needed to run the model are documented in [`config.json`](config.json), including I/O specs, cache shapes, the streaming protocol, and ANE profiling results.
|
| 66 |
+
|
| 67 |
+
### Audio Preprocessing
|
| 68 |
+
|
| 69 |
+
| Parameter | Value |
|
| 70 |
+
|-----------|-------|
|
| 71 |
+
| Sample rate | 16000 Hz |
|
| 72 |
+
| Sample format | S16_LE (16-bit signed little-endian) |
|
| 73 |
+
| Pre-emphasis | 0.97 |
|
| 74 |
+
| FFT size | 512 |
|
| 75 |
+
| Hop length | 160 samples (10ms) |
|
| 76 |
+
| Window length | 400 samples (25ms) |
|
| 77 |
+
| Window type | Hann |
|
| 78 |
+
| Mel bands | 128 |
|
| 79 |
+
| Mel norm | Slaney |
|
| 80 |
+
| Mel layout | **Band-major** `[n_mels, n_frames]` (not frame-major) |
|
| 81 |
+
|
| 82 |
+
### Encoder Streaming
|
| 83 |
+
|
| 84 |
+
| Parameter | Value |
|
| 85 |
+
|-----------|-------|
|
| 86 |
+
| Chunk size | 56 mel frames (560ms audio) |
|
| 87 |
+
| Pre-encode cache | 9 mel frames (prepended from previous chunk) |
|
| 88 |
+
| Total input frames | 65 per chunk (56 + 9) |
|
| 89 |
+
| Layers | 24 |
|
| 90 |
+
| Dimension | 1024 |
|
| 91 |
+
| `cache_last_channel` shape | `[1, 24, 70, 1024]` FP32 in, FP16 out (init zeros) |
|
| 92 |
+
| `cache_last_time` shape | `[1, 24, 1024, 8]` FP32 in, FP16 out (init zeros) |
|
| 93 |
+
| `cache_last_channel_len` | `[1]` int32 (init zero) |
|
| 94 |
+
|
| 95 |
+
Feed cache outputs back as next chunk's cache inputs. Convert FP16 outputs to FP32 before feeding back (model expects FP32 inputs).
|
| 96 |
+
|
| 97 |
+
### RNNT Decoder
|
| 98 |
+
|
| 99 |
+
| Parameter | Value |
|
| 100 |
+
|-----------|-------|
|
| 101 |
+
| Blank token ID | 1024 |
|
| 102 |
+
| Vocab size | 1025 (1024 tokens + blank) |
|
| 103 |
+
| Max symbols per frame | 10 |
|
| 104 |
+
| Prediction layers | 2 (LSTM) |
|
| 105 |
+
| Prediction hidden | 640 |
|
| 106 |
+
| `input_states_1/2` shape | `[2, 1, 640]` FP32 in, FP16 out (init zeros) |
|
| 107 |
+
|
| 108 |
+
For each encoder output frame: feed single frame `[1, 1024, 1]` to decoder, argmax logits over 1025 vocab, if not blank emit token and loop (up to 10), if blank move to next frame. Feed decoder states back for next symbol/frame.
|
| 109 |
+
|
| 110 |
+
## Files
|
| 111 |
+
|
| 112 |
+
```
|
| 113 |
+
config.json # Machine-readable runtime parameters + ANE profile
|
| 114 |
+
|
| 115 |
+
fp16/
|
| 116 |
+
βββ encoder.mlmodelc/ # Pre-compiled encoder (load directly with MLModel)
|
| 117 |
+
β βββ model.mil
|
| 118 |
+
β βββ coremldata.bin
|
| 119 |
+
β βββ weights/weight.bin
|
| 120 |
+
βββ encoder.mlpackage/ # Source encoder (for runtime compilation fallback)
|
| 121 |
+
β βββ Data/com.apple.CoreML/
|
| 122 |
+
β βββ model.mlmodel
|
| 123 |
+
β βββ weights/weight.bin
|
| 124 |
+
βββ decoder.mlmodelc/ # Pre-compiled fused decoder+joint
|
| 125 |
+
βββ decoder.mlpackage/ # Source fused decoder+joint
|
| 126 |
+
βββ metadata.json # Cache shapes, vocab size, model parameters
|
| 127 |
+
```
|
| 128 |
+
|
| 129 |
+
## Usage
|
| 130 |
+
|
| 131 |
+
Download:
|
| 132 |
+
|
| 133 |
+
```bash
|
| 134 |
+
# Download compiled models (recommended)
|
| 135 |
+
hf download danielbodart/nemotron-speech-600m-coreml fp16/ config.json --local-dir ./model
|
| 136 |
+
|
| 137 |
+
# Download only .mlmodelc (skip .mlpackage to save space)
|
| 138 |
+
hf download danielbodart/nemotron-speech-600m-coreml fp16/encoder.mlmodelc/ fp16/decoder.mlmodelc/ fp16/metadata.json config.json --local-dir ./model
|
| 139 |
+
```
|
| 140 |
+
|
| 141 |
+
Load with CoreML (Swift):
|
| 142 |
+
|
| 143 |
+
```swift
|
| 144 |
+
import CoreML
|
| 145 |
+
|
| 146 |
+
let config = MLModelConfiguration()
|
| 147 |
+
config.computeUnits = .cpuAndNeuralEngine
|
| 148 |
+
|
| 149 |
+
let encoder = try MLModel(contentsOf: URL(fileURLWithPath: "model/fp16/encoder.mlmodelc"),
|
| 150 |
+
configuration: config)
|
| 151 |
+
|
| 152 |
+
let decConfig = MLModelConfiguration()
|
| 153 |
+
decConfig.computeUnits = .cpuOnly
|
| 154 |
+
let decoder = try MLModel(contentsOf: URL(fileURLWithPath: "model/fp16/decoder.mlmodelc"),
|
| 155 |
+
configuration: decConfig)
|
| 156 |
+
```
|
| 157 |
+
|
| 158 |
+
Load with CoreML (Python/coremltools):
|
| 159 |
+
|
| 160 |
+
```python
|
| 161 |
+
import coremltools as ct
|
| 162 |
+
|
| 163 |
+
encoder = ct.models.MLModel("model/fp16/encoder.mlpackage")
|
| 164 |
+
decoder = ct.models.MLModel("model/fp16/decoder.mlpackage")
|
| 165 |
+
```
|
| 166 |
+
|
| 167 |
+
## Conversion Reproducibility
|
| 168 |
+
|
| 169 |
+
All conversion and validation scripts are in the companion GitHub repo: **[danielbodart/nemotron-speech-600m-coreml](https://github.com/danielbodart/nemotron-speech-600m-coreml)**
|
| 170 |
+
|
| 171 |
+
- `convert.py` β NeMo β CoreML conversion (wrap, trace, convert, compile)
|
| 172 |
+
- `validate.py` β 3-level validation (wrapper equiv, CoreML vs PyTorch, end-to-end transcript)
|
| 173 |
+
- `wrappers.py` β PyTorch wrappers (EncoderWrapper, FusedDecoderJointWrapper)
|
| 174 |
+
|
| 175 |
+
Requires macOS with Apple Silicon, Python 3.10, coremltools 9.0b1.
|
| 176 |
+
|
| 177 |
+
## Related
|
| 178 |
+
|
| 179 |
+
- **[danielbodart/nemotron-speech-600m-onnx](https://huggingface.co/danielbodart/nemotron-speech-600m-onnx)** β ONNX Runtime version for Linux (CUDA + CPU, FP16/INT8)
|
| 180 |
+
- **[nvidia/nemotron-speech-streaming-en-0.6b](https://huggingface.co/nvidia/nemotron-speech-streaming-en-0.6b)** β Original NeMo model
|
| 181 |
+
|
| 182 |
+
## License
|
| 183 |
+
|
| 184 |
+
The original model is licensed under [CC-BY-4.0](https://creativecommons.org/licenses/by/4.0/) by NVIDIA.
|