声纹识别单元-总体设计篇

长文。声纹识别单元的综述文档以及一致方案。声纹识别是一类典型的模式识别问题,在身份验证和说话人识别分类等领域获得广泛的应用。

课题来源及研究的目的和意义

声纹是语音中所蕴涵的、能表征和标识说话人的语音特征,以及基于这些特征(参数)所建立的语音模型的总称。声纹作为生物特征,在身份认证的应用中具有不会丢失、被盗或遗忘的特性。声纹识别技术是当下最热门的技术之一,在远程认证等应用领域具有独特优势。与其他生物特征相比,作为行为特征的声纹具有以下特点:

  • 蕴含声纹特征的语音获取方便,在采集过程中涉及到的用户个人隐私信息较少。因此使用者更易接受;
  • 语音采集装置成本低廉,使用简单,一个麦克风即可;
  • 配合语音识别技术,可以使声纹口令动态变化而无需担心密码遗忘、丢失和窃取的问题,防止录音假冒,也适合远程身份认证。

声纹识别是根据待识别语音的声纹特征识别该段语音所对应的说话人的过程。与指纹类似,每个人在说话过程中所蕴涵的语音特征和发音习惯几乎是独一无二的。

声纹识别和语音识别看似相同实则不同。声纹识别的过程是试图找到区别每个人的个性特征,而语音识别则是侧重于对话者所表述的内容进行区分。虽然大部分声纹识别系统用的都是声学层面的特征,但是表征一个人特点的特征应该是多层面的,包括以下几点:

  • 与人类的发音机制的解剖学结构有关的声学特征(如频谱、倒频谱、共振峰、基音、反射系数等等)、鼻音、带深呼吸音、沙哑音、笑声等;
  • 受社会经济状况、受教育水平、出生地等影响的语义、修辞、发音、言语习惯等;
  • 个人特点或受父母影响的韵律、节奏、速度、语调、音量等特征。从利用数学方法可以建模的角度出发,声纹自动识别模型可以使用的特征包括:
    • 声学特征(倒频谱);
    • 词法特征(说话人相关的词n-gram,音素n-gram);
    • 韵律特征(利用n-gram描述的基音和能量“姿势”);
    • 语种、方言和口音信息;
    • 通道信息(使用何种通道)。

在实际应用中往往把语音识别技术和声纹识别技术结合起来使用,可以进一步提高声纹身份认证系统的安全性能。本课题条件有限,所以尽可能的使用声学特征。

总体来说,声纹识别是一类典型的模式识别问题,其主要包含说话人模型训练和测试语音识别2个阶段。

  • 训练阶段(特征提取) 对使用系统的说话人预留充足的语音,并对不同说话人语音提取声学特征,然后根据每个说话人的语音特征训练得到对应的说话人模型,最终将全体说话人模型集合在一起组成系统的说话人模型库。

    根据不同的任务需求,声纹识别还面临一个特征选择或特征选用的问题。例如,对于信道相关的信息,在刑侦应用上是不会采用的。也就是说刑侦应用希望弱化信道对说话人识别的影响,这样不管说话人用什么信道系统,在刑侦上都可以辨认出来;而在银行交易上,更多会采用信道信息,即信道对说话人识别有较大影响,从而可以剔除录音、模仿等带来的影响。

    总之,较好的特征能够有效的区分不同的说话人,但又能在同一说话人语音发生变化时保持相对的稳定,并不易被他人模仿或能够较好地解决被他人模仿问题,同时还具有较好的抗噪性能。当然以上这些问题可以通过模型方法去解决。

  • 识别阶段(模式识别) 进行识别认证时,系统对识别语音进行相同的特征提取过程,并将语音特征与说话人模型库进行比对,得到对应说话人模型的相似性打分,最终根据识别打分判别得到识别语音的说话人身份。

    识别阶段需要解决的关键问题还有很多,诸如:短话音问题,能否用很短的语音进行模型训练,而且用很短的时间进行识别。这主要是声音不易获取的应用所需求的;声音模仿(或放录音)问题要有效地区分开模仿声音(录音)和真正的声音多说话人情况下目标说话人的有效检出不同语言、内容、方式、身体状况、时间、年龄等)带来的影响消除信道差异和背景噪音带来的影响;此时需要用到其他一些技术来辅助完成,如去噪、自适应等技术。

声纹识别几乎可以应用到人们日常生活的各个角落,本课题的目的是打造专为教学操作系统设计的身份识别认证。在功能性上要解决的有下列问题:

  • 用户身份确认。为了提供安全性,可以采取以下措施:密码和声纹双保险,如随机提示文本用文本相关的声纹识别技术进行身份确认(随机提示文本保证无法用事先录好的音去假冒)甚至可以把验证时声音录下来以备查询。
  • (可选)声纹识别可以在中心应用中为用户提供友好的个性化交互服务。

课题调研的边缘计算平台有下列三种:STM32系列、Sipeed Maix Dock K210 开发板和兼容RISC-V核(D1)及Arm核(R528)的综合平台。教学操作系统选择清华ucore。

国内外在该方向的研究现状及分析

2011年,苹果公司最新的智能手机iPhone 4S首次搭载了智能语音助手Siri;2014年,美国亚马逊公司开发的智能音箱Echo横空出世。此后,2015年京东与科大讯飞合作开发了智能音箱叮咚;2016年谷歌发布搭载了谷歌助手Google Assistant的智能音箱Google Home;2017年苹果推出自家的智能音箱HomePod;同年,阿里巴巴人工智能实验室发布智能音箱天猫精灵,小米发布小米AI音箱,百度发布智能音箱Raven H,喜马拉雅发布小雅AI音箱。这些商业产品的背后,都凝聚着音频处理、语音识别和自然语言处理等多个领域数十年的研究成果。但很可惜,上述产品在最初发布的时候都没有加入任何声纹识别方面的技术,这就导致智能语音助手无法根据说话人的身份,提供个性化的回答,并决定是否提供较为隐私的用户信息。

而谷歌公司在声纹领域的领军地位,除了其率先发表的关于d-vector技术的多篇论文外,更在于其首次将声纹技术部署到了其诸多产品之中。谷歌推出语音搜索后不久,便将唤醒词 “OK Google”部署到了安卓手机操作系统上,使得用户能够选择通过唤醒词的声纹来解锁手机。2017年,谷歌率先将基于唤醒词的文本相关的声纹识别技术部署到了智能音箱Google Home使得用户能够与智能语音助手进行个性化的语音交互,2018年,谷歌又将文本无关的声纹识别技术部署到了GoogleHome上,用于进一步扩充应用场景,以及提升声纹识别的准确率。2020年,谷歌将声纹识别技术部署到了包括Sonos和Bose在内的所有支持谷歌语音助手的第三方设备上,使得更多用户能够体验声纹识别带来的个性化交互体验。

