Nemotron 스트리밍
NVIDIA의 두 스트리밍 ASR 모델이 Swift 타깃 NemotronStreamingASR을 공유합니다. 둘 다 600M 파라미터의 cache-aware FastConformer 인코더와 RNN-T 디코더 조합이며, 둘 다 구두점과 대소문자를 일반 BPE 토큰으로 네이티브 출력하고, 둘 다 CoreML을 통해 Apple Neural Engine에서 실행됩니다. 다국어 버전은 추가로 GPU 상주 추론용 MLX 번들도 제공합니다. 애플리케이션에 맞는 것을 선택하세요:
| 버전 | 지원 범위 | 기본 chunk | 업스트림 |
|---|---|---|---|
| Nemotron 3.5 다국어 | 40개 언어-로케일 (en-US, en-GB, es-ES, fr-FR, de-DE, ja-JP, ko-KR, zh-CN, hi-IN, ar, …) | 320 ms | nvidia/nemotron-3.5-asr-streaming-0.6b |
| Nemotron Speech Streaming (영어) | 영어 전용 — 더 작은 번들, 더 낮은 기본 지연 | 160 ms | nvidia/nemotron-speech-streaming-en-0.6b |
공통 속성
- 네이티브 구두점·대소문자 — 후처리 불필요. 마침표·쉼표·케이스가 어휘의 일부
- 600M 파라미터 — cache-aware 24-레이어 FastConformer 인코더 + 2-레이어 LSTM RNN-T 디코더 + joint 네트워크
- Cache-aware 스트리밍 — attention과 conv 캐시가 chunk 간에 흘러 chunk 경계를 가로질러 컨텍스트를 유지
- 다양한 chunk 크기 — 다국어: 80, 320, 560, 1120 ms (기본 320 ms); 영어: 80, 160, 560, 1120 ms (기본 160 ms)
- 다국어 전용: prompt kernel (Linear 1152→2048→1024)이 one-hot 언어 슬롯을 인코딩된 모든 프레임에 통합하여, 동일한 가중치가 40개 언어-로케일 전체를 처리합니다. 영어 전용 버전에는 prompt kernel이 없습니다.
아키텍처
오디오 chunk마다 3개의 CoreML 모델이 파이프라인으로 실행됩니다:
| 컴포넌트 | 설명 |
|---|---|
| 인코더 | 24-레이어 cache-aware FastConformer, 1024 hidden. 32-프레임 mel chunk (기본 320 ms)와 6개 상태 텐서 — attention KV 캐시 [24, 1, 56, 1024], depthwise conv 캐시 [24, 1, 1024, 8], pre_cache mel 루프백, 그리고 prompt kernel을 구동하는 128-슬롯 one-hot language_mask — 를 입력으로 받습니다. |
| Prompt kernel | Linear(1152→2048) → ReLU → Linear(2048→1024) — 언어 one-hot을 인코딩된 모든 프레임에 통합하여, 동일한 600M 가중치가 40개 언어-로케일 전체를 처리합니다. |
| 디코더 | 2-레이어 LSTM 예측 네트워크, 640 hidden. 직전 non-blank 토큰을 입력으로 받아 embedding과 업데이트된 (h, c) 상태를 출력합니다. |
| Joint | 인코더와 디코더 출력을 융합해 13 087 BPE 토큰 + blank에 대한 logits를 생성합니다. 구두점·대소문자·언어 태그는 모두 BPE 어휘 내 추가 토큰이며 별도의 head가 없습니다. |
EOU head 없음
Parakeet-EOU와 달리, Nemotron은 발화 종료 전용 토큰을 출력하지 않습니다. 연속 오디오를 발화로 분할하는 두 가지 방법:
- 외부 VAD — 세션을 Silero VAD와 결합. 지속적인 무음 시
finalize()를 호출해 현재 발화를 커밋하고, 다음 발화를 위해createSession()호출. - 구두점 경계 — 부분 트랜스크립트가
.,?,!로 끝나면 자연스러운 커밋 큐로 취급. 추가 모델은 필요 없지만, 오디오가 실제로 종결 구두점을 유도하는지에 달려 있음.
번들
Nemotron-3.5-ASR-Streaming-0.6B의 공개된 5개 버전과, 같은 Swift 타깃 위의 이전 영어 전용 모델:
| 버전 | 디스크 | 스트리밍 피크 (M5 Pro) | HuggingFace |
|---|---|---|---|
| CoreML INT8 (기본) | 612 MB | 1238 MB | aufklarer/Nemotron-3.5-ASR-Streaming-0.6B-CoreML-INT8 |
| MLX bf16 | 1217 MB | 1474 MB | aufklarer/…MLX-bf16 |
| MLX 5-bit (네이티브 기본) | 538.6 MB | 800 MB | aufklarer/…MLX-5bit |
| MLX 8-bit | 732.6 MB | 992 MB | aufklarer/…MLX-8bit |
| MLX 4-bit | 473 MB | 747 MB | aufklarer/…MLX-4bit |
| 영어 전용 (CoreML INT8) | ~580 MB | — | aufklarer/Nemotron-Speech-Streaming-0.6B-CoreML-INT8 |
업스트림: nvidia/nemotron-3.5-asr-streaming-0.6b (다국어) 및 nvidia/nemotron-speech-streaming-en-0.6b (영어 전용).
실제 캐시 인식 320 ms 경로에서 6개 FLEURS 언어의 평균 WER은 MLX 5-bit가 11.53%, MLX 8-bit가 11.01%입니다. 기본 5-bit는 디스크 약 193 MB와 최대 RSS 192 MB를 절약합니다. MLX 4-bit는 품질 저하가 더 커 연구용 내보내기로 남아 있습니다.
빠른 시작 — 네이티브 MLX 스트리밍
Swift 런타임은 공개된 MLX 5-bit 및 8-bit 번들을 지원합니다. 기본값은 5-bit이며, 각 세션의 캐시는 독립적이고 하나의 로드된 모델을 공유할 때 추론을 직렬화합니다. MLX는 검증된 320 ms 구성을 사용하며 현재 워드 부스팅은 제공하지 않습니다.
import NemotronStreamingASR
let model = try await NemotronStreamingASRMLXModel.fromPretrained(
variant: .int5
)
let session = try model.createSession(language: "en-US")
for chunk in microphoneChunks16kHz {
for partial in try session.pushAudio(chunk) {
print(partial.text)
}
}
let final = try session.finalize().last?.text
빠른 시작 — CoreML 배치 트랜스크립션
SpeechRecognitionModel을 준수하므로, 범용 STT 모델을 받는 어느 코드 경로에든 그대로 들어갑니다:
import NemotronStreamingASR
let model = try await NemotronStreamingASRModel.fromPretrained()
let text = try model.transcribeAudio(audioSamples, sampleRate: 16000, language: "en-US")
빠른 시작 — 비동기 스트리밍
for await partial in model.transcribeStream(audio: samples, sampleRate: 16000) {
if partial.isFinal { print("FINAL: \(partial.text)") }
else { print("... \(partial.text)") }
}
각 PartialTranscript는 text, isFinal (finalize() 후 마지막 부분 결과에서만 true), confidence, 단조 증가하는 segmentIndex를 포함합니다.
장기 세션 API (마이크 입력)
let session = try model.createSession()
// each mic chunk:
let partials = try session.pushAudio(float32Chunk16kHz)
for p in partials { showPartial(p.text) } // isFinal is false mid-stream
// when the utterance ends (VAD silence or explicit stop):
let trailing = try session.finalize()
for p in trailing { commit(p.text) }
명령줄
speech transcribe recording.wav --engine nemotron --language en-US # batch
speech transcribe recording.wav --engine nemotron --language en-US --stream # streaming final
speech transcribe recording.wav --engine nemotron --language ja-JP --stream --partial # partials, Japanese
speech transcribe meeting.wav --engine nemotron --language de-DE # any of the 40 locales
Nemotron vs Parakeet-EOU
| Nemotron Streaming 0.6B | Parakeet-EOU 120M | |
|---|---|---|
| 파라미터 | 600M | 120M |
| 인코더 | 24-레이어 FastConformer, 1024 hidden | 17-레이어 FastConformer, 512 hidden |
| 디코더 | 2-layer LSTM, RNN-T | 1-layer LSTM, RNN-T |
| EOU 검출 | 외부 (VAD 또는 구두점) | 내장 <EOU> 토큰 |
| 구두점 | 네이티브 인라인 BPE 토큰 | 없음 (후처리) |
| 언어 | 40개 언어-로케일 (en-US, en-GB, es-ES, fr-FR, de-DE, ja-JP, ko-KR, zh-CN, hi-IN, ar, …) | 유럽 25개 |
| 기본 chunk | 320 ms | 320 ms |
| 번들 크기 | 612 MB (CoreML INT8); 538.6 MB (네이티브 MLX 5-bit) | ~150 MB |
…다국어 스트리밍 트랜스크립션이 필요하고 (40개 언어-로케일 중 어느 것이든) 박스에서 바로 구두점과 대소문자를 얻고 싶으며, 발화 분할은 직접 처리해도 좋은 경우 (VAD 또는 구두점 큐). 자원이 제한된 영어 전용 iOS dictation과 내장 EOU 신호가 필요한 경우, Parakeet-EOU가 여전히 더 작은 선택입니다.
회귀 테스트
겹치는 음성 회귀 테스트는 두 Kokoro 음성 중 두 번째를 320 ms 늦게 시작하고 3 dB 줄여 혼합한 저장소의 WAV 파일을 사용합니다. 매번 디코딩할 때 언어 태그가 없는 비어 있지 않은 전사 결과가 나와야 합니다. 고정 오디오는 실시간 합성의 변동성을 없애며, 야간 워크플로는 Nemotron을 별도 샤드에서 실행합니다. 야간 테스트와 동일한 CPU 전용 설정으로 Core ML 회귀 테스트를 실행하세요:
SPEECH_COREML_COMPUTE_UNITS=cpuOnly \
swift test --disable-sandbox --no-parallel \
--filter '^NemotronStreamingASRTests[.]E2ENemotronHarshAudioTests/'