应用深度学习使用 Tensorflow 对音频进行分类
在視覺和語言領(lǐng)域的深度學(xué)習(xí)方面取得了很多進(jìn)展,文中一步步說明當(dāng)我們處理音頻數(shù)據(jù)時(shí),使用了哪些類型的模型和流程。
作者 /?Dimitre Oliveira
原文鏈接 / https://pub.towardsai.net/a-gentle-introduction-to-audio-classification-with-tensorflow-c469cb0be6f5
圖片來源:?https://www.tensorflow.org/tutorials/audio/simple_audio
最近在視覺和語言領(lǐng)域的深度學(xué)習(xí)方面取得了很多進(jìn)展,能很直觀地理解為什么CNN在圖像上表現(xiàn)得很好,因?yàn)橄袼氐木植肯嚓P(guān),以及因?yàn)樗哂许樞蛐?#xff0c;像RNN或轉(zhuǎn)化器這樣的順序模型在語言上也表現(xiàn)得非常好。但音頻呢?當(dāng)我們處理音頻數(shù)據(jù)時(shí),使用了哪些類型的模型和流程?
在本文中,你將學(xué)習(xí)如何處理一個(gè)簡單的音頻分類問題。你將學(xué)習(xí)到一些常用的、有效的方法,以及Tensorflow代碼來實(shí)現(xiàn)。
聲明:本文給出的代碼是基于我為“Rainforest Connection Species Audio Detection”Kaggle比賽開發(fā)的工作,但出于演示目的,我將使用“Speech Commands(語音指令)”數(shù)據(jù)集。
波形圖
我們通常有".wav "格式的音頻文件,它們通常被稱為 waveforms(波形),它是一個(gè)時(shí)間序列,其中有每個(gè)特定時(shí)間的信號振幅,如果我們將這些波形樣本之一可視化,會(huì)得到下圖這樣:
直覺上人們可能會(huì)考慮使用某種RNN模型對這些數(shù)據(jù)建模為一個(gè)常規(guī)時(shí)間序列(例如股票價(jià)格預(yù)測),事實(shí)上這可以做到,但由于我們使用的是音頻信號,更合適的選擇是將波形樣本轉(zhuǎn)化為聲譜圖。
聲譜圖
聲譜圖是波形信號的圖像表示,它顯示了其隨時(shí)間變化的頻率強(qiáng)度范圍,它在想評估信號隨時(shí)間變化的頻率分布時(shí)非常有用。下圖是上文中波形圖像的聲譜圖表示。
x 軸是采樣時(shí)間,y 軸是頻率
語音命令用例
為了使本教程更簡單,我們將使用“Speech Commands語音命令”數(shù)據(jù)集,該數(shù)據(jù)集有一秒鐘的音頻片段,帶有 "下"、"走"、"左"、"不"、"右"、"停"、"上 "和 "是"等口語化的詞語。
使用Tensorflow進(jìn)行音頻處理
現(xiàn)在我們已經(jīng)知道了如何使用深度學(xué)習(xí)模型來處理音頻數(shù)據(jù),可以繼續(xù)看代碼實(shí)現(xiàn),我們的流水線將遵循下圖描述的簡單工作流程:
簡單的音頻處理圖
值得注意,在我們的用例的第1步,將數(shù)據(jù)直接從“. wav”文件中加載的,第3個(gè)步是可選的,因?yàn)橐纛l文件每個(gè)只有一秒鐘,因?yàn)槲募^長裁剪音頻可能是一個(gè)好主意,也是為了保持所有樣本的固定長度。
加載數(shù)據(jù)
def load_dataset(filenames):dataset = tf.data.Dataset.from_tensor_slices(filenames)return datasetload_datasetv函數(shù)將負(fù)責(zé)加載.wav文件并將其轉(zhuǎn)換為Tensorflow數(shù)據(jù)集。
提取波形和標(biāo)簽
commands = np.array(tf.io.gfile.listdir(str(data_dir))) commands = commands[commands != 'README.md']def decode_audio(audio_binary):audio, _ = tf.audio.decode_wav(audio_binary)return tf.squeeze(audio, axis=-1)def get_label(filename):label = tf.strings.split(filename, os.path.sep)[-2]label = tf.argmax(label == commands)return labeldef get_waveform_and_label(filename):label = get_label(filename)audio_binary = tf.io.read_file(filename)waveform = decode_audio(audio_binary)return waveform, label在加載.wav文件后,可以用tf.audio.decode_wav函數(shù)來對它們進(jìn)行解碼,它將把.wav文件變成float tensor。接下來,我們需要從文件中提取標(biāo)簽,在這個(gè)特定的用例中,我們可以從每個(gè)樣本的文件路徑中獲取標(biāo)簽,之后只需要對它們進(jìn)行一次編碼。
一個(gè)例子
首先,我們得到一個(gè)像這樣的文件路徑:
"data/mini_speech_commands/up/50f55535_nohash_0.wav"然后提取第二個(gè)"/"后面的文本,在這種情況下,標(biāo)簽是UP,最后使用commands列表對標(biāo)簽進(jìn)行一次編碼。
Commands: ['up' 'down' 'go' 'stop' 'left' 'no' 'yes' 'right'] Label = 'up'After one-hot encoding: Label = [1, 0, 0, 0, 0, 0, 0, 0]將波形轉(zhuǎn)換為聲譜表
下一步是將波形文件轉(zhuǎn)換為聲譜圖,幸運(yùn)的是Tensorflow有一個(gè)函數(shù)可以做到這一點(diǎn),?tf.signal.stft應(yīng)用短時(shí)Fourier變換(STFT)將音頻轉(zhuǎn)換為時(shí)頻域,然后我們應(yīng)用?tf.abs?算子去除信號相位,只保留幅值。注意,tf.signal.stft函數(shù)有一些參數(shù),如frame_length?和frame_step,它們會(huì)影響生成的聲譜圖,我不會(huì)詳細(xì)介紹如何調(diào)整它們,但你可以參考這個(gè)視頻來了解更多。(:https://www.coursera.org/lecture/audio-signal-processing/stft-2-tjEQe)
def get_spectrogram(waveform, padding=False, min_padding=48000):waveform = tf.cast(waveform, tf.float32)spectrogram = tf.signal.stft(waveform, frame_length=2048, frame_step=512, fft_length=2048)spectrogram = tf.abs(spectrogram)return spectrogramdef get_spectrogram_tf(waveform, label):spectrogram = get_spectrogram(waveform)spectrogram = tf.expand_dims(spectrogram, axis=-1)return spectrogram, label將聲譜圖轉(zhuǎn)化為RGB圖像
最后一步是將聲譜圖轉(zhuǎn)換為RGB圖像,這一步是可選的,但這里我們將使用在ImageNet數(shù)據(jù)集上預(yù)訓(xùn)練的模型,該模型需要輸入3個(gè)通道的圖像。否則,你只可以保留一個(gè)通道的聲譜圖。
def prepare_sample(spectrogram, label):spectrogram = tf.image.resize(spectrogram, [HEIGHT, WIDTH])spectrogram = tf.image.grayscale_to_rgb(spectrogram)return spectrogram, label將所有的東西結(jié)合起來
HEIGHT, WIDTH = 128, 128 AUTO = tf.data.AUTOTUNEdef get_dataset(filenames, batch_size=32):dataset = load_dataset(filenames)dataset = files_ds.map(get_waveform_and_label, num_parallel_calls=AUTO)dataset = dataset.map(get_spectrogram_tf, num_parallel_calls=AUTO)dataset = dataset.map(prepare_sample, num_parallel_calls=AUTO) dataset = dataset.shuffle(256)dataset = dataset.repeat()dataset = dataset.batch(batch_size)dataset = dataset.prefetch(AUTO)return dataset將所有東西集合在一起,有?get_dataset?函數(shù)將文件名作為輸入,在執(zhí)行了上面描述的所有步驟后,返回一個(gè)帶有RGB光譜圖圖像及其標(biāo)簽的Tensorflow數(shù)據(jù)集。
模型
def model_fn(input_shape, N_CLASSES):inputs = L.Input(shape=input_shape, name='input_audio')base_model = efn.EfficientNetB0(input_tensor=inputs, include_top=False, weights='imagenet')x = L.GlobalAveragePooling2D()(base_model.output)x = L.Dropout(.5)(x)output = L.Dense(N_CLASSES, activation='softmax',name='output')(x)model = Model(inputs=inputs, outputs=output)return model我們的模型將有一個(gè)EfficientNetB0主干,在其頂部添加了一個(gè)GlobalAveragePooling2D,然后是一個(gè)Dropout,最后一個(gè)Dense層將進(jìn)行實(shí)際的多類分類。
對于一個(gè)小的數(shù)據(jù)集,EfficientNetB0可能是一個(gè)很好的基線,即使是一個(gè)快速而輕巧的模型,它也有不錯(cuò)的準(zhǔn)確性。
訓(xùn)練
model = model_fn((None, None, CHANNELS), N_CLASSES)model.compile(optimizer=tf.optimizers.Adam(), loss=losses.CategoricalCrossentropy(), metrics=[metrics.CategoricalAccuracy()])model.fit(x=get_dataset(FILENAMES), steps_per_epoch=100, epochs=10)訓(xùn)練代碼對于Keras模型來說是非常標(biāo)準(zhǔn)的,所以你可能不會(huì)在這里找到任何新東西。
結(jié)論
現(xiàn)在你應(yīng)該對將深度學(xué)習(xí)應(yīng)用于音頻文件的工作流程有了更清楚的了解,雖然這不是你能做到的唯一方法,但它是關(guān)于易用性和性能之間的權(quán)衡的最佳選擇。如果你打算對音頻進(jìn)行建模,你可能還要考慮其他有前途的方法,如變壓器。
作為額外的預(yù)處理步驟,截?cái)嗷蛱畛洳ㄐ慰赡苁且粋€(gè)好主意,如果你的樣本有不同的長度,或者如果樣本太長,只需要其中的一小部分,你可以在下面的參考資料部分找到如何做的代碼。
參考文獻(xiàn)
-?Simple audio recognition: Recognizing keywords
https://www.tensorflow.org/tutorials/audio/simple_audio
-?Rainforest-Audio classification Tensorflow starter
https://www.kaggle.com/dimitreoliveira/rainforest-audio-classification-tensorflow-starter
-?Rainforest-Audio classification TF Improved
https://www.kaggle.com/dimitreoliveira/rainforest-audio-classification-tf-improved/notebook
詳情請掃描圖中二維碼或點(diǎn)擊閱讀原文了解大會(huì)更多信息。
總結(jié)
以上是生活随笔為你收集整理的应用深度学习使用 Tensorflow 对音频进行分类的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 未来,让我们一起想象— “Imagine
- 下一篇: QUIC助力Snapchat提升用户体验