以苹果Siri为例(以下图源:https://machinelearning.apple.com/research/hey-siri),苹果的Siri允许用户免提的调用Siri,这个过程是硬件、软件和互联网无缝的协同工作。当用户在忙碌的时候可以通过Hey Siri~来唤醒,Siri大部分实现是在云端,包括主要的自动语音识别、自然语言处理和声学模型的更新等信息服务。

1.png

iPhone的麦克风是以每秒16000转的速度将语音转换为瞬时波形流,在频谱分析的时候会将其转换为一系列的帧,每个帧大概描述约0.01秒的声音频谱,一次约20左右的帧被输入声学模型(深度神经网络DNN),描述一个语音的概率分布。所有计算都在模型中完成,当满足阈值条件后就会激活Siri。(阈值是动态的,以便在困难的条件下更轻松的激活Siri)。

上述功能的实现,就注定了传感器不仅要准确,而且要快速,对电池续航时间没有显著影响,而且还要最大限度的减少内存使用和处理器的需求。iPhone始终在一个低功率的辅助处理器来访问麦克风信号,并用这些有限的处理能力来运行声学模型。所以要充分考虑硬件之间,以及硬件和软件之间的协同工作。

关于声纹识别的安全性问题,我国的声扬科技除了研发出防录音攻击技术,还攻克了4大难点:短语音的识别文本无关识别、跨信道识别和环境噪音影响。以短语音识别为例,传统的声纹识别注册、验证的时间大多在数十秒以上,想缩短用时就要牺牲准确率和安全性。而依托首创的语音深度处理神经网络技术(DPNN和DHNN),声扬科技的声纹识别技术只需要一句短语就可以验证。经测试,声扬科技拥有行业领先的识别准确率达99.5%。

三大硬件平台

前文提及,本课题涉及三大硬件平台:STM32系列、Sipeed Maix Dock K210 开发板和兼容RISC-V核(D1)及Arm核(R528)的综合平台。下面对STM32系列进行进一步的选型。

内核概况

STM32是基于ARM内核的32位MCU系列,它的内核是Cortex-M内核,是标准的ARM架构。不过在19年时意法半导体推出了第一颗通用型STM32 MPU,内核从Cortex-M跨到了Cortex-A,软件上兼顾了运行在A7核上的Linux 与跑在M4内核的 STM32Cube。

ARM Cortex内核系列提供非常广泛的具有可扩展性的性能选项,设计人员有机会在多种选项中选择最适合自身应用的内核,而非千篇一律的采用同一方案。Cortex系列组合大体上分为三种类别:

  • Cortex-A:面向性能密集型系统的应用处理器内核,对成本敏感型的智能手机和平板电脑来说是理想的选择。
  • Cortex-R:面向实时应用的高性能内核,针对高性能实时应用而设计。例如硬盘控制器、企业中的网络设备和打印机、消费电子设备以及汽车应用(安全气囊、制动系统和发动机管理)
  • Cortex-M:面向各类嵌入式应用的微控制器内核。

根据需求,我们不需要过强的Cortex-A,Cortex-M足矣。

M系列横向对比与选型

Arm Cortex-M系列处理器内核是专为高能效和确定性操作而优化的一系列核心。它广泛用于微控制器(MCU)并且也可以嵌入到多核微处理器(MPU)中。从最初的Cortex®-M3微处理器内核和引入专为低功率(如Cortex®-M0以及随后的Cortex®-M0+)、性能(采用Cortex®-M7)、实时性(采用Cortex®-M4)或安全性(采用最新的Cortex®-M33)优化的内核变体,Arm Cortex-M架构成为了32位通用MCU的实际标准架构。它也为通用8位和16位MCU架构提供了有竞争力的替代选择。图源(https://www.eet-china.com/mp/a54021.html)

f2.png

由图中信息可知:

  • Cortex-M0、Cortex-M0+、Cortex-M1系列内核使用Armv6-M架构。

    Cortex M0处理器是ARM最小的处理器之一,主要特点是小体积,目的是使开发人员能够在8位的价格实现 32 位的性能。Cortex M0+处理器在Cortex M0处理器的基础上,进一步降低了功耗,提升了性能。Cortex M1是首个专为FPGA的实现而设计的处理器。

  • 常用的Cortex-M3、Cortex M4、Cortex M7系列内核使用Armv7-M架构

    Cortex-M3处理器是专为高性能、低成本平台开发设计的,包括汽车车身系统、工业控制系统、无线网络、传感器等。Cortex-M4处理器是一款高效的嵌入式处理器,使用3个AMBA AHB-Lite 总线,三级流水线,支持Thumb/Thumb-2部分指令集,支持8 to 256优先级等级。相比Cortex-M3,Cortex-M4增加了 DSP 扩展和可选的单精度浮点单元。Cortex M7处理器是一款高性能、节能的处理器,6 级大规模流水线,支持Thumb/Thumb-2指令集,支持8 to 256优先级等级,支持DSP扩展、可选的单精度浮点单元,使用1个64-bit AMBA4 AXI总线,1个32-bit AHB外设接口、1个为外部主机访问TCMs内存提供的32-bit AMBA AHB从机接口,拥有指令cache、数据cache、指令TCM、数据 TCM

  • Cortex-M23系列使用Armv8-M Baseline架构,Cortex-M33、Cortex-M33P、Cortex-M55 系列使用Armv8-M Mainline架构。

    Cortex M23处理器是一款非常简洁的处理器,对于大多数需要安全性的IoT和嵌入式应用,带有TrustZone的Cortex-M23是一个理想的处理器。Cortex-M33适用于需要有效安全性或者数字信号控制的嵌入式和IoT应用场景。Cortex-M33有非常多的可选特性,包括DSP 扩展、用于硬件强制隔离的TrustZone安全特性、一个协处理器接口、内存保护单元和浮点计算单元。后续的不再过多赘述

这些Cortex-M内核对应的芯片型号如下图所示,其中Cortex-M4和Cortex-M33都能满足我们的需求。图源(https://www.stmcu.com.cn/ecosystem/app/ai)

f1.png

根据需求最终确定型号

机器学习是AI的分支,在计算机科学领域的应用使计算机无需显式编程就能学习。机器学习由能够基于数据进行学习和预测的算法组成:

  • 这类算法在前面样本基础上进行训练,以构建和估计模型;
  • 在传统编程不可行的情况下,通常采用机器学习;
  • 如果经过适当的训练,可以适应新的案例应用。

机器学习有不同的实现方法,其中包括常见的:

  • 决策树
  • 聚类
  • 基于规则的学习
  • 归纳逻辑编程
  • 深度学习

深度学习是利用神经网络进行的学习:

  • 灵感来自生物神经网络
  • 深度是指有很多中间的学习步骤
  • 需要大量数据

其中深度学习有如下的优势和劣势:

优势 劣势
数据模式和关系的自主学习 大量数据集
高准确度 高计算需求
容易改进和微调 难以理论解释
适应性解决方案 黑盒子(对于大多数人)

意法半导体关于AI的相关生态如下图所示:

f3.png

由于声音处理不需要过高的数字信号计算,所以我们主要是根据深度学习资源来选择最终型号。根据低功耗原则,最后选择STM32L4+

不过,因出于机器学习的需要,最后我选择的是STM32F413 discovery。

2.png

板子内直接内置数字麦克风、音频DAC、sd卡接口和usb接口,方便我们快速采集音频。

三大硬件平台所持有资源情况

STM32F413ZH

主要参数如下:

3.png

Sipeed Maix Dock K210

主要参数如下:

  • CPU:64bit RISC-V双核,with FPU/KPU/APU,主频400MHz
  • 内存:8MB SDRAM (6MB通用SRAM+2MB的AI专用SRAM)
  • 外设:UART、GPIO、SPI、Timer等
  • 板载资源:128Mbit Flash1、RGB灯1、USB2UART等
  • 板载接口:USBType-C接口、MicroSD卡槽等
  • 尺寸:52.3*37.3mm
  • 供电电压:5.0v @300mA
  • 工作温度:-30度~85度

4.png

KPU 是一个通用的神经网络处理器,具有内置的卷积、批量归一化、激活和池化操作。 它可以实时检测人脸或物体。 具体特点如下:

  • 支持主流训练框架根据特定限制规则训练的定点模型;
  • 网络层数没有直接限制,每层卷积神经网络参数可以单独配置,包括输入输出通道数,输入输出行宽列高;
  • 支持1x1和3x3卷积核;
  • 支持任何形式的激活函数;
  • 实时工作支持的最大神经网络参数大小为 5MB至5.9MB;
  • 非实时工作时支持的最大网络参数大小为flash size - software size

值得一提的是,目前K210支持的深度学习模型很有限,有tensorflow tflite, caffe1.0以及onnx。这3个模型类型所支持的算子有限,这会导致复杂些模型不能在k210上运行,而且模型部署还要经历量化的过程才能在K210上运行,可以说是限制重重了。另外,K210内置了SRAM, 给AI模型的内存大小只有2MB,这样它只能支持2MB以内的模型。

APU预处理模块负责语音方向和语音数据输出的预处理。APU预处理模块的功能特点是:

  • 8个音频输入数据通道,即4个立体声通道;
  • 对16个方向的声源同时进行扫描预处理和波束成形;
  • 支持主动语音流输出;
  • 16位宽的内部音频信号处理;
  • 支持12位、16位、24位和32位位宽数据输入;
  • 多路原始信号直接输出;
  • 高达192kHz的采样率;
  • 内置FFT单元,支持音频数据的512-point FFT;
  • 使用system DMAC将输出数据存储在系统内存中。

FFT 加速器是快速傅里叶变换的硬件实现。

全志D1(RISC-V)+双核ARM

如下图,硬件资源非常丰富。

5.png

主要参数如下:

  • CPU:XuanTie C906 RISC-V CPU 32 KB I-cache + 32 KB D-cache
  • DSP:HiFi4 DSP 32 KB I-cache + 32 KB D-cache 64 KB I-ram + 64 KB D-ram
  • Memory:DDR2/DDR3, up to 2 GB
  • Audio:2 DACs and 3 ADCs
    • Analog audio interfaces:MICIN1P/N,MICIN2P/N,MICIN3P/N,FMINL/R,LINEINL/R,LINEOUTLP/N,LINEOUTRP/N,HPOUTL/R
    • Digital audio interfaces:I2S/PCM, DMIC, OWA IN/OUT

三大硬件的任务目标

STM32F413 Discovery

鉴于MCU和内存资源相对紧缺,所以在该平台上仅需要完成简单的声纹辨认部署,即M元分类问题。无需唤醒词。至于是文本相关还是文本无关,要看平台自身的处理能力。STM32不具备单独制作数据集的能力,所以我们在上面做的所有工作都会是浅尝辄止的。

前几年STM32推出了Cube.AI人工智能神经网络开发工具包,目标是将AI引入微控制器供电的智能设备,位于节点边缘,以及物联网,智能建筑,工业和医疗应用中的深度嵌入式设备。

Cube.AI的主要特点:

  • 从预先训练的神经网络模型生成STM32优化的库。
  • 支持各种深度学习框架,如Keras,Caffe,ConvnetJS和Lasagne。
  • 通过STM32Cube集成,可轻松实现不同STM32微控制器系列的便携性。

目前种种条件已经使得STM32能做相关深度学习的弱应用。

Sipeed Maix Dock K210

Sipeed Maix Dock K210可以搭载os,所以声纹识别在其中的作用更多偏向声纹验证,即二元判别问题。用户在完成声纹的录入后,再准备唤醒机器时可以进行关键词的唤醒,将图形化界面唤出。在界面唤出后,会带动声纹验证算法完成身份验证的流程。具体形式是文本提示型。即用户阅读提示词,完成解锁。

K210初步具备在机器上制作数据集的能力,可以尝试。

全志D1(RISC-V)+双核ARM

功能同K210,即声纹验证的部署。但由于资源比K210更加丰富,所以在os层面会进一步对兼容指令集和异构计算的方面有更多的工作。这是后话。但显而易见,我们能在全志上能做的上限极高

主要研究内容与研究方案

系统整体架构

系统架构图如下图所示:

system.png

(对系统对的综合性,总结性的叙述,待填)

ucore

目前还不是重点,会回来填坑。

音频信号的采集、预处理和特征提取

从音频信号到特征帧的处理流程如下:

f5.png

无论部署的模型多么先进,算法多么精妙,在离不开与声音打交道。只有接上了正确的音频信号.并从其中提取出了有意义的特征表示,后面的模型才能最大程度地发挥其作用。要开发一个好的声纹模型,使用好的数据进行训练格外重要。具体到声纹识别的问题,声纹识别所需要的数据比较简单, 每一则数据只需要以下信息:

  • 一段只包含单一说话人语音的音频;
  • 用于表示该音频所包含的说话人身份的独特标签。

除以上特定需求外,特征提取的过程中最好有如下特点:

  • 说话人音频尽可能短(短语音的识别);
  • 降低环境噪声影响;
  • 保留信道差异,防录音攻击;
  • 消除声音变化带来的影响等等。

我们从音频模拟信号开始,循序渐进的讨论。

人耳特征

人耳对声音的感知是非线性的,这是由人耳的生理构造决定的。这种非线性主要体现在两方面:对频率感知的非线性,以及对声强感知的非线性。一个好的音频信号处理系统,需要考虑这两方面的因素。为了描述人耳对于频率感知的非线性,学术界提出巴克刻度、梅尔刻度和ERB刻度等。同时人耳对声强的感知也是非线性的。一般来说,人耳对于高振幅信号的差距,不如对低振幅信号的差距那么敏感。因此,在许多音频信号处理系统中,都会对信号的振幅应用一个非线性函数来模拟人耳的这一特性。最常用的两个非线性函数,分别是对数函数与幂函数。例如在梅尔倒谱系数特征中,采用对数函数;而感知线性编码特征则采用立方根函数。

信号采集

音频处理的第一步就是用音频采集设备将声波转换为电信号。这种采集设备也就是麦克风,同时也是我们唯一需要的外接设备。出于小型化、抗干扰、SMT焊接和抑制和消除环境噪声和通话回声等的需要,麦克风数字化趋势越来越明显。其中数字MEMS(微机电系统)麦克风专为需要小尺寸、高音质、高可靠性和高经济效益的音频应用而设计,它们的封装尺寸小且噪声低,可在单个器件中实现多个麦克风,并通过提供免提人机界面、 噪声消除和高质量音频捕获,促进了工业和消费类应用中音频技术的不断发展。

6.png

MEMS麦克风输出并不是直接来自MEMS换能单元。换能器实质上是一个可变电容,并且具有特别高的兆欧级输出阻抗。在麦克风封装中,换能器信号先被送往前置放大器,而这个放大器的首要功能是阻抗变换,当麦克风接进音频信号链时将输出阻抗降低到更合适的值。麦克风的输出电路也是在这个前置放大电路中实现的。在数字MEMS麦克风中,这个放大器与模数转换器(ADC)集成在一起,以脉冲密度调制(PDM)提供数字输出,从而实现了从麦克风到处理器的全数字音频捕获通道。在STM32平台上,数字MEMS麦克风可以连接至单声道和立体声配置中的STM32 MCU和MPU中嵌入的SPI/I2SSAIDFSDM外设;在K210开发板上自带有MEMS麦克风及高性能麦克风阵列处理器;全志D1板子上目前只见麦克风子板接口,但应该也没有问题。

采样与量化

计算机所处理、存储的音频信号通常都是数字信号,将连续的模拟信号转换为离散的数字信号有两个步骤:采祥和量化。通过采样与量化,我们能够将连续的音频信号表示为一个离散的整数序列。但计算机存储音频文件,以及在网络间进行传输时,所使用的是二进制的字节序列表示。为了更有效率地表示音频信号,我们需要对音频信号进行编码处理。相应地,将二进制字节恢复成音频信号的过程称为解码。最简单的编码方式就是采样过后直接将得到的振幅进行量化。这种方法称为称为脉冲编码调制(PCM)。

7.png

实际应用中,数字麦克风输出的就是PDM调制后的高速比特流,已经完成了采样和量化的过程。PDM和PCM都是一种调制形式,用于表示数字域中的模拟信号。PDM是1位数字采样的高频数据流。在PDM信号中,脉冲的相对密度对应于模拟信号的幅度,大量的1s对应于高(正)幅度值,而大量的0s对应于低(负)幅度值,交替的1s和0s对应于幅度值0。

8.png

PDM信号无法直接驱动DA进行声音播放,它要变为声音信号还需要进行下采样,经过一次低通滤波和抽样,然后成为PCM信号。目前大多数现代的数字音频系统使用PCM以表征信号,这使得信号处理的操作可以在音频流上完成,例如混合,滤波和均衡。而PDM只用1bit来传输音频,在概念上和可实行度上比PCM更简单。它正被普遍应用在手机中,将音频从麦克风传输给信号处理器的过程。PDM在理论上很适合这个任务,例如低噪声和免于干扰信号等,且成本较低。

在得到数据流后,我们可以将其加工为需要的编码格式。例如,鉴于人耳的听觉具有非线性,我们在量化的时候,可以对低振幅的信号采用较高的精度,而对高振幅的信号采用较低的精度。这种编码通常称为非线性脉冲编码。除此方法外还有很多优秀的编码方法。最后我们会得到一段音频信号。这些加工过程往往需要借助一些工具,比较著名的就是SoX工具,号称音频界的瑞士军刀。方便的话可以整合进ucore中,在bash里使用。

短时分析技术、分帧与加窗

对于一整段音频信号,其长度通常不是固定的,可以短至几百毫秒,或者长达数十分钟。如何从不定长度的音频信号中提取出固定长度的特征向量呢?

传统的特征分析方法,是将整段音频当成一个整体,然后提取其中的一些统计量。例如,一个简单的做法是将整段信号进行傅里叶变换,得到信号的频谱。该频谱具备固定的维度,因此可以作为这段音频的一个特征。此外,可以估算整段音频的基频、共振峰等特性,将其作为该音频的特征的一部分。这种基于整段音频信号的全局特征有着显而易见的缺点。音频信号是随着时间的变化而变化的,在人们说话的时候,每发出一个音节,其对应的音频特征都会与这段音频的其他部分截然不同。传统的全局特征分析方法,相当于对音频信号在时间轴上做了某种平滑处理,从而使时间分辨率降为零。这种做法会丢失信号中的大量局部信息。 如果音频中有一些噪音片段,那么这些片段会对最后得到的特征造成进一步污染。

由此可见,全局特征只有当信号十分平稳的时候才是有意义的。例如信号本身是周期信号,其局部特征不随时间变化而变化,那么其全局特征便等价于其局部特征。然而,对于大多数音频信号,尤其是语音信号来说,信号本身是不平稳的。因此,需要从局部提取特征,因为在每一个局部的短时间内,可以近似地认为信号是平稳的。这一点,便是音频信号特征分析的基础:短时分析技术。

在观看视频的时候,我们看到的其实是一帧一帧的图像。这些图像帧按照特定的频率播放,从而让人产生视觉上的连续性。而对于语音信号,我们一样可以将采样信号在时间轴上分割为很多短小的片段,这些片段称为帧。在分帧过程中,最重要的两个参数便是帧本身的长度,以及帧与帧之间的间隔。通常,我们可以假定语音信号在10毫秒的范围内是较为平稳的,因此可以将帧的长度设置在这个范围内。一组在业界比较常见的分帧设置,是采用25毫秒的帧长度,以及10毫秒的帧间隔。在这个设定下,假如音频采样率为16000Hz,我们对每一帧提取40维的特征。那么考虑一段长度为一秒的音频,其本身有16000个采样点,而经过分帧之后再提取特征,将得到100×40=4000个特征,需要处理的数据量减少了75%。分帧通常是所有短时分析技术的第一步。不同的音频信号,其采样率可能会不同,但是在经过分帧之后,所得到的帧的频率却是固定的。这对于需要处理来自不同设备、包含不同采样率的信号的语音识别或声纹识别系统来说极为重要。

在对采样信号进行分帧处理之后,便可以对每一帧信号进行特征提取。为了避免吉布斯现象频谱泄漏所带来的负面影响,可以对分帧之后的信号迸行加窗处理,就是将一帧信号的每个值乘以不同的权重。而不同的窗函数,对应着不同的权重设计思路。窗函数的设计重点在于,通过将较大的权重赋予靠近窗中心的信号,将接近零的权重赋予靠近窗边缘的信号,减轻分帧时造成的信号不连续性。满足上述条件的最简单的窗函数,便是高斯函数。业界常用的窗函数是汉宁窗和汉明窗。窗函数处理后即可进行特征提取

特征提取、帧叠加与帧采样

通过对数字信号进行分帧、加窗处理,我们得到固定时间间隔的音频帧。从这些音频帧中提取出固定维度的特征向量,再对这些特征进行帧叠加与帧采样,从而得到最终的特征帧。这些最终的特征帧将被作为机器学习算法的输入,去完成语音检测、语音识别及声纹识别等高级任务。

音频信号的特征一般分为时域特征频域特征两大类。前者直接对以时间为自变量的采样信号进行特征提取;后者先通过傅里叶分析将信号转换到频域,再进行特征提取。目前大部分实用系统都采用频域特征。我们通常使用离散傅里叶变换计算频域特征,频谱幅值特征算是最简单的频域特征,已经能够直接作为机器学习系统的输入,去实现语音识别等高级任务。但实际上,业界很少直接利用频谱幅值建模,而是会对频谱进行进一步的处理,比如感知线性顶测(PLP)、功率正则化倒谱系数(PNCC)、梅尔倒谱系数(MFCC)等音频特征。其中梅尔倒谱系数广受业界应用。

功能模块 PLP MFCC PNCC
信号预处理 预加重 预加重
频域转换 STFT STFT STFT
频率校正 巴克刻度,临界频带 梅尔三角滤波器组 Gammatone滤波器组
环境补偿 不对称噪声抑制等
声强校正 y=x^(1/3) y=logx y=x^(1/15)
最终处理 IDFT IDFT IDFT

简要介绍一下MFCC的计算过程:

  • 对音频信号进行预加重处理,从而降低部分高频能量;
  • 对预加重处理后的信号进行分帧、加窗处理。一般采用汉明窗 ;
  • 对每一帧信号进行快速傅里叶变换,得到频谱;
  • 将频谱通过一组按照梅尔刻度设计好的三角形滤波器组,得到带通滤波后的结果;
  • 用对数函数校正人耳对于声强的非线性;
  • 通过逆离散傅里叶变换计算倒谱;
  • 前一步得到了12个倒谱系数,再增加一个该帧的能量,得到第13个特征。通过相邻帧计算这13个特征的一阶差分及二阶差分,最终得到39个特征。这39个特征便是最终的MFCC特征。

在进行特征提取之后,理论上这些特征可以直接用于语音检测、语音识别、声纹识别等不同的音频处理系统。不过有时我们会发现,不同的系统所采用的模型对特征的上下文的要求会不太一样。对于语音识别系统来说,我们将每一帧的信息单独输入模型,可能效果不如每次将连续的4帧特征同时输入模型。这是因为,连续多帧的特征组合在一起后,能够对单帧周围的上下文信息有一个更好的描述,可以更好地覆盖完整的音节。但是对于其他系统,同样的配置却未必是最优的。例如,我们可能发现对于声纹识别系统来说,2帧的上下文已经足够,而对于语音检测,可能l帧就够了

将相邻帧的特征拼接起来合成一个新的帧的做法,称为帧叠加。不过需要注意在帧叠加的过程中,初始和结尾的若干帧由于没有足够的相邻帧与其拼接,需要进行一些特殊处理。此外,将连续的多帧信息作为模型输入时,帧的维度会增加数倍,因此模型的参数显然会大量增加。为了不使计算开销过大,在运行模型的时候,可以有规律地跳过一些帧来减小计算量,这种做法常被称为帧采样。不过这里的采样一定是降采样

以上内容,除了音频信号采集需要连接麦克风外设外,剩下的对声音数据流的处理都在语音处理框架涵盖的范围内参考的项目有kaldi

https://github.com/kaldi-asr/kaldi

数据集的制作

声纹识别所需要的数据比较简单,每一则数据只得要以下信息:

  • 一段只包含单一说话人语音的音频;
  • 用于表示该音频所包含的说话人身份的独特标签。

在准备声纹识别数据集的时候,通常需要认真考虑以下几点:

  • 说话人数量
  • 每个说话人的语音数量

    在声纹识别模型的训练中,我们既需要正样本(来自同一说话人的语音),也需要负样本。

  • 文本的多样性

    对于文本相关的声纹识别而言,需要保证音频所对应的文本的准确性,而对于文本无关的声纹识别而言,更需要文本的多样性。

  • 口音、语调、录制设备及环境的多样性

    除了文本的多样性,许多其他方面的多样性也同样值得关注。以口音为例,如果所有的数据都采集自居住在特定区域的说话人,那么得到的模型可能只能在该区域的口音上有较好的准确率。以语调为例,如果所有的数据都来自发音标准、吐字清晰的语音电子书,那么在新闻、电话等其他复杂的情况下就不可能有好的识别性能。此外,数据集的采集最好来自多种不同的录制设备,例如耳麦、手机麦克风、电脑麦克风、智能音箱麦克风等。录制的环境最好也有足够的多样性,例如不同的房间、不同的背景噪声等。这样有充足的正样本和负样本的积累。

  • 数据的正确性

    声纹识别所使用的数据包含两部分信息:音频和说话人标签。音频的正确性,意味着音频中确实包含着来自说话人的语音,而非单纯的噪声,或者同时包含其他说话人的声音。说话人标签的正确性,意味着该标签确实对应着音频中的说话人。

制作数据集有如下步骤:

  • 数据预处理
    • 数据筛选

      在数据的采集过程中,通常很难保证数据的完全正确性。所以有两种方法。

      • 当数据量很大时,手工对数据进行筛选显然成本过高。不过,我们可以搭建一些自动化的流程来对这些数掘进行初步的筛选。例如,可以用已经训练好的语音识别模型对训练数据的音频进行识别。如果语音识别模型无法识别出任何文字,或者识别结果的可信度很低(一些语音识别算法会给出识别结果的概率),那么很有可能该音频数据并不包含有意义的语音,可以将这部分音频从训练数据中剔除。
      • 如果数据集中可能包含一些错误标注的数据,那么可以先用该数据集训练一个初始声纹识别模型。由于数据集的质量问题,该初始模型的性能可能不符合要求。不过,我们可以利用该初始模型对数据集中每一个说话人的所有音频计算出嵌入码,然后求取这些嵌入码的中心。对于那些明显过分偏离了对应说话人中心的嵌入码,可将其对应的音频从训练数据中剔除,能大大减少数据中的错误正样本。
    • 语音检测

      声纹识别需要基于有意义的语音内容。大量本身只包含了单一说话人的音频,因为说话停顿,或者数据采集方式导致音频的首尾,以及部分中间的停顿部分,包含了静音或纯背景噪音的信号。无论是声纹识别模型的训练,还是实际运行时,我们都不希望将这部分信号输入到声纹识别模型中,而是希望模型专注于有意义的语音信号。因此,在提取音频特征时,我们通常需要利用事先训练好的语音检测模型检测出音频中有意义的语音部分,并只对该部分提取音频特征。对于非语音信号,我们直接将其丢弃,不作为后续模块的输入。

    • 特征提取

      前面有介绍原理,这里介绍做法。

      • 可以事先对整个数据集进行特征提取,然后将提取的特征存储在额外的硬盘空间上。训练模型时,我们直接读取这些已经提取完成的特征文件。
      • 可以在实际训练的过程中,具体构建一个批的数据时,实时地调用特征提取代码。

      这两种方法显然各有优劣。第一种方法需要额外的硬盘开销,特别是当数据集规模很大时,这种开销不容忽视。第二种方法虽然节省了硬盘开销,却增加了CPU、内存等资源的开销,甚至会导致训练过程变慢。尤其是需要训练许多个模型来比较不同的方法时,本来可以只进行一次特征提取,但是这种方法却在每次训练时都单独进行提取,这是对 计算资源的一种浪费。此外,实时调用特征提取代码比较难以调试,出现问题时很难确定问题出在机器学习部分还是特征提取部分。

      特征提取部分还有一个非常值得注意的问题,那就是特征的正则化。训练神经网络时,我们通常会将正则化之后的数据作为输入。因此,我们可以先用一小部分数据进行特征提取,然后从这些特征中计算出均值向量和标准差向量;对完整数据进行特征提取时,再利用这两个向量对特征进行正则化。如果这么做的话,则需要将均值向量和标准差向量好好保留起来。模型训练完成之后,实际运行时也需要用这两个向量对特征进行正则化,并将正则化之后的特征作为模型的输入。

    • 数据分组

  • 数据增强
    • 音频信号的数据增强

      前面提到过,声纹识别的训练数据最好具有环境的多样性,例如不同的房间大小、结构,会产生不同的混响效果。不同的录制场景也会含有不同的背景噪声,例如大街上交通工具的声音,餐馆里嘈杂的人声,或者车辆行驶过程中汽车引擎的声音等等。如果训练数据缺乏此类多样性,那么在实际应用中,若是遇到类似场景,声纹识别的性能便会有所下降。对本课题而言,数据集的构建肯定无法满足环境多样性的要求,所以可以使用数据增强技术,通过模拟算法增加数据多样性。例如:

      • 改变语音信号的音量。这样可以让我们的模型对不同音量的信号具备更好的鲁棒性。
      • 改变语音信号的采样率。这可以让模型在更多的场景下稳定工作。
      • 对语音信号的速度进行扰动,用以模拟不同的语速变化。即使只是简单地将每一份训练音频复制为0.9倍速、1倍速,以及1.1倍速共三份,也能有效地提升语音识别模型的性能。
      • 对语音信号的基频进行扰动,可以将语音信号的频谱向高频或低频方向偏移。这种扰动并不会改变语音中包含的文本内容信息。
    • 多风格训练

      尽管前面提到的几个简单的音频增强方法能够有效地增加数据量,减轻由于数据不足造成的过拟合效应,但依然无法解决语音领域中最重要的一个问题:噪声环境对系统的影响。这可以借助Python的开源工具库。

学术界目前也有通用的开源数据集,像TIMIT等等。

声纹识别算法设计

语音识别是将语音信号识别为文本内容的技术,在绝大多数情况下不会关心说话人的身份是谁,并需要做到对不同说话人声音的稳健性。而声纹识别技术,尤其是文本无关的声纹识别技术则与之相反,需要在不同的文本内容中稳健地识别出说话人的身份。由此可以看出,语音识别与声纹识别在某种意义上被视为两个相互“正交”的问题:语音识别希望从信号中滤除与说话人身份相关的信息,只保留文本信息;而声纹识别希望从信号中滤除与文本相关的信息,只保留说话人的身份信息。

声纹识别技术按照其所要识别的任务及应用场景主要分成两类:声纹验证和声纹辨认。声纹验证技术需要解决的问题是这段话是否由特定的人所说?这里我们只关心某个特定的说话人,因此声纹验证技术可以看作一个二值判别的问题,只需要回答“是”或“否”。声纹辨认需要解决的问题是“这段话由谁所说?”。显然,这里的“谁”不可能涵盖全世界70多亿人,而是限定在某个特定的候选说话人集合之中。假如这个集合包含M位说话人,那么声纹辨认可以看作一个M元分类问题。

声纹验证对应的应用主要是唤醒和安全。在智能手机或智能音箱等产品上,可以对唤醒词进行额外的声纹验证。这样一来,一些容易与唤醒词相混淆的噪声信号,会因其不具备用户的声纹特征而不会意外将设备唤醒,从而降低唤醒词的错误接受率。在一些安全领域(如门禁系统、支付系统等),声纹验证能够与人脸识别、指纹识别等技术相结合,确保操作来自被授权的用户,而非冒名顶替者。声纹辨认对应的应用场最主要是个性化。例如,对于智能音箱产品而言,这里的候选说话人集合可以是一个家庭的所有成员。对于每一次语音交互,可以通过声纹辨认,识别出正在使用产品的用户是哪一位家庭成员,并由此提供个性化的交互。例如用户说请播放音乐。那么智能音箱可以根据相应家庭成员的音乐偏好或者历史播放记录,播放该成员喜欢的音乐。在本课题中,算法设计偏向的领域是声纹验证

声纹验证技术需要由目标说话人事先提供音频样本,通过特定算法,从音频样本中提取能够表征该目标说话人声纹特征的说话人模型(模板)。完成声纹录入后,对于一段新的音频,我们便能够将其与目标说话人模型(模板)进行匹配,得到一个匹配分数。该分数越高,表示我们越倾向于认为这段新的音频来自目标说话人。我们可以将该匹配分数与某个事先设定好的阈值进行比较,并根据最后的比较结果进行二值判别。在实际应用中,像苹果的Siri,设定的都是动态阈值,这也是为用户及用户所处环境综合设计的成果

无论是声纹验证还是声纹辨认,按照其识别的内容可以分为三类:文本相关的声纹识别、文本无关的声纹识别,以及文本提示型声纹识别。

文本相关的声纹识别,通常称为“固定文本”的声纹识别。也就是说,需要被识别的音频,其内容对应的文本总是固定的。这意味着,对于每一位需要识别的说话人,其录入的音频及待识别的音频包含着完全相同的音节。这显然是对问题的一种极大的简化。文本相关的另一层简化在于,可以假设待识别的音频长度被限制在某个有限的变化范围内,甚至是固定的时间长度。这是因为对于固定的文本,其音节数是固定的,而人们发出每个音节的持续时间也在很小的波动范围内。固定的时间长度意味着固定的音频帧数和固定的特征帧数,因此可以得到固定的特征维度,将其直接用于机器学习算法的输入。在实际应用中,文本相关的声纹识别系统主要用于 唤醒词或验证口令的声纹识别。

文本无关的声纹识别,顾名思义,就是指无论说话人说的是什么内容,都要能够识别出说话人的身份。通常,文本无关的声纹识别还是会要求语音的内容是特定的语言,例如中文或者英文,此时称之为语言相关、文本无关的声纹识别。如果不对说话内容的语言做限定,则称之为语言无关、文本无关的声纹识别。即使限定了语言,文本无关的声纹识别依然是一个十分困难的问题,本课题平台的能力有限,就不做这方面的探讨

无论是文本相关还是文本无关的声纹识别,其都面临着这样一种风险,那就是冒名顶替者可以将目标用户的声音提前录下来,在声纹验证时播放,让系统误以为这是目标用户的声音。这种可能性的存在严重威胁着声纹验证系统的安全性。在语音领域有专门的分支来研究如何区分原始的声音和转录后的声音(后面会介绍,并进行探讨)。不过在声纹识别中,有一种简单的方法可以在某种程度上防止这种情况的发生,这便是文本提示型声纹识别

文本提示型声纹识别将文本内容限定在某个小规模的集合中。用户在录入声纹的时候,需要对集合中的每一条文本进行录入。在实际验证的过程中,系统会随机生成该集合中的一条文本,要求待验证者说出该文本。只有当待验证者提供的语音既与该文本匹配,又与事先录入的声纹匹配时,才能通过验证。由于验证时每次生成的文本都不同,冒名顶替者无法事先将目标用户的对应语音录制下来,从而避免了相应的风险。我们可以看到,文本提示型声纹识别介于文本相关与文本无关的声纹识别之间。当文本内容集合的大小减少至1时,其等价于文本相关的声纹识别;当文本内容集合增加至无穷大时,其等价于文本无关的声纹识别。通常我们希望文本集合不要太小,否则很容易被冒名顶替者破解,我们也不希望这个文本集合太大,否则需要用户录入大量的音频,使用户体验变得十分糟糕。

无论是针对特定说话人的声纹验证,还是针对多个说话人的声纹辨认,系统的运作都包含两个阶段:事先完成的声纹录入阶段和实际运行的识别阶段

声纹录入与声纹识别

声纹录入阶段的流程图如下图所示:

f1_1.png

在声纹录入阶段,目标说话人一般都要提供多段语音,若是文本无关的声纹识别,会额外要求这些语音对应的文本互不相同,以覆盖更多的音节、字词。每一段语音会进行分帧、加窗并提取特征(在必要的时候考虑进行帧叠加),然后进行声纹建模。对目标说话人提供的每一段录入音频进行声纹建模后,还会额外对这些模型进行聚合,从而得到一个单一的说话人模型,用来表征声纹特征。

声纹识别的流程图如下图所示:

f3_1.png

在识别阶段,待验证的音频需要通过与录入阶段完全相同的特征提取及声纹建模过程,得到其声纹模型。然后,需要将该验证音频的声纹模型与所有目标说话人的说话人模型进行相似匹配,根据匹配结果进行判别,并得到最终的识别结果。

无论是声纹录入阶段还是识别阶段,我们都假定声纹建模的过程是已知的、固定的。通常,声纹建模的过程本身也依赖于某些复杂的模型,而这个模型的构建过程通常需要大量的训练数据。因此,从机器学习的角度来看,我们将声纹录入阶段和识别阶段都称为测试阶段,将声纹建模这部分的构建过程称为训练阶段

这里需要对一些概念进行区分。“说话人模型”或者“声纹模型”通常指的是声纹建模过程的输出,是通过声纹录入阶段得到的。每个说话人都拥有自己的说话人模型。声纹建模过程本身所依赖的模型,则是训练阶段的产物,该模型适用于所有的说话人。显然,将这两个概念都称为“模型”很容易产生混淆,所以我们有时将说话人模型称为声纹嵌入码,而将声纹建摸过程本身所依赖的模型称为声纹编码器,以便于区分和理解。声纹识别系统流程不同阶段的输入与输出如下表所示。

流程阶段 输入 输出
训练阶段 训练数据 声纹编码器参数
声纹录入阶段 目标说话人录入音频 目标说话人声纹嵌入码
识别阶段 验证音频 识别结果

声纹建模单元

这部分探讨从音频特征到说话人模型的声纹建模模块。该模块的任务是:对一段语音所对应的音频特征序列进行变换,从而得到能够更好地表征其说话人声纹特征的模型。该模块目前业界主流都是采用基于深度学习的方法,现在随着各种神经网络库的成熟与普及,神经网络技术无论是在代码实现,还是在产品、服务中的部署,都比深度学习之前的方法要容易得多。深度学习有几个基础的网络结构,分别是前馈神经网络卷积神经网络循环神经网络等。这里不深入探讨。

目前直接用于声纹识别的神经网络,并没有一个统一的实现方法。各个公司、大学和研究机构提出的架构都有诸多的不同。这些不同主要集中在两个方面:其一是运行时的推理逻辑的不同;其二是训练过程中的损失函数的不同。若不考虑上述两方面的不同,目前大部分直接用于声纹识别的神经网络都可以用下面的通用架构进行概括。

f2_1.png

左侧为长度不一的各个音频特征序列,这些序列可以来自不同的说话人。每一段音频特征序列经过神经网络后,得到一个固定长度的嵌入码。因此,该神经网络也常被称作声纹编码器。运行时的推理逻辑,指的是从音频特征序列得到嵌入码的过程。根据这些嵌入码及每段音频特征序列所对应的真实说话人,可以计算出某个用以衡量嵌入码性能的损失函数。在训练过程中,我们用随机梯度下降或Adam等算法对损失函数进行优化,从而更新神经网络编码器的参数,直至其收敛为止。

运行时的推理逻辑

在声纹识别系统中,为了将不同的音频进行声纹相似匹配,需要将音频表示为固定维度的嵌入码。这一过程中的难点在于,音频本身的长度是不确定的。给定一段不定长度的音频特征序列,通过神经网络将其转换为一个固定维度的嵌入码,这个过程便是神经网络运行时的推理逻辑。当我们将神经网络部署到产品中,无论产品中的神经网络是在服务器端运行还是在设备端运行,在运行过程中,通常都不需要更新产品中的神经网络的参数,而是直接调用神经网络的推理逻辑来处理输入信号

在各种推理逻辑中,最简单、直观的便是将特征序列中的每一帧看作一组独立的特征作为神经网络的输入,然后得到该帧的输出。这种做法通常称为逐帧推理

相关文章为Tandem deep features for text-dependent speaker verification

在逐帧推理方法中,由于每一帧的输入和输出都是互相独立的,神经网络不需要拥有任何记忆,用简单的前馈神经网络便可。如果每一帧涵盖的时间范围较短,特征较少,导致神经网络输入的信息量不足,则可以考虑使用帧叠加与帧采样方法,使每一帧的特征包含尽可能多的上下文信息。

f.png

不过,逐帧推理网络的缺点也是显而易见的。即便采用了帧叠加与帧采样的方法,一帧音频特征所涵盖的音频内容也不过数十毫秒。该网络单独用于声纹识别时性能不佳,只有将其与传统方法综合才能达到不错的性能,所以pass。

对于文本相关的声纹识别,尤其是基于特定唤醒词的声纹识别,通常可以假定该文本对应的音频长度固定在某个较稳定的范围内。如果唤醒词检测算法在检测唤醒词的同时给定了唤醒词的边界,则可通过该边界提取固定长度的窗口,从而完成固定窗推理

固定窗推理方法较早也较具代表性的工作,是谷歌于2014年发表的一篇论文(Deep neural networks for small footprint text-dependent speaker verification),就是大名鼎鼎的d-vector。该论文中的声纹识别系统被用于识别谷歌的唤醒词“OK Google”所对应的说话人。唤醒词检测算法持续在长度为800毫秒的窗口上运行,一旦唤醒词被检测到,声纹识别网络便会触发,并在对应的800毫秒窗口上运行。因为固定窗推理的输入序列长度是固定的,所以没有必要逐帧进行处理,而是可以将所有音频帧叠加在一起,组成一个较大的输入,然后通过神经网络直接得到输出。不过这样会导致神经网络的输入维度会比较大。例如每帧包含40维特征,帧间距为10毫秒,那么800毫秒的固定窗便会包含总共3200个特征。如果每帧特征或者固定窗的长度增加,则神经网络的输入维度也会相应增加,导致网络参数和计算量非常大。为了解决这个问题,谷歌在训练神经网络的时候,引入dropout的方法(具体来说是maxout方法),而后谷歌于2015年提出了另一种方法,引入局部连接及卷积神经网络,从而大大减少网络的参数。

逐帧推理的神经网络可以处理任意长度的音频特征序列,固定窗推理的神经网络可以有效利用每一帧的上下文信息,那么将两者的优势结合起来就是基于全序列推理的神经网络。

全序列推理的方法需要借助循环神经网络来实现。在我们输入音频特征序列之前,循环神经网络会重置其状态为初始状态。我们将音频特征序列中的特征帧按时间顺序依次作为输入,每当循环神经网络处理完一帧输入之后,其状态便会更新,并影响到之后的输出。因为循环神经网络在音频特征序列的每一帧都有输出,因此输出序列也是不定长度的。为了将不定长度的输出序列转换为固定长度的嵌入码,一般有两种设计方法:一种是基于池化的全序列推理;另一种是基于末帧的全序列推理。基于池化的方法由循环神经网络的输出序列计算一组统计量,作为最后的嵌入码。最常见的做法就是计算其输入序列的平均值向量,例如百度的deep speaker声纹识别系统便采用这个方法。除了平均值向量,还可以计算出标准差向量,作为额外的统计量,与平均值向量进行拼接,得到更大的嵌入码,例如约翰斯·霍普金斯大学的声纹识别系统便采用了这种做法(大名鼎鼎的x-vector)。值得注意的是,无论是百度还是约翰斯·霍普金斯大学的声纹识别系统,都不是将池化的输出直接作为最终的嵌入码,而是在池化之后额外增加一层前馈神经网络,然后将该网络的输出作为最终的嵌入码。这种做法可以有效提升系统对于池化运算的鲁棒性。

基于池化的全序列推理乍看上去与逐帧推理十分相似,但两者却有着本质的不同,这里将其不同点罗列如下:

  • 逐帧推理的每一帧都是完全独立的,全序列推理的每一帧依靠循环神经网络互相关联;
  • 逐帧推理的向量平均值只有在运行时才会计算,而在训练的时候,每一帧都作为独立的输入进行训练;全序列推理的池化运算是整个网络的一部分,训练的时候也会被调用;
  • 逐帧推理的向量平均值一般直接被用作最终嵌入码;全序列推理的池化输出一般需要经过额外的前馈神经网络才得到最终嵌入码。

基于末帧的全序列推理,其实现比基于池化的全序列推理简单很多。对于循环神经网络的每一帧输出,我们只保留最后一帧输出直接作为最终的嵌入码,而将其他输出全部丢弃。这种做法既不需要额外的池化操作,也不需要额外的前馈神经网络。之所以选择末帧,是因为在推理过程中,只有最后一帧的输出是已经“看过”所有输入的,有能力去表示整个序列的信息。而其他帧都只“看过”其之前的输入,不包含关于其之后输入的任何信息。基于末帧的全序列推理,也可以理解成基于池化的全序列推理的一种特例,不过其池化操作并不是常见的均值池化、标准差池化或者最大值池化等,而是一种内置的“末尾值池化” 。

全序列推理神经网络是目前比较常用的一种运行时推理逻辑。具体选择基于池化还是基于末帧的方法,通常取决于具体产品的要求。如果是离线推理,并且不需要实时的声纹识别结果,那么基于池化的全序列推理是比较好的选择。因为其循环神经网络可以采用双向的结构,达到最佳的识别性能;如果是在线推理,也就是随着说话人说话,即时更新当前的识别结果,那么基于末帧的全序列推理则是最佳的选择。因为在推理过程中的任意时刻,循环神经网络在当前帧的输出,等价于当前子序列的末帧输出,而该输出可直接用于序列的判别而不会有延迟。

值得注意的是,尽管全序列推理神经网络有着诸多优点,但其也有一个致命的缺点:其无法简单地通过批处理实现高效的大规模训练。批处理通常要求同一批输入数据的维度是一致的,只有这样才能通过张量运算计算整批输入数据的损失函数与梯度,从而进行优化。而在全序列推理神经网络的训练过程中,通常每一个输入序列的长度都是不一样的,因此其批的大小只能被设定为l。这一缺点在小规模数据集上可能并不明显,一旦需要在包含数十万说话人的数据集上进行训练,便会发现全序列推理神经网络的收敛速度极慢,非常不适用于计算资源有限或者开发周期紧张的项目。以上缺点可以通过改变神经网络的训练方法来克服。为了更好地对数据进行批处理,常用的做法是从训练数据的每一段语音中截取一部分片段用来训练,并将截取长度相同的那些音频片段合并为一个批,这样便能够高效地进行批处理训练了。尽管这种训练方式(基于部分片段)与推理的方式(基于整段音频)并不完全一致,但在实际应用中是可取的。

谷歌对之前几种推理方法取长补短,于2018年做出了滑动窗推理方法的尝试。此处不再过多赘述。(端到端)

根据考察,最终我们选择x-vector(全序列推理)作为声纹识别的推理逻辑。

x-vector也是目前学术界和一些比赛的baseline,在录音反欺诈上也有大量的应用。

本课题在声纹录入阶段推理逻辑的选择的构想如下:STM32平台舍弃唤醒,在力所能及的范围内实现声纹识别的分类功能;针对教学系统ucore,可以基于固定窗推理的唤醒词,再加上基于池化的全序列推理的声纹识别身份验证。

声纹识别中的损失函数

前面已经介绍了声纹识别神经网络的多种推理逻辑实现方法,但最终决定声纹识别性能的,除了推理逻辑,更重要的是模型训练过程,而这其中就包括了数据的预处理方法、损失函数的设计、优化器的选取等多方面因素

若考虑由M个说话人组成的闭集内的声纹辨认问题,那么该问题可以近似地看作一个M元的分类问题。对于用于多元分类的神经网络,机器学习领域已经存在一些非常成熟的标准做法,其中最常用的便是交叉熵损失函数。若要使用交叉熵损失函数,神经网络的最后一层需要采用M元的归一化指数函数,该函数能将任意实数值的向量转换为相同维度的概率分布。一旦有了概率分布,我们希望其能够尽可能地接近真实概率。交叉熵就是用来描述两个概率分布的相似程度的函数。

尽管交叉熵损失函数在分类问题上效果极佳,不过具体到声纹识别领域,却出现了一个问题,那就是限定在某个闭集内的声纹辨认其实并不太实用。更多时候,我们希望将通过交叉熵损失函数训练得到的神经网络,应用于闭集之外的说话人的声纹验证。因此,交叉熵损失函数一般只在早期的工作中比较常见,较为先进的声纹识别系统一般不会采用这种训练方式。

在本课题的工作中,并不关注声纹辨认的问题所以不会选择像三元损失函数这种优化方案

端到端损失函数最早由谷歌于2016年提出,其设计思想是训练时的损失函数应该尽可能地“模 拟”声纹验证系统运行时的性能指标。而这里的“模拟”主要涉及两个方面:

  • 声纹验证系统在运行时,需要额外的声纹录入步骤,因此损失函数也要考虑到多个录入音频取平均所带来的影响;
  • 声纹验证系统在运行时,既会遇到真实目标说话人,也会遇到冒名顶替者,因此损失函数也要对这两种情况进行优化,而非简单地用三元损失函数一以概之。

假如在实际运行阶段,我们事先要求用户提供M段录入音频,以构建用户的说话人模型,那么在训练过程中,同样要构建一个M+l元组,其中包含M段录入音频,以及一段验证音频。验证音频既可以来自该说话人(正样本),也可以来自不同的说话人(负样本)。在训练过程中,我们需要保证每一个批内的正样本和负样本数量相差不太大。

t1.png

因为端到端的损失函数最终将问题变成了一个正样本与负样本的二值分类问题,所以最终的损失函数可以直接采用两类交叉熵的形式:

\[L=\begin{cases} -log(1-\hat y) &y=0\\ -log\hat y & y=1 \end{cases}\]

谷歌在2018年提出广义端到端损失函数,其核心思想在于,在每一个批的内部,针对最困难的冒名顶替者进行优化。在相关参考文献中,对于文本相关的声纹识别,基于对比度函数的广义端到端损失函数性能较好;而对于难度更大的文本无关的声纹识别,则是基于归一化指数函数的广义端到端函数性能更好。在实际代码实现时,广义端到端损失函数还有着一个非常大的优势,那就是可以非常高效地利用训练过程中的批处理,同时对所有嵌入码计算损失函数

声纹识别的评价指标

声纹识别技术有统一的指标来衡量这些系统之间的优劣。具体方法有相似匹配、录入集和验证集、ROC曲线的等错率、最小检测代价函数、辨认准确率等等。

关于声纹验证,基本方法就是一旦通过神经网络计算出两段音频的嵌入码,便可利用余弦相似度、欧氏距离或者本身包含可训练参数的机器学习模型计算两个嵌入码之间的相似度,然后将该相似度与事先设定好的阈值比较大小,再做出最终判别。不过这种做法存在一个问题,那就是不同的说话人验证分数的分布也会略微不同。这时如果利用一个全局设定好的阈值对所有说话人进行判别,便会出现问题。分数正则化便是将上面所述的不同说话人的验证分数的差异化考虑到判别过程中,从而减轻全局阈值所带来的问题的做法。具体后续会添加进来。

声纹识别的部署

模型不等于产品。训练数据,利用特定算法训练出一组声纹识别模型,并在测试数据上验证其性能,这些工作加在一起,足以构成一个完整的研究项目。不过,在拥有一个性能不错的声纹识别模型仅仅是万里长征的第一步。要将声纹模型部署到产品中,还有着无数的工程问题需要解决,例如系统的架构、模型的发布、软件的维护,以及用户与产品之间的交互等等。不过本项目规模较小,应用场景特殊,不会存在软件管理上的问题。不过一些隐形的工程问题还是存在的。不过目前确定下来的部署设置如下:

  • 声纹识别需要在设备端本地运行,不能依赖于任何服务器端的计算资源
  • 唤醒词+文本提示型,比文本无关的难度容易一些。
  • ucore能移植哪些库?
  • 软件的正确性

基于这些问题,需要以下措施:

  • 需要一套配置编译、连接方式,并描述依赖关系的构建自动化框架。
  • 设计文档
  • 单元测试
  • 持续集成工具

针对声纹验证的特性,我们需要考虑声纹录入阶段的设计、实现及交互方式。这对其后的声纹识别阶段的准确率有极大的影响。下面结合这三个硬件平台分别进行讨论。

声纹录入阶段的工程问题

文本相关的录入

文本相关的声纹录入在录入唤醒词时会涉及。在声纹录入阶段 ,通常需要向用户呈现特定的界面来引导用户提供多段录入音频。在这个过程中需要解决两个问题。

  • 什么时候开始录音?
  • 什么时候结束录音?

    因为文本是特定唤醒词,那么只要在录入的过程中同时运行唤醒词检测算法即可。如果需要N段录入音频,那么当唤醒词检测算法检测到N次唤醒词之后,就结束录音。在整个过程中,用户界面的设计也需要注重给予足够的引导与反馈信息。例如在录入界面可以提示用户当前需要说出怎样的文本,一共需要说多少次,并且可以通过绘制麦克风动画暗示用户 应用程序现在正在等待用户说话。当用户说完文本后,界面需要更新,告诉用户已经完成了多少次录入,还剩余多少次,甚至最好在界面绘制进度条或进度环,来直观地向用户呈现声纹录入的进度,直至用户成功提供所有音频为止。

文本无关的录入

文本无关的声纹录入比较类似于非唤醒词的文本相关声纹录入,可以使用语音检测模型来决定语音的开始与结束。

语音检测模块的协助

无论是语音识别系统还是声纹识别系统,其前端特征提取部分都离不开语音检测模块。只有利用语音检测模块将语音信号与非语音信号区分开,才能保证语音识别、声纹识别等系统的输入只包含有意义的语音部分。如果去掉语音检测摸块,大量不包含语音信号的背景噪声将被作为其他系统的输入,导致其他系统训练难度大幅提升,性能大幅下降。

大部分语音检测模型都可以被看作一个逐帧二元分类器。给定一个音频特征帧作为输入,语音检测模型输出两个类别中的一个:s表示语音信号,ns表示非语音信号。非语音信号对应的音频特征帧将被直接忽略,而语音信号对应的音频特征帧将被用作语音识别、声纹识别等系统的输入。由于语音检测是一个简单的二值分类模型,可以采用高斯混合模型、前馈神经网络等任意模型。 但由于音频特征帧构成一个输入序列,最普遍的做法是采用LSTM等循环神经网络。

由于语音检测模型的任务相比于语音识别、声纹识别等任务要简单得多,语音检测模型的参数通常要远远少于其他模型。当其他模型的尺寸以GB为单位时,语音检测模型的尺寸常以KB为单位。因此,对许多应用而言,语音检测模型还肩负着降低系统整体计算成本的任务。

以智能语音助手为例,有时我们希望智能语音助手能够在任何时候响应我们的语音请求,并且不依赖于关键词检测。例如,当用户说出“现在天气如何”时,智能语音助手能够立即进行识别,并判断出该语音是面向智能语音助手的请求,从而做出答复。这时,语音检测模型的存在就能过滤掉绝大部分信号,使得计算成本昂贵的语音识别模型只在语音检测模型检测到语音信号时运行。由于语音检测模型本身计算成本很小,可以24小时不间断运行,所以不用担心它占用太多CPU资源或者功耗过高。

尽管传统的语音检测模型已经能够大幅降低语音识别等系统的整体计算成本,但是在一些特殊场景下,计算成本可能依然过于高昂。考虑智能手机等移动设备上的语音助手,如果该语音助手需要能够24小时随时响应用户的任意语音请求,而不依赖特定的唤醒词,就要求语音检测模型长期不间断运行。但是,当用户携带智能手机进入较嘈杂的场合时,环境中可能包含来自其他人的语音信号,例如周围人群的交谈声,或者电视节目里的说话声等。语音检测模型无法甄别这些声音并非来自用户,而是会将其作为语音信号传递给语音识别等模块。持续运行的语音识别等任务将会占用大量的CPU和内存等资源,导致手机电量快速下降,这对用户体验来说几乎是一场灾难。但这暂时不在本课题的讨论范围内

声纹识别阶段的工程问题

声纹录入阶段通常对系统的延迟没有过高的要求。我们完全可以在录入阶段仅收集初始录入音频,至于运行神经网络并得到嵌人码和用户声纹模型,这一步完全可以在用户录入成功之后再在后台运行。而在声纹识别阶段,通常对系统的延迟有较高的要求,多数情况下我们需要立即得到识别结果,并让系统根据该结果做出不同的回应。

与唤醒词检测的协同运作

对于文本相关的声纹识别,很多情况下声纹识别需要和唤醒词检测协同运作。在这种情况下,一般在唤醒词被触发之后,由唤醒词检测算法将唤醒词对应的音频片段传入声纹识别算法。这就要求唤醒词检测系统在设计的时候注意两点:

  • 唤醒词检测算法需要将处理过的音频缓存起来,并且该缓存区的大小不能小于声纹识别系统所要求的音频长度。
  • 唤醒词检测算法需要能够提供唤醒词对应的起点与终点。

也就是说,唤醒词检测算法需要以被检测到的唤醒词的起点与终点为边界,从缓存区的音频中,截取出声纹识别系统所需要的输入信号。当声纹识别系统运行完成之后,其运行结果将会与唤醒词检测的结果共同作为判定依据,从而提升整个系统的综合性能。例如:

  • 当唤醒词检测的分数很高,但是声纹识别的分数很低时,可以认为这是由于系统检测到了由冒名顶替者说出的唤醒词而造成的。
  • 如果唤醒词检测的分数略微低于检测阈值,本不应得到响应,但声纹识别的分数却非常高,则可以认为是唤醒词检测的准确率不够导致的。此时,我们依然触发唤醒词,这种做法可以帮助我们降低唤醒词的错误拒绝率。

针对录音欺诈的部署

在反欺诈系统中,通常将欺诈攻击分为两类:物理访问攻击和逻辑访问攻击。物理访问攻击指的是,攻击者的欺诈音频必须在物理上通过系统的麦克风进行采集;而逻辑访问攻占指的是,攻击者可以直接越过系统的麦克风等硬件设备,向后端的音频信号处理模块提供输入音频。举例说明,在智能音箱设备及安防系统中,由于攻击者难以直接访问系统的软件层面,系统受到的大多是物理访问攻击,而在一些声纹识别的云端服务中,由于攻击者可以不经过硬件层面,直接向云端发送请求,系统容易受到逻辑访问攻击。在本课题的应用场景中只需要关注物理访问攻击即可

由于声纹识别系统通常很容易被伪造的音频所欺骗,我们会训练专门的模型,用来判断音频信号是真实音频还是伪造音频。在实际应用中,反欺诈系统通常与声纹识别系统进行并联。只有当反欺诈系统认为输入音频为真实音频,并且声纹识别系统认为该音频来自目标说话人时,我们才最终认定目标说话人验证成功。

t2.png

物理访问攻击与逻辑访问攻击,是从系统被攻击的软件和硬件层面进行的分类。从具体的攻击方式上讲,反欺诈系统面临的攻击主要有四种:

  • 人为冒名顶替:冒名顶替者通过模仿目标说话人的声音,试图欺骗声纹识别系统。
  • 转录:冒名顶替者可以事先在目标说话人不知情的情况下,偷偷录制一段目标说话人的语音,再将该语音提供给声纹识别系统,从而达到欺骗该系统的目的。用文本提示型声纹识别可以有效地防止此类攻击。但是对于文本相关或文本无关的声纹识别,则需要反欺诈系统帮助甄别。
  • 语音合成:只要有一小段目标说话人的音频作为参考音频,便能基于任意文本生成相应的语音,所以即使是文本提示型声纹识别系统也无法抵御此类攻击。(这种情况躺平就好了嘛~)
  • 声纹转换

反欺诈系统本质上是一个以待验证音频的音频特征序列为输入的分类器。其既可以是一个二值分类器,即只需要区分真实音频与欺诈音频即可,也可以是一个能够将多种攻击方式区分开的多类分类器。该分类器可以采用各种类型的模型,但近年来主要以神经网络模型为主。训练出可靠的反欺诈模型,就需要充足的训练数据。每两年举办一次的反欺诈挑战赛ASVspoof,便致力于构建这样的数据集,并邀请诸多学术界、工业界的研究机构参与反欺诈相关的研究。所以也是本课题重要的参考来源。

语音处理引擎

无论是信号处理还是机器学习领域,都有大量以Python语言编写的库。这些库方便安装,容易使用。不过在部署上往往不会使用这些。学术上利用各种Python的库来搭建网络,但Python具有效率低下,环境局限等特点,所以在确定了硬件后,采用C/C++编写引擎可以针对具体硬件进行优化,将运行效率提升至极致。不过信号处理的分帧、窗函数处理、傅里叶变换等都通过专用引擎来实现,机器学习部分就必须通过调用该引擎来提取特征。即使第三方的Python库可以提取类似的特征,并且将Python库的参数设置为与专用引擎完全一致,也很难保证两者的实现完全一致。尤其对于较长的时间序列而言,实现方式非常细微的差别都可能导致最终信号处理结果的迥然相异。

本课题的语音处理引擎设计目标是具备特征提取、模式识别和模型训练的所有功能。在语音处理引擎实现的时候,为了保证代码的可复用性和系统的可扩展性,在这里将采用计算图的设计模式。一个完整的系统可以用一个有向无环图来表示。图的每一个节点表示一个处理模块,图的每一条边表示数据的传输,而边的方向则表示数据的传输方向。

无论是音频解码、分帧、窗函数处理等前端处理模块,还是FFT、MFCC等特征提取模块,甚至是语音检测、声纹识别、语音识别等高级模块,都可以表示成计算图中的一个节点。实际上像语音识别这样的高级功能,实现的时候可能会通过更多模块的组合来完成,例如声学模型、词汇模型、语言模型等,每个模型都可以拥有自己的模块。而计算图的有向边,则能够非常清晰地表示出数据的流动方式和模块之间的互相依赖。例如,窗函数处理模块只需要对已完成分帧后的音频数据进行操作即可,不需要考虑音频信号的采样率、编码方式等信息。

f6.png

计算图是一种非常常见的设计模式。在机器学习领域,TensorFlow便采用了这种设计模式,其每一个节点被称为一个操作,而节点之间传输的数据便是张量。

计算图在运行的时候,通常采用从后级模块向前级模块拉取结果的方式来实现。例如,我们需要一帧MFCC特征,那么MFCC模块就会先调用前级模块FFT,从中拉取一帧数据,再对该帧数据计算MFCC作为输出;而FFT模块被调用时,又需要调用其前级模块窗函数处理;依此类推,最终需要音频解码模块先从数据缓冲区中读取音频信号,其他模块才能顺利运行。如果面临多个前级模块,就需要时间戳的辅助了。即当前已有结果的时间标记,决定了下一次从上级模块中拉取结果的顺序。与次相比,多个后级模块会使效率更高,要实现这种操作,就需要在两者之间额外增加一个结果缓存模块,直到该结果被所有后级模块拉取一遍,才会从缓存区中删除。这种设计方式保证了每一个后级模块从前级模块拉取数据时,都能得到同样的结果;与此同时,前级模块的每一个输出又只被拉取过一次。

在配置上,计算图的设计模式有时会基于JSON、XML、YAML或Protocol Buffers等数据交换语言来定义一种计算图描述语言。一旦有了这样一种语言,我们只需要将一个用该语言编写的描述文件作为语音处理引擎的配置文件,即可实现高度自定义的语音处理系统。方便修改,实现来逻辑与配置之间的分离

全设备端部署

边缘端部署面临的资源挑战

一般来说,产品部署的方式有三类:全设备端部署、全服务器端部署,以及复合式部署。本课题的目标就是全设备部署。这样无论是架构,还是版本迭代更新策略都非常简单,但是这种部署方式有一个巨大的挑战,那就是设备端有限的资源。包括CPU、内存、硬盘、电池等。

  • 编译并构建语音处理引擎的时候,尽量减少对其他库的依赖,以保证部署到设备端的引擎库占用最小的硬盘资源。
  • 语音处理引擎可以针对具体硬件进行相应的优化,例如如果设备端有DSP芯片,那么语音处理引擎便可以在该芯片上运行一部分模型,从而降低CPU的负担。
  • 在架构上,声纹识别模型应尽量减少使用卷积神经网络等计算量庞大的运算,节省CPU开销。
  • 可利用帧叠加与帧采样技术,对输入帧进行降采样作为声纹识别模型的输入,从而降低声纹识别模型的运行次数,节省CPU的开销。
  • 利用模型压缩或模型稀疏化等技术,减少模型参数,从而降低CPU、内存和硬盘等开销。
  • 利用模型量化技术,将模型中的浮点实数以单字节整数格式存储,从而降低模型占用的硬盘与内存空间、并充分利用硬件所支持的整数运算指令集提升运算速度。

模型压缩和量化的主要瓶颈是由平台所确定的,所以在这里不再过多讨论。不过可以讨论一些应用较多的方法。

木桶的水位由最短的木板确定,那资源的短板是哪呢?

无论是哪种类型的神经网络,其中占据空间最多的参数,便是用以表示输入向量、输出向量和各种隐藏向量之间的连接关系的权重短阵W。最耗费CPU计算资源的运算,自然也是权重矩阵与其输入之间的矩阵乘法运算 W·X。当然,这里的输入也可以是向量,为了不失一般性,用矩阵X表示输入。

一般来说,神经网络中的权重矩阵X通常用浮点实数表示,既可以是64位双精精度浮点实数double,也可以是32位单精度浮点实数float。为了节省空间并提升速度,大部分模型都采用32位float格式存储模型。假如模型有五百万个参数,就意味着需要20MB的硬盘空间来存储该模型。在模型运行的时候,我们就需要分配20MB的内存来加载该模型的参数。这样的硬盘和内存开销,对于许多设备端的应用来说实在太高。如果我们可以用8位无符号整数uint8存储模型的大部分参数,则模型只需要占用大约5MB的空间,从而大大减小硬盘和内存的开销。这是具有五百万参数的模型所需的空间,所以我们必须必须压制参数数量,同时寻求更精细的量化剪枝方法

进度安排,预期达到的目标

工作分为三个阶段。

STM32L4+阶段

2022年1月22日到2022年1月24日 调研完善,对下一阶段的软件设计作出合理的设计文档。

2022年1月23日到2月20日 构建STM32平台的语音处理引擎和数据集,在PC平台上编写深度学习算法,在相应平台上剪枝量化,烧写到板子上。由于任务较为简单,预估能在这段时间内完成。在这段时间其余时间内熟悉ucore和两种指令集。

2022年2月20日到2月22日 完成STM32的任务后,总结经验,编写文档,对本文档做出进一步扩充,并准备完成下一阶段的任务。

待定