实战:基于特征词的语音唤醒

本章前面介绍了纯理论知识,目的是阐述语音识别的方法。接着搭建了开发环境,让读者可以动手编写代码。下面以识别特定词为例,使用深度学习方法和Python语言实现一个实战项目——基于特征词的语音唤醒。

说明:本例的目的是演示一个语音识别的Demo。如果读者已经安装开发环境,可以直接复制代码运行;如果没有,可学习完本章后再回头练习。我们会在本节中详细介绍每一步的操作过程和设计方法。

2.3.1  数据的准备

深度学习的第一步(也是重要的步骤)是数据的准备。数据的来源多种多样,既有不同类型的数据集,也有根据项目需求由项目组自行准备的数据集。由于本例的目的是识别特定词语而进行语音唤醒,因此采用一整套专门的语音命令数据集SpeechCommands,我们可以使用PyTorch专门的下载代码获取完整的数据集,代码如下:

#直接下载PyTorch数据库的语音文件

from torchaudio import datasets

datasets.SPEECHCOMMANDS(

    root="./dataset",               # 保存数据的路径

    url='speech_commands_v0.02',    # 下载数据版本URL

    folder_in_archive='SpeechCommands',

    download=True                   # 这个记得选True

)

SpeechCommands的数据量约为2GB,等待下载完毕后,可以在下载路径中查看下载的数据集,如图2-21所示。

打开数据集可以看到,根据不同的文件夹名称,其中内部被分成了40个类别,每个类别以名称命名,包含符合该文件名的语音发音,如图2-22和图2-23所示。

                        

可以看到,根据文件名对每个发音进行归类,其中包含:

  1. 训练集包含51088个WAV语音文件。
  2. 验证集包含6798个WAV语音文件。
  3. 测试集包含6835个WAV语音文件。

读者可以使用计算机自带的语音播放程序试听部分语音。

2.3.2  数据的处理

下面开始进入这个语音识别Demo的代码实现部分。相信读者已经试听过部分语音内容,摆在读者面前的第一个难题是,如何将语音转换成计算机可以识别的信号。

梅尔频率是基于人耳听觉特性提出来的,它与Hz频率呈非线性对应关系。梅尔频率倒谱系数(Mel-Frequency Cepstral Coefficients,MFCC)则是利用它们之间的这种关系计算得到的Hz频谱特征,主要用于语音数据特征提取和降低运算维度。例如,对于一帧有512维(采样点)的数据,经过MFCC后可以提取出最重要的40维(一般而言),数据同时也达到了降维的目的。

这里,我们将MFCC理解成使用一个“数字矩阵”来替代一段语音即可。计算MFCC实际上是一个烦琐的任务,需要使用专门的类库来实现对语音MFCC的提取,代码处理如下:

【程序2-1】

import os
import numpy as np

#获取文件夹中所有的文件地址
def list_files(path):
    files = []
    for item in os.listdir(path):
        file = os.path.join(path, item)
        if os.path.isfile(file):
            files.append(file)
    return files

# 这里是一个对单独序列的cut或者pad的操作
# 这里输入的y是一个一维的序列,将输入的一维序列y拉伸或者裁剪到length长度
def crop_or_pad(y, length, is_train=True, start=None):
    if len(y) < length:		#对长度进行判断
        y = np.concatenate([y, np.zeros(length - len(y))])	#若长度过短则进行补全操作

        n_repeats = length // len(y)
        epsilon = length % len(y)
        y = np.concatenate([y] * n_repeats + [y[:epsilon]])

    elif len(y) > length:	#对长度进行判断,若长度过长则进行截断操作
        if not is_train:
            start = start or 0
        else:
            start = start or np.random.randint(len(y) - length)

        y = y[start:start + length]
    return y

