數(shù)據(jù)背景
作為“世界滅絕之都”,夏威夷已經(jīng)失去了68%的鳥(niǎo)類物種,其后果可能會(huì)損害整個(gè)食物鏈。研究人員利用種群監(jiān)測(cè)來(lái)了解本地鳥(niǎo)類對(duì)環(huán)境變化和保護(hù)措施的反應(yīng)。但島上的許多鳥(niǎo)類都被隔離在難以接近的高海拔棲息地。由于身體監(jiān)測(cè)困難,科學(xué)家們轉(zhuǎn)向了聲音記錄。這種被稱為生物聲學(xué)監(jiān)測(cè)的方法可以為研究瀕危鳥(niǎo)類種群提供一種被動(dòng)的、低成本的、經(jīng)濟(jì)的策略。 目前處理大型生物聲學(xué)數(shù)據(jù)集的方法涉及對(duì)每個(gè)記錄的手工注釋。這需要專門的訓(xùn)練和大量的時(shí)間。因此使用機(jī)器學(xué)習(xí)技能,通過(guò)聲音來(lái)識(shí)別鳥(niǎo)類的種類,可以節(jié)約大量成本。具體來(lái)說(shuō),開(kāi)發(fā)一個(gè)模型,可以處理連續(xù)的音頻數(shù)據(jù),然后從聲音上識(shí)別物種。最好的條目將能夠用有限的訓(xùn)練數(shù)據(jù)訓(xùn)練可靠的分類器。

