赞
踩
encoder:
输入波形,通过一个一维卷积,提取特征,得到一个特征矩阵。
# input encoder
self.encoder = nn.Conv1d(1, 512, 256, bias=False, stride=16)
#输入信号通道为1,帧长256,帧移16
#1*3200->1*512*185[(3200-256)/16+1=185]
separation:
由卷积的一维扩张卷积块组成的时间卷积网络(TCN)估计每个spk的mask,使网络可以对语音信号的长期依赖性进行建模。经过4个repeat,d=8,增加感受野。
这里用TCN, 和传统卷积不同的是,膨胀卷积允许卷积时的输入存在间隔采样,采样率受图中的d控制。 最下面一层的d=1,表示输入时每个点都采样,中间层d=2,表示输入时每2个点采样一个作为输入。一般来讲,越高的层级使用的d的大小越大。所以,膨胀卷积使得有效窗口的大小随着层数呈指数型增长。这样卷积网络用比较少的层,就可以获得很大的感受野。
后面再用卷积先扩大通道数,对不同说话人进行不同通道的区分,然后就可以分离为不同说话人个数的mask。
例如:
1512185->11024185,再把11024185分离为12512*185
# generate masks
masks = th.sigmoid(self.TCN(enc_output)).view(batch_size, self.num_spk, self.enc_dim, -1)
# B, C, N, L C是要分离的个数
masked_output = enc_output.unsqueeze(1) * masks # B, C, N, L
decoder:
# output decoder
self.decoder = nn.ConvTranspose1d(self.enc_dim, 1, self.win, bias=False, stride=self.stride)
所以网络可以总结为由三个部分组成:编码器、分离器、解码器。
编码器:把混合波形转换为特征空间中表示,就是提取特征。
分离器:根据前面提取的特征,估计每个源的波形掩码,特征和掩码相乘,得到各个源对应的特征。
解码器:把各个源对应的特征进行解码,得到各个源的波形。
语音分离相关背景知识:
目前大多数语音分离是把语音从时域转换为频域中做的,用STFT转换,首先可能会有相位重建问题,其次要求对混合信号进行高分辨率的频率分解,这需要较长的时间窗来计算STFT,可能会增加系统的最小延迟。
mobilenet主要提出了一个深度可分离卷积的方式,降低了参数量。
11卷积滤波器,在深度可分离卷积的上下文中称为逐点卷积.
假设我们使用DkDk的卷积核,输入为DfDfM的图片,且输出为DfDfN,那么对于传统卷积来说,其参数量为:
DkDkMNDfDf
而对于可分离卷积来说,首先进行一个depthwise conv(逐通道)的操作,即分别对输入图像的每一个通道进行卷积,每个卷积核的输出也是单通道,所以需要M个DkDk1的卷积核,接着使用一个pointwise conv(逐像素)的操作,进行M通道的特征融合,并将通道数从M变为N,这个过程就需要N个11M的卷积核,其参数量为:
DkDkMDfDf+MNDkDf
这样的话,其参数量由原来的相乘变为相加,即降低参数量百分比为:1/N+1/D^2k
对比传统卷积,其网络结构的变化为:
VQ-VAE-2模型:
数据在整个模型中的变化为:
第一阶段:size为(长x宽x3)的图像 → size为(长x宽xd)的三维数据
第二阶段:size为(长x宽xd)的三维数据 → size为(长x宽)的二维数据
第三阶段:size为(长x宽)的二维数据 → size为(长x宽xd)的三维数据
第四阶段:size为(长x宽xd)的三维数据 → size为(长x宽x3)的图像
从VAE说起
我们知道,在生成对抗网络之前,变分自动编码器(VAE)是很常用的一个生成模型。它通过对编码器添加约束,强迫它产生服从单位高斯分布的潜在变量,在生成的时候只需要从高斯分布中采样得到一个潜在变量然后将其送入解码器进行解码就能得到有意义的输出。在这个模型中,潜在向量的采样方法不再是从高斯分布中采样而是用自回归的方式进行采样,接下来的介绍你会发现用这种采样方法要求潜在变量是离散的而不是平常所知的连续值。
编码器学习到数据的分布信息,应该融入一些随机性,所以引入了高斯噪声。这两部分信息融合以后,应该由解码器解码。VAE使用概率的思想,通过计算生成数据分布与真实数据分布的相似度(KL散度)来判断。假设编码器输出的z是服从高斯分布的,编码器输出z的过程实际上可以分解为两步:1)首先输出高斯分布的参数(均值和方差);2)将噪声和该高斯分布融合并从中采样获得z。解码器的输入是隐向量z,输出是数据的概率分布。
损失函数第一项是重构损失,目的是让原始数据生成数据尽可能相似。第二项KL散度是正则项用来衡量两个分布的近似程度。正则项的存在就是想让编码器输出z接近正态分布。如果没有正则项,模型为了减小重构损失,会不断减小随机性,也就是编码器输出的方差,没有了随机性变分自编码器也就无法生成各种数据了。所以需要z接近正态分布。所以损失函数中要对编码器施加惩罚。
第一个创新点:压缩与量化
压缩是为了解决自回归模型慢的特性带来的问题(逐像素地生成的,所以要每个像素地进行随机采样)经过压缩的处理得到潜在变量,再在潜在变量上进行自回归采样,这样就避开了慢的缺点,使得无论图像尺寸多大都不影响自回归模型的运行。
**量化(离散化)**是因为PixelCNN生成的是离散序列,想用PixelCNN建模潜在变量,那就意味着潜在变量也是离散的才行。而这里的自编码器生成的潜在变量都是连续性变量,无法直接生成离散变量。因此有了向量表与向量映射以服务于将潜在变量离散化为整数。
量化的具体的步骤是:原始图像通过CNN之后得到size为(长x宽xd)的三维数据,每个如图中①所示的向量都会经过图中右部的映射过程,映射算法用一句话来说就是“寻找向量空间中离自身最近的e,其中e属于向量表”。映射过程将原向量映射为向量表中的某个向量e,那又是如何对应到离散的整数的呢,答案是取向量e在向量表中的索引。这一步骤也是模型题目中VQ(Vector Quantised,向量量化)的来源。用vq的想法是,每类噪声,都有自己的特征空间。
至此,模型将输入图像压缩并离散化为一个二维的整数矩阵。
量化就是通过编码表,把自编码器生成的向量E(x)离散化。codebook,可以理解为一个离散的编码表,举一张人脸图像为例,codebook就包括头发颜色,脸型,表情和肤色等等。
解码器通过另一个非线性函数重建数据,重建错误的梯度从解码器反向传播到编码器.
VQ-VAE还引入了codebook loss和commitment loss来align编码表codebook的向量空间和encoder的输出。
在Encoder和Decoder部分,分别采用常规卷积函数、BatchNorm、残差网络进行构建。
训练时的损失函数分为3部分。第1部分是重建损失,第2部分和第3部分都利用了”stop-gradient”,在前向时计算损失,而在反向传播时,相应放弃忽略项目。具体说明如下:x表示原始信号,e表示字典中的最近邻向量,sg表示stop-gradient,那么损失函数中,第1项x-Decoder(e),第2项sg(Encoder(x))-e,第3项Encoder(x)-sg(e),三者都是平方损失。这里需要说明的是,第2项是在惩罚e,所以目的是让字典更新的与Encoder接近,第3项是在惩罚Encoder,所以目的是让Encoder更新的与字典接近,在训练时,可以根据需要调整相应的系数比例,来权衡字典和Encoder的重要程度。
在代码实现中,有几点说明:一是查找CodeBook方面。比如计算A=[K,D]和B=[L,D]大小矩阵中每一行D维向量的欧式距离(a-b)(a-b)=aa-2ab+bb。首先计算A,B中每行D维向量的平方,item1(aa) = A.pow(2).sum(1,keepdim=True)和 item3(bb) = B.pow(2).sum(1),然后计算item2(ab) = AB.t(),那么最后的结果为item1 + item3 -2itme2。其中,item1和item3相加,在pytorch中列向量加行向量,自动生成行列矩阵,其每个元素来自于行向量和列向量中的对应元素相加。二是stop-gradient操作。在pytorch中,则在计算损失时将E变为E.detach(),这样对于变量E就不做反向梯度传播了。
生成模型相关知识:
目前生成模型大概可分为两种:
1.基于可能性的模型:VAEs、基于flow的模型和自回归模型
2.内隐生成模型:GANs
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。