يمكن أن يكون التسجيل رديئًا بطريقتين مختلفتين، والإصلاحات لا تتداخل.
الطريقة الأولى: يجلس ضجيج خلفي فوق الكلام — حركة مرور، مروحة، طنين غرفة. الإشارة المهمة موجودة؛ لكن شيئًا آخر ممتزج بها. إزالة ذلك هي إزالة الضوضاء (denoising).
الطريقة الثانية: لم يلتقط التسجيل الإشارة الكاملة أصلًا. يُؤخذ الصوت الهاتفي بمعدّل 8000 عيّنة في الثانية (8 كيلوهرتز)؛ بينما يكون التسجيل الكامل الجودة عادةً بـ48 كيلوهرتز. يحدّد معدّل أخذ العينات أعلى تردد يستطيع تمثيله في إشارة رقمية، لذا فإن مكالمة بـ8 كيلوهرتز لا تحتوي أي محتوى فوق 4 كيلوهرتز على الإطلاق — ليس هادئًا، ولا مُرشَّحًا، بل ببساطة لم يُسجَّل قط. جعل ذلك الصوت يبدو كاملًا مجددًا يعني اختراع ترددات عالية معقولة لم تُلتقَط قط. تلك هي توسعة النطاق الترددي (bandwidth extension).
تتعامل audiosronnx مع هاتين المشكلتين بوصفهما مختلفتين بنقطتَي دخول مختلفتين، لأن استخدام النقطة الخاطئة يفعل الشيء الخاطئ. شغّل موسِّع نطاق ترددي على إشارة صاخبة وسيعيد بناء نسخة عالية التردد من الضجيج بأمانة. يجب أن تحدث إزالة الضوضاء أولًا.
from audiosronnx import load_denoise, load_sr
clean, rate = load_denoise("dpdfnet").denoise("noisy_call.wav") # remove noise
wide, _ = load_sr("lavasr").upscale(clean, rate) # extend to 48 kHz
يرفض load_denoise() وload_sr() محركات بعضهما — طلب موسِّع نطاق ترددي من load_denoise يثير خطأً بدلًا من القيام بالمهمة الخاطئة بصمت.
لماذا يأتي هذا قبل التعرّف
عادةً ما تُدرَّب أنظمة التعرّف على الكلام وتحديد هوية المتحدث على صوت نظيف نسبيًا. أطعم أداة تعرّف صوتًا هاتفيًا بـ8 كيلوهرتز، أو كلامًا تعمل مروحة تحته، وسيرتفع معدّل خطأ الكلمات — ليس لأن النموذج سيّئ، بل لأن المدخل لم يعد يشبه ما دُرِّب عليه. الأمر نفسه ينطبق على تضمينات المتحدث المُستخدَمة للتعرّف أو الفرز الحواري: يشوّه الضجيج والنطاق الترددي المفقود التفصيل الصوتي الدقيق الذي تعتمد عليه تلك التضمينات.
هذا يجعل التنظيف مرحلة خط أنابيب تقع قبل التعرّف، لا بديلًا عنه. يبدو خط أنابيب حقيقي لمكالمة هاتفية صاخبة بـ8 كيلوهرتز كالتالي: أزل الضوضاء، ثم وسِّع إلى 48 كيلوهرتز، ثم شغّل التعرّف أو تحديد هوية المتحدث على النتيجة. استبدال أداة تعرّف أفضل دون إصلاح المدخل أولًا ينفق جهدًا في المكان الخاطئ — يتدهور النموذج على الإشارة التالفة نفسها مهما كان جيدًا.
سجل المحركات
تشحن audiosronnx عشرة مزيلات ضوضاء وسبعة موسِّعات نطاق ترددي، كلها قابلة للتحميل بالاسم عبر load_denoise() / load_sr()، وكلها ONNX خالص دون torch وقت التشغيل.
مزيلات الضوضاء:
| المحرك | المعدّل | الحجم | الرخصة |
|---|---|---|---|
| dpdfnet (الافتراضي) | 8/16/48 كيلوهرتز | 8.7–14.9 ميغابايت | Apache-2.0 |
| mossformer2 | 48 كيلوهرتز | 229 ميغابايت | Apache-2.0 |
| frcrn | 16 كيلوهرتز | 57.5 ميغابايت | Apache-2.0 |
| mpsenet | 16 كيلوهرتز | 9.7 ميغابايت | MIT |
| gtcrn | 16 كيلوهرتز | 0.54 ميغابايت | MIT |
| cmgan | 16 كيلوهرتز | 7.8 ميغابايت | MIT |
| metadenoiser | 16 كيلوهرتز | 19–34 ميغابايت | CC-BY-NC-4.0 |
| mossformergan | 16 كيلوهرتز | 17.7 ميغابايت | Apache-2.0 |
| voicefixer | 44.1 كيلوهرتز | 415 ميغابايت | MIT |
| deepfilternet | 48 كيلوهرتز | ~2 ميغابايت | MIT |
موسِّعات النطاق الترددي:
| المحرك | المدخل | الحجم | الرخصة |
|---|---|---|---|
| lavasr (الافتراضي) | 8–48 كيلوهرتز | ~52 ميغابايت | Apache-2.0 |
| novasr | 16 كيلوهرتز | ~0.2 ميغابايت | Apache-2.0 |
| flowhigh | أي معدّل | ~200 ميغابايت | MIT |
| hifiganbwe | أي معدّل | ~4 ميغابايت | MIT |
| apbwe | أي معدّل (نطاق 12 كيلوهرتز) | ~120 ميغابايت | MIT |
| sidon | 16 كيلوهرتز | ~410 ميغابايت | MIT |
| callenhancer | 8–16 كيلوهرتز | ~3 غيغابايت / ~1.3 غيغابايت int8 | CC-BY-NC-4.0 |
أصغر نموذج في المكتبة، gtcrn، بحجم 0.54 ميغابايت. أما الأكبر، voicefixer، فبحجم 415 ميغابايت — أكبر بنحو 800 مرة، ويقوم بمهمة مختلفة: إنه نموذج استعادة يتعامل مع الضجيج، وصدى الغرفة، والقصّ، والنطاق الترددي المفقود معًا بدلًا من مشكلة واحدة في كل مرة.
معظم الأوزان مرخّصة بـ MIT أو Apache-2.0. اثنان ليسا كذلك: يُشحَن metadenoiser وcallenhancer تحت CC-BY-NC-4.0، غير تجارية. تغطي تلك الرخصة الأوزان، لا الصوت المُعالَج بها، وتذكر المكتبة ذلك في كل نقطة استخدام — يبلّغ audiosronnx list عنها لكل محرك. لا شيء يمنع المستدعي من اختيار metadenoiser لأجل بنيته في المجال الزمني، لكن الاختيار يجب أن يتمّ عن علم.
يوجد السجل لأن لا نموذج واحد يفوز على كل تسجيل. dpdfnet هو الافتراضي لأنه لا يحتاج اعتماديات إضافية ويغطي 8 و16 و48 كيلوهرتز من نموذج واحد. mossformer2 هو الخيار الأفضل مقيسًا على مدخل النطاق الكامل. يسجّل mossformergan أعلى درجة PESQ منشورة (3.47) بين مزيلات الضوضاء المشحونة. gtcrn هو الخيار حين يكون القيد الملزم هو البصمة، عند 0.54 ميغابايت. في مقطع اختبار واحد بضجيج غاوسي واسع النطاق، استعادت مزيلات الضوضاء من 3.5 إلى 5.9 ديسيبل من نسبة الإشارة إلى الضجيج عند إدخال بـ19 ديسيبل، مرتفعة إلى 7.5–13.7 ديسيبل عند إدخال أصعب بـ5 ديسيبل. تلك حالة ضجيج اصطناعية وقاسية: ترتّب المحركات باتّساق لكنها تقول القليل عن ضجيج الثرثرة أو عيوب المُرمِّز، وهو بالضبط سبب احتفاظ السجل بعشرة نماذج بدلًا من شحن الفائز فقط.
cmgan هو الحالة الأوضح لنموذج مُبقًى عليه عمدًا رغم خسارته: يهيمن عليه gtcrn في PESQ ونسبة الإشارة إلى الضجيج معًا، بأربعة عشر ضعف الحجم، ويبقى مع ذلك — كي تظل النتائج المنشورة المبنية على cmgan قابلة لإعادة الإنتاج وتبقى بنية متمايزة متاحة للمقارنة معها.
على جانب توسعة النطاق الترددي، يقوم sidon وcallenhancer بمهمة مختلفة عن lavasr أو novasr: بدلًا من إضافة نطاق عالٍ معقول فوق الإشارة الموجودة، يعيدان تخليق الكلام من الصفر عبر مُصوِّت عصبي، وهو ما يستطيع إصلاح أضرار المُرمِّز التي لا يستطيع موسِّع نطاق لمسها — بتكلفة حسابية أعلى بكثير. يُدرَّب callenhancer خصيصًا على صوت الاتصالات الهاتفية، وهذا سبب حمل أوزانه للرخصة غير التجارية.
ما لم يصل إلى الشحن
تشحن audiosronnx محركًا فقط حين يُصدَّر إلى رسم ONNX ثابت واحد، ويعمل على وحدة المعالجة المركزية عبر onnxruntime، ويحمل رخصة واضحة، وتم التحقق منه من البداية إلى النهاية مقابل التنفيذ الأصلي — لا مقابل النموذج الخام فقط، لأن رسمًا يطابق الشبكة لكن لا يطابق التطبيع المحيط بها ينتج صوتًا يبدو جيدًا وهو خاطئ بصمت.
يوثّق ملف docs/not-shipped.md الخاص بالمشروع كل مرشّح قيّمه ورفضه، مع السبب المحدد، ما يجعله من أكثر الوثائق فائدة في المستودع لأنه يُظهر الحدود الفعلية لما يستطيع “ONNX خالص، وحدة معالجة مركزية فقط” فعله اليوم بدلًا من الادّعاء بها.
أخذات العينات التكرارية لا تملك رسمًا ثابتًا للتصدير. تُشغِّل نماذج الانتشار ومطابقة التدفق شبكة مرات عديدة لكل نطق، بحلقة طولها غير ثابت وقت التصدير. يقع AudioSR (خط أنابيب انتشار كامن بحجم نحو 6 غيغابايت مع VAE ومُرمِّز LDM ومُصوِّت منفصلين) وSGMSE ضمن هذه الفئة — حتى المتابعة البثّية الخاصة بـSGMSE لعام 2025 لا تصل إلى الزمن الحقيقي إلا على وحدة معالجة رسومات استهلاكية، ناهيك عن وحدة المعالجة المركزية.
الالتفافات المتغيّرة الموقع تبدو مُقصية لكنها ليست كذلك في الغالب. رُفض resemble-enhance طويلًا في هذه الوثيقة بسبب LVCNet، الالتفاف المتغيّر الموقع الخاص بالمُصوِّت، على نظرية أن النوى المُتنبَّأ بها لكل موضع عبر unfold وeinsum لا يمكن أن تُطوى في رسم ثابت. وباختباره مباشرةً، تبيّن أن ذلك خاطئ — كلتا العمليتين لهما مقابلات في ONNX. الفشل الفعلي خطأ تتبّع منفصل ومفهوم جيدًا (“تصدير ONNX للالتفاف بنواة مجهولة الشكل”) سبق حلّه في مكان آخر من قاعدة الشيفرة لأجل مُعيدات أخذ العينات في BigVGAN. ما يبقي resemble-enhance خارجًا الآن هو الحجم: أربع شبكات تتضمن أخذ عينات ODE لـCFM ومُرمِّزًا تلقائيًا، عند 44.1 كيلوهرتز — قرار نطاق، لا استحالة.
بعض النماذج لا تملك شيئًا مُدرَّبًا للتصدير. يُشحَن RNNoise كشيفرة C مكتوبة يدويًا، لا رسمًا في إطار قابل للتدريب — نقله يعني إعادة تدريب شبكة مكافئة من الصفر. تنشر Fast-ULCNet شيفرة البنية فقط، دون أي نقطة تفتيش على الإطلاق.
الرخصة المقيِّدة قرار توسيم، لا إقصاء تلقائي — وهذا بالضبط سبب شحن callenhancer وmetadenoiser. أما ما يُقصي فعلًا فهو أوزان منشورة دون أي رخصة على الإطلاق: رُفض mdctGAN لهذا السبب بالضبط، إضافةً إلى واجهة أمامية قائمة على torch.fft لا تُصدَّر بموثوقية.
استدعاء torch.stft داخل النموذج عائق بنيوي حقيقي. حلقة أخذ العينات في NU-Wave2 ليست المشكلة — يمكن لتلك أن تعمل بـnumpy خارج الرسم، بالطريقة نفسها التي يعمل بها STFT الخاص بكل محرك آخر. ما يعيقه هو أن أسلوبه forward يستدعي torch.stft وtorch.istft داخليًا، وهو ما تُبقيه المكتبة عمدًا خارج كل رسم تشحنه، وهو أيضًا المُعامِل الأقل موثوقية في التصدير عمومًا. إصلاحه يعني تقسيم النموذج عند حدود التحويل، إعادة هيكلة حقيقية لا مجرد استبدال مُعامِل.
إعادة إنتاج بنية نموذج ليست مثل إعادة إنتاج مخرجاته. يبلغ LiSenNet 56 ألف معامل، أقل من 300 كيلوبايت — وسيكون أصغر محرك في المكتبة. نسخته المنقولة إلى ONNX والمتاحة للعموم تعمل وتنتج صوتًا مخفَّفًا يبدو معقولًا، لكن مقيسًا من البداية للنهاية فهو يدمّر الإشارة: −10.8 ديسيبل من نسبة الإشارة إلى الضجيج عند إدخال بـ11 ديسيبل. إعادة إنتاج التنفيذ المرجعي الخاص بالنسخة نفسه بدقّة تعطي النتيجة السالبة نفسها بالضبط، ما يعني أن التنفيذ المرجعي نفسه لا يطابق الواجهة الأمامية التي يصفها توثيقه الخاص — لا يوجد هدف صحيح للتحقق منه بعد.
النمط عبر كل هذه هو أن الإخفاقات المثيرة نادرًا ما تكون “النموذج كبير جدًا” أو “الانتشار بطيء”. إنها محددة: مُعامِل غير مدعوم له بديل دقيق (torch.complex ليس له عملية في ONNX، لكن atan2(im, re) يحسب زاوية الطور نفسها)، أو مصفوفة مبنية من شكل وقت تشغيل مدخل لا يستطيع متتبّع تثبيته، أو تحويل موضوع على الجانب الخاطئ من حدود الرسم.
التأكد من أن المخرجات تحسّنت فعلًا
ملف ONNX يعمل ليس إثباتًا على تحسّن تسجيل. يبدو نمطا فشل مختلفان متطابقين من الخارج: مزيل ضوضاء يكتم الكلام مع الضجيج، وموسِّع نطاق ترددي يضيف نطاقًا عاليًا بمحتوى توافقي خاطئ، كلاهما ينتج صوتًا يعمل دون خطأ وقد يبدو حتى أنظف عند استماع عابر.
توجد المكتبة الشقيقة speechonnxmetrics لجعل ذلك الحكم قابلًا للقياس بدلًا من انطباعي. تقيّم الصوت على MOS (درجة الرأي المتوسط، تقييم من 1 إلى 5 للجودة المُدرَكة) بطريقتين: مُقدِّرات عصبية بلا مرجع مثل DNSMOS وUTMOS، تقيّم تسجيلًا دون أصل نظيف للمقارنة معه، ومقاييس تدخّلية مثل STOI وSI-SDR، تحتاج المرجع النظيف وتقيس مدى قرب المخرجات منه فعلًا.
import speechonnxmetrics as s
s.score("clean.wav", ["utmos"])
# -> {'utmos': 4.41}
s.score("denoised.wav", ["stoi", "si_sdr"], ref="clean.wav")
# -> {'stoi': 0.66, 'si_sdr': -26.9}
شغّلها قبل وبعد مزيل ضوضاء أو موسِّع نطاق ويظهر شكل مقارنة حقيقية: DNSMOS أو UTMOS على الصوت الخام والمُعالَج لمعرفة ما إذا تحرّكت الجودة المُدرَكة على الإطلاق، و — حين يوجد مرجع نظيف، وهو موجود لاختبارات الضجيج الاصطناعي لكن نادرًا لمكالمة هاتفية حقيقية — SI-SDR أو STOI لمعرفة ما إذا كانت الإشارة المُعالَجة قد اقتربت منه فعلًا لا أنها بدت مختلفة فقط. هذا هو الانضباط نفسه خلف أرقام نسبة الإشارة إلى الضجيج في جدول مزيلات الضوضاء أعلاه: رقم مرتبط بحالة ضجيج محدَّدة، لا صفة. العائلة الأوسع من مكتبات ONNX الخالصة التي يندرج هذا ضمنها، بما فيها speechonnxmetrics نفسها، مذكورة في عائلة من مكتبات الكلام القائمة على ONNX الخالص.
تنظيف الصوت قبل وصوله إلى أداة تعرّف، أو نظام تحديد هوية متحدث، أو مستمع بشري هو قطعة هندسية بذاتها، بسجل مقايضات خاص بها، وقائمة مناهج جُرِّبت ولم تنجُ من الاحتكاك بإشارة حقيقية.
للأسئلة حول تطبيق هذا على خط أنابيب محدَّد: تواصل معنا.