การบอกพิมพ์แบบสตรีมมิ่ง

Parakeet-EOU-120M เป็นโมเดล ASR แบบสตรีมมิ่ง RNN-T ขนาดเล็กพร้อมหัว end-of-utterance (EOU) ที่ชัดเจน สร้างขึ้นสำหรับการบอกพิมพ์เรียลไทม์บน Neural Engine ของ Apple Silicon คู่มือนี้ยังครอบคลุม DictateDemo ซึ่งเป็นแอปตัวอย่างบนเมนูบาร์ macOS ที่ผูกโมเดลสตรีมมิ่งเข้ากับ Silero VAD เพื่อการบอกพิมพ์แบบไม่ต้องใช้มือพร้อมวางผลลัพธ์ได้ทุกที่

คืออะไร

สถาปัตยกรรม

โมเดล CoreML สามตัวต่อกันเป็น pipeline ต่อ chunk เสียง:

ส่วนประกอบคำอธิบาย
EncoderConformer แบบรับรู้ cache รับ chunk mel 64 frame (640 ms) พร้อม tensor สถานะหกตัว ได้แก่ KV cache ของ attention, cache ของ depthwise conv และ pre_cache mel loopback ที่ใส่เสียงในอดีตล่าสุดไว้ด้านหน้าเพื่อให้ FFT มองเห็นสัญญาณต่อเนื่องข้ามขอบเขตของ chunk
Decoderเครือข่ายทำนาย LSTM แบบขั้นเดียว รับ token non-blank ก่อนหน้าและส่ง embedding พร้อมสถานะ (h, c) ที่อัปเดต
Joint + หัว EOUรวมเอาต์พุตของ encoder กับ decoder เป็น logits ครอบคลุม vocab + blank + EOU คลาส EOU คือสัญญาณชัดของโมเดลว่าประโยคจบแล้ว

ทำไมต้องมี token EOU แยก

RNNT ล้วน ๆ จะปล่อย blank ในช่วงเงียบ ซึ่ง decoder ดูดซับโดยไม่ส่งสัญญาณว่า "ประโยคจบแล้ว" หัว EOU เฉพาะทำให้โมเดลสามารถตัดสินใจอย่างเด็ดขาดในการ commit ผลลัพธ์บางส่วนให้เป็นผลสุดท้าย รีเซ็ตสถานะการใส่เครื่องหมายวรรคตอน/ตัวพิมพ์ใหญ่ และกระตุ้นการกระทำต่อ ๆ ไป เช่น paste เข้าแอป

EOU มีสัญญาณรบกวนในโลกจริง

เสียงคลิกคีย์บอร์ด การเคลื่อนเมาส์ และเสียงในห้องระหว่างช่วง "เงียบ" อาจทำให้ joint ปล่อย token non-blank บางครั้ง รีเซ็ตตัวจับเวลา debounce ของ EOU และทำให้ commit ติดขัด pipeline ระดับ production จึงจับคู่ EOU ของ joint เข้ากับแบ็คอัพ forceEndOfUtterance() ภายนอกที่ขับด้วย VAD ดูที่ DictateDemo ด้านล่าง

โมเดล

โมเดลขนาดHuggingFace
Parakeet-EOU-120M (CoreML INT8)~120 MBaufklarer/Parakeet-EOU-120M-CoreML-INT8

ประสิทธิภาพ

ตัวชี้วัดค่า
หน่วยความจำของน้ำหนัก~120 MB (INT8)
หน่วยความจำการอนุมานสูงสุด~200 MB
Chunk latency (ชิป M-series)~30 ms คำนวณ / 640 ms ของเสียง (RTF ~0.056)
Partial latency end-to-end~340 ms (หนึ่ง chunk)
Commit latency (เส้นทาง VAD)~1 s หลังหยุดพูด
เป้าหมายการประมวลผลNeural Engine (CoreML)

Quick start — การถอดเสียงเป็นชุด

โมเดลสตรีมมิ่งยังเข้ากันกับ SpeechRecognitionModel จึงใช้แทนกันได้กับโค้ดใด ๆ ที่รับโมเดล STT ทั่วไป:

import ParakeetStreamingASR

