فصل المصادر
يقسّم Open-Unmix HQ مقطعًا موسيقيًا ستيريو إلى أربع طبقات مستقلّة — vocals وdrums وbass وother. تنتج أربعة نماذج BiLSTM مستقلّة (واحد لكل طبقة) أقنعة بمقدار فوق STFT الخلطة؛ ويعمل مرشّح Wiener اللاحق الاختياري على التوفيق بينها. يعمل النموذج على Apple Silicon عبر MLX.
ما هو
- 4 طبقات لكل مقطع — vocals وdrums وbass وother. كل ملف طبقة بقناتين بمعدّل 44.1 كيلوهرتز.
- نموذج إخفاء بمقدار — يتنبأ كل نموذج طبقة بقناع غير سالب يُطبّق على طيف الخلطة، ويُؤخذ الطور من الخلطة.
- مرشّح Wiener اللاحق (اختياري) — تنقيح بقناع ناعم عبر الطبقات الأربع كي تتجمّع بترابط لتعطي الخلطة. يضيف نحو 0.5 ديسيبل من SDR.
- بصمة صغيرة — 8.9 مليون معامِل لكل طبقة، ~136 ميغابايت إجمالًا للطبقات الأربع.
- Apache-2.0 — الأوزان الأصلية تحت رخصة MIT، وتحويلنا إلى CoreML/MLX تحت Apache-2.0.
المعمارية
أربع طبقات مستقلّة، كلٌّ منها نسخة من الشبكة نفسها:
| المرحلة | الشكل / العملية |
|---|---|
| STFT | FFT بـ 4096 نقطة، قفزة 1024، نافذة Hann دورية مع reflect-pad. 2049 حزمة تردّد لكل إطار. |
| تطبيع الدخل | قصّ إلى 1487 حزمة (≈16 كيلوهرتز)، وتطبيق متوسّط ومقياس مكتسبَين لكل حزمة من التدريب. |
| المُرمِّز | Linear 2974 → 512 + BatchNorm + tanh. الدخل قناتان × 1487 حزمة. |
| BiLSTM | 3 طبقات، 256 وحدة مخفية لكل اتجاه (512 فعليًا). يلتقط السياق الزمني عبر الإطارات. |
| المُفكِّك | دمج تخطّي (Skip-concat) لمخرجات المُرمِّز وLSTM (1024) → Linear 1024 → 512 + BN + ReLU → Linear 512 → 4098. |
| إلغاء تطبيع المخرج + قناع | ضرب عنصري بمقدار الخلطة، طور من الخلطة، ثم iSTFT بتراكب وإضافة. |
| Wiener (اختياري) | أقنعة نسبة قدرة عبر تقديرات الطبقات الأربع. يحسّن الطور حتى تتجمّع الطبقات لتعطي الخلطة. |
النموذج
| المكوّن | القيمة |
|---|---|
| المعامِلات لكل طبقة | 8.9 مليون |
| إجمالي المعامِلات (4 طبقات) | ~35.6 مليون |
| معدّل العيّنات | 44.1 كيلوهرتز ستيريو |
| زمن استجابة القطعة | دون اتصال (STFT للمقطع كاملًا) |
| الأوزان | aufklarer/OpenUnmix-HQ-MLX (safetensors، ~136 ميغابايت) |
| المصدر الأصلي | sigsep/open-unmix-pytorch (Stöter et al., JOSS 2019) |
بداية سريعة — Swift
import SourceSeparation
import AudioCommon
let separator = try await SourceSeparator.fromPretrained()
let stereo = try AudioFileLoader.loadStereo(
url: URL(fileURLWithPath: "song.wav"),
targetSampleRate: 44100
)
let stems = separator.separate(audio: stereo, sampleRate: 44100)
// stems[.vocals], stems[.drums], stems[.bass], stems[.other]
// Each is [[Float]] — left channel, right channel.
try WAVWriter.writeStereo(
left: stems[.vocals]![0],
right: stems[.vocals]![1],
sampleRate: 44100,
to: URL(fileURLWithPath: "vocals.wav")
)
مرّر wiener: true (الافتراضي) للحصول على أفضل جودة. مرّر targets: [.vocals] لاستخراج مجموعة فرعية من الطبقات فقط وتخطّي بقيّة النماذج.
CLI
speech separate song.wav # all 4 stems into song_stems/
speech separate song.wav --stems vocals # vocals only
speech separate song.wav --stems vocals,drums # subset
speech separate song.wav --output-dir /tmp/stems/ # custom output dir
speech separate song.wav --verbose # show timing
متى تستخدمه
…تحتاج إلى تمريرة فصل مصادر خفيفة دون اتصال داخل تطبيق أو خط أنابيب على Apple Silicon. تُبقي 8.9 مليون معامِل لكل طبقة حجم التنزيل والذاكرة معتدلَين. يعطي الإخفاء بمقدار مع Wiener طبقات جيّدة في معظم محتوى البوب والروك. أمّا لعزل صوتي بمستوى الاستوديو على المحتوى الاستوديوي، فستلجأ إلى نموذج أكبر من فئة Demucs/MDX-Net؛ تستهدف هذه الحزمة الجانب العملي القابل للشحن داخل تطبيقك من هذه المقايضة.