基于DPRNN的信号分离任务(科研小记)

1. 背景:信号分离任务

信号分离与重建任务在深度学习领域已经取得了长足进步。特别是在纯语音分离领域,深度聚类方法和置换不变训练方法为语音分离的起步夯实了基础。在传统的信号分离任务中,基于时频域的信号分离需要将信号进行短时傅里叶变换,将时域信号转换为时频域信号。因为时频域信号更易于提取语音特征,例如基于人耳听觉的特征MFCC等。同时,经过短时傅里叶变换的时频域信号容易通过逆傅里叶变换重建为时域信号。而基于时域的信号分离需要搭建一个编码器-解码器的端到端模型。其中编码器将时域信号映射成高位特征向量,而解码器会重建分离的信号特征。基于时频域和时域的信号分离,都依赖于神经网络模型训练后给出的掩码。通过将时频域信号或编码的时域信号与掩码相乘,达到信号分离的目的。如何构建合适的神经网络来计算出合适的掩码,是信号分离的首要问题。

图1 语音分离的流程图
图1 语音分离的流程图

2. 基于双通道循环神经网络的信号碰撞分离与重建

双通道循环神经网络(Dual-Path Recurrent Neural Network)的分离与重建是基于时域的信号分离方式。双通道循环神经网络(下称DPRNN)将长的序列输入分成较小的块,并迭代地应用块内和块间操作,其中每个操作的输入长度可以与原始序列长度的平方根成比例。DPRNN模型由三个阶段组成:分段、块处理和重叠相加。分段阶段将连续输入分成重叠的块,并将所有块连接成一个三维张量。然后将张量传递给堆叠的DPRNN块,以交替方式迭代应用局部(块内)和全局(块间)建模。最后一层的输出使用重叠添加方法转换回连续输出。信号保真度的改善程度可以通过信噪比的改善(SDRi)和尺度不变的信噪比改善(SI-SNRi)来衡量。
图2 DPRNN信号分离模型
图2 DPRNN信号分离模型

DPRNN的算法流程为如下:
分割阶段的目标是将输入的采样数为L的长序列截断,将长的信号序列输入分成较短的块,每个块包含K个连续的时间步长,重叠的部分长度为P。当K=2P时,每个相邻块有一半部分与前块重叠,另一半与后块重叠。假设原始序列含N维特征,每个块长度为K,分成S块,则会得到N×K×S的三维张量。
图3 分割阶段
图3 分割阶段

对于每个块,首先使用块内RNN进行局部建模,然后使用块间RNN进行全局建模。 在块内RNN中,每个块的时间步长被视为序列的长度,因此可以使用较小的RNN进行建模。 在块间RNN中,所有块的信息被聚合以执行帧级别的处理。如果说块内RNN学习到的可能更多的是比较局部,相邻的区域的特征的话,那块间RNN学习到的就是不同块之间的联系。通过迭代应用块内和块间操作,DPRNN可以有效地建模长序列,同时避免了梯度消失或爆炸的问题。
图4 DPRNN块
图4 DPRNN块

在分块后,块内RNN和块间RNN均需经过一个双向RNN层,一个全连接层和一次层归一化,最终进行残差连接。双向RNN可以避免单向RNN遗忘早期输入的问题,加强了对长序列的建模能力。若T为对应的输入张量,f为双向RNN的映射函数,则双向RNN的输出U为:
U=[f(T[;,;,i]),i=1,…,S]
全连接层将双向RNN的输出进行线性变换。这一步可能会使得不同层的权重矩阵和偏置差距较大。若G为全连接层的权重,m为偏置,则全连接层的输出U’为:
U’=[GU[;,;,i]+m,i=1,…,S]
层归一化将不同层的内部实现标准化。最后,残差连接进一步改善了梯度消失和过拟合的问题。
最后将经过Mask处理的块进行重叠相加操作,恢复成线性序列。将块T_b+1拆分,重新拼接成输出序列Q。
图5 重叠相加图5 重叠相加

最终,DPRNN可以用于碰撞任务,通过将信号分成多个频带并在每个频带上应用DPRNN模型,从碰撞信号中分离并在解码器中重建出不同水声目标的时域信号。

3. 置换不变性训练

置换不变性训练用于解决模型预测值的标签与真实标签的对应问题。该方法将分离误差最小化,即找到一种损失最小的标签排列组合的方法。
该方法首先使用深度学习模型估计一组掩码Mask。然后,估计单一信号的频谱图,通过掩码点乘混合频谱图。假设S代表时域上信号序列,X_s (t,f)表示这些信号对应的短时傅里叶变换的结果。而Y(t,f)表示所有信号对应的X_s (t,f)之和,即
Y(t,f)=∑_(S=1)^S▒〖X_s (t,f)〗

该方法是第一个估计掩码的方法,因此可以优化模型参数以最小化估计掩码M’与理想比率掩码M=(|X_s |)/(|Y|)之间的均方误差。
在这里插入图片描述

