- Moshi เป็นโมเดลพื้นฐานแบบ speech-text สำหรับการสนทนาด้วยเสียงแบบเรียลไทม์ และเป็นเฟรมเวิร์กสนทนาด้วยเสียงแบบ full-duplex โดยมีทั้งไลฟ์เดโมและโมเดลบน Hugging Face
- ใน repository แยก inference stack ไว้เป็น PyTorch สำหรับงานวิจัยและการทดลอง, MLX สำหรับการอนุมานบนอุปกรณ์ iPhone/Mac และ Rust สำหรับ production
- โมเดลจัดการ สตรีมเสียงสองสตรีม ได้แก่ เสียงพูดของ Moshi และเสียงพูดของผู้ใช้ พร้อมทั้งคาดการณ์ inner monologue ซึ่งเป็นโทเคนข้อความที่สอดคล้องกับเสียงพูดของ Moshi เอง เพื่อยกระดับคุณภาพการสร้างผลลัพธ์
- โคเดก Mimi ประมวลผลเสียง 24kHz แบบสตรีมมิงเป็นตัวแทนความถี่ 12.5Hz และแบนด์วิดท์ 1.1kbps มีความหน่วงของเฟรม 80ms โดยความหน่วงเชิงทฤษฎีของ Moshi อยู่ที่ 160ms และความหน่วงรวมที่วัดได้จริงบน L4 GPU ต่ำสุด 200ms
- โมเดลที่เปิดเผยประกอบด้วยเสียงสังเคราะห์ชาย Moshiko, เสียงสังเคราะห์หญิง Moshika และโคเดกเสียง Mimi โดยน้ำหนักโมเดลเผยแพร่ภายใต้ CC-BY 4.0, โค้ด Python และเว็บไคลเอนต์ภายใต้ MIT, และแบ็กเอนด์ Rust ภายใต้ไลเซนส์ Apache
เป้าหมายและองค์ประกอบของ Moshi
- Moshi เป็น speech-text foundation model และเฟรมเวิร์ก full-duplex สำหรับการสนทนาด้วยเสียงแบบเรียลไทม์
- ไลฟ์เดโมมีให้ที่ moshi.chat และคอลเลกชันโมเดลเผยแพร่บน Hugging Face
- repository มี inference stack 3 แบบ
- PyTorch: สำหรับงานวิจัยและการทดลอง อยู่ในไดเรกทอรี
moshi/
- MLX: สำหรับการอนุมานบนอุปกรณ์ iPhone และ Mac อยู่ในไดเรกทอรี
moshi_mlx/
- Rust: สำหรับ production อยู่ในไดเรกทอรี
rust/
- รวม implementation ของ Mimi บน Rust และ Python binding
rustymimi
- โค้ดเว็บ UI ไคลเอนต์ที่ใช้ในเดโม Moshi อยู่ในไดเรกทอรี
client/
- การ fine-tuning Moshi จัดการใน repository แยก kyutai-labs/moshi-finetune
โมเดล Kyutai ที่เกี่ยวข้อง
- โค้ดเบส Moshi ยังใช้รันโมเดลที่เกี่ยวข้องของ Kyutai ซึ่งใช้ multi-stream architecture คล้ายกับ Moshi
สถาปัตยกรรมโมเดล
- Moshi โมเดล สตรีมเสียงสองสตรีม
- สตรีมหนึ่งคือสตรีมที่ Moshi พูด
- อีกสตรีมคือสตรีมที่ผู้ใช้พูด
- นอกจากสตรีมเสียงทั้งสองแล้ว Moshi ยังทำนาย inner monologue ซึ่งเป็นโทเคนข้อความที่สอดคล้องกับเสียงพูดของตนเอง และวิธีนี้ช่วยปรับปรุงคุณภาพการสร้างผลลัพธ์ได้อย่างมาก
- Depth Transformer ขนาดเล็กใช้โมเดล dependency ระหว่าง codebook ใน time step เฉพาะ
- Temporal Transformer ขนาดใหญ่ระดับ 7B พารามิเตอร์ ใช้โมเดล dependency ตามเวลา
- ความหน่วงเชิงทฤษฎีอยู่ที่ 160ms
- ขนาดเฟรม Mimi 80ms
- ความหน่วงด้านอะคูสติก 80ms
- ความหน่วงรวมในทางปฏิบัติบน L4 GPU ต่ำสุดอยู่ที่ 200ms
โคเดกเสียง Mimi
- Mimi เป็นโคเดกเสียงแบบ neural network ที่ลดเสียง 24kHz ลงเป็นตัวแทนความถี่ 12.5Hz
- Mimi ทำงานแบบสตรีมมิงเต็มรูปแบบ มีแบนด์วิดท์ 1.1kbps และความหน่วงเท่ากับขนาดเฟรมคือ 80ms
- ตาม README ระบุว่า Mimi มีประสิทธิภาพดีกว่าโคเดกเดิมที่ไม่ใช่แบบสตรีมมิง
- Mimi อ้างอิงจากโคเดกเสียง neural network รุ่นก่อนหน้าอย่าง SoundStream และ EnCodec
- เพิ่ม Transformer ทั้งฝั่ง encoder และ decoder
- ปรับ stride เพื่อให้ frame rate รวมอยู่ที่ 12.5Hz
- frame rate 12.5Hz ใกล้เคียงกับ frame rate เฉลี่ยของโทเคนข้อความประมาณ 3~4Hz มากขึ้น และช่วยลดจำนวนขั้นตอน autoregressive ของ Moshi
- คล้ายกับ SpeechTokenizer, Mimi ใช้ distillation loss เพื่อให้โทเคน codebook ตัวแรกสอดคล้องกับตัวแทนแบบ self-supervised ของ WavLM
- เช่นเดียวกับ EBEN, Mimi ใช้ เฉพาะ adversarial training loss ร่วมกับ feature matching และช่วยปรับปรุงคุณภาพเชิงอัตวิสัยได้อย่างชัดเจนแม้ใน bitrate ต่ำ
โมเดลที่เผยแพร่และรูปแบบ
- โมเดลที่เผยแพร่มี 3 รายการ
- Moshiko: Moshi ที่ fine-tune ด้วยเสียงสังเคราะห์ชาย
- Moshika: Moshi ที่ fine-tune ด้วยเสียงสังเคราะห์หญิง
- Mimi: โคเดกเสียง
- file format และ quantization ที่ใช้ได้จะแตกต่างกันตามแบ็กเอนด์
- Mimi ถูก bundle ไปกับแต่ละโมเดล และใช้รูปแบบ checkpoint เดียวกันเสมอ
- โมเดล PyTorch
- โมเดล MLX
- โมเดล Rust/Candle
- โมเดลทั้งหมดเผยแพร่ภายใต้ไลเซนส์ CC-BY 4.0
ข้อกำหนดและข้อจำกัดในการติดตั้ง
- ต้องใช้ Python อย่างน้อย 3.10 และแนะนำ 3.12
- PyTorch และ MLX client ติดตั้งได้จาก PyPI
pip install -U moshi
pip install -U moshi_mlx
pip install rustymimi
- หากไม่ใช่ Python 3.12 อาจเกิดข้อผิดพลาดระหว่างติดตั้ง
moshi_mlx หรือ dependency อย่าง rustymimi ซึ่งในกรณีนี้ต้องติดตั้ง Rust toolchain หรือเปลี่ยนไปใช้ Python 3.12
- คาดว่าจะทำงานบน Windows ได้ แต่ไม่มีการสนับสนุนอย่างเป็นทางการ
- เวอร์ชัน MLX ทดสอบบน MacBook Pro M3
- เวอร์ชัน PyTorch ปัจจุบันยังไม่รองรับ quantization จึงต้องใช้หน่วยความจำ GPU ค่อนข้างมากระดับ 24GB
- แบ็กเอนด์ Rust ต้องใช้ Rust toolchain เวอร์ชันล่าสุด
- หากต้องการคอมไพล์การรองรับ GPU ต้องมี CUDA ที่ตรงกับ GPU และ
nvcc
วิธีรัน
-
PyTorch
- PyTorch API อยู่ในไดเรกทอรี
moshi และให้ เวอร์ชันสตรีมมิง ของ Mimi audio tokenizer และ Moshi language model
- โหมดโต้ตอบต้องรัน model server ก่อน แล้วใช้เว็บ UI หรือ command-line client
python -m moshi.server [--gradio-tunnel] [--hf-repo kyutai/moshika-pytorch-bf16]
- โดยค่าเริ่มต้น เว็บ UI เข้าถึงได้ที่
localhost:8998
- หากเข้าถึง GPU บนเครื่องรีโมตผ่าน HTTP การใช้ไมโครโฟนอาจถูกบล็อกโดยนโยบายความปลอดภัยของเบราว์เซอร์
- สามารถใช้ SSH
-L เพื่อ forward พอร์ต 8998 ของเครื่องรีโมตมายัง localhost ได้
- ใช้
--gradio-tunnel เพื่อสร้าง tunnel ที่เข้าถึงได้จากทุกที่
- tunnel นี้วิ่งผ่านสหรัฐฯ และเมื่ออ้างอิงจากยุโรปอาจเพิ่มความหน่วงสูงสุดถึง 500ms
- ใช้
--gradio-tunnel-token เพื่อตั้ง secret token แบบคงที่และ reuse ที่อยู่เดิมได้
- ใช้
--hf-repo เพื่อเลือกโมเดล pre-trained อื่นบน Hugging Face ได้
- มี command-line client ให้ใช้ด้วย แต่ต่างจากเว็บเบราว์เซอร์ตรงที่ไม่มี echo cancellation และไม่ข้ามเฟรมเพื่อชดเชย latency ที่สะสม
python -m moshi.client [--url URL_TO_GRADIO]
-
MLX
- หลังติดตั้ง
moshi_mlx แล้ว สามารถรันการอนุมานแบบ local บน macOS ได้
python -m moshi_mlx.local -q 4
python -m moshi_mlx.local -q 8
python -m moshi_mlx.local -q 4 --hf-repo kyutai/moshika-mlx-q4
python -m moshi_mlx.local -q 8 --hf-repo kyutai/moshika-mlx-q8
- flag
-q และ --hf-repo ต้องสอดคล้องกันเสมอ
- command-line interface ของ MLX ก็เป็นแบบ barebone และไม่มี echo cancellation หรือการชดเชย latency ที่สะสม
- สามารถรันเว็บ UI ด้วย
python -m moshi_mlx.local_web และ HTTP connection ให้บริการที่ localhost:8998
-
Rust
- inference server ของ Rust รันจากไดเรกทอรี
rust
cargo run --features cuda --bin moshi-backend -r -- --config moshi-backend/config.json standalone
- บน macOS สามารถใช้
--features metal แทน --features cuda ได้
- หากใช้
config-q8.json แทน config.json จะใช้ โมเดล quantization q8 ได้
- เลือกโมเดล pre-trained อื่นได้โดยเปลี่ยนคีย์
"hf_repo" ในไฟล์ config
- เมื่อ server แสดงผล
standalone worker listening ก็สามารถใช้เว็บ UI ได้
- Rust server ใช้ HTTPS เป็นค่าเริ่มต้น จึงเข้าถึงได้ที่
https://localhost:8998
- ในเบราว์เซอร์อาจมีคำเตือนว่าเป็นไซต์ไม่ปลอดภัย และใน Chrome สามารถกด “Details” หรือ “Advanced” เพื่อเข้าถึง localhost ต่อได้
ไคลเอนต์และการพัฒนา
- แนะนำให้ใช้เว็บ UI เพราะมี echo cancellation ซึ่งช่วยคุณภาพโดยรวมของโมเดล
- คำสั่งส่วนใหญ่จะ serve เว็บ UI โดยตรงจาก URL ที่ให้มา
- มี command-line interface สำหรับ Rust และ Python ด้วย และใช้ protocol เดียวกับเว็บ UI จึงไม่ต้องแก้ไขฝั่ง server
- การ build เว็บ UI ทำในไดเรกทอรี
client
cd client
npm install
npm run build
- Rust command-line client รันจากไดเรกทอรี
rust
cargo run --bin moshi-cli -r -- tui --host localhost
- Python PyTorch client รันด้วยคำสั่งต่อไปนี้
python -m moshi.client
- เดโม Gradio รันหลังติดตั้ง
gradio-webrtc>=0.0.18
python -m moshi.client_gradio --url <moshi-server-url>
docker compose up
ไลเซนส์และการอ้างอิง
- โค้ดส่วน Python เผยแพร่ภายใต้ไลเซนส์ MIT
- แบ็กเอนด์ Rust เผยแพร่ภายใต้ไลเซนส์ Apache
- โค้ดเว็บไคลเอนต์เผยแพร่ภายใต้ไลเซนส์ MIT
- โค้ดบางส่วนอ้างอิงจาก AudioCraft ซึ่งใช้ไลเซนส์ MIT
- น้ำหนักโมเดลเผยแพร่ภายใต้ไลเซนส์ CC-BY 4.0
- หากใช้ Mimi หรือ Moshi ขอให้อ้างอิงบทความ
Moshi: a speech-text foundation model for real-time dialogue
1 ความคิดเห็น
ความคิดเห็นบน Hacker News
ความเห็นที่นี่แทบทั้งหมดเป็นเชิงลบ เลยขอฝากฟีดแบ็กไว้ว่า latency ดีมาก ดีจนรู้สึกเหมือนมันขัดจังหวะพูดอยู่บ่อย ๆ ด้วยซ้ำ
ในฐานะโมเดลโอเพนซอร์ส ถือว่าเป็นความสำเร็จครั้งใหญ่ แต่ช่วงนี้ผู้คนคุ้นเคยกับโมเดลภาษาขนาดใหญ่ที่เก่งมาก ๆ กันแล้ว และคุณภาพเนื้อหาคำตอบของโมเดลนี้ยังห่างจากโมเดลระดับแนวหน้าในปัจจุบันมาก ให้ความรู้สึกใกล้เคียงกับโมเดลภาษาขนาดใหญ่ที่เคยเห็นราวปี 2019 มากกว่า ดังนั้นฝั่งเสียงน่าจะมาถึงระดับ “ดีพอ” แล้ว และต่อจากนี้ควรไปโฟกัสที่ คุณภาพคำตอบ จะดีกว่า
คำถามที่เกิดขึ้นตามธรรมชาติคือ มีวิธีนำ “โมเดลภาษาขนาดใหญ่ที่ดีกว่า” มาใช้โดยไม่ทำลายประสบการณ์ของ Moshi ได้หรือไม่
Moshi เป็น CC-BY และยังมีโมเดลสนทนาเรียลไทม์แบบเสียง-ข้อความขนาดใกล้เคียง 7B ที่เพิ่งเปิดเผยภายใต้ Apache v2 ด้วย: https://tincans.ai/slm3 / https://huggingface.co/collections/tincans-ai/gazelle-v02-65...
ช่วงหลังมีการพัฒนาด้าน โมเดลภาษาที่รองรับเสียง มากขึ้น เช่น https://github.com/ictnlp/LLaMA-Omni, https://github.com/gpt-omni/mini-omni
เซิร์ฟเวอร์ inference ของพวกเขาเขียนด้วย Rust โดยใช้ crate Candle ของ huggingface หนึ่งในผู้เขียน Moshi ก็เป็นผู้เขียนหลักของ Candle ด้วย
เราก็กำลังสร้าง inference stack บน Candle อยู่ และใช้งานได้ค่อนข้างน่าพอใจ
ระหว่างหาเดโมบน YouTube ไปเจอวิดีโอตลก ๆ จากไม่กี่เดือนก่อน: https://youtu.be/coroLWOS7II?si=TeVghP_Zi0P9exQh
ตอนนี้น่าจะปรับปรุงขึ้นแล้วแน่นอน :-)
น่าสนใจดี ชอบที่ตรงนี้โฟกัสเรื่อง latency และอ้างว่าบน GPU แบบโลคัลทำได้จริงราว 200ms
เพราะอิงกับโมเดล Transformer 7B ก็คงไม่ได้ฉลาดมากนัก ถ้าจินตนาการว่า latency ของโมเดล 70B อยู่ราว 1 วินาที ก็ดูเป็นไปได้ที่จะมี สถาปัตยกรรมระบบ ที่ให้การตอบสนองคั่นกลางเพื่อบอกเป็นคำพูดว่า “โมเดลกำลังพูดอยู่ตอนนี้” ใช้โมเดลระดับ 7B/Phi-3 ให้คำตอบเริ่มต้นเร็ว ๆ แล้วค่อยส่งต่อไปยังโมเดลใหญ่กว่า โมเดล Phi-3 อาจรับหน้าที่ปรับแต่ง เช่น รับคำตอบที่ถูกต้องจริง ๆ แล้วถ้าจำเป็นก็ขอโทษและแก้ไขให้ถูก
จากประสบการณ์ส่วนตัว ผมคิดว่าสมองคนเราหลายครั้งก็ทำงานแบบนี้เหมือนกัน คือโต้ตอบเร็ว แล้วอีก 1–2 วินาทีค่อยแก้หรือเสริม แน่นอนว่าก็มีคนที่ไม่แก้เลยเหมือนกัน หรือคนที่หยุดคิดนานแล้วค่อยให้คำตอบที่ไตร่ตรองมาดีครบถ้วน
ลองใช้แล้ว ใส่อีเมลอะไรก็ได้ มันตอบทันที แทบจะทันควัน แม้เรายังพูดไม่จบก็ตาม
แต่นั่นดูเหมือนเป็นแค่ ประโยคเติมช่องว่าง และอาจเป็นคำตอบที่ cache ไว้ คำตอบต่อสิ่งที่ถามจริง ๆ จะออกมาทีหลังมาก และต้องไม่ให้มันหลุดเข้า loop ระหว่างนั้น
ผมกำลังทำโซลูชันเสียงเรียลไทม์ → โมเดลภาษาขนาดใหญ่ → เอาต์พุตเสียง และคิดว่าส่วนที่น่าสนใจที่สุดตรงนี้คือ neural audio codec แบบสตรีมมิง เพราะในทางปฏิบัติทำ speech-to-text แบบสตรีมมิงให้ดีด้วย Whisper ได้ยาก
แต่จากมุมมองผลิตภัณฑ์ ผมไม่แน่ใจว่าอยากป้อนสิ่งนั้นเข้าโมเดลภาษาขนาดใหญ่โดยตรงเพื่อให้ตอบเลย ในหลาย use case ผมคิดว่าต้องมีขั้นตอน tool/function calling ก่อนตอบเสมอ ถ้ามีใครทำงานในทิศทางนี้ ผมยินดีคุยได้ทุกเมื่อ
tincans ที่มีคนพูดถึงด้านล่างก็ดูยอดเยี่ยม แต่เห็นว่าการพัฒนา tincans จบลงแล้ว ดังนั้นทิศทางนี้ยังมีพื้นที่ให้ทำต่ออีก 10000% ถ้า Chris อ่านอยู่ ผมอยากอธิบาย use case ด้านผลิตภัณฑ์/ธุรกิจที่สิ่งนี้แก้ได้จริง ๆ ไม่ว่าโมเดลภาษาขนาดใหญ่จะเก่งขึ้นแค่ไหนก็ตาม
โมเดลภาษาขนาดใหญ่ไม่ได้ตอบเองโดยตรง แค่เลือก node ใน tree ที่มีเอาต์พุต text-to-speech เตรียมไว้แล้ว มีพารามิเตอร์ “ความยาวช่วงหยุด” เพื่อ判断ว่าผู้ใช้พูดจบหรือยัง แล้วจึงส่งผลถอดเสียงให้โมเดล ซึ่งไม่ได้ซับซ้อนเป็นพิเศษ ผมยังคิดต่ออยู่เรื่อย ๆ ว่าจะจัดการอินพุตเสียงให้ถูกต้องได้อย่างไร หรือจะควบคุมโมเดลให้แม่นพอจนตัด IVR tree ออกได้ด้วยการจัด prompt อย่างเดียวหรือไม่ ตอนนี้ก็ทำงานได้ค่อนข้างดีแล้ว แต่ยังมีพื้นที่ให้ปรับปรุงอีกมาก
ความเร็วในการตอบสนอง น่าประทับใจ แต่ “คุณภาพ” ของคำตอบไม่ใช่แบบนั้น บันทึกบทสนทนาของการทดสอบครั้งที่สองเป็นแบบนี้
Moshi: “สวัสดีครับ มีอะไรเหรอ?”
ผม: “ตอนนี้ปีอะไร?”
Moshi: “อ้อ ปี 2019 ครับ น่าจะประมาณหนึ่งปีก่อนมั้งครับ”
ผม: “แน่ใจเหรอว่าเป็นปี 2019?”
Moshi: “อ้อ ครับ แน่ใจครับ ต้องเป็นปี 2019 แน่นอน ตัวเลขนั้นเอาไว้สำหรับอันสุดท้ายครับ”
ผม: “COVID-19 คืออะไร?”
Moshi: “มันเป็นโรคหายากครับ เกิดจากระบบภูมิคุ้มกันที่ทำงานมากเกินไปซึ่งโจมตีผิวหนังครับ”
ถึงจุดนี้มันก็ไม่ตอบอีกแล้ว
Moshi เป็นโมเดลที่สนุกที่สุดเท่าที่เคยมีมา ประสบการณ์ล่าสุดอยู่ที่นี่: https://x.com/tommoor/status/1809051817860354471
แต่อย่าคาดหวังเรื่อง ความถูกต้อง จะดีกว่า