import librosa as lb
# 计算梅尔频率图
def compute_melspec(y, sr, n_mels, fmin, fmax):
    """
    :param y:传入的语音序列,每帧的采样
    :param sr: 采样率
    :param n_mels: 梅尔滤波器的频率倒谱系数
    :param fmin: 短时傅里叶变换(STFT)的分析范围 min
    :param fmax: 短时傅里叶变换(STFT)的分析范围 max
    :return:
    """
    # 计算Mel频谱图的函数
    melspec = lb.feature.melspectrogram(y=y, sr=sr, n_mels=n_mels, fmin=fmin, fmax=fmax)  # (128, 1024) 这个是输出一个声音的频谱矩阵
    # Python中用于将语音信号的功率值转换为分贝(dB)值的函数
    melspec = lb.power_to_db(melspec).astype(np.float32)
    return melspec

# 对输入的频谱矩阵进行正则化处理
def mono_to_color(X, eps=1e-6, mean=None, std=None):
    mean = mean or X.mean()
    std = std or X.std()
    X = (X - mean) / (std + eps)

    _min, _max = X.min(), X.max()

    if (_max - _min) > eps:		#对越过阈值的内容进行处理
        V = np.clip(X, _min, _max)
        V = 255. * (V - _min) / (_max - _min)
        V = V.astype(np.uint8)
    else:
        V = np.zeros_like(X, dtype=np.uint8)
    return V

#创建语音特征矩阵
def audio_to_image(audio, sr, n_mels, fmin, fmax):
	#获取梅尔频率图
    melspec = compute_melspec(audio, sr, n_mels, fmin, fmax)
	#进行正则化处理
    image = mono_to_color(melspec)
    return image
使用创建好的MFCC生产函数获取特定语音的MFCC矩阵也很容易,代码如下:
import numpy as np
from torchaudio import datasets
import sound_untils
import soundfile as sf

print("开始数据处理")
target_classes = ["bed","bird","cat","dog","four"]

counter = 0
sr = 16000
n_mels = 128
fmin = 0
fmax = sr//2
file_folder = "./dataset/SpeechCommands/speech_commands_v0.02/"
labels = []
sound_features = []
for classes in target_classes:
    target_folder = file_folder + classes
    _files = sound_untils.list_files(target_folder)
    for _file in _files:
        audio, orig_sr = sf.read(_file, dtype="float32")  # 这里均值是 1308338,   0.8中位数是1730351,所以作者采用了中位数的部分
        audio = sound_untils.crop_or_pad(audio, length=orig_sr)  # 作者的想法是把audio做一个整体输入,在这里所有的都做了输入
        image = sound_untils.audio_to_image(audio, sr, n_mels, fmin, fmax)
        sound_features.append(image)
        label = target_classes.index(classes)
        labels.append(label)
sound_features = np.array(sound_features)
print(sound_features.shape) #(11965, 128, 32)
print(len(labels))                  #(11965, 128, 32)

最终打印结果如下:

(11965,128,32)

11965

可以看到,根据作者设定的参数,特定路径指定的语音被转换成一个固定大小的矩阵,这也是根据前面超参数的设定而计算出的一个特定矩阵。有兴趣的读者可以将其打印出来并观察其内容。

2.3.3  模型的设计

对于深度学习而言,模型的设计是非常重要的步骤,由于本节的实战案例只是用于演示,因此采用了最简单的判别模型,实现代码如下(仅供读者演示,详细的内容在后续章节中介绍):

【程序2-2】

#这里使用ResNet作为特征提取模型,仅供读者演示,详细的内容在后续章节中介绍
import torch

class ResNet(torch.nn.Module):
    def __init__(self,inchannels = 32):
        super(ResNet, self).__init__()
	   #定义初始化神经网络层
        self.cnn_1 = torch.nn.Conv1d(inchannels,inchannels*2,3,padding=1)
        self.batch_norm = torch.nn.BatchNorm1d(inchannels*2)
        self.cnn_2 = torch.nn.Conv1d(inchannels*2,inchannels,3,padding=1)
        self.logits = torch.nn.Linear(128 * 32,5)

    def forward(self,x):
	   #使用初始化定义的神经网络计算层进行计算
        y = self.cnn_1((x.permute(0, 2, 1)))
        y = self.batch_norm(y)
        y = y.permute(0, 2, 1)
        y = torch.nn.ReLU()(y)
        y = self.cnn_2((y.permute(0, 2, 1))).permute(0, 2, 1)
        output = x + y
        output = torch.nn.Flatten()(output)
        logits = self.logits(output)
        return logits

