機械学習における音声データの水増し

データの水増し画像ばっかり

# 音声データの水増し方法について考えよう
出来そうなこと

- 音量上げ/下げ
- 音声の引き延ばし/縮め
- ノイズの付加
- 時間シフト
- 音の高さ（ピッチ）の変更
- 残響付加

Kaggleの[これ](https://www.kaggle.com/CVxTz/audio-data-augmentation)とか見てると前半の4つくらいはやってるけど、むしろ音声認識みたいな室内で使うような音声モデルを扱いたいなら後半二つこそやるべきだと思う。前半のやつについてはそのままコードを借ります。

**データ読み込み**

```wav.py
import librosa
filename = "unko.wav"
data, _ = librosa.load(filename,sr=16000)
```
## 1.音量を変える
もうこれでいいと思う。音量が1.2倍になる

```sample.py
data_vol = data * 1.2
```

ランダムに音量を変えたければこんな感じで良さそう

```sample.py
import random
data_vol = data * random.uniform(0.8, 1.2) 
```

## 2.音声を伸縮する
つまり早口にしたりゆっくりにしたりする。
これは上のkaggleのリンク先のコードを拝借してます。
`rate`で何倍速で話すか設定してます。

```sample.py
def stretch(data, rate=1):
    input_length = len(data)
    data = librosa.effects.time_stretch(data, rate)
    if len(data)>input_length:
        data = data[:input_length]
    else:
        data = np.pad(data, (0, max(0, input_length - len(data))), "constant")
    return data

data_stretch = stretch(data, rate=random.uniform(0.5, 1.5)) #ランダムデータ伸縮
```

## 3.音声をずらす
話しはじめの時間をずらします。
`shift`タップ分の音声のスタート地点を後ろにずらして、ずらしてはみ出たぶんの音声は最初にまわります。

```sample.py
def time_shift(data,shift):
    data_roll = np.roll(data, shift)
    return data_roll

data_timeshift = time_shift(data,2**10)
```

## 4.音の高さを変える
ピッチを変えます。
`bins_per_octave=12`というのは１オクターブを１２に分けてるよってやつです。
１２音階はピアノの鍵盤と一緒です。
ここではあんまり関係ないですけど、`bins_per_octave=12`のとき`shift`は  

    +12:1オクターブ上
    -12:1オクターブ下
    +7:完全５度
    +5:完全４度
に対応します。

```sample.py
def pitch_shift(data,sample_rate,shift):
    ret = librosa.effects.pitch_shift(data, sample_rate, shift, bins_per_octave=12, res_type='kaiser_best')
    return ret

data_pitch = pitch_shift(data,16000,random.uniform(-12, 12))
```

## 5.ノイズの付加
音声強調ではできるだけ綺麗な音声が望ましいですが、音声認識や識別の場合何かしらのノイズを付与することでデータを増やすことがあります。ここで付与される音声はホワイトノイズが使われることが多いですが、音声の場合画像と違って何もホワイトノイズに囚われる必要はなくて、環境音だったり音楽だったりもノイズとして付与できます。

下ではノイズデータの大きさを`noise_rate`で調整して、音声データに比べて長さが足りない場合はリピート再生させることで長さを伸ばしています。

```sample.py

noise_data,_ = librosa.load("noise.wav",sr=16000)
def addnoise(data,noise_data,noise_rate):
    if len(data) < len(noise_data):
        ret = data + (noise_data[:len(data)]*noise_rate)
    else:
        while len(noise_data) < len(data):
            noise_data = torch.cat((noise_data,noise_data),0)[:audio_len]
        ret = data + (noise_data[:len(data)]*noise_rate)
    return ret

data_addnoise = addnoise(data,noise_data,1.0)
```

ホワイトノイズを付与したい場合は次の通り

```sample.py
wn = np.random.randn(len(data))
data_wn = data + 0.005*wn
```

## 6.響きをつける
音声認識とかの場合、その辺で配布されているような響きのないドライな音声というのはあんまり現実的ではなくて、実際には室内の反響の影響を大きく受けています。学習させるならこの辺こそやった方がいい。

[こんな感じ](https://qiita.com/oozzZZZZ/items/8dd90f17aad100b8ec43#%E3%82%B7%E3%83%9F%E3%83%A5%E3%83%AC%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E3%81%95%E3%82%8C%E3%81%9F%E9%9F%B3%E3%82%92%E8%81%B4%E3%81%8F)にリバーブをシミュレーションしてつけてみるのもいいんですけど、いちいちこんなことしてたらきりないので、「室内　インパルス応答　データ」とかで検索してインパルス応答のwavファイルをいくつか拾ってきて

```sample.py
from scipy.signal import fftconvolve

ir_data ,_ = librosa.load("inpulse_responce.wav",sr=16000)
data_riv = fftconvolve(data,ir_data)
```

こんな感じでやれば響きを付与できます。

実際そんないくつもインパルス応答を用意する必要はないと思うので、[ここから](https://qiita.com/oozzZZZZ/items/8dd90f17aad100b8ec43#%E3%82%A4%E3%83%B3%E3%83%91%E3%83%AB%E3%82%B9%E5%BF%9C%E7%AD%94%E3%82%92%E7%A2%BA%E8%AA%8D%E3%81%99%E3%82%8B)４種類くらい壁の吸音率や部屋の大きさの条件を変えてインパルス応答を用意しといて、ランダムに選択する感じでいいと思います。

**追記** ラボメンが擬似的にインパルス応答を生成する方法を書いてくれました。神です。
[[Qiita]残響曲線から残響フィルタを算出する](https://qiita.com/kabewall/items/5e8e148a9f88164a308d)

# 終わりに

こんな感じで音響工学的視点でもいろいろ水増しできると思うのでぜひ試してみては。
実際精度は上がります。
それでは〜