數(shù)據(jù)介紹
數(shù)據(jù)集來(lái)源:https://www.kaggle.com/competitions/birdclef-2022/data
下載方式:https://github.com/Kaggle/kaggle-api kaggle competitions download -c birdclef-2022
-
train_metadata.csv:為訓(xùn)練數(shù)據(jù)提供了廣泛的元數(shù)據(jù)- primary_label -鳥(niǎo)類的編碼。可以通過(guò)將代碼附加到https://ebird.org/species/來(lái)查看有關(guān)鳥(niǎo)類代碼的詳細(xì)信息,例如美國(guó)烏鴉的代碼添加到https://ebird.org/species/amecro
- secondary_labels: 記錄員標(biāo)注的背景物種,空列表并不意味著沒(méi)有背景鳥(niǎo)的聲音。
- author - 提供錄音的eBird用戶
- Filename:關(guān)聯(lián)音頻文件。
- rating: 浮動(dòng)值在0.0到5.0之間,作為Xeno-canto的質(zhì)量等級(jí)和背景物種數(shù)量的指標(biāo),其中5.0是最高的,1.0是最低的。0.0表示此記錄還沒(méi)有用戶評(píng)級(jí)。
train_audio:大量的訓(xùn)練數(shù)據(jù)由xenocanto.org的用戶慷慨上傳的單個(gè)鳥(niǎo)類叫聲的短錄音組成。這些文件已被下采樣到32khz,適用于匹配測(cè)試集的音頻,并轉(zhuǎn)換為ogg格式。test_soundscapes:當(dāng)您提交一個(gè)筆記本時(shí),test_soundscapes目錄將填充大約5500段錄音,用于評(píng)分。每一個(gè)都是1分鐘幾毫秒的ogg音頻格式,并只有一個(gè)音景可供下載。-
test.csv:測(cè)試數(shù)據(jù)- row_id:行的唯一標(biāo)識(shí)符。
- file_id:音頻文件的唯一標(biāo)識(shí)符。
- bird :一行的ebird代碼。每個(gè)音頻文件每5秒窗口有一排為每個(gè)得分物種。
- end_time:5秒時(shí)間窗口(5、10、15等)的最后一秒。
音頻特征提取
特征提取是突出信號(hào)中最具辨別力和影響力的特征的過(guò)程。本文將引導(dǎo)完成音頻處理中的一些重要特征提取,你可以將其擴(kuò)展到適合的問(wèn)題域的許多其他類型的特征。本文的其余部分只是一個(gè)生物技術(shù)學(xué)生的嘗試,向你解釋ta在過(guò)去幾天能夠理解的任何信號(hào)處理。
我們將討論的三種主要音頻特征提取類型 ```
- Time Domain 2. Frequency Domain 3. Spectrum-Based
import os import pandas as pd import torch import torchaudio import numpy as np import seaborn as sns import matplotlib.pyplot as plt %matplotlib inline import plotly.express as px import librosa import librosa.display import IPython.display as ipd import sklearn import warnings import seaborn as sns warnings.filterwarnings('ignore') #導(dǎo)入數(shù)據(jù) train_csv=pd.read_csv('../input/birdclef-2021/train_metadata.csv') train_csv.head()
加載并頻文件
- 將音頻文件加載為浮點(diǎn)時(shí)間序列并提供其原生采樣率
- 采樣頻率(或采樣率)是音頻中每秒的采樣數(shù)(數(shù)據(jù)點(diǎn))
- 可以通過(guò)將數(shù)據(jù)點(diǎn)總數(shù)除以采樣頻率來(lái)檢查音頻長(zhǎng)度
y, sr = librosa.load(subfly)
print('y:', y, '\n')
print('y shape:', np.shape(y), '\n')
print('Sample Rate (KHz):', sr, '\n')
print('Check Len of Audio:', np.shape(y)[0]/sr)
audio_file, _ = librosa.effects.trim(y)
print('Audio File:', audio_file, '\n')
print('Audio File shape:', np.shape(audio_file))
#用在例子中
y_astfly, sr_astfly = librosa.load(astfly)
audio_astfly, _ = librosa.effects.trim(y_astfly)
y_casvir, sr_casvir = librosa.load(casvir)
audio_casvir, _ = librosa.effects.trim(y_casvir)
y_subfly, sr_subfly = librosa.load(subfly)
audio_subfly, _ = librosa.effects.trim(y_subfly)
y_wilfly, sr_wilfly = librosa.load(wilfly)
audio_wilfly, _ = librosa.effects.trim(y_wilfly)
y_verdin, sr_verdin = librosa.load(verdin)
audio_verdin, _ = librosa.effects.trim(y_verdin)
y_solsan, sr_solsan = librosa.load(solsan)
audio_solsan, _ = librosa.effects.trim(y_solsan)
1.時(shí)域特征
波形可視化
fig, ax = plt.subplots(6, figsize = (16, 12))
fig.suptitle('Sound Waves', fontsize=16)
librosa.display.waveplot(y = audio_astfly, sr = sr_astfly, color = "#A300F9", ax=ax[0])
librosa.display.waveplot(y = audio_casvir, sr = sr_casvir, color = "#4300FF", ax=ax[1])
librosa.display.waveplot(y = audio_subfly, sr = sr_subfly, color = "#009DFF", ax=ax[2])
librosa.display.waveplot(y = audio_wilfly, sr = sr_wilfly, color = "#00FFB0", ax=ax[3])
librosa.display.waveplot(y = audio_verdin, sr = sr_verdin, color = "#D9FF00", ax=ax[4])
librosa.display.waveplot(y = audio_solsan, sr = sr_solsan, color = "r", ax=ax[5]);
for i, name in zip(range(6), birds):
ax[i].set_ylabel(name, fontsize=13)
頻譜圖
頻譜圖是信號(hào)頻率隨時(shí)間變化的頻譜的直觀表示,它們是信號(hào)的時(shí)頻圖。使用頻譜圖,我們可以看到能量水平 (dB) 如何隨時(shí)間變化。它是一種直觀的方式,表示信號(hào)在特定波形中出現(xiàn)的各種頻率下隨時(shí)間變化的信號(hào)強(qiáng)度或“響度”。頻譜圖是通常被描述為熱圖,即通過(guò)改變顏色或亮度來(lái)顯示強(qiáng)度的圖像。
n_fft=2048
hop_length=512
# Short-time Fourier transform (STFT)
D_astfly = np.abs(librosa.stft(audio_astfly, n_fft = n_fft, hop_length = hop_length))
# Convert an amplitude spectrogram to Decibels-scaled spectrogram.
DB_astfly = librosa.amplitude_to_db(D_astfly, ref = np.max)
# === PLOT ===
fig, ax = plt.subplots(1, 1, figsize=(12, 6))
fig.suptitle('Log Frequency Spectrogram', fontsize=16)
# fig.delaxes(ax[1, 2])
img=librosa.display.specshow(DB_astfly, sr = sr_astfly, hop_length = hop_length, x_axis = 'time',
y_axis = 'log', cmap = 'cool', ax=ax)
ax.set_title('ASTFLY', fontsize=13)
plt.colorbar(img,ax=ax)
RMSE
信號(hào)的能量對(duì)應(yīng)于其總幅度,其對(duì)于音頻信號(hào),這大致表征了信號(hào)的響度。RMSE是一種表征信號(hào)能量的方法,計(jì)算均方的平方根(音頻幀幅度平方的平均值).
S, phase = librosa.magphase(librosa.stft(audio_astfly))
S_db=librosa.amplitude_to_db(S, ref=np.max)
rms = librosa.feature.rms(S=S)
fig, ax = plt.subplots(nrows=2, sharex=True,figsize = (16, 6))
times = librosa.times_like(rms)
ax[0].semilogy(times, rms[0], label='RMS Energy')
ax[0].set(xticks=[])
ax[0].legend()
ax[0].label_outer()
librosa.display.specshow(S_db,
y_axis='log', x_axis='time', ax=ax[1])
ax[1].set(title='log Power spectrogram')
plt.show()
梅爾光譜圖
梅爾頻譜圖是將頻率轉(zhuǎn)換為梅爾標(biāo)度的頻譜圖
# Create the Mel Spectrograms
S_astfly = librosa.feature.melspectrogram(audio_astfly, sr=sr_astfly)
S_DB_astfly = librosa.amplitude_to_db(S_astfly, ref=np.max)
# === PLOT ====
fig, ax = plt.subplots(1, 1, figsize=(12, 6))
fig.suptitle('Mel Spectrogram', fontsize=16)
img=librosa.display.specshow(S_DB_astfly, sr = sr_astfly, hop_length = hop_length, x_axis = 'time',
y_axis = 'log', cmap = 'cool', ax=ax)
ax.set_title('ASTFLY', fontsize=13)
plt.colorbar(img,ax=ax)
過(guò)零率(ZCR)
音頻信號(hào)的 ZCR 定義為信號(hào)改變符號(hào)的速率。 ZCR 是檢測(cè)語(yǔ)音幀是有聲、無(wú)聲還是無(wú)聲的一種有效且簡(jiǎn)單的方法。 預(yù)計(jì)清音段產(chǎn)生比語(yǔ)音段更高的ZCR,理想情況下靜音段的 ZCR 等于 0
# Total zero_crossings in our 1 song
zero_astfly = librosa.zero_crossings(audio_astfly, pad=False)
zero_casvir = librosa.zero_crossings(audio_casvir, pad=False)
zero_wilfly = librosa.zero_crossings(audio_wilfly, pad=False)
zero_subfly = librosa.zero_crossings(audio_subfly, pad=False)
zero_verdin = librosa.zero_crossings(audio_verdin, pad=False)
zero_solsan = librosa.zero_crossings(audio_solsan, pad=False)
zero_birds_list = [zero_astfly, zero_casvir, zero_wilfly, zero_subfly, zero_verdin,zero_solsan]
for bird, name in zip(zero_birds_list, birds):
print("{} change rate is {:,}".format(name, sum(bird)))
'''
astfly change rate is 92,121
casvir change rate is 1,651,380
subfly change rate is 30,477
wilfly change rate is 740,062
verdin change rate is 1,246,690
solsan change rate is 923,452
'''
Harmonic和Percussive Signals的分離
聲音大致可以分為兩類。- 一方面,諧波是我們感知為音高的聲音,是什么讓我們聽(tīng)到旋律和和弦。
- 另一方面,敲擊聲類似于噪音,通常源于樂(lè)器的聲部,如擊鼓聲或語(yǔ)音中的輔音。
y_harm_casvir, y_perc_casvir = librosa.effects.hpss(audio_casvir)
D_casvir = np.abs(librosa.stft(audio_casvir, n_fft = n_fft, hop_length = hop_length))
DB_casvir = librosa.amplitude_to_db(D_casvir, ref = np.max)
plt.figure(figsize = (16, 6))
plt.plot(y_perc_casvir, color = '#FFB100')
plt.plot(y_harm_casvir, color = '#A300F9')
plt.legend(("Perceptrual", "Harmonics"))
plt.title("Harmonics + Percussive : Casvir Bird", fontsize=16);
H, P = librosa.decompose.hpss(librosa.stft(audio_casvir))
plt.figure(figsize=(16, 6))
plt.subplot(3, 1, 1)
librosa.display.specshow(DB_casvir, y_axis='log')
plt.colorbar(format='%+2.0f dB')
plt.title('Full power spectrogram: Harmonic + Percussive')
# harmonic spectrogram will show more horizontal/pitch-dependent changes
plt.subplot(3, 1, 2)
librosa.display.specshow(librosa.amplitude_to_db(np.abs(H), ref=np.max), y_axis='log')
plt.colorbar(format='%+2.0f dB')
plt.title('Harmonic power spectrogram')
plt.subplot(3, 1, 3)
# percussive spectrogram will show more vertical/time-dependent changes
librosa.display.specshow(librosa.amplitude_to_db(np.abs(P), ref=np.max), y_axis='log')
plt.colorbar(format='%+2.0f dB')
plt.title('Percussive power spectrogram')
plt.tight_layout()
plt.show()
節(jié)拍提取
tempo, beat_frames = librosa.beat.beat_track(y=y_harm_casvir, sr=sr_casvir)
print('Detected Tempo: '+ str(tempo) + ' beats/min')
beat_times = librosa.frames_to_time(beat_frames, sr=sr)
beat_time_diff = np.ediff1d(beat_times)
beat_nums = np.arange(1, np.size(beat_times))
fig, ax = plt.subplots()
fig.set_size_inches(20, 5)
ax.set_ylabel("Time difference (s)")
ax.set_xlabel("Beats")
g = sns.barplot(beat_nums, beat_time_diff, palette="rocket",ax=ax)
g = g.set(xticklabels=[])
# Create Tempo BPM variable
tempo_astfly, _ = librosa.beat.beat_track(y_astfly, sr = sr_astfly)
tempo_casvir, _ = librosa.beat.beat_track(y_casvir, sr = sr_casvir)
tempo_wilfly, _ = librosa.beat.beat_track(y_wilfly, sr = sr_wilfly)
tempo_subfly, _ = librosa.beat.beat_track(y_subfly, sr = sr_subfly)
tempo_verdin, _ = librosa.beat.beat_track(y_verdin, sr = sr_verdin)
tempo_solsan, _ = librosa.beat.beat_track(y_solsan, sr = sr_solsan)
data = pd.DataFrame({"Type": birds ,
"BPM": [tempo_astfly, tempo_casvir, tempo_wilfly, tempo_subfly, tempo_verdin,tempo_solsan] })
# Plot
plt.figure(figsize = (16, 6))
ax = sns.barplot(y = data["BPM"], x = data["Type"], palette="rocket")
plt.ylabel("BPM", fontsize=14)
plt.yticks(fontsize=13)
plt.xticks(fontsize=13)
plt.xlabel("")
plt.title("BPM for 6 Different Bird Species", fontsize=16);
頻域特征
色譜圖
- 特征是音樂(lè)音頻的強(qiáng)大表示,其中我們使用稱為色度向量的 12 元素光譜能量表示,其中 12 個(gè) bin 中的每一個(gè)代表西方音樂(lè)的 12 個(gè)等律音高等級(jí)(半音間距)。
- 特征或向量通常是一個(gè) 12 元素的特征向量,指示信號(hào)中存在的每個(gè)音級(jí) {C、C#、D、D#、E、...、B} 的能量。 簡(jiǎn)而言之,它提供了一種健壯的方式來(lái)描述音樂(lè)片段之間的相似性度量。
- 圖中可以清楚地看到 12 個(gè) bin。它可以通過(guò)輸入聲音信號(hào)的對(duì)數(shù)短時(shí)傅里葉變換計(jì)算得出,也稱為色度
chroma=librosa.feature.chroma_stft(y=audio_casvir, sr=sr_casvir)
fig, ax = plt.subplots(1,figsize = (10, 5))
img = librosa.display.specshow(chroma, y_axis='chroma', x_axis='time', ax=ax)
fig.colorbar(img, ax=ax)
ax.set(title='Chromagram')
#using an energy(magnitude) spectrum
S = np.abs(librosa.stft(audio_casvir))
chroma = librosa.feature.chroma_stft(S=S, sr=sr_casvir)#applying the logarithmic fourier transform
fig, ax = plt.subplots(1,figsize = (10, 5))
img = librosa.display.specshow(chroma, y_axis='chroma', x_axis='time', ax=ax)
fig.colorbar(img, ax=ax)
ax.set(title='Chromagram')
恒定 Q 變換 (CQT)
恒定 Q 變換將數(shù)據(jù)序列變換到頻域,它與傅里葉變換有關(guān)。 一般來(lái)說(shuō),該變換非常適合音樂(lè)數(shù)據(jù),并且在頻率跨越幾個(gè)八度音階時(shí)證明是有用的。
chroma_stft = librosa.feature.chroma_stft(y=audio_casvir, sr=sr_casvir)
chroma_cq = librosa.feature.chroma_cqt(y=audio_casvir, sr=sr_casvir)
fig, ax = plt.subplots(nrows=2, sharex=True, sharey=True,figsize = (10, 9))
librosa.display.specshow(chroma_stft, y_axis='chroma', x_axis='time', ax=ax[0])
ax[0].set(title='chroma_stft')
ax[0].label_outer()
img = librosa.display.specshow(chroma_cq, y_axis='chroma', x_axis='time', ax=ax[1])
ax[1].set(title='chroma_cqt')
# ax[1].label_outer()
# img = librosa.display.specshow(chroma_cens, y_axis='chroma', x_axis='time', ax=ax[2])
# ax[2].set(title='chroma_cens')
fig.colorbar(img, ax=ax)
Chroma Energy distribution Normalized Statistics (CENS)
基于色度的特征是色度能量分布?xì)w一化統(tǒng)計(jì) (CENS),它通常用于識(shí)別給定音樂(lè)的不同解釋之間的相似性。 CENS 通常用于音頻匹配和相似性任務(wù)。
chroma_stft = librosa.feature.chroma_stft(y=audio_casvir, sr=sr_casvir)
chroma_cens = librosa.feature.chroma_cens(y=audio_casvir, sr=sr_casvir)
fig, ax = plt.subplots(nrows=2, sharex=True, sharey=True,figsize = (10, 9))
librosa.display.specshow(chroma_stft, y_axis='chroma', x_axis='time', ax=ax[0])
ax[0].set(title='chroma_stft')
ax[0].label_outer()
img = librosa.display.specshow(chroma_cens, y_axis='chroma', x_axis='time', ax=ax[1])
ax[1].set(title='chroma_cens')
fig.colorbar(img, ax=ax)
頻譜相關(guān)功能
光譜質(zhì)心
頻譜質(zhì)心是表征給定頻譜的“質(zhì)心”的量度。頻譜質(zhì)心計(jì)算為給定信號(hào)中存在的頻率的加權(quán)平均值,使用傅里葉變換確定,頻率幅度作為權(quán)重,這里S(k)是頻段k處的頻譜幅度,f(k)是頻段k處的頻率。
# Calculate the Spectral Centroids
spectral_centroids = librosa.feature.spectral_centroid(audio_casvir, sr=sr_casvir)[0]
# Shape is a vector
print('Centroids:', spectral_centroids, '\n')
print('Shape of Spectral Centroids:', spectral_centroids.shape, '\n')
# Computing the time variable for visualization
frames = range(len(spectral_centroids))
# Converts frame counts to time (seconds)
t = librosa.frames_to_time(frames)
print('frames:', frames, '\n')
print('t:', t)
# Function that normalizes the Sound Data
def normalize(x, axis=0):
return sklearn.preprocessing.minmax_scale(x, axis=axis)
#Plotting the Spectral Centroid along the waveform
plt.figure(figsize = (16, 6))
librosa.display.waveplot(audio_casvir, sr=sr_casvir, alpha=0.4, color = '#A300F9', lw=3)
plt.plot(t, normalize(spectral_centroids), color='#FFB100', lw=2)
plt.legend(["Spectral Centroid", "Wave"])
plt.title("Spectral Centroid: Casvir Bird", fontsize=16);
光譜對(duì)比度
譜峰和譜谷之間的差異將反映譜對(duì)比度分布。
contrast = librosa.feature.spectral_contrast(y=y_harm_casvir,sr=sr_casvir)
plt.figure(figsize=(15,5)) librosa.display.specshow(contrast, x_axis='time')
plt.colorbar() plt.ylabel('Frequency bands') plt.title('Spectral contrast')
SPECTRAL ROLLOFF
Spectral rolloff point定義為功率譜分布的第 N 個(gè)百分位頻率,通常為 85% 或 95%,滾降點(diǎn)是 N% 幅度分布集中的頻率。
# Spectral RollOff Vector # Spectral RollOff Vector
spectral_rolloff = librosa.feature.spectral_rolloff(audio_astfly, sr=sr_astfly)[0]
# Computing the time variable for visualization
frames = range(len(spectral_rolloff))
# Converts frame counts to time (seconds)
t = librosa.frames_to_time(frames)
# The plot
plt.figure(figsize = (16, 6))
librosa.display.waveplot(audio_astfly, sr=sr_astfly, alpha=0.4, color = '#A300F9', lw=3)
plt.plot(t, normalize(spectral_rolloff), color='#FFB100', lw=3)
plt.legend(["Spectral Rolloff", "Wave"])
plt.title("Spectral Rolloff: Astfly Bird", fontsize=16);
梅爾頻率倒譜系數(shù) (MFCC)
一種流行的音頻特征提取方法是梅爾頻率倒譜系數(shù) (MFCC),它有 39 個(gè)特征,特征計(jì)數(shù)足夠小,足以迫使模型學(xué)習(xí)音頻的信息。 12個(gè)參數(shù)與頻率的幅度有關(guān),它模擬了人聲的特征,MFCC特征的提取流程如下圖所示:
此功能是提取音頻信號(hào)特征的最重要方法之一,主要用于處理音頻信號(hào)。
mfcc=librosa.feature.mfcc(y=audio_astfly, sr=sr_astfly)
fig, ax = plt.subplots(1,figsize = (12, 6))
img = librosa.display.specshow(mfcc, x_axis='time', ax=ax)
print(mfcc.shape)
fig.colorbar(img, ax=ax)
ax.set(title='MFCC')