if __name__ == '__main__':
    image = torch.randn(size=(3,128,32))
    ResNet()(image)

上面代码中的ResNet类继承自torch中的nn.Module类,目的是创建一个可以运行的深度学习模型,并在forward函数中通过神经网络进行计算,最终将计算结果作为返回值返回。

2.3.4  模型的数据输入方法

接下来设定模型的数据输入方法。深度学习模型的每一步都需要数据内容的输入,但是,一般情况下,由于计算硬件——显存的大小有限制,因此在输入数据时需要分步骤一块一块地将数据输入训练模型中。此处数据输入的实现代码如下:

【程序2-3】

#创建基于PyTorch的数据读取格式
import torch
class SoundDataset(torch.utils.data.Dataset):
	#初始化数据读取地址
    def __init__(self, sound_features = sound_features,labels = labels):

        self.sound_features = sound_features
        self.labels = labels

    def __len__(self):
        return len(self.labels)	#获取完整的数据集长度
	
    def __getitem__(self, idx):
        #对数据进行读取,在模板中每次读取一个序号指向的数据内容
        image = self.sound_features[idx]
        image = torch.tensor(image).float()		#对读取的数据进行类型转换

        label = self.labels[idx]
        label = torch.tensor(label).long()		#对读取的数据进行类型转换

        return image, label

在上面代码中,首先根据传入的数据在初始化时生成供训练使用的训练数据和对应的标签,之后的getitem函数建立了一个“传送带”,目的是源源不断地将待训练数据传递给训练模型,从而完成模型的训练。

2.3.5  模型的训练

对模型进行训练时,需要定义模型的一些训练参数,如优化器、损失函数、准确率以及训练的循环次数等。模型训练的实现代码如下:

import torch
from torch.utils.data import DataLoader, Dataset
from tqdm import tqdm

device = "cuda"

from sound_model import ResNet
sound_model = ResNet().to(device)

BATCH_SIZE = 32
LEARNING_RATE = 2e-5

import get_data
#导入数据集
train_dataset = get_data.SoundDataset()
#以PyTorch生成数据模板进行数据的读取和输出操作
train_loader = (DataLoader(train_dataset, batch_size=BATCH_SIZE,shuffle=True,num_workers=0))

#PyTorch中的优化器
optimizer = torch.optim.AdamW(sound_model.parameters(), lr = LEARNING_RATE)
#对学习率进行修正的函数
lr_scheduler = torch.optim.lr_scheduler.CosineAnnealingLR(optimizer,T_max = 1600,eta_min=LEARNING_RATE/20,last_epoch=-1)
#定义损失函数
criterion = torch.nn.CrossEntropyLoss()

for epoch in range(9):
    pbar = tqdm(train_loader,total=len(train_loader))
    train_loss = 0.
    for token_inp,token_tgt in pbar:
        #将数据传入硬件中
        token_inp = token_inp.to(device)
        token_tgt = token_tgt.to(device)
        #采用模型进行计算
        logits = sound_model(token_inp)
        #使用损失函数计算差值
        loss = criterion(logits, token_tgt)
        #计算梯度
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        lr_scheduler.step()  # 执行优化器
        train_accuracy = ((torch.argmax(torch.nn.Softmax(dim=-1)(logits), dim=-1) == (token_tgt)).type(torch.float).sum().item() / len(token_tgt))

        pbar.set_description(
            f"epoch:{epoch + 1}, train_loss:{loss.item():.4f},, train_accuracy:{train_accuracy:.2f}, lr:{lr_scheduler.get_last_lr()[0] * 1000:.5f}")

上面代码完成了一个可以运行并持续对结果进行输出的训练模型,首先初始化模型的实例,之后建立数据的传递通道,而优化函数和损失函数也可以通过显式定义完成。
 

