دسته بندی صدا با استفاده از Deep Learning

مقدمه
تصاویر و صداها دو مورد از رایج‌ترین اطلاعاتی هستند که انسان‌ها درک می‌کنند. برای بیشتر افراد، تحلیل و درک این حواس به‌صورت شهودی کار ساده‌ای است. همان‌طور که پردازش زبان طبیعی (NLP) برای انسان‌ها آسان است، برای ماشین‌ها این‌طور نبوده و در گذشته نتایج مطلوبی حاصل نمی‌شد. اما با ظهور و پیشرفت مدل‌های یادگیری عمیق در دهه گذشته، امکان انجام محاسبات پیچیده و حل پروژه‌های دشوار با دقت بالاتر فراهم شده است.
در این مقاله و مقالات آینده، بررسی خواهیم کرد که چگونه مدل‌های یادگیری عمیق برای حل وظایف طبقه‌بندی صوت و حتی تولید موسیقی استفاده می‌شوند. تمرکز اصلی این مقاله بر روی پروژه طبقه‌بندی صوت خواهد بود و تلاش می‌کنیم با استفاده از معماری‌های ساده، به نتایج مطلوبی دست یابیم.
طبقه‌بندی صوت چیست؟
طبقه‌بندی صوت فرایندی است که طی آن، هر نوع صدا، نویز، نت‌های موسیقی یا هر داده صوتی مشابه، تحلیل و شناسایی شده و در دسته‌بندی‌های مناسب قرار می‌گیرد. داده‌های صوتی می‌توانند اشکال متنوعی داشته باشند، مانند:
• صداهای حاصل از دستگاه‌های صوتی
• آکوردهای موسیقی از سازها
• گفتار انسان
• صداهای طبیعی مانند آواز پرندگان
تکنیک‌های مدرن یادگیری عمیق به ما این امکان را می‌دهند که به نتایج پیشرفته‌ای در پردازش سیگنال‌های صوتی دست پیدا کنیم.
پیش‌نیازها
هدف اصلی این مقاله، درک کامل پروژه طبقه‌بندی صوت و یادگیری مفاهیم اساسی پردازش سیگنال است. همچنین برخی از بهترین روش‌های موجود برای دستیابی به نتایج مطلوب را بررسی خواهیم کرد.
قبل از ورود به محتوای مقاله، توصیه می‌شود که با فریمورک‌های یادگیری عمیق و برخی مفاهیم پایه‌ای دیگر آشنا شوید. حال، اجازه دهید برخی از مفاهیم اساسی طبقه‌بندی صوت را بررسی کنیم.
مفاهیم اولیه در طبقه‌بندی صوت
در این بخش، به بررسی برخی از اصطلاحات کلیدی که برای درک طبقه‌بندی صوت با یادگیری عمیق ضروری هستند، خواهیم پرداخت. این مفاهیم نقش مهمی در انجام پروژه‌های پردازش صوت دارند. بیایید برخی از این مفاهیم کلیدی را به‌طور خلاصه تحلیل کنیم.
موج صوتی
قبل از اینکه موج صوتی و پارامترهای مختلف آن را بررسی کنیم، باید بفهمیم که صدا چیست. صدا، ارتعاشاتی است که یک جسم تولید می‌کند و باعث نوسان ذرات هوا در اطراف آن می‌شود. تغییرات مربوط به فشار هوا این امواج صوتی را ایجاد می‌کنند. صدا یک موج مکانیکی است که در آن انرژی از یک منبع به منبع دیگر منتقل می‌شود.
موج صوتی یک نمایش شماتیک است که به ما کمک می‌کند تا جابه‌جایی امواج صوتی را در طول زمان، همراه با سایر پارامترهای ضروری برای یک وظیفه خاص، تحلیل کنیم.
از سوی دیگر، فرکانس در یک موج صوتی نشان‌دهنده تعداد دفعاتی است که موج در یک بازه زمانی یک‌ثانیه‌ای تکرار می‌شود. نقطه اوج موج که در بالاترین قسمت آن قرار دارد، قله نامیده می‌شود، در حالی که پایین‌ترین نقطه موج دره نام دارد.
دامنه، فاصله از خط مرکزی تا بالای یک قله یا پایین یک دره است.
با درک مختصری از این مفاهیم اساسی، می‌توانیم به بررسی سایر موضوعات ضروری برای طبقه‌بندی صوت بپردازیم.
طیف‌نگار
طیف‌نگارها
طیف‌نگارها نمایش‌های بصری از طیف فرکانس‌های موجود در یک سیگنال صوتی هستند. اصطلاحات فنی دیگر برای طیف‌نگار شامل سونُوگراف، ویس‌پرینت (voiceprint) یا ویس‌گرام (voicegram) است. طیف‌نگارها به‌طور گسترده‌ای در زمینه‌هایی مانند پردازش سیگنال، تولید موسیقی، طبقه‌بندی صوتی، تحلیل زبان‌شناختی، تشخیص گفتار و بسیاری کاربردهای دیگر استفاده می‌شوند. در این مقاله نیز از طیف‌نگارها برای وظیفه طبقه‌بندی صوتی استفاده خواهیم کرد. برای اطلاعات بیشتر در مورد این موضوع، پیشنهاد می‌شود به لینک زیر مراجعه کنید.
پردازش سیگنال صوتی
پردازش سیگنال صوتی شاخه‌ای از علم است که به بررسی سیگنال‌های صوتی، امواج صوتی و دستکاری فرکانس‌های صوتی می‌پردازد. در حوزه یادگیری عمیق برای پردازش سیگنال صوتی، کاربردهای متعددی وجود دارد که می‌توان روی آن‌ها کار کرد.
در این مقاله، ما موضوع طبقه‌بندی صوتی را با جزئیات بیشتری پوشش خواهیم داد. برخی دیگر از کاربردهای مهم شامل تشخیص گفتار، کاهش نویز صوتی، بازیابی اطلاعات صوتی، تولید موسیقی و بسیاری موارد دیگر هستند. ترکیب یادگیری عمیق با پردازش سیگنال صوتی امکانات بی‌شماری را به وجود آورده است که ارزش بررسی و تحقیق دارد.
درک پروژه طبقه‌بندی صوتی
حال، پیش از آنکه به پیاده‌سازی طبقه‌بندی صوتی از ابتدا بپردازیم، بیایید این پروژه را بهتر درک کنیم.
درک پروژه طبقه‌بندی صوتی
طبقه‌بندی صوتی یکی از بهترین پروژه‌های مقدماتی برای شروع یادگیری عمیق صوتی است. هدف از این پروژه درک شکل‌موج‌ها (waveforms) در قالب خام و تبدیل داده‌های موجود به شکلی است که برای توسعه‌دهندگان قابل استفاده باشد. با تبدیل شکل‌موج خام داده‌های صوتی به صورت اسپکتروگرام، می‌توان آن‌ها را از طریق مدل‌های یادگیری عمیق ارسال کرد تا داده‌ها تحلیل و تفسیر شوند. در طبقه‌بندی صوتی، معمولاً طبقه‌بندی دودویی انجام می‌دهیم که در آن تعیین می‌کنیم که آیا سیگنال ورودی صدای دلخواه ما است یا خیر.
در این پروژه، هدف ما بازیابی صدای وارد شده از یک پرنده است. سیگنال نویز وارد شده به شکل‌موج تبدیل می‌شود که می‌توانیم برای پردازش و تحلیل بیشتر از آن استفاده کنیم، با کمک فریم‌ورک یادگیری عمیق TensorFlow. پس از موفقیت‌آمیز بودن دریافت شکل‌موج، می‌توانیم آن را به اسپکتروگرام تبدیل کنیم که یک نمایش بصری از شکل‌موج موجود است. از آنجایی که این اسپکتروگرام‌ها تصاویر بصری هستند، می‌توانیم از شبکه‌های عصبی کانولوشنی (CNN) برای تحلیل آن‌ها استفاده کنیم و مدل یادگیری عمیق را برای انجام یک نتیجه طبقه‌بندی دودویی ایجاد کنیم.
پیاده‌سازی پروژه طبقه‌بندی و شناسایی صوتی با یادگیری عمیق
همانطور که قبلاً بحث کردیم، هدف پروژه ما خواندن صداهای وارد شده از جنگل و تفسیر این که آیا داده‌های دریافتی مربوط به یک پرنده خاص (پرنده کاپوچین) است یا خیر، یا این که نویز دیگری است که ما علاقه‌ای به شناسایی آن نداریم. برای ساخت این پروژه، از فریم‌ورک‌های یادگیری عمیق TensorFlow و Keras استفاده خواهیم کرد.
نصب اضافی دیگری که برای این پروژه لازم است، کتابخانه TensorFlow-io است که به ما امکان دسترسی به سیستم‌ فایل‌ها و فرمت‌های فایل‌هایی که در پشتیبانی داخلی TensorFlow موجود نیست، می‌دهد. دستور pip زیر برای نصب این کتابخانه در محیط کاری شما استفاده می‌شود:
pip install tensorflow-io[tensorflow]
وارد کردن کتابخانه‌های ضروری
در گام بعدی، تمام کتابخانه‌های ضروری که برای ساخت پروژه نیاز داریم را وارد خواهیم کرد. برای این پروژه از مدل نوع Sequential استفاده می‌کنیم که به ما اجازه می‌دهد یک شبکه عصبی کانولوشنی ساده بسازیم تا اسپکتروگرام‌های تولید شده را تحلیل کرده و نتیجه مطلوبی بدست آوریم. از آنجایی که معماری مدل توسعه یافته بسیار ساده است، نیاز به استفاده از API مدل عملکردی یا قابلیت مدل‌سازی سفارشی نداریم.
ما از لایه‌های کانولوشنی برای معماری استفاده خواهیم کرد و همچنین از لایه‌های Dense و Flatten. همانطور که قبلاً اشاره کردیم، از کتابخانه ورودی/خروجی TensorFlow برای مدیریت تعداد زیادی از سیستم‌ فایل‌ها و فرمت‌ها مانند فرمت‌های .wav و .mp3 استفاده خواهیم کرد. وارد کردن کتابخانه سیستم‌عامل به ما کمک می‌کند تا به تمام فایل‌های مورد نیاز در فرمت‌های مربوطه دسترسی داشته باشیم:
import tensorflow as tf 
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Conv2D, Dense, Flatten
import tensorflow_io as tfio
from matplotlib import pyplot as plt
import os
بارگذاری دیتاست
دیتاست این پروژه از چالش Kaggle برای پردازش سیگنال – Z توسط HP Unlocked Challenge 3 در دسترس است که می‌توانید آن را از این لینک دانلود کنید.
برای دانلود داده‌ها:
1. یک حساب کاربری Kaggle بسازید.
2. یک توکن API ایجاد کنید و فایل kaggle.json را ذخیره کنید. (توجه: ممکن است نیاز به ایجاد یک توکن API جدید داشته باشید اگر قبلاً ایجاد کرده‌اید.)
3. فایل kaggle.json را به نوت‌بوک Jupyter خود آپلود کنید.
4. یا سلول زیر را اجرا کنید یا دستورات زیر را در ترمینال اجرا کنید (این ممکن است مدتی طول بکشد).
ترمینال:
mv kaggle.json ~/.kaggle/
pip install kaggle
kaggle datasets download kenjee/z-by-hp-unlocked-challenge-3-signal-processing
unzip z-by-hp-unlocked-challenge-3-signal-processing.zip
سلول:
!mv kaggle.json ~/.kaggle/
!pip install kaggle
!kaggle datasets download kenjee/z-by-hp-unlocked-challenge-3-signal-processing
!unzip z-by-hp-unlocked-challenge-3-signal-processing.zip
پس از دانلود و استخراج دیتاست، سه پوشه در پوشه داده مشاهده می‌کنیم. سه پوشه به شرح زیر است:
1. ضبط‌های جنگلی که یک کلیپ سه دقیقه‌ای از صداهای تولید شده در جنگل هستند.
2. کلیپ‌های سه ثانیه‌ای از ضبط‌های صدای پرنده کاپوچین.
3. کلیپ‌های سه ثانیه‌ای از ضبط‌های صداهایی که توسط پرنده کاپوچین تولید نشده‌اند.
در قطعه کد بعدی، متغیرهایی برای تنظیم مسیر این پوشه‌ها تعریف خواهیم کرد:
CAPUCHIN_FILE = os.path.join(‘data’, ‘Parsed_Capuchinbird_Clips’, ‘XC3776-3.wav’)
NOT_CAPUCHIN_FILE = os.path.join(‘data’, ‘Parsed_Not_Capuchinbird_Clips’, ‘afternoon-birds-song-in-forest-0.wav’)
در گام بعدی، ما تابع بارگذاری داده‌ها را تعریف خواهیم کرد که برای ایجاد شکل‌موج‌های مورد نیاز در فرمت دلخواه برای محاسبات بعدی مفید خواهد بود. تابع تعریف‌شده در قطعه کد زیر به ما این امکان را می‌دهد که داده‌ها را بخوانیم و آن‌ها را به حالت مونو (یا تک‌کاناله) تبدیل کنیم تا تحلیل راحت‌تری انجام دهیم. همچنین فرکانس سیگنال‌ها را تغییر می‌دهیم تا بتوانیم دامنه کلی را تغییر دهیم و نمونه‌های داده‌ای کوچک‌تری برای تحلیل کلی به‌دست آوریم.
def load_wav_16k_mono(filename):
    # Load encoded wav file
    file_contents = tf.io.read_file(filename)
    # Decode wav (tensors by channels)
    wav, sample_rate = tf.audio.decode_wav(file_contents, desired_channels=1)
    # Removes trailing axis
    wav = tf.squeeze(wav, axis=-1)
    sample_rate = tf.cast(sample_rate, dtype=tf.int64)
    # Goes from 44100Hz to 16000hz – amplitude of the audio signal
    wav = tfio.audio.resample(wav, rate_in=sample_rate, rate_out=16000)
    return wav
