[深度学习进阶 - 实操笔记] 语音识别基础

语音识别基础

1. 深度学习在语音领域上的应用

(1)语音识别
(2)语音唤醒
(3)语音命令
(4)声纹识别
(5)生成语音

2. 音频领域基本概念

(1)采样率:每秒采集数据的次数。
一般是8000Hz、16000Hz…
采样率越高,音频损失越小。根据奈奎斯特采样定理:当采样率高于最高频率2倍以上,音频数据就不会失真。因此处理数据的采样率选择,一般只要高于最高频率2倍以上就行。
(2)采样精度:每次采样数据的位数。即保存数据的精度:一般为一字节(8位)、两字节(16位)…
(3)通道数:存在几路音频。(左声道/右声道)
(4)比特率:针对编码格式,表示压缩编码后每秒的音频数据量大小。(bps,bit/s)
(5)音频格式:pcm、wav、MP3…
(6)声波:声音数据是连续的波形。但是计算机只能处理离散的数据,因此我们需要对数据进行采样。(通过上面哪些参数进行采样)

3. 语音识别

(1)首先需要用到torchaudio库。官方文档

① window下下载的方式:cmd

conda install -c conda-forge librosa
conda install -c groakat sox
git clone https://github.com/pytorch/audio.git

python setup.py install

② 载入数据,并绘制波形图。
载入的波形数据为(C,L):通道数,幅值,以及一个采样率。

filename = "../_static/img/steam-train-whistle-daniel_simon-converted-from-mp3.wav"
waveform, sample_rate = torchaudio.load(filename)

print("Shape of waveform: {}".format(waveform.size()))
print("Sample rate of waveform: {}".format(sample_rate))

plt.figure()
plt.plot(waveform.t().numpy())

(2)音频数据处理需要解决的几个问题:

① 音频数据长度不一: 补齐、截取、缩放…
补齐:在短的数据后面补0。
截取:截取长数据和短数据相等的一节。
缩放:自适应平均池化。(数据格式:NCL)即将一组数据缩放至一个统一的尺寸。
② 音频数据太长 (例如:1 * 50408)
方案一:原始数据做一维卷积,到25以内的长度后,用RNN做输出层输出。(利用大卷积核和大步长)
方案二:将音频信号从时域上转换到频域上进行处理。
( * 方案一理论可行,但是效果不好。模型没有先验,比较笨。)
③ 数据长度不一,每次训练只能一条数据作为一个批次进行训练,效果不好。
通过①的解决方案,将数据统一后,放入一个批次进行训练。

(3)MFCC 梅尔频率倒谱系数

根据上面(2)中的方案二,我们要将音频信号数据转换到频谱图上进行操作。(利用图进行训练,对神经网络而已比较简单。)
MFCC,简单的说就是根据人耳的接收能力进行音频信号处理,最终转换为频谱图。因此,相当于给了模型一个人耳的先验。具体内容参照这个博客

(4) 项目实战:

① 数据:可以使用谷歌语音识别官方数据的speech_commands来学习。我挑选一小部分数据进行学习。
首先将载入的音频数据(波形数据)转换为频谱图数据。然后对数据进行归一化。

# 可以直接在上面链接内下载,也可以通过下面代码下载。
import torchaudio,torch

dataset = torchaudio.datasets.SPEECHCOMMANDS(r"F:\data", url='speech_commands_v0.02', folder_in_archive='SpeechCommands', download=False)
data_loader = torch.utils.data.DataLoader(dataset, batch_size=1, shuffle=True)

for x in data_loader:
    print(x)
#这里采样率是载入时候读入的采样率
tf = torchaudio.transforms.MFCC(sample_rate=8000)

# 转换后的频谱图并没有归一化,因此要对数据做归一化
def normalize(tensor):
    tensor_minusmean = tensor - tensor.mean()
    return tensor_minusmean / tensor_minusmean.max()
#将数据统一长度,分批打包训练
datas = []
tags = []
for data, _, tag in data_loader:
	tag = torch.stack(tag, dim=1).float()
	specgram = normalize(tf(data))
	datas.append(F.adaptive_avg_pool2d(specgram, (32, 256)))
	tags.append(tag)