本文节选自《PyTorch语音识别实战》,获出版社和作者授权发布。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/433013.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

当Sora风靡,AI风潮吹醒金融科技

以下文章来源&#xff1a;凤凰网 前有OpenAI发布了Sora&#xff0c; 后有苹果放弃了秘密进行了十年的造车项目&#xff0c;转身拥抱AI&#xff0c; 再有国内市场上此起彼伏的AI呐喊声&#xff0c; 一场以AI为主导的新热浪&#xff0c;正在来袭。 当AI的风潮开始兴盛&#x…

JavaScript 原型链继承:掌握面向对象的基础

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

springboot + jpa + 达梦数据库兼容 Mysql的GenerationType.IDENTITY主键生成策略

导入达梦数据库对hibernate的方言包 <dependency><groupId>com.dameng</groupId><artifactId>DmDialect-for-hibernate5.6</artifactId><version>8.1.2.192</version></dependency>配置文件中添加方言配置和主键生成策略配置…

(译) 理解 Prometheus 的范围向量 (Range Vector)

Prometheus 中 Range Vector 的概念是有一点不直观的&#xff0c;除非你彻底阅读并理解了官方提供的文档。谁会这样做呢&#xff0c;去读官方文档&#xff1f;大多的人应该会花些错误的时间去做了一些错误的事情&#xff0c;然后随机去寻找一篇像本文一样的文章去理解这个概念&…

2024年Java者未来的出路在哪里,java多线程面试

重要 大环境对于我们能力要求越来越高&#xff0c;医学专家又说今年冬天新冠肺炎将“席卷重来”。 如果疫情再次爆发&#xff0c;势必将再次影响企业的正常运作&#xff0c;一波裁员浪潮你又能否抗住&#xff1f; 不管如何&#xff0c;明年金三银四又是一波跳槽时机&#xf…

AbaqusCST仿真软件功能对比简介

一、功能对比 支持维度CST&#xff1a;用于设计、分析和优化电磁部件及系统。适用于整个 EM 范围内各类应用领域的电磁场解算。Abaqus&#xff1a;ABAQUS 是一套功能强大的工程模拟的有限元软件&#xff0c;其解决问题的范围从相对简单的线性分析到复杂的非线性问题。 ABAQUS 包…

基于springboot+vue的精简博客系统

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、阿里云专家博主、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战&#xff0c;欢迎高校老师\讲师\同行交流合作 ​主要内容&#xff1a;毕业设计(Javaweb项目|小程序|Pyt…

flutter弹窗动画,2024年上半年最接地气的Android面经

正文 腾讯研发人数将近 2 万人&#xff0c;T4 级别的人数大概也不超过 500 人&#xff0c;这还是在近两年 T3 到 T4 级别人数增多的情况下。 该资料一共有五大章节&#xff0c;452页&#xff0c;是这位腾讯T4大佬耗时半个月熬夜整理出来的。 目录 第一章 深入解析 Binder. …

Java面试题【必知必会】Mybatis常见面试题(2024)

近期一直在准备面试&#xff0c;所以为了巩固知识&#xff0c;也为了梳理&#xff0c;整理了一些java的基础面试题&#xff01;同时也希望各位英雄和女侠能够补充&#xff01;不胜荣幸&#xff01;&#xff01;&#xff01; 名称地址Java面试题【必知必会】基础&#xff08;202…

Web3 赛道屠夫:「铁顺」是谁?

撰文&#xff1a;Terry 加密世界从不缺传奇故事&#xff0c;从不会编程的「失业青年」Hayden Adams 一入 Web3 便推出巅峰之作 Uniswap&#xff08;《交易平台搅局者「Uniswap 之父」&#xff0c;不会编程的「失业青年」&#xff0c;出手即巅峰》&#xff09;&#xff0c;到 An…

VMware虚拟机安装linux教程