let model = try await ParakeetStreamingASRModel.fromPretrained()
let text = try model.transcribeAudio(audioSamples, sampleRate: 16000)

Quick start — สตรีมมิ่งแบบ async

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 ยิงเองหรือถูก force-finalize) และ segmentIndex ที่เพิ่มขึ้นเป็นลำดับ

API session แบบยาว (อินพุตจากไมโครโฟน)

สำหรับการบอกพิมพ์สด ให้สร้าง session ครั้งเดียวแล้วป้อน chunk เข้าไปเมื่อมาจากไมโครโฟน Session จะเก็บบัฟเฟอร์ภายในและรัน encoder เมื่อสะสมตัวอย่างพอ คุณจึงป้อน chunk ขนาดใดก็ได้:

let session = try model.createSession()

// แต่ละ chunk จากไมค์:
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()

แพทเทิร์น force-finalize ด้วย VAD

เมื่อมี Silero VAD รันอยู่ใน pipeline ของคุณแล้ว ให้ใช้มันขับ commit สำรองเพื่อไม่ให้เสียงรบกวนพื้นหลังทำให้ตัวจับเวลา debounce ของ EOU ติดขัด:

if hasPendingUtterance && !vadSpeechActive && vadSilentChunks >= 30 {
    // ~960 ms ของความเงียบต่อเนื่องตาม Silero
    if let forced = session.forceEndOfUtterance() {
        commit(forced.text)
    }
    hasPendingUtterance = false
}

// guardrail: อย่า commit ซ้ำหาก joint ยิง EOU ไปแล้ว
if partials.contains(where: { $0.isFinal }) {
    hasPendingUtterance = false
}

DictateDemo — แอปตัวอย่างเมนูบาร์ macOS

DictateDemo เป็น agent บนเมนูบาร์ macOS แบบครบเครื่องที่สร้างบน session สตรีมมิ่ง รันเป็นแอปเบื้องหลัง ถอดเสียงจากไมโครโฟนพร้อมผลลัพธ์บางส่วนแบบสด คอมมิตประโยคอัตโนมัติเมื่อเจอ EOU หรือ VAD เงียบ และ paste ผลลัพธ์ไปยังแอปที่อยู่ด้านหน้า

cd Examples/DictateDemo
swift build
.build/debug/DictateDemo

การ implement เต็มอยู่ใน Examples/DictateDemo/DictateDemo/DictateViewModel.swift ได้แก่ audio sink นอก main thread พร้อมบัฟเฟอร์ที่ป้องกันด้วย lock, ตัวจับเวลา tick ทุก 300 ms เพื่อระบายบัฟเฟอร์, Silero VAD พร้อมการส่งต่อ leftover sample และ force-finalize ที่มี guard เทสต์ regression ที่จับคู่กันใน Examples/DictateDemo/Tests/DictateDemoTests.swift ครอบคลุมสถานการณ์หลายประโยค EOU ติดขัด และความเงียบที่มีสัญญาณรบกวน

สตรีมมิ่งเทียบกับ Parakeet แบบ batch

Parakeet-EOU-120M (สตรีมมิ่ง)Parakeet TDT 0.6B (batch)
กรณีใช้งานการบอกพิมพ์สด คำบรรยายเรียลไทม์การถอดเสียงไฟล์ งาน offline
DecoderRNN-T + หัว EOUToken-and-Duration Transducer
ขนาด chunkสตรีมมิ่ง 640 msทั้งไฟล์เป็น batch
หน่วยความจำน้ำหนัก~120 MB500 MB
Throughput~18 เท่าของเรียลไทม์~32 เท่าของเรียลไทม์
Latencyผลลัพธ์บางส่วน ~340 msเฉพาะตอนจบไฟล์
เลือกโมเดลสตรีมมิ่งเมื่อ…

…คุณต้องการผลลัพธ์บางส่วนก่อนที่ผู้ใช้จะพูดจบ สำหรับการถอดเสียงไฟล์เป็น batch Parakeet TDT 0.6B ที่ใหญ่กว่าจะเร็วกว่าแบบ end-to-end และแม่นยำกว่า ทั้งสองโมเดลใช้ vocabulary SentencePiece เดียวกัน คุณจึงสลับระหว่างกันได้โดยไม่ต้องเปลี่ยน tokenization