스트리밍 받아쓰기
Parakeet-EOU-120M은 명시적 발화 종료(EOU) 헤드를 갖춘 소형 RNN-T 스트리밍 ASR 모델이며, Apple Silicon의 Neural Engine에서 실시간 받아쓰기를 위해 제작되었습니다. 이 가이드는 핸즈프리, 어디에든 붙여넣기 받아쓰기를 위해 스트리밍 모델을 Silero VAD와 연결한 macOS 메뉴 바 레퍼런스 앱인 DictateDemo도 다룹니다.
무엇인가
- 라이브 파셜 — 말하는 동안 각 청크 후 약 340 ms에 텍스트가 업데이트됩니다
- 명시적 EOU — 모델이 발화가 끝났음을 결정하며 수동 버튼이 필요 없습니다
- VAD 기반 강제 파이널라이즈 — Silero 백스탑이 배경 소음으로 EOU가 멈출 때도 발화를 커밋합니다
- 120 MB INT8 CoreML — Neural Engine에서 실행되어 GPU는 다른 모델에 사용 가능합니다
- 25개 유럽어 — 상위 NeMo Parakeet TDT와 동일한 어휘 계열
아키텍처
오디오 청크마다 세 개의 CoreML 모델이 파이프라인으로 연결됩니다:
| 구성 요소 | 설명 |
|---|---|
| Encoder | Cache-aware Conformer. 64프레임 멜 청크(640 ms)와 6개의 상태 텐서(어텐션 KV 캐시, depthwise conv 캐시, 청크 경계에 걸쳐 FFT가 연속 신호를 볼 수 있도록 최근 오디오를 앞에 추가하는 pre_cache 멜 루프백)를 입력으로 받습니다. |
| Decoder | 단일 스텝 LSTM 예측 네트워크. 이전 non-blank 토큰을 소비하고 임베딩과 업데이트된 (h, c) 상태를 방출합니다. |
| Joint + EOU 헤드 | encoder와 decoder 출력을 vocab + blank + EOU에 대한 logits로 결합합니다. EOU 클래스는 발화가 끝났다는 모델의 확정적 신호입니다. |
EOU 토큰을 별도로 두는 이유
일반 RNNT는 침묵 동안 blank를 방출하며 디코더는 "발화 종료" 신호 없이 이를 흡수합니다. 전용 EOU 헤드는 모델이 파셜을 최종으로 커밋하고, 문장부호/대문자 상태를 리셋하며, 앱에 붙여넣기 같은 다운스트림 작업을 트리거하는 확정적 컷을 만들 수 있게 해줍니다.
"조용한" 일시 정지 동안의 키보드 클릭, 마우스 이동, 룸톤 때문에 joint가 때때로 non-blank 토큰을 방출해 EOU debounce 타이머를 리셋하고 커밋을 지연시킬 수 있습니다. 프로덕션 파이프라인은 joint EOU를 외부 VAD 기반 forceEndOfUtterance() 백스탑과 함께 사용합니다 — 아래의 DictateDemo를 참조하세요.
모델
| 모델 | 크기 | HuggingFace |
|---|---|---|
| Parakeet-EOU-120M (CoreML INT8) | 약 120 MB | aufklarer/Parakeet-EOU-120M-CoreML-INT8 |
성능
| 지표 | 값 |
|---|---|
| 웨이트 메모리 | 약 120 MB (INT8) |
| 피크 추론 메모리 | 약 200 MB |
| 청크 지연 (M 시리즈) | 연산 약 30 ms / 오디오 640 ms (RTF 약 0.056) |
| 엔드투엔드 파셜 지연 | 약 340 ms (한 청크) |
| 커밋 지연 (VAD 경로) | 음성 종료 후 약 1초 |
| 연산 타겟 | Neural Engine (CoreML) |
빠른 시작 — 배치 전사
스트리밍 모델은 SpeechRecognitionModel도 준수하므로 범용 STT 모델을 받는 어떤 코드에서도 그대로 사용할 수 있습니다:
import ParakeetStreamingASR
let model = try await ParakeetStreamingASRModel.fromPretrained()
let text = try model.transcribeAudio(audioSamples, sampleRate: 16000)
빠른 시작 — 비동기 스트리밍
for await partial in model.transcribeStream(audio: samples, sampleRate: 16000) {
if partial.isFinal { print("FINAL: \(partial.text)") }
else { print("... \(partial.text)") }
}
각 PartialTranscript는 text, isFinal, confidence, eouDetected (joint가 발화한 것인지 강제 파이널라이즈된 것인지), 그리고 단조 증가하는 segmentIndex를 가집니다.
장시간 세션 API (마이크 입력)
라이브 받아쓰기를 위해 세션을 한 번 생성하고 마이크에서 도착하는 청크를 공급합니다. 세션은 내부적으로 버퍼링하며 충분한 샘플이 누적되면 encoder를 실행하므로 임의 크기의 청크를 푸시할 수 있습니다:
let session = try model.createSession()
// 각 마이크 청크:
let partials = try session.pushAudio(float32Chunk16kHz)
for p in partials {
if p.isFinal { commit(p.text) }
else { showPartial(p.text) }
}
// 스트림이 종료되면:
let trailing = try session.finalize()
VAD 강제 파이널라이즈 패턴
파이프라인에서 이미 Silero VAD가 실행 중이라면 이를 사용해 폴백 커밋을 구동함으로써 배경 소음이 EOU debounce 타이머를 멈추게 하지 않도록 할 수 있습니다:
if hasPendingUtterance && !vadSpeechActive && vadSilentChunks >= 30 {
// Silero 기준 지속 침묵 약 960 ms
if let forced = session.forceEndOfUtterance() {
commit(forced.text)
}
hasPendingUtterance = false
}
// 가드레일: joint가 이미 EOU를 발화했다면 이중 커밋 방지
if partials.contains(where: { $0.isFinal }) {
hasPendingUtterance = false
}
DictateDemo — macOS 메뉴 바 레퍼런스 앱
DictateDemo는 스트리밍 세션 위에 구축된 완전한 macOS 메뉴 바 agent입니다. 백그라운드 앱으로 실행되며, 라이브 파셜과 함께 마이크에서 전사하고, EOU 또는 VAD 침묵에 따라 발화를 자동 커밋한 뒤 결과를 최전면 앱에 붙여넣습니다.
- 전역
Cmd+Shift+D핫키를 갖춘 메뉴 바 앱 - 플로팅 HUD와 오디오 레벨 표시와 함께 라이브 파셜
- VAD 보호 강제 파이널라이즈 (위의 프로덕션 패턴)
Cmd+Shift+V로 최전면 앱에 붙여넣기- 모델은 첫 실행 시 자동 다운로드됩니다 (약 120 MB)
cd Examples/DictateDemo
swift build
.build/debug/DictateDemo
전체 구현은 Examples/DictateDemo/DictateDemo/DictateViewModel.swift에 있습니다: 메인 스레드 밖의 오디오 싱크와 락 보호 버퍼, 300 ms 타이머 틱으로 버퍼를 비우는 구조, leftover-sample 이월을 적용한 Silero VAD, 가드된 강제 파이널라이즈. 대응하는 리그레션 테스트는 Examples/DictateDemo/Tests/DictateDemoTests.swift에 있으며, 다중 발화, 멈춘 EOU, 잡음 섞인 침묵 시나리오를 다룹니다.
스트리밍 대 배치 Parakeet
| Parakeet-EOU-120M (스트리밍) | Parakeet TDT 0.6B (배치) | |
|---|---|---|
| 유스 케이스 | 라이브 받아쓰기, 실시간 캡션 | 파일 전사, 오프라인 작업 |
| 디코더 | RNN-T + EOU 헤드 | Token-and-Duration Transducer |
| 청크 크기 | 640 ms 스트리밍 | 파일 전체 배치 |
| 웨이트 메모리 | 약 120 MB | 500 MB |
| 처리량 | 실시간의 약 18배 | 실시간의 약 32배 |
| 지연 | 파셜 약 340 ms | 파일 종료 후에만 |
…사용자가 말을 끝내기 전에 파셜이 필요한 경우입니다. 오디오 파일의 배치 전사에는 더 큰 Parakeet TDT 0.6B가 엔드투엔드로 더 빠르고 정확합니다. 두 모델은 동일한 SentencePiece 어휘를 공유하므로 토크나이징을 변경하지 않고 서로 교체할 수 있습니다.