CentOS7下载 下载 (centos.org)https://www.centos.org/download/新建虚拟机 选择自定义安装 这里要注意兼容性&#xff0c;如果是VMware12创建的虚拟机复制到VM11、10或者更低的版本会出现一不兼容的现象。如果是用VMware10创建的虚拟机在VMware12中打开则不会出现兼容性问题…

二,几何相交----2.线段相交测试----(1)bruteforce

将与X轴平行的线段扩展到一般平面上的线段。 则可以使用burteforce两两测试&#xff0c;使用四次toleft即可。比如&#xff0c;线段(a,b)和线段(c,d)相交&#xff0c;必然线段的两个端点在另一个线段的两侧。这样时间复杂度就是成为了o(n2) 其实&#xff0c;时间复杂度可以降低…

半导体分析实验常用清洗器皿特氟龙塑料PFA实验室耗材

晶圆是一种用于制造集成电路和其他半导体器件的基础材料&#xff0c;通常是由单晶硅制成的圆形薄片&#xff0c;随着半导体行业的兴起&#xff0c;其作为行业内常用元件的基础材料&#xff0c;为了保证它可以正常工作&#xff0c;晶圆表面要保持洁净&#xff0c;无不相关的颗粒…

酷开科技以酷开系统为媒介,打造欢乐生活场景

家人相聚在一起的时光总是那么美好&#xff0c;在欢聚的日子里&#xff0c;我们也总是希望能够让时间变得慢一点&#xff0c;再慢一点&#xff0c;但是随着春节假期的结束&#xff0c;很多人已经开始了新一年的忙碌&#xff0c;大家纷纷回到工作、学习岗位&#xff0c;回归之前…

自动驾驶预测与决策规划(nuplan数据集)

欢迎大家关注我的B站&#xff1a; 偷吃薯片的Zheng同学的个人空间-偷吃薯片的Zheng同学个人主页-哔哩哔哩视频 (bilibili.com) 目录 1.概述 2 数据采集 3.开环与闭环仿真 4.数据注释 5.场景 6.规划框架 6.1Train 6.2Simulation 6.3Metric 6.4Visualization 7.下载…

如何使用DS file+cpolar内网穿透实现远程访问本地群晖NAS传输文件

文章目录 1. 群晖安装Cpolar2. 创建TCP公网地址3. 远程访问群晖文件4. 固定TCP公网地址5. 固定TCP地址连接 DS file 是一个由群晖公司开发的文件管理应用程序&#xff0c;主要用于浏览、访问和管理存储在群晖NAS&#xff08;网络附加存储&#xff09;中的文件。这个应用程序具有…

阿里云2024年有什么优惠活动?阿里云30个热门优惠活动汇总

对于想要购买阿里云各种云产品的用户来说&#xff0c;不管是新用户还是老用户&#xff0c;最为关心的是阿里云当下有哪些优惠活动&#xff0c;本文汇集了2024年阿里云官方目前正在进行中的所有优惠活动&#xff0c;其中优惠券和代金券活动4个&#xff0c;官方精选活动10个&…

鹅厂打工8年,我为啥突然裸辞?

公众号&#xff1a;程序员白特&#xff0c;欢迎一起交流学习~ 原文&#xff1a;以下文章来源于沐洒 &#xff0c;作者ASCII26 今天跟大家分享一个重磅消息&#xff0c;沐洒终于从腾讯离职了&#xff01; 不知不觉已经在鹅厂打了8年工&#xff0c;如果说在大厂里工作如同在高校…

基于 HBase Phoenix 构建实时数仓(1)—— Hadoop HA 安装部署

目录 一、主机规划 二、环境准备 1. 启动 NTP 时钟同步 2. 修改 hosts 文件 3. 配置所有主机间 ssh 免密 4. 修改用户可打开文件数与进程数&#xff08;可选&#xff09; 三、安装 JDK 四、安装部署 Zookeeper 集群 1. 解压、配置环境变量 2. 创建配置文件 3. 创建新…

各中间件性能、优缺点对比

参考资料&#xff1a; Kafka、ActiveMQ、RabbitMQ、RocketMQ 有什么优缺点&#xff1f;