الصوت
درس 6 من 7
6الصوت
الصورة الكبيرةالصوت موجة: آلاف الأرقام في الثانية. النماذج لا تقرؤها خامًا عادة، بل تحوّلها إلى صورة اسمها الطيف الزمني الترددي، ثم تطبّق عليها نفس أدوات الرؤية. وفي العربية، أكبر تحدٍّ ليس التقنية بل البيانات: لهجات كثيرة، وتسجيلات قليلة.
ماذا تشاهد في الرسم: منحنى ميل يصعد بسرعة في الترددات المنخفضة ثم يتسطّح، أما الهرتز فخط مستقيم. هكذا يعطي النموذج دقة أكبر حيث يعيش الكلام، كما تميّز الأذن 100 من 200 هرتز ولا تكاد تميّز 7000 من 7100.
خارطة هذا الجزء
المفاهيم بالترتيب، اضغط أيًّا منها للقفز إليه:
طريقان إلى نفس الفكرة
الصوت موجة تهتز في الهواء. لكي يفهمه النموذج، نحوّله إلى صورة تشبه خريطة حرارية: الأفقي هو الزمن، والعمودي هو الطبقة من الغليظ إلى الحاد، واللون هو القوة. وبعدها يستطيع النموذج أن «يرى» الكلام. واللهجات العربية ما زالت تحديًا لكثير من النماذج.
تُؤخذ عيّنات الموجة بمعدل مثل 16 kHz، ثم تحويل فورييه قصير المدى STFT يعطي الطيف، ومقياس ميل mel يحاكي الأذن. نماذج التعرّف على الكلام مثل Whisper تحوّل الطيف إلى نص، وتقاس بمعدل خطأ الكلمات WER.
قبل أن تبدأ
🖼️الصورة كموتر
تعرف أن الصورة مصفوفة أرقام، فالطيف الزمني الترددي صورة للصوت تعمل عليها نفس الأدوات.
🧮المصفوفات مع NumPy
تقطع مصفوفة إلى نوافذ وتطبّق عملية على كل صف، مثل np.fft.rfft هنا.
الفكرة الجوهرية
الصوت موجة طويلة من الأرقام. تبدأ هنا بالموجة ومعدّل العيّنات، ثم الترددات، ثم الطيف الزمني الذي يحوّل الصوت إلى صورة، ثم مقياس ميل، ثم قياس التعرّف على الكلام.
1الموجة ومعدّل العيّنات
الميكروفون يقيس ضغط الهواء آلاف المرات في الثانية، فيعطي أرقامًا بين -1 و1. عدد القياسات في الثانية هو معدّل العيّنات.
انظر إلى الرسم: الكلام 16 ألفًا في الثانية، والموسيقى 44.1 ألفًا، والمكالمات الهاتفية 8 آلاف.
المعدّل يجب أن يطابق ما تدرّب عليه النموذج، وإلا سمع الصوت أسرع أو أبطأ. وثانية واحدة من الكلام 16000 رقم، وهذا طويل جدًا على النموذج ليقرأه خامًا.
2الترددات: تحويل فورييه
لنعرف ما في الصوت نسأل: أي الترددات يحتوي، وبأي قوة؟ تحويل فورييه السريع FFT يجيب عن هذا السؤال.
import numpy as np
rate = 16000
t = np.arange(rate) / rate
wave = 0.6 * np.sin(2 * np.pi * 440 * t) + 0.3 * np.sin(2 * np.pi * 1200 * t)
print("samples in one second:", len(wave))
spectrum = np.abs(np.fft.rfft(wave))
freqs = np.fft.rfftfreq(len(wave), d=1 / rate)
top = np.argsort(spectrum)[-2:]
print("strongest frequencies (Hz):", sorted(freqs[top].astype(int).tolist()))
صنعنا صوتًا من نغمتين، 440 هرتز (نغمة «لا») و1200 هرتز، ثم حلّلناه بتحويل فورييه السريع FFT. التحويل وجد الترددين بالضبط. الكلام أعقد بكثير من نغمتين، لكن الفكرة نفسها: كل صوت مجموع ترددات بأحجام مختلفة.
3الطيف الزمني: صورة الصوت
الكلام يتغيّر كل لحظة، فلا يكفي طيف واحد للملف كله. نقطّع الصوت إلى نوافذ قصيرة متتالية، ونحلّل كل نافذة وحدها.
انظر إلى الرسم: كل نافذة 25 ملّي ثانية تتقدّم 10 ملّي ثانية، وتصبح عمودًا من الترددات. النتيجة شبكة: الزمن في محور والتردد في الآخر.
نصف ثانية بنغمة 300 هرتز، ثم نصف ثانية بـ2000 هرتز. نقطع الصوت إلى نوافذ من 400 عيّنة (25 مللي ثانية) بخطوة 160 (10 مللي ثانية)، ونحلّل كل نافذة.
import numpy as np
rate = 16000
t = np.arange(rate) / rate
wave = np.where(t < 0.5, np.sin(2 * np.pi * 300 * t), np.sin(2 * np.pi * 2000 * t))
frame, hop = 400, 160
frames = np.stack([wave[i:i + frame] * np.hanning(frame) for i in range(0, len(wave) - frame, hop)])
spec = np.abs(np.fft.rfft(frames, axis=1))
freqs = np.fft.rfftfreq(frame, d=1 / rate)
print("spectrogram shape (time, freq):", spec.shape)
for i in [10, 40, 60, 90]:
print(f"frame {i:2} at {i * hop / rate:.2f}s -> peak {freqs[spec[i].argmax()]:.0f} Hz")
98 نافذة زمنية، و201 تردد في كل نافذة: صورة. قبل 0.5 ثانية القمة عند 320 هرتز، وبعدها عند 2000. لماذا 320 لا 300؟ لأن نافذة من 400 عيّنة تميّز الترددات بدقة 16000 / 400 = 40 هرتز فقط، فأقرب خانة لـ300 هي 320. نوافذ أطول تعطي دقة تردد أعلى ودقة زمن أقل، وهذه مقايضة لا مفرّ منها.
4مقياس ميل
الأذن تميّز الفروق في الترددات المنخفضة أفضل بكثير من العالية. مقياس ميل يضغط الترددات العالية ليشبه السمع البشري.
نماذج الكلام تستخدم عادةً 80 حزمة ميل، أقل بكثير من 201 تردد خام.
import numpy as np
def hz_to_mel(f):
return 2595 * np.log10(1 + f / 700)
for low, high in [(100, 200), (1000, 1100), (7000, 7100)]:
print(f"{low:5}-{high:5} Hz: {hz_to_mel(high) - hz_to_mel(low):6.1f} mel apart")
نفس الفرق 100 هرتز يساوي 133 ميل في الترددات المنخفضة و14.5 فقط عند 7000. الأذن تسمع الفرق بين 100 و200 هرتز بوضوح، ولا تكاد تميّز 7000 من 7100. نماذج الكلام تحاكي ذلك، فتخصّص دقة أكبر لما يهم في الكلام.
5التعرّف على الكلام ونسبة الخطأ
نادرًا ما تبني نموذج كلام من الصفر. Whisper وأمثاله تدرّبت على مئات آلاف الساعات، وعملك الحقيقي هو القياس.
المقياس هو نسبة خطأ الكلمات WER: الإضافات والحذوفات والاستبدالات مقسومة على عدد كلمات النص الصحيح.
هذا الكود يحتاج مكتبة transformers وتنزيل النموذج، فهو للقراءة هنا.
from transformers import pipeline
asr = pipeline("automatic-speech-recognition", model="openai/whisper-small")
result = asr("voice_note.wav", generate_kwargs={"language": "arabic"})
print(result["text"])
ثلاثة أسطر. حدّد اللغة صراحة، لأن النموذج إن ترك ليخمّن قد يكتب جملة عربية بحروف لاتينية أو يترجمها. ثم سجّل عشرين مقطعًا حقيقيًا من مستخدميك، واكتب نصّها الصحيح بيدك، واحسب نسبة خطأ الكلمات بمكتبة jiwer. هذا الرقم هو ما يقرّر هل النموذج صالح، لا العرض التوضيحي.
كيف يعمل، خطوة بخطوة: كيف يصير الصوت صورة يقرؤها النموذج
سجّل الموجة بمعدّل 16000 عيّنة في الثانية، وهو المعدّل الذي يتوقّعه أغلب نماذج الكلام.
قطّعها إلى نوافذ من 400 عيّنة (25 ms) تتقدّم 160 عيّنة (10 ms) كل مرة.
طبّق تحويل فورييه على كل نافذة، فتصير عمودًا من الترددات وتصير الثانية صورة 98 × 201.
اضغط الترددات إلى 80 حزمة ميل، فتصغر الصورة وتقترب من السمع البشري.
مثال محلول
الميكروفون يسجّل ضغط الهواء 16000 مرة في الثانية (16 كيلوهرتز، المعيار في التعرّف على الكلام). ثانية واحدة من الصوت هي 16000 رقم. ولكي نعرف ما في الصوت، نسأل: ما الترددات الموجودة فيه؟
librosa.resample أو torchaudio.functional.resample أولًا.
جرّب بلا كود
خرافة مقابل حقيقة
| الخرافة | الحقيقة |
|---|---|
| معدّل العيّنات لا يهم ما دام الملف يُفتح. | تسجيل بـ 8 أو 44.1 كيلوهرتز في نموذج 16 كيلوهرتز يُسمع مشوّهًا، والنص الناتج سيئ بلا رسالة خطأ. أعد أخذ العيّنات أولًا. |
| الطيف الزمني الترددي يزيل الضجيج. | الضجيج يبقى فيه. فائدته أنه أقصر بكثير من الموجة ويعرض الترددات التي تميّز الأصوات مباشرة. |
| رقم الخطأ على مقاطع الأخبار هو أداء النموذج. | مقاطع الأخبار فصحى واضحة بميكروفون جيد. الرقم الحقيقي هو معدّل خطأ الكلمات على تسجيلات تشبه ما يرسله مستخدموك، بلهجاتهم وضجيجهم. |
جرّب بنفسك
نافذة من 512 عيّنة على صوت بمعدّل 16000. ما دقة التمييز بين الترددات تقريبًا؟
16000 / 512 ≈ 31 هرتز بين كل خانتي تردد. نافذة أطول تعطي دقة تردد أفضل، لكنها تغطّي زمنًا أطول (32 مللي ثانية هنا) فتطمس الأحداث السريعة.
لماذا تحوّل نماذج الكلام الصوت إلى طيف ميل بدل استخدام الموجة الخام مباشرة غالبًا؟
ثانية واحدة 16000 رقم كموجة، و100 عمود في 80 نطاقًا كطيف ميل. والأصوات الكلامية تتميّز بتردداتها، فالطيف يقدّم المعلومة جاهزة بدل أن يكتشف النموذج تحويل فورييه بنفسه. الضجيج يبقى في الطيف، ولا يُحذف تلقائيًا.
بطاقات مراجعة سريعة
تحقق من فهمك
نموذج كلام حصل على نسبة خطأ 8% على مقاطع أخبار، و35% على رسائل صوتية من مستخدمين. ما التفسيرات المحتملة، وماذا تفعل؟
المقاطع الإخبارية فصحى واضحة بميكروفون جيد، والرسائل الصوتية لهجات وضجيج وكلام سريع وكلمات إنجليزية مخلوطة. افعل: قسّم الأخطاء لترى أيها الأكثر (لهجة؟ ضجيج؟ أسماء؟)، وجرّب نموذجًا أكبر أو نموذجًا مضبوطًا على لهجتك، وأضف قائمة الأسماء الشائعة كتلميح، واعرف أن الضبط على ساعات قليلة من تسجيلاتك قد يخفض الخطأ كثيرًا. والأهم: 35% هو رقمك الحقيقي، لا 8%.
في الطيف اليدوي ظهرت قمة 300 هرتز عند 320. لماذا؟
لأن نافذة من 400 عيّنة على 16000 هرتز تفصل الترددات كل 40 هرتز فقط، وأقرب خانة إلى 300 هي 320. نافذة أطول تفصل أدق لكنها تغطّي زمنًا أطول.
مصادر هذا الدرس
مرتّبة بالنوع. ابدأ بالتوثيق الرسمي إذا تبي المرجع الدقيق، وبالمقال أو الفيديو إذا تبي الشرح أولًا.
خلّصت الدرس؟
سجّل الدخول ليُحفظ تقدّمك.