这个方法解决了两个问题。首先,在静默段中,实际声音的Mask=0且混合频谱的Mask=0,所以Mask之间的差异直接转换为频谱图之间的差异。其次,在模型训练过程中,每当遇到标签对应问题时,可以选择迭代计算使得损失最小的标签对应方法,从而解决标签置换问题。

4.基于双通道循环神经网络的仿真实验

仿真数据为基于Matlab循环生成的40类不同目标的信号组合。每一类目标中,均包含10个不同周期,21个潜标组,以及来自15种不同深度,共3150段信号。所有信号的采样率均为125000Hz。基于双通道循环神经网络对以上数据集进行混合信号的分离与重建仿真实验。选取两种与三种不同目标在时域完全重叠情形,进行信号分离与重建的仿真实验。
首先,以两种分布在不同频段的目标混合,进行仿真实验。目标1与目标40信号分布在不同频段。分别随机选取目标1与目标40中的一条信号进行混合,得到的频谱图如图6所示。
在这里插入图片描述
图6 目标1、目标40及其混合频谱

将目标1与目标40的数据按8:2划分为数据集与测试集。经过DPRNN训练15epoch后,上述混合信号分离重建后的频谱如图7所示。
图7 目标1、目标40的混合及其分离频谱
图7 目标1、目标40的混合及其分离频谱

其次,以两种分布在相同频段的目标混合,进行仿真实验。目标1与目标10信号分布在相同频段。分别随机选取目标1与目标10中的一条信号进行混合,得到的频谱图如图8所示。
图8 目标1、目标10及其混合频谱
图8 目标1、目标10及其混合频谱

将目标1与目标10的数据按8:2划分为数据集与测试集。经过DPRNN训练15epoch后,上述混合信号分离重建后的频谱如图9所示。
图9 目标1、目标40的混合及其分离频谱
图9 目标1、目标40的混合及其分离频谱

最后,以目标1、目标10和目标20三种目标混合进行仿真实验。其中目标1和目标10分布在同一频段,目标20则高于该频段。分别随机选取目标1、目标10与目标20中的一条信号进行混合,得到的频谱图如10所示。
图10 目标1、目标10和目标20及其混合频谱
图10 目标1、目标10和目标20及其混合频谱

将目标1、目标10和目标20的数据按8:2划分为数据集与测试集。经过DPRNN训练15epoch后,上述混合信号分离重建后的频谱如图11所示。
图11 目标1、目标10和目标20的混合及其分离频谱
图11 目标1、目标10和目标20的混合及其分离频谱

信号保真程度一般通过尺度不变的信噪比改善(SI-SNRi)来衡量。SI-SNRi通过模型分离前后的尺度不变信噪比(SISNR)相差得到。SISNR作为衡量信号分离精度和评估指标的模型。SISNR的计算公式如下:
在这里插入图片描述

其中:x为估计的信号;x^*为干净的真值源信号;x_E为与估计信号相垂直的无关噪声信号;x_T为估计信号中的真值信号分量。
本仿真实验共尝试三种情形下的信号分离与重建:两种不同频段信号混合、两种相同频段信号混合、三种信号混合。三种情形分别计算得到的尺度不变信噪比改善(SI-SNRi)如表1所示:
在这里插入图片描述
由于目标1与目标40处在不同频段,分离重建后信号的尺度不变信噪比相对高;目标1与目标10处在相同频段,分离重建后信号的尺度不变信噪比相对较低。

  • 24
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Protobuf是一种高效的序列化协议,可以用于数据交换和数据存储。它的主要优势是大小小,速度快,可扩展性强。下面是使用Protobuf的一些小记: 1. 定义消息格式 首先,需要定义消息格式,以便Protobuf可以将数据序列化和反序列化。消息格式定义在.proto文件中,使用protobuf语言编写。例如,下面是一个简单的消息格式定义: ``` syntax = "proto3"; message Person { string name = 1; int32 age = 2; } ``` 这个消息格式定义了一个名为Person的消息,包含两个字段:name和age。 2. 生成代码 一旦消息格式定义好,就可以使用Protobuf编译器生成代码。编译器将根据消息格式定义生成相应的代码,包括消息类、序列化和反序列化方法等。可以使用以下命令生成代码: ``` protoc --java_out=. message.proto ``` 这将生成一个名为message.pb.java的Java类,该类包含Person消息的定义以及相关方法。 3. 序列化和反序列化 一旦生成了代码,就可以使用Protobuf序列化和反序列化数据。例如,下面是一个示例代码,将一个Person对象序列化为字节数组,并将其反序列化为另一个Person对象: ``` Person person = Person.newBuilder() .setName("Alice") .setAge(25) .build(); byte[] bytes = person.toByteArray(); Person deserializedPerson = Person.parseFrom(bytes); ``` 这个示例代码创建了一个Person对象,将其序列化为字节数组,然后将其反序列化为另一个Person对象。在这个过程中,Protobuf使用生成的代码执行序列化和反序列化操作。 以上是使用Protobuf的一些基本步骤和注意事项,希望对你有所帮助!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

maplesea7

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值