تصویر بالا نمای بصری از شکل‌موج‌های سیگنال‌های Capuchin و Non-Capuchin را نشان می‌دهد.
آماده‌سازی دیتاست
در این بخش از مقاله، مسیرهای مثبت و منفی برای کلیپ‌های پرنده کاپوچین را تعریف خواهیم کرد. متغیرهای مسیر مثبت، مسیر پوشه‌ای که شامل ضبط‌های صوتی پرنده کاپوچین است را ذخیره می‌کنند، در حالی که مسیرهای منفی در یک متغیر دیگر ذخیره می‌شوند. سپس فایل‌ها در این پوشه‌ها را به فرمت‌های .wav لینک کرده و برچسب‌های مربوطه را اضافه خواهیم کرد. این برچسب‌ها در قالب طبقه‌بندی دودویی هستند و به‌صورت ۰ یا ۱ برچسب‌گذاری می‌شوند. برچسب‌های مثبت به مقدار ۱ اختصاص داده می‌شوند که به این معنی است که کلیپ شامل سیگنال صوتی از پرنده کاپوچین است. برچسب‌های منفی با صفرها نشان می‌دهند که سیگنال‌های صوتی نویز تصادفی هستند و شامل ضبط‌های صوتی پرنده کاپوچین نیستند.
# Defining the positive and negative paths
POS = os.path.join(‘data’, ‘Parsed_Capuchinbird_Clips/*.wav’)
NEG = os.path.join(‘data’, ‘Parsed_Not_Capuchinbird_Clips/*.wav’)
# Creating the Datasets
pos = tf.data.Dataset.list_files(POS)
neg = tf.data.Dataset.list_files(NEG)
# Adding labels
positives = tf.data.Dataset.zip((pos, tf.data.Dataset.from_tensor_slices(tf.ones(len(pos)))))
negatives = tf.data.Dataset.zip((neg, tf.data.Dataset.from_tensor_slices(tf.zeros(len(neg)))))
data = positives.concatenate(negatives)
همچنین می‌توانیم طول موج میانگین صدای پرنده کاپوچین را تحلیل کنیم، همانطور که در قطعه کد زیر نشان داده شده است، با بارگذاری پوشه نمونه‌های مثبت و استفاده از تابع بارگذاری داده‌ای که قبلاً ایجاد کردیم.
# Analyzing the average wavelength of a Capuchin bird
lengths = []
for file in os.listdir(os.path.join(‘data’, ‘Parsed_Capuchinbird_Clips’)):
    tensor_wave = load_wav_16k_mono(os.path.join(‘data’, ‘Parsed_Capuchinbird_Clips’, file))
    lengths.append(len(tensor_wave))
# The minimum, mean, and maximum wave length cycles are provided below.
<tf.Tensor: shape=(), dtype=int32, numpy=32000>
<tf.Tensor: shape=(), dtype=int32, numpy=54156>
<tf.Tensor: shape=(), dtype=int32, numpy=80000>
تبدیل داده‌ها به اسپکتروگرام‌ها
در گام بعدی، تابعی برای انجام پیش‌پردازش‌های لازم برای تحلیل صوتی ایجاد خواهیم کرد. ما شکل‌موج‌هایی که قبلاً دریافت کرده‌ایم را به صورت اسپکتروگرام تبدیل خواهیم کرد. این سیگنال‌های صوتی بصری‌شده در قالب اسپکتروگرام‌ها توسط مدل یادگیری عمیق ما در مراحل بعدی برای تحلیل و تفسیر نتایج استفاده خواهند شد. در قطعه کد زیر، تمام شکل‌موج‌ها را دریافت کرده و تبدیل فوریه کوتاه‌مدت سیگنال‌ها را با استفاده از کتابخانه TensorFlow محاسبه می‌کنیم تا یک نمایش بصری به‌دست آوریم، همانطور که در تصویر زیر نشان داده شده است.
def preprocess(file_path, label): 
    for i in os.listdir(file_path):
        i = file_path.decode() + “/” + i.decode()
        wav = load_wav_16k_mono(i)
        wav = wav[:48000]
        zero_padding = tf.zeros([48000] – tf.shape(wav), dtype=tf.float32)
        wav = tf.concat([zero_padding, wav], 0)
        spectrogram = tf.signal.stft(wav, frame_length=320, frame_step=32)
        spectrogram = tf.abs(spectrogram)
        spectrogram = tf.expand_dims(spectrogram, axis=2)
        return spectrogram, label
filepath, label = positives.shuffle(buffer_size=10000).as_numpy_iterator().next()
spectrogram, label = preprocess(filepath, label)
ساخت مدل یادگیری عمیق
پیش از شروع به ساخت مدل یادگیری عمیق، ابتدا باید یک پایپ‌لاین داده ایجاد کنیم و داده‌ها را بارگذاری کنیم. ما داده‌های اسپکتروگرام را که از مرحله پیش‌پردازش به دست آمده‌اند، بارگذاری خواهیم کرد. می‌توانیم این داده‌ها را با استفاده از قابلیت‌های داخلی TensorFlow کش و شافل کنیم و همچنین یک اندازه بچ ۱۶ برای بارگذاری داده‌ها تعیین کنیم. قبل از اینکه به ساخت مدل یادگیری عمیق بپردازیم، می‌توانیم مجموعه داده‌ها را به نمونه‌های آموزشی و آزمایشی تقسیم کنیم، همان‌طور که در قطعه کد زیر نشان داده شده است:
# ایجاد پایپ‌لاین داده در TensorFlow
data = data.map(preprocess)
data = data.cache()
data = data.shuffle(buffer_size=1000)
data = data.batch(16)
data = data.prefetch(8)
# تقسیم به مجموعه‌های آموزشی و آزمایشی
train = data.take(36)
test = data.skip(36).take(15)
ساخت مدل یادگیری عمیق
در مرحله بعد، یک مدل از نوع Sequential خواهیم ساخت. می‌توان معماری مدل را با استفاده از API تابعی یا الگوی مدل سفارشی توسعه داد. سپس لایه‌های کانولوشنی را با شکل مناسب برای برچسب نمونه اضافه می‌کنیم تا دو بلوک از لایه‌های کانولوشنی با ۱۶ فیلتر و اندازه کرنل (۳,۳) ایجاد شود. در ساخت این لایه‌های کانولوشنی از تابع فعال‌سازی ReLU استفاده شده است. سپس، خروجی حاصل از لایه‌های کانولوشنی را فلت می‌کنیم تا برای پردازش‌های بعدی مناسب باشد. در نهایت، لایه‌های کاملاً متصل را با تابع فعال‌سازی Sigmoid اضافه می‌کنیم که دارای یک نود خروجی برای انجام طبقه‌بندی دودویی خواهد بود. قطعه کد و خلاصه مدل ساخته‌شده در زیر آورده شده است:
model = Sequential()
model.add(Conv2D(16, (3,3), activation=’relu’, input_shape=(1491, 257,1)))
model.add(Conv2D(16, (3,3), activation=’relu’))
model.add(Flatten())
# model.add(Dense(128, activation=’relu’))
model.add(Dense(1, activation=’sigmoid’))
model.summary()
خلاصه مدل ساخته‌شده:
Model: “sequential”
_________________________________________________________________
 Layer (type)                Output Shape              Param #   
=================================================================
 conv2d (Conv2D)             (None, 1489, 255, 16)     160       
 conv2d_1 (Conv2D)           (None, 1487, 253, 16)     2320      
 flatten (Flatten)           (None, 6019376)           0         
 dense (Dense)               (None, 1)                 6019377   
=================================================================
Total params: 6,021,857
Trainable params: 6,021,857
Non-trainable params: 0
_________________________________________________________________
کامپایل و آموزش مدل
پس از تکمیل معماری مدل، می‌توانیم آن را کامپایل کرده و آموزش دهیم. برای کامپایل مدل، از بهینه‌ساز Adam، تابع هزینه Binary Crossentropy برای طبقه‌بندی دودویی و همچنین معیارهای دقت و یادآوری برای تحلیل مدل استفاده خواهیم کرد. سپس مدل را با داده‌های آموزشی که قبلاً ساخته‌ایم، آموزش می‌دهیم و آن را برای چندین دوره آموزشی (epochs) با داده‌های آزمایشی اعتبارسنجی می‌کنیم. قطعه کد و نتایج این مرحله در زیر آمده است:
# کامپایل و تنظیم مدل
model.compile(‘Adam’, loss=’BinaryCrossentropy’, metrics=[tf.keras.metrics.Recall(), tf.keras.metrics.Precision()])
# آموزش مدل
model.fit(train, epochs=4, validation_data=test)
خروجی فرآیند آموزش:
Epoch 1/4
36/36 [==============================] – 204s 6s/step – loss: 1.6965 – recall: 0.8367 – precision: 0.8483 – val_loss: 0.0860 – val_recall: 0.9254 – val_precision: 0.9688
Epoch 2/4
36/36 [==============================] – 200s 6s/step – loss: 0.0494 – recall: 0.9477 – precision: 0.9932 – val_loss: 0.0365 – val_recall: 1.0000 – val_precision: 0.9846
Epoch 3/4
36/36 [==============================] – 201s 6s/step – loss: 0.0314 – recall: 0.9933 – precision: 0.9801 – val_loss: 0.0228 – val_recall: 0.9821 – val_precision: 1.0000
Epoch 4/4
36/36 [==============================] – 201s 6s/step – loss: 0.0126 – recall: 0.9870 – precision: 1.0000 – val_loss: 0.0054 – val_recall: 1.0000 – val_precision: 0.9861
تحلیل و ارزیابی مدل
پس از ساخت و آموزش موفقیت‌آمیز مدل، می‌توانیم نتایج را تحلیل و اعتبارسنجی کنیم. معیارهای به‌دست‌آمده نشان‌دهنده پیشرفت خوبی در عملکرد مدل هستند. بنابراین، می‌توان مدل ساخته‌شده را برای انجام پیش‌بینی‌های نسبتاً موفق در مورد صدای پرندگان کاپوچین و شناسایی فرکانس نویز آن‌ها مناسب دانست. در بخش بعدی، به مراحل مربوط به این فرآیند خواهیم پرداخت.
انجام پیش‌بینی‌های مورد نیاز
در مرحله نهایی این پروژه، نحوه انجام پیش‌بینی‌های مناسب روی تمام فایل‌های موجود در ضبط‌های جنگلی را بررسی خواهیم کرد. اما قبل از آن، نحوه پیش‌بینی در یک دسته (batch) واحد را در کد زیر مشاهده می‌کنیم.
# پیش‌بینی برای یک دسته
X_test, y_test = test.as_numpy_iterator().next()
yhat = model.predict(X_test)
# تبدیل مقادیر خروجی به کلاس‌های دودویی
yhat = [1 if prediction > 0.5 else 0 for prediction in yhat]
اکنون که نحوه انجام پیش‌بینی برای یک دسته را بررسی کردیم، باید بدانیم که چگونه می‌توان پیش‌بینی‌ها را روی تمام فایل‌های موجود در دایرکتوری ضبط‌های جنگلی انجام داد. هر کلیپ در این مجموعه حدود سه دقیقه طول دارد. از آنجایی که پیش‌بینی‌های ما روی کلیپ‌های سه‌ثانیه‌ای انجام می‌شود، این کلیپ‌های طولانی‌تر را به طیف‌های پنجره‌ای تقسیم می‌کنیم.
ما می‌توانیم کلیپ‌های سه‌دقیقه‌ای (۱۸۰ ثانیه) را به ۶۰ قطعه کوچکتر تقسیم کرده و تعداد کل فراخوان‌های پرنده Capuchin را در این بخش شناسایی کنیم. هر کلیپ در اینجا مقدار ۰ یا ۱ خواهد داشت. پس از تعیین تعداد صداها برای هر طیف پنجره‌ای، می‌توانیم تعداد کل دفعات شنیده شدن صدای پرنده را در کل کلیپ محاسبه کنیم. این تعداد کل دفعات، مشخص می‌کند که صدای پرنده Capuchin چند بار در طول فایل صوتی شنیده شده است.
در قطعه کد زیر، اولین تابع مورد نیاز برای این عملیات را می‌سازیم. این تابع مشابه عملکردی است که در بخش قبل مورد بحث قرار گرفت، اما این بار کلیپ‌های ضبط‌شده را که در فرمت MP3 هستند (به جای WAV) پردازش می‌کند. این تابع فایل MP3 را ورودی گرفته و آن را به یک تنسور (Tensor) تبدیل می‌کند. سپس میانگین مقدار ورودی چندکاناله را محاسبه کرده و آن را به یک کانال مونو (Mono) تبدیل می‌کند تا سیگنال صوتی با فرکانس موردنظر به دست آید.
def load_mp3_16k_mono(filename):
    “”” بارگذاری یک فایل صوتی، تبدیل آن به یک تنسور عددی، بازنمونه‌برداری به ۱۶ کیلوهرتز و تبدیل به صدای تک‌کاناله. “””
    res = tfio.audio.AudioIOTensor(filename)
    # تبدیل به تنسور و ادغام کانال‌ها
    tensor = res.to_tensor()
    tensor = tf.math.reduce_sum(tensor, axis=1) / 2 
    # استخراج نرخ نمونه‌برداری و تبدیل آن
    sample_rate = res.rate
    sample_rate = tf.cast(sample_rate, dtype=tf.int64)
    # بازنمونه‌برداری به ۱۶ کیلوهرتز
    wav = tfio.audio.resample(tensor, rate_in=sample_rate, rate_out=16000)
    return wav
mp3 = os.path.join(‘data’, ‘Forest Recordings’, ‘recording_00.mp3’)
wav = load_mp3_16k_mono(mp3)
audio_slices = tf.keras.utils.timeseries_dataset_from_array(wav, wav, sequence_length=48000, sequence_stride=48000, batch_size=1)
samples, index = audio_slices.as_numpy_iterator().next()
در قطعه کد بعدی، تابعی را ایجاد می‌کنیم که به ما کمک می‌کند تا قطعات صوتی را به طیف‌نگارهای پنجره‌ای (Windowed Spectrograms) تبدیل کنیم تا پردازش‌های بعدی انجام شود. داده‌ها را متناسب با این روش نقشه‌برداری (Mapping) کرده و بخش‌های موردنیاز را برای انجام پیش‌بینی‌های مناسب ایجاد می‌کنیم.
# تابعی برای تبدیل کلیپ‌ها به طیف‌نگارهای پنجره‌ای
def preprocess_mp3(sample, index):
    sample = sample[0]
    zero_padding = tf.zeros([48000] – tf.shape(sample), dtype=tf.float32)
    wav = tf.concat([zero_padding, sample],0)
    spectrogram = tf.signal.stft(wav, frame_length=320, frame_step=32)
    spectrogram = tf.abs(spectrogram)
    spectrogram = tf.expand_dims(spectrogram, axis=2)
    return spectrogram
audio_slices = tf.keras.utils.timeseries_dataset_from_array(wav, wav, sequence_length=16000, sequence_stride=16000, batch_size=1)
audio_slices = audio_slices.map(preprocess_mp3)
audio_slices = audio_slices.batch(64)
yhat = model.predict(audio_slices)
yhat = [1 if prediction > 0.5 else 0 for prediction in yhat]
در قطعه کد نهایی این مقاله، ما این فرآیند را روی تمام فایل‌های موجود در ضبط‌های جنگلی اجرا کرده و نتیجه کلی را دریافت خواهیم کرد. نتایج شامل مقادیر ۰ و ۱ برای کلیپ‌های صوتی خواهد بود. مجموع مقادیر ۱ نشان‌دهنده تعداد دفعات شنیده شدن صدای پرنده Capuchin در هر کلیپ است. این تعداد در نهایت برای تعیین کل میزان تماس‌های ضبط‌شده این پرنده مورد استفاده قرار می‌گیرد. کد مربوط به این بخش در ادامه آمده است.
results = {}
class_preds = {}
for file in os.listdir(os.path.join(‘data’, ‘Forest Recordings’)):
    FILEPATH = os.path.join(‘data’,’Forest Recordings’, file)
    wav = load_mp3_16k_mono(FILEPATH)
    audio_slices = tf.keras.utils.timeseries_dataset_from_array(wav, wav, sequence_length=48000, sequence_stride=48000, batch_size=1)
    audio_slices = audio_slices.map(preprocess_mp3)
    audio_slices = audio_slices.batch(64)
    yhat = model.predict(audio_slices)
    results[file] = yhat
for file, logits in results.items():
    class_preds[file] = [1 if prediction > 0.99 else 0 for prediction in logits]
class_preds
منابع و بهبودهای احتمالی
دو منبع اصلی این پروژه، یکی نوت‌بوک Kaggle و دیگری لینک GitHub مرتبط با آن هستند. بیشتر کدهای این پروژه از این منابع گرفته شده است، بنابراین توصیه می‌شود که به آن‌ها مراجعه کنید. می‌توان یک نوت‌بوک جدید با این آدرس به عنوان Workspace URL ایجاد کرد تا این کدها را مستقیماً در قالب یک .ipynb درون یک نوت‌بوک بارگذاری کنید.
چندین بهبود اضافی می‌توانند در این پروژه اعمال شوند تا نتایج بهتری حاصل شود. برای مثال، می‌توان پیچیدگی شبکه عصبی را افزایش داد و از روش‌های نوآورانه برای بهبود دقت تحلیل الگوهای صوتی پرنده Capuchin استفاده کرد. در مقالات آینده، به پروژه‌های دیگری در زمینه پردازش سیگنال‌های صوتی خواهیم پرداخت.
نتیجه‌گیری
پردازش سیگنال‌های صوتی با یادگیری عمیق به دلیل نرخ موفقیت بالای آن، به شدت مورد توجه قرار گرفته است. بسیاری از پروژه‌های پیچیده مانند تشخیص صدا، طبقه‌بندی موسیقی، دسته‌بندی صداهای محیطی و موارد دیگر را می‌توان با استفاده از یادگیری عمیق انجام داد.
در این مقاله، طبقه‌بندی صوتی با یادگیری عمیق را بررسی کردیم. اجزای اساسی موردنیاز برای درک کامل این مفهوم را تحلیل کرده و سپس پیاده‌سازی آن را با استفاده از TensorFlow انجام دادیم. چندین بهبود می‌توانند به این پروژه اضافه شوند تا نتایج بهتری حاصل شود.
در مقالات آینده، به پروژه‌های جذاب‌تری در زمینه پردازش سیگنال‌های صوتی با یادگیری عمیق خواهیم پرداخت. همچنین، پروژه‌هایی مرتبط با تولید موسیقی، شبکه‌های مولد تخاصمی (GANs) و شبکه‌های عصبی از ابتدا را بررسی خواهیم کرد. تا آن زمان، از کاوش و ساخت پروژه‌های جدید لذت ببرید!
برای امتیاز به این نوشته کلیک کنید!
[کل: 0 میانگین: 0]

نظرات کاربران

دیدگاهی بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *