音訊資料增強及python實現

凌逆戰發表於2020-10-02

部落格作者:凌逆戰

部落格地址:https://www.cnblogs.com/LXP-Never/p/13404523.html


  音訊時域波形具有以下特徵:音調,響度,質量。我們在進行資料增強時,最好只做一些小改動,使得增強資料和源資料存在較小差異即可,切記不能改變原有資料的結構,不然將產生“髒資料”,通過對音訊資料進行資料增強,能有助於我們的模型避免過度擬合併變得更加通用。

  我發現對聲波的以下改變是有用的:Noise addition(增加噪音)、增加混響Time shifting(時移)Pitch shifting(改變音調)Time stretching(時間拉伸)

本章需要使用的python庫:

  • matplotlib:繪製影像
  • librosa:音訊資料處理
  • numpy:矩陣資料處理

使用先畫出原始語音資料的語譜圖和波形圖

import librosa
import numpy as np
import matplotlib.pyplot as plt

plt.rcParams['font.sans-serif'] = ['SimHei']  # 用來正常顯示中文標籤
plt.rcParams['axes.unicode_minus'] = False  # 用來正常顯示符號
fs = 16000

wav_data, _ = librosa.load("./p225_001.wav", sr=fs, mono=True)

# ########### 畫圖
plt.subplot(2, 2, 1)
plt.title("語譜圖", fontsize=15)
plt.specgram(wav_data, Fs=16000, scale_by_freq=True, sides='default', cmap="jet")
plt.xlabel('秒/s', fontsize=15)
plt.ylabel('頻率/Hz', fontsize=15)

plt.subplot(2, 2, 2)
plt.title("波形圖", fontsize=15)
time = np.arange(0, len(wav_data)) * (1.0 / fs)
plt.plot(time, wav_data)
plt.xlabel('秒/s', fontsize=15)
plt.ylabel('振幅', fontsize=15)

plt.tight_layout()
plt.show()

加噪

  新增的噪聲為均值為0,標準差為1的高斯白噪聲,有兩種方法對資料進行加噪

第一種:控制噪聲因子

def add_noise1(x, w=0.004):
    # w:噪聲因子
    output = x + w * np.random.normal(loc=0, scale=1, size=len(x))
    return output

Augmentation = add_noise1(x=wav_data, w=0.004)

第二種:控制訊雜比

  通過訊雜比的公式推匯出噪聲。

$$SNR=10*log_{10}(\frac{S^2}{N^2})$$

$$N=\sqrt{\frac{S^2}{10^{\frac{SNR}{10}}}}$$

def add_noise2(x, snr):
    # snr:生成的語音訊雜比
    P_signal = np.sum(abs(x) ** 2) / len(x)  # 訊號功率
    P_noise = P_signal / 10 ** (snr / 10.0)  # 噪聲功率
    return x + np.random.randn(len(x)) * np.sqrt(P_noise)

Augmentation = add_noise2(x=wav_data, snr=50)

波形位移

  語音波形移動使用numpy.roll函式向右移動shift距離

numpy.roll(a, shift, axis=None)

引數

  • a:陣列
  • shift:滾動的長度
  • axis:滾動的維度。0為垂直滾動,1為水平滾動,引數為None時,會先將陣列扁平化,進行滾動操作後,恢復原始形狀
x = np.arange(10)
# array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

print(np.roll(x, 2))
# array([8, 9, 0, 1, 2, 3, 4, 5, 6, 7])

波形位移函式:

def time_shift(x, shift):
    # shift:移動的長度
    return np.roll(x, int(shift))

Augmentation = time_shift(wav_data, shift=fs//2)

波形拉伸

  在不影響音高的情況下改變聲音的速度 / 持續時間。這可以使用librosa的time_stretch函式來實現。

def time_stretch(x, rate):
    # rate:拉伸的尺寸,
    # rate > 1 加快速度
    # rate < 1 放慢速度
    return librosa.effects.time_stretch(x, rate)

Augmentation = time_stretch(wav_data, rate=2)

音高修正(Pitch Shifting)

  音高修正只改變音高而不影響音速,我發現-5到5之間的步數更合適

def pitch_shifting(x, sr, n_steps, bins_per_octave=12):
    # sr: 音訊取樣率
    # n_steps: 要移動多少步
    # bins_per_octave: 每個八度音階(半音)多少步
    return librosa.effects.pitch_shift(x, sr, n_steps, bins_per_octave=bins_per_octave)

# 向上移三音(如果bins_per_octave為12,則六步)
Augmentation = pitch_shifting(wav_data, sr=fs, n_steps=6, bins_per_octave=12)
# 向上移三音(如果bins_per_octave為24,則3步)
Augmentation = pitch_shifting(wav_data, sr=fs, n_steps=3, bins_per_octave=24)
# 向下移三音(如果bins_per_octave為12,則六步)
Augmentation = pitch_shifting(wav_data, sr=fs, n_steps=-6, bins_per_octave=12)

 

相關文章