Magpie-TTS متعدّد اللغات
NVIDIA Magpie-TTS متعدّد اللغات 357M بلغة Swift على Apple Silicon — نموذج تركيب كلام انحداريّ متعدّد الـ codebooks فوق Nano-Codec من NeMo بـ 22.05 kHz. تسع لغات (الإنجليزية والإسبانية والألمانية والفرنسية والإيطالية والفيتنامية والهندية والصينية المندرين واليابانية) مع خمس هويّات متحدّث مدمجة. يُشحن مُكمَّمًا بـ INT4 (~247 MB) أو INT8 (~411 MB). جاهز للبثّ بزمن استجابة الحزمة الأولى ~120 ms.
Magpie هو الخيار الصحيح حين تحتاج إلى حزمة واحدة صغيرة تتكلّم بتسع لغات بصوت ثابت. يحافظ المتحدّثون الخمسة المدمجون على هويّتهم عبر اللغات — مفيد للمساعدات متعدّدة اللغات وتطبيقات التعليم وسرد الكتب الصوتية مع تبديل اللغة. لاستنساخ الصوت بـ zero-shot استخدم بدلًا منه CosyVoice3 أو Qwen3-TTS Base أو VoxCPM2.
البنية
Magpie خطّ معالجة MLX من 4 حزم: مُرمِّز النصّ → مفكِّك بانتباه متقاطع → رأس codebook بـ LocalTransformer → كوديك صوت Causal HiFi-GAN. تتشارك الحزم أوزان المفكِّك بين نقطتي دخول prefill وstep لمطابقة تخطيط CoreML من FluidInference في المنبع.
| المرحلة | الوحدة | التفاصيل |
|---|---|---|
| 1. الترميز | MagpieTokenizer | G2P لكلّ لغة (قاموس IPA / بايتات byT5 / pinyin / katakana)، مفردات مشتركة من 2360 رمزًا مع إزاحات لكلّ مُرمِّز، EOS يُضاف دائمًا |
| 2. مُرمِّز النصّ | MagpieTextEncoder | 6 طبقات Transformer سببيّة، d=768، FFN تلافيفيّ k=3 |
| 3. Decoder prefill | MagpieDecoder | 12 طبقة سببيّة بانتباه متقاطع. يُمهِّد ذاكرة KV بسياق المتحدّث المدمج (110 إطارات) + BOS. |
| 4. LocalTransformer | MagpieLocalTransformer | رأس AR لـ codebook من طبقة واحدة، d=256. يُعاين الـ 8 codebooks لكلّ إطار تتابعيًّا بناءً على مخفيّ المفكِّك. |
| 5. Decoder step | MagpieDecoder | خطوة AR واحدة لكلّ إطار حتى EOS أو سقف 500 إطار (~23 ث). |
| 6. NanoCodec | MagpieNanoCodec | عكس FSQ → HiFi-GAN سببيّ → موجة أحاديّة بـ 22.05 kHz. |
اللغات وG2P
اللغات التسع كلّها تتمّ رحلة العودة عبر Qwen3-ASR في اختبار testMultilingualRoundTrip في الـ SDK. كلّ لغة تحظى بخطّ معالجة مُفصَّل:
| اللغة | الرمز | خطّ معالجة G2P |
|---|---|---|
| الإنجليزية | en | قاموس CMU IPA (125 ألف مدخل، مُضمَّن) |
| الإسبانية | es | قاموس IPA إسبانيّ (مُضمَّن) |
| الألمانية | de | قاموس IPA ألمانيّ (مُضمَّن) |
| الفرنسية | fr | مُرمِّز بايتات UTF-8 من byT5 |
| الإيطالية | it | مُرمِّز بايتات UTF-8 من byT5 |
| الفيتنامية | vi | مُرمِّز بايتات UTF-8 من byT5 |
| الهندية | hi | بحث codepoint للديفاناغاريّ + مفردات فرعية last-wins |
| الصينية المندرين | zh | تقسيم كلمات بـ NLTokenizer(.simplifiedChinese) + .mandarinToLatin من Apple + قاموس pinyin → IPA مُضمَّن + علامات نغمة #N |
| اليابانية | ja | قراءة kanji بـ CFStringTokenizer + dakuten محفوظ بـ NFC + علامات نبر heiban + استبدالات للحروف الوظيفية/التحيات |
المفردات المشتركة من 2360 مدخلًا تُلصق المُرمِّز الفرعيّ لكلّ لغة طرفًا إلى طرف مع إزاحة لكلّ لغة (مُسجَّلة في MagpieSubVocab). تُضيف تضمينات النصّ صفّين إضافيّين بعد المفردات لـ BOS / EOS؛ ويُضاف eos_id = 2361 إلى كلّ تسلسل إدخال.
المتحدّثون المدمجون
تُدمج نقطة المرجع خمسة سياقات متحدّث (110 إطارات × 768 بُعدًا لكلٍّ) تُستخدم كبادئة لكلّ فكّ ترميز AR. هويّة المتحدّث ثابتة عبر اللغات التسع.
| الفهرس | اسم CLI | الهويّة |
|---|---|---|
| 0 | sofia | Sofia (افتراضي) |
| 1 | aria | Aria |
| 2 | jason | Jason |
| 3 | leo | Leo |
| 4 | john | John Van Stan |
صيغ النموذج
| الصيغة | القرص | الذاكرة (التحميل + فكّ الترميز) | HuggingFace |
|---|---|---|---|
| INT4 (افتراضي) | ~247 MB | ~1.3 GB | aufklarer/Magpie-TTS-Multilingual-357M-MLX-4bit |
| INT8 | ~411 MB | ~1.6 GB | aufklarer/Magpie-TTS-Multilingual-357M-MLX-8bit |
تعتمد الحزمتان كَمَّنة MLX أفينية مسطّحة (mlx_affine_flat، حجم المجموعة 64) وتُفكَّك كَمَّنتها إلى FP32 عند التحميل — تنشيطات وقت التشغيل بدقّة كاملة. INT4 لا يُميَّز سمعيًّا عن INT8 في هذا النموذج؛ اختر INT4 ما لم يكن لديك مساحة تخزين فائضة.
استخدام CLI
# الإنجليزية، فكّ ترميز greedy
speech speak "Hello, world." --engine magpie --magpie-speaker aria \
--magpie-temperature 0 -o out.wav
# الإسبانية (أيّ من اللغات التسع — اختر بـ --language)
speech speak "Hola, mundo." --engine magpie --language es \
--magpie-speaker aria -o out.wav
# اليابانية — تحتاج فكّ ترميز عشوائيًّا (greedy يعلق عند العبارة الأولى)
speech speak "こんにちは世界、これは音声合成システムです。" \
--engine magpie --language ja --magpie-temperature 0.6 \
--magpie-top-k 80 --seed 42 -o out.wav
# تركيب بثّيّ مع التشغيل
speech speak "Streaming test" --engine magpie --stream --play
# سرد المتحدّثين الخمسة المدمجين
speech speak --engine magpie --list-speakers
# IPA مُفنَّم مسبقًا يتجاوز G2P لكلّ لغة
speech speak "həˈloʊ" --engine magpie --magpie-prephonemized -o out.wav
الخيارات
| الخيار | الافتراضي | الوصف |
|---|---|---|
--magpie-variant | int4 | صيغة الكَمَّنة: int4 أو int8 |
--magpie-speaker | sofia | متحدّث مدمج: sofia، aria، jason، leo، john |
--magpie-temperature | 0.6 | درجة حرارة المعاينة (0 = greedy) |
--magpie-top-k | 80 | مرشِّح top-k للمعاينة |
--magpie-max-frames | 500 | سقف قاسٍ لإطارات الكوديك (~23 ث) |
--magpie-min-frames | 4 | أدنى إطارات قبل السماح بـ EOS |
--magpie-prephonemized | off | عامل الإدخال على أنه تيّار IPA / فونيمات؛ يتجاوز G2P لكلّ لغة |
--language | english | يختار خطّ المُرمِّز لكلّ لغة |
--stream | off | يُصدر AsyncStream<AudioChunk> بدلًا من ملفّ WAV واحد |
--seed | — | معاينة Gumbel قابلة للتكرار |
المدخلات اليابانية الأطول من كلمة واحدة تحتاج فكّ ترميز عشوائيًّا (--magpie-temperature 0.6 --magpie-top-k 80 --seed 42 يُحاكي اختبار NeMo المرجعيّ). يعلق greedy عند العبارة الأولى لأن استدلاليّة نبر heiban تنحرف عن الحقيقة لكلّ كلمة.
استنساخ الصوت — غير مدعوم
لا يحوي Magpie اشتراط متحدّث بـ zero-shot داخل النموذج؛ تُشحن في الحزمة الهويّات الخمس المدمجة فقط. ترفض CLI الرايات المشتركة --voice-sample و--speaker و--instruct برسالة خطأ قابلة للتنفيذ توجِّه المستخدمين إلى راية --magpie-speaker أو إلى المحرّكات التي تدعم الاستنساخ (Qwen3-TTS Base، CosyVoice3، VoxCPM2).
الأداء (M4 Pro)
| الإعداد | الصوت | الزمن الحقيقيّ | RTF |
|---|---|---|---|
| Batch، INT4، greedy، موجِّه قصير | 2.8 ث | 0.88 ث | 0.32 |
| Batch، INT4، greedy، جملة | 5.8 ث | 1.35 ث | 0.23 |
| Batch، INT4، مُعايَن، إخراج 23 ث | 23 ث | 5.6 ث | 0.24 |
| بثّ، INT4، مُعايَن | 23 ث | 21.6 ث | 0.93 |
زمن استجابة الحزمة الأولى في وضع البثّ ≈120 ms بعد تحميل النموذج. RTF البثّ أعلى لأن الكوديك يُستدعى من جديد على ذاكرة الرموز الكاملة في كلّ إصدار حُزمة (نسخة مستقبلية قد تُخزِّن حالة الكوديك).
واجهة Swift
import MagpieTTS
let model = try await MagpieTTS.fromPretrained(variant: .int4)
// Batch synthesis (en/es/de/fr/it/vi/hi/zh — greedy works)
let audio = try model.synthesize(
text: "Hello, world.",
speaker: .aria,
language: .english,
params: MagpieTTSParams(temperature: 0, topK: 1, maxSteps: 500))
// Japanese — use stochastic sampling
let audioJA = try model.synthesize(
text: "こんにちは世界、これは音声合成システムです。",
speaker: .aria,
language: .japanese,
params: MagpieTTSParams(temperature: 0.6, topK: 80,
maxSteps: 300, seed: 42))
// Streaming (AsyncStream<AudioChunk>)
let stream = model.synthesizeStream(
text: "Streaming text",
speaker: .aria,
language: .english,
firstChunkFrames: 8,
framesPerChunk: 25)
for try await chunk in stream {
// chunk.samples is 22.05 kHz mono Float32
}
الواجهة الخلفية CoreML (--engine magpie-coreml)
إلى جانب حزمة MLX، يشحن Magpie حزمة CoreML (aufklarer/Magpie-TTS-Multilingual-357M-CoreML-8bit، ~342 MB INT8). أربع حزم .mlmodelc — text_encoder، decoder_prefill، decoder_step، nanocodec_decoder — تعمل على ANE / GPU؛ ويحوّل عكس FSQ من جانب Swift الرموز المُعايَنة إلى كُمونات الـ 32 بُعدًا التي يستهلكها الكوديك.
# 8 لغات (دون اليابانية)، 5 متحدّثين مدمجين
speech speak "Hello world." --engine magpie-coreml --magpie-speaker aria -o hi.wav
speech speak "Hola mundo." --engine magpie-coreml --language es --magpie-speaker leo -o es.wav
# --language ja يُحوَّل تلقائيًّا إلى الواجهة الخلفية MLX (ملاحظة في stderr)
speech speak "こんにちは" --engine magpie-coreml --language ja -o ja.wav
تحفّظات مقارنةً بـ --engine magpie:
- خطّ معالجة هجين اليوم. لا يُشحن داخل حزمة CoreML LocalTransformer من طبقة واحدة (رأس معاينة الـ codebook الفعليّ الذي يدرّبه NeMo) ولا جداول تضمين الصوت الثمانية. عند أوّل تركيب، يُحمِّل محرّك CoreML حزمة MLX INT4 كسولًا لتشغيل القطعتين. رحلة العودة عبر ASR مطابقة بِتًّا بِتٍّ للواجهة الخلفية MLX؛ والفرق هو أن هذا المحرّك يجلب حزمة MLX أيضًا. لمسلك CoreML خالص للنشر على iOS بـ ANE فقط، يجب أن تشحن الحزمة
local_transformer/*.npy+audio_embedding_*.npyوLT بـ Swift Accelerate (متابعة مُسجَّلة). - لا بثّ. يُتعقَّب
nanocodec_decoder.mlmodelcعند نافذة ثابتة من 64 إطارًا. نُقطِّع التسلسلات الأطول داخليًّا، لكنّ زمن استجابة الحزمة الأولى سيكون ~3 ث إن أصدرنا عند حدود التقطيع. تُرفض--streamبرسالة خطأ قابلة للتنفيذ. - لا مُرمِّز يابانيّ. لم تشحن حزمة CoreML بعدُ ملفّات JSON للمُرمِّز اليابانيّ.
--language jaمع هذا المحرّك يرجع تلقائيًّا إلى الواجهة الخلفية MLX.
ترتيب المتحدّثين يطابق speaker_info.json في حزمة CoreML (0=John, 1=Sofia, 2=Aria, 3=Jason, 4=Leo — يختلف عن MLX)، ويُربط enum المتحدّث داخليًّا بحيث تعمل أسماء CLI على المحرّكين.
ملاحظات التنفيذ
ثلاثة أخطاء يجدر معرفتها إن كنت تنقل تركيب كلام متعدّد لغات على غرار NeMo:
- القسمة الأرضية في FSQ —
/في MLX-swift قسمة حقيقية (mlx_divide)؛ بينما يستخدم عكس FSQ في NeMo//في Python. استخدمMLX.floorDivide(...)وإلّا فكّت كلّ خانة FSQ إلى إزاحات كسرية وضبَّب الكوديك الصوت. - إزاحات المفردات الفرعية — يُلصق
AggregatedTTSTokenizerفي NeMo مفردات كلّ لغة مع إزاحات. مفهرسة عالمية ساذجة بأوّل ظهور تقع دائمًا في المنطقة الإنجليزية وتُنتج صوتًا لا معنى له للغات الأخرى. - إلغاء التكرار في الهندية بمنهج last-wins — يُصدر
HindiCharsTokenizerمدخلات ديفاناغاريّ مكرّرة (يتداخل CHARSET مع PUNCT_LIST). فهم{l: i for i, l in enumerate(tokens)}في Python يحفظ آخر إسناد؛ احذُ حذوه ولا تستخدم أوّل ظهور.
الإصلاحات الثلاثة موثَّقة سطريًّا في وحدة Swift.
المصدر
- الأوزان من المنبع: nvidia/magpie_tts_multilingual_357m (NVIDIA Open Model License)
- الكوديك: nvidia/nemo-nano-codec-22khz-1.89kbps-21.5fps
- الورقة البحثية: NanoCodec: Towards High-Quality Ultra Fast Speech LLM Inference (2025)
- منفذ CoreML المرجعيّ: FluidInference/mobius
- وحدات Swift: MagpieTTS (MLX) + MagpieTTSCoreML (CoreML)
- حزمة CoreML: aufklarer/Magpie-TTS-Multilingual-357M-CoreML-8bit
الترخيص
- أوزان النموذج: NVIDIA Open Model License (الاستخدام التجاريّ مسموح؛ راجع PDF المرتبطة في صفحة HuggingFace)
- منفذ Swift + قواميس IPA / pinyin المُضمَّنة: نفس ترخيص NeMo من المنبع (Apache 2.0 للقواميس، وNVIDIA OML للنموذج)