specgrams = torch.cat(datas, dim=0)
tags = torch.cat(tags, dim=0)

② 神经网络:
由于频谱图是长宽比较大,所以将长和宽拆开,分别处理。
卷积核选用(1,3)步长选用(1,2)padding为(0,1);即在序列上用卷积核为3,步长为2进行卷积,在特征上采用卷积核为1,步长为1进行卷积。(行为序列,列为特征)
频谱图:132256 通过卷积后:N43232
在进行正常的卷积:N
888
最后根据数据分类,变成想要的输出格式。(按音频的数据标签)
(或者也可以通过接入RNN或者全连接层输出)

class Net(torch.nn.Module):

    def __init__(self):
        super().__init__()
        self.seq = torch.nn.Sequential(
            torch.nn.Conv2d(1, 4, (1, 3), (1, 2), (0, 1)),
            torch.nn.BatchNorm2d(4),
            torch.nn.ReLU(),
            torch.nn.Conv2d(4, 4, (1, 3), (1, 2), (0, 1)),
            torch.nn.BatchNorm2d(4),
            torch.nn.ReLU(),
            torch.nn.Conv2d(4, 4, (1, 3), (1, 2), (0, 1)),# 4*32*32
            torch.nn.BatchNorm2d(4),
            torch.nn.ReLU(), 
            torch.nn.Conv2d(4, 8, 3, 2, 1),
            torch.nn.BatchNorm2d(8),
            torch.nn.ReLU(),
            torch.nn.Conv2d(8, 8, 3, 2, 1), # 8*8*8
            torch.nn.BatchNorm2d(8),
            torch.nn.ReLU(),
            torch.nn.Conv2d(8, 1, (8, 1)),# 这里使用的数据一个音频序列中有8个类别值,因此将数据转换成 1*1*8 
        )

    def forward(self, x):
        h = self.seq(x)
        return h.reshape(-1, 8)

③ 损失:这里直接使用MSELoss,将预测值与标签做MSE损失。

完整代码:

import torch
import torchaudio
from torch.nn import functional as F


def normalize(tensor):
    tensor_minusmean = tensor - tensor.mean()
    return tensor_minusmean / tensor_minusmean.max()


tf = torchaudio.transforms.MFCC(sample_rate=8000)


class Net(torch.nn.Module):

    def __init__(self):
        super().__init__()
        self.seq = torch.nn.Sequential(
            torch.nn.Conv2d(1, 4, (1, 3), (1, 2), (0, 1)),
            torch.nn.BatchNorm2d(4),
            torch.nn.ReLU(),
            torch.nn.Conv2d(4, 4, (1, 3), (1, 2), (0, 1)),
            torch.nn.BatchNorm2d(4),
            torch.nn.ReLU(),
            torch.nn.Conv2d(4, 4, (1, 3), (1, 2), (0, 1)),
            torch.nn.BatchNorm2d(4),
            torch.nn.ReLU(),
            torch.nn.Conv2d(4, 8, 3, 2, 1),
            torch.nn.BatchNorm2d(8),
            torch.nn.ReLU(),
            torch.nn.Conv2d(8, 8, 3, 2, 1),
            torch.nn.BatchNorm2d(8),
            torch.nn.ReLU(),
            torch.nn.Conv2d(8, 1, (8, 1)),
        )

    def forward(self, x):
        h = self.seq(x)
        return h.reshape(-1, 8)


if __name__ == '__main__':

    data_loader = torch.utils.data.DataLoader(torchaudio.datasets.YESNO('.',download=True), batch_size=1, shuffle=True)

    net = Net()
    opt = torch.optim.Adam(net.parameters())

    loss_fn = torch.nn.MSELoss()

    for epoch in range(100000):
        datas = []
        tags = []
        for data, _, tag in data_loader:
            tag = torch.stack(tag, dim=1).float()
            specgram = normalize(tf(data))
            datas.append(F.adaptive_avg_pool2d(specgram, (32, 256)))
            tags.append(tag)

        specgrams = torch.cat(datas, dim=0)
        tags = torch.cat(tags, dim=0)
        y = net(specgrams)
        loss = loss_fn(y, tags)

        opt.zero_grad()
        loss.backward()
        opt.step()
        print(loss)

你可能感兴趣的:(深度学习)