راهنمای عملی بر پردازش افتراقی سیگنال دیجیتال با استفاده از شبکههای عصبی
پیش از پرداختن به موضوع پردازش افتراقی سیگنال دیجیتال لازم است اشارهای به شبکههای عصبی و اهمیت آنها خواهیم داشت. در حوزهی رو به رشد علم و فناوری، هوش مصنوعی و پیشرفتهای اخیرش، جایگاه برجسته و محبوبیت بالایی به دست آوردهاند. تا جایی که مفاهیمی از قبیل هوش مصنوعی و یادگیری ماشین از موضوعات داغ این روزها به شمار میروند.
اکنون، به لطف هوش مصنوعی، ماشینها میتوانند بر اساس تجاربشان، با استفاده از دادهها و پردازش آنها بیاموزند و مسائل را به شکلی کارآمد انجام دهند.
شبکههای عصبی مصنوعی با الهام از ساختار مغز انسانها ساخته شده و به کامپیوترها و ماشینها، قابلیت تفکر و پردازش شبهانسانی ارائه میدهند. با هر گامی که فناوری بر میدارد، چیزهای بیشتری را باید در مورد ساختار شبکههای عصبی هوش مصنوعی و رویههای کاریشان بیاموزیم.
شبکههای عصبی مصنوعی یا ANNها، ابزاری کلیدی برای یادگیری ماشین به شمار میروند. شبکههای عصبی از لایههای ورودی و خروجی و یک لایهی نهان که در وسط معماری قرار دارد، تشکیل شدهاند. لایهی نهان شامل واحدهایی است که ورودی را پردازش میکنند تا در لایهی خروجی قابل استفاده باشد.
ANNها در بازیابی الگوهای پیچیده یا فراوان به برنامهنویسها کمک میکنند. هدف از آموزش ماشینها نیز تشخیص الگوهای مهم و ارزشمند است. ANNها از چندین گره تشکیل شدهاند؛ گرهها معادل نورونهای زیستی موجود در مغز انسان هستند.
نورونهای شبکهی عصبی به هم متصل هستند و در طول پردازش اطلاعات، به صورت پیوسته با یکدیگر تعامل دارند. گرههای ورودی دادههای ورودی را گرفته و چندین عملیات روی آنها انجام دهند. نتیجهی این عملیاتها به نورونهای دیگر منتقل میشود.
تقلید از مغز انسان
خروجی هر گره با یک مقدار فعالسازی (مقدار گره) همراه است. این تکنیک پردازشی نیز از کارکرد مغز انسان تقلید شده و پایه و اساس ساخت الگوریتمهایی است که در مدلسازی الگوهای پیچیده یا مسائل پیشبینی به کار میروند.
به این نوع شبکهها MLP یا پرسپترون چندلایهای نیز میگویند، چون چندین لایه دارند. لایهی نهان اطلاعات مهم را تشخیص داده و تنها آنها را برای پردازش انتخاب میکند و بدین طریق، سرعت شبکه را افزایش میدهد. بدین منظور، با توجه به وزنهای اختصاص یافته به اطلاعات، موارد اضافی را کنار میگذارد.
راز ساخت یک مدل پیشبین خوب و دقیق، یافتن مقادیری بهینه برای وزنهاست که بتوانند خطای پیشبینی را به حداقل برسانند. بدین منظور باید از الگوریتم پسانتشار استفاده کرد. پسانتشار نوعی خاصیت خودیادگیرندگی به ANN ارائه میدهد که آن را قادر میسازد از اشتباهاتش آموخته و بدین طریق، بهتر و بهتر شود. آموزش و افزایش دقت شبکههای عصبی به شدت وابسته به دادههای آموزشی است.
الگوریتمهای یادگیری، بعد از تنظیم دقیق، به ابزارهای هوش مصنوعی و علوم کامپیوتر قدرتمندی تبدیل میشوند که به ما اجازه میدهند حجم عظیمی داده را طبقهبندی و خوشهبندی کنیم.
مسائلی همچون تشخیص گفتار یا شناسایی تصویر که به صورت دستی ساعتها طول میکشد را میتوان به کمک این ابزارها در عرض چند دقیقه انجام داد. الگوریتم جستجوی گوگل مصداق بارز یک شبکهی عصبی خوشساخت است.
کاربرد این فناوریها در کسب و کارها عمدتاً مربوط به حل مسائل پیچیدهای همچون تشخیص الگو یا شناسایی چهره میشود. از دیگر موارد کاربرد آنها میتوان به تبدیل گفتار به نوشتار، تحلیل داده، تشخیص دست خط برای پردازش چکها، پیشبینی آب و هوا و پردازش سیگنال اشاره کرد.
پردازش افتراقی سیگنال دیجیتال چیست؟
DDSP یا پردازش سیگنال دیجیتال Digital Signal Processing را میتوان یکی از ستونهای اصلی جامعهی مدرن دانست که دامنه کاربردش تا حوزههای مخابرات، حمل و نقل، فناوریهای صوتی و پزشکی گسترده است. پردازشگرهای سیگنال دیجیتال، دادههایی به شکل موج (صدا، صوت، ویدئو، دما و …) را دریافت کرده و با اجرای عملیات ریاضی، دستکاری میکنند.
هدف اصلی DSP، ایجاد سیگنالهایی واقعی و پیچیده از طریق کنترل و تنظیم دقیق پارامترهای فراوان آنهاست. برای مثال، با استفاده از مجموعهای از فیلترهای خطی و نوسانسازهای سینوسی میتوان صدایی شبیه یک ویولن واقعی تولید کرد، به شرطی که فرکانسها و پاسخها به درستی تنظیم شده باشند.
با این حال، گاهی کنترل دستی همهی این پارامترها دشوار میشود. به همین دلیل است که خروجی ترکیبکنندههای صدا غیرطبیعی و شبیه رباتهاست. پردازش افتراقی سیگنال دیجیتال کتابخانهی متنبازی است که با استفاده از یک شبکه عصبی، ورودی کاربر را به کنترلهای DSP پیچیدهای تبدیل و به تولید سیگنالهای واقعگرایانهتر کمک میکنند. ورودی میتواند هر نوع صوت یا حتی ویژگیهای استخراج شده از فایل صوتی هم باشد.
از آنجایی که واحدهای DDSP افتراقی هستند، شبکه عصبی را میتوان به نحوی آموزش داد تا با استفاده از پسانتشار، با دیتاستها سازگار شود. پردازش افتراقی سیگنال دیجیتال به عنوان لایهی خروجی آخر خودرمزنگارها قرار میگیرد و یک ترکیبکنندهی هارمونیک افزایشی (مسئول تولید امواج سینوسی با فرکانسهای گوناگون) را با یک ترکیبکننده افتراقی نویز (مسئول حذف نویزهایی با فیلترهای زمانی متفاوت) ترکیب میکند.
سیگنال این ترکیبکنندهها با هم ترکیب شده و وارد ماژول پژواک میشود تا موج صوتی خروجی را تولید کند. زیان مدل با مقایسهی طیفسنجی صوت تولیدشده و صوت اصلی در شش اندازه فریم متفاوت، به دست میآید. از آنجایی که همهی اجزاء افتراقی هستند، میتوانیم برای آموزش یکپارچه شبکه، از پسانتشار و گرادیان کاهشی تصادفی استفاده کنیم.
کدها
این پژوهش از کتابخانهی پردازش افتراقی سیگنال دیجیتال و شبکه های عصبی استفاده میکند تا یک مبدل صدا-به-موسیقی تولید کند.
این مدل، صدای صحبت افراد را به عنوان ورودی دریافت کرده و سپس این امواج صوتی را با موسیقی (تقلیدشده از صدای یک ویولن) جایگزین میکند. با مقایسهی صدای اصلی با صدای پردازش شده میتوان متوجه تفاوت واضح بین آنها شد. کدی که در ادامهی مطلب میبینید، پیادهسازی رسمی سازندگان DDSP و Magneta است.
راهاندازی کتابخانه
گام اول راهاندازی کتابخانهی موردنیاز است:
#Installing the Library !pip install -qU ddsp==1.6.3
انتقال وابستگیها
سپس نوبت انتقال وابستگیها و توابعی است که به ساخت روال پردازشی کمک و نرخ نمونه را برای مبدل صوتی تعیین میکنند:
#Importing necessary dependencies import copy import os import time import crepe import ddsp import ddsp.training from ddsp.colab.colab_utils import ( auto_tune, get_tuning_factor, download, play, record, specplot, upload, DEFAULT_SAMPLE_RATE) from ddsp.training.postprocessing import ( detect_notes, fit_quantile_transform ) import gin from google.colab import files import librosa import matplotlib.pyplot as plt import numpy as np import pickle import tensorflow.compat.v2 as tf import tensorflow_datasets as tfds # Helper Functions sample_rate = DEFAULT_SAMPLE_RATE # 16000
ضبط صدا برای پردازش
در گام بعدی، باید یک صدای ضبط شده 5 ثانیهای را به عنوان ورودی در اختیار مدل قرار دهیم؛ روال پردازشی مدل این صدا را پردازش میکند:
#recording audio record_or_upload = "Record" record_seconds = if record_or_upload == "Record": audio = record(seconds=record_seconds) else: filenames, audios = upload() audio = audios[0] audio = audio[np.newaxis, :] print('\nExtracting audio features...') # Plot. specplot(audio) play(audio) # Setup the session. ddsp.spectral_ops.reset_crepe() # Computing the speech audio features. start_time = time.time() audio_features = ddsp.training.metrics.compute_audio_features(audio) audio_features['loudness_db'] = audio_features['loudness_db'].astype(np.float32) audio_features_mod = None print('Audio features took %.1f seconds' % (time.time() - start_time)) TRIM = -15
حال ویژگیهای صدای پردازش شده را به تصویر درمیآوریم:
# Plot the Speech audio Features. #Extracts fundamental frequency (f0) and loudness features fig, ax = plt.subplots(nrows=3, ncols=1, sharex=True, figsize=(6, 8)) ax[0].plot(audio_features['loudness_db'][:TRIM]) ax[0].set_ylabel('loudness_db') ax[1].plot(librosa.hz_to_midi(audio_features['f0_hz'][:TRIM])) ax[1].set_ylabel('f0 [midi]') ax[2].plot(audio_features['f0_confidence'][:TRIM]) ax[2].set_ylabel('f0 confidence') _ = ax[2].set_xlabel('Time step [frame]')
خروجی
توجه داشته باشید که فایلهای صوتی خروجی تنها هنگام اجرا قابل مشاهده است.
خروجی، صدای صوتی 5 ثانیهای ضبط شده را پخش میکند و ویژگیهای آن (بلندی، فرکانس و اطمینان) را به تصویر در میآورد.
بارگذاری مدل و ترکیب صداها حال میخواهیم صدای صحبت ضبط شده را با یک صدای یک آلت موسیقی ترکیب کنیم تا صدایی جدید به دست آوریم. اینجا صدای یک ویولن را بارگذاری میکنیم:
#Loading an audio model model = 'Violin' MODEL = model # Iterate through directories until model directory is found def find_model_dir(dir_name): for root, dirs, filenames in os.walk(dir_name): for filename in filenames: if filename.endswith(".gin") and not filename.startswith("."): model_dir = root break return model_dir if model in ('Violin', 'Flute', 'Flute2', 'Trumpet', 'Tenor_Saxophone'): # Load Pretrained models. PRETRAINED_DIR = '/content/pretrained' . !rm -r $PRETRAINED_DIR &> /dev/null !mkdir $PRETRAINED_DIR &> /dev/null GCS_CKPT_DIR = 'gs://ddsp/models/timbre_transfer_colab/2021-07-08' model_dir = os.path.join(GCS_CKPT_DIR, 'solo_%s_ckpt' % model.lower()) !gsutil cp $model_dir/* $PRETRAINED_DIR &> /dev/null model_dir = PRETRAINED_DIR gin_file = os.path.join(model_dir, 'operative_config-0.gin') else: # User models. UPLOAD_DIR = '/content/uploaded' !mkdir $UPLOAD_DIR uploaded_files = files.upload() for fnames in uploaded_files.keys(): print("Unzipping... {}".format(fnames)) !unzip -o "/content/$fnames" -d $UPLOAD_DIR &> /dev/null model_dir = find_model_dir(UPLOAD_DIR) gin_file = os.path.join(model_dir, 'operative_config-0.gin') # Load the dataset statistics. DATASET_STATS = None dataset_stats_file = os.path.join(model_dir, 'dataset_statistics.pkl') print(f'Loading dataset statistics from {dataset_stats_file}') try: if tf.io.gfile.exists(dataset_stats_file): with tf.io.gfile.GFile(dataset_stats_file, 'rb') as f: DATASET_STATS = pickle.load(f) except Exception as err: print('Loading dataset statistics from pickle failed: {}.'.format(err)) # Ensure dimensions and sampling rates are equal time_steps_train = gin.query_parameter('F0LoudnessPreprocessor.time_steps') n_samples_train = gin.query_parameter('Harmonic.n_samples') hop_size = int(n_samples_train / time_steps_train) time_steps = int(audio.shape[1] / hop_size) n_samples = time_steps * hop_size gin_params = [ 'Harmonic.n_samples = {}'.format(n_samples), 'FilteredNoise.n_samples = {}'.format(n_samples), 'F0LoudnessPreprocessor.time_steps = {}'.format(time_steps), 'oscillator_bank.use_angular_cumsum = True', ] with gin.unlock_config(): gin.parse_config(gin_params) # Trim all input audio vectors to correct lengths for key in ['f0_hz', 'f0_confidence', 'loudness_db']: audio_features[key] = audio_features[key][:time_steps] audio_features['audio'] = audio_features['audio'][:, :n_samples] # Set up the model just to predict audio given new conditioning model = ddsp.training.models.Autoencoder() model.restore(ckpt) # Build a model by running a batch through it. start_time = time.time() _ = model(audio_features, training=False) print('Restoring model took %.1f seconds' % (time.time() - start_time))
تولید صدای بازترکیب شده
گام آخر، تولید صدایی منحصر به فرد از طریق آموزش و پردازش صدای اصلی با صدای بارگذاری شده است.
#Resynthesize Audio af = audio_features if audio_features_mod is None else audio_features_mod # Run a batch of predictions. start_time = time.time() outputs = model(af, training=False) audio_gen = model.get_audio_from_outputs(outputs) print('Prediction took %.1f seconds' % (time.time() - start_time)) # Plotting graph for comparison print('Original') play(audio) print('Resynthesis') play(audio_gen) specplot(audio) plt.title("Original") specplot(audio_gen) _ = plt.title("Resynthesis")
خروجی شامل دو صوت میباشد: صدای صحبت اصلی که ضبط کردیم و دومی، صوت ترکیبشده.
حال به کمک نمودارهای رسم شده، به راحتی میتوانیم تفاوت بین این دو صوت را مشاهده کنیم.
جمعبندی
در این نوشتار، شبکهی عصبی و کاربردهای بالقوهی آن را معرفی کردیم. همچنین، با استفاده از شبکههای عصبی و کتابخانهی پردازش افتراقی سیگنال دیجیتال، یک مبدل صدای صحبت به صدای موسیقیایی ساختیم. در انتها، صدای اصلی را با صدای پردازششده و تولیدشده مقایسه کردیم. پیادهسازی مربوطه در این لینک از کولب قابل دسترس است.