杂记(2019.04.13)
这本是近三个月间零零散散看到的知识点,今记录于此。
韵律预测
口语句子的韵律结构是指某些词似乎自然地结合在一起,而某些词似乎有明显间隔或彼此分开。如:
I want to go London, but could only get tickets for France.
包含两个语调短语,边界即是逗号处。
在第一个短语中,似乎还有更小的韵律边界,通常称为中间短语,把单词做如下分割:
I wanted/to go/to London.
从一个语调短语的开始到结尾,\(F_0\)往往会有一个轻微的下降,然后在一个新的韵律短语开始的时候,\(F_0\)又会复位。可以将短语边界的预测看成是一个二元分类问题,对于一个给定的单词,判定在它后面是否存在一个韵律边界。边界预测的简单模型是基于确定性规则的。现行精确度最高的规则:
- 在标点符号之后都插入一个韵律边界;
- 在实词之后如果有一个虚词,则在虚词之前插入一个韵律边界
如果将韵律预测作为一个机器学习问题,在该问题中通常最有效的特征有:
- 长度特征
- 话语中单词和音节总数;句子开始至句子结尾的距离;单词离最后一个标点符号的距离
- 相邻词类和标点:前两个单词词类与后两个单词词类;后面一个标点符号的类型
语音情感
情感语音数据库分为离散情感数据库和维度情感数据库。其中离散情感问题是分类问题;而维度情感是打分连续值,是回归问题。
语音情感特征提取:
- 韵律学特征
- 基于谱的相关特征
- 音质特征
这些特征常常以帧为单位进行提取,但是以全局特征统计值的形式参与情感的识别。
韵律学特征
韵律是指语音中凌驾于语义符号之外的音高、音长、快慢和轻重方面的变化。常用的韵律特征有时长、基频、能量等。基频均值、能量均值、基频方差,基础对数的动态范围。
基于谱的相关特征
线性谱特征一般有:LPC
,OSALPC
,LFPC
倒谱特征一般有:LPCC
,OSALPCC
,MFCC
声学质量特征
对语音质量产生影响的声学表现有:喘息、颤音、哽咽等
因此,声音质量的声学特征一般有:共振峰频率及其带宽,频率微扰和振幅
分类器
-
离散语音情感分类器
- 线性
- 朴素贝叶斯
- Linear ANN(Artificial Neural Network)
- Linear SVM
- 非线性
- 决策树
- KNN
- 非线性ANN
- 非线性SVM
- GMM
- HMM
使用最广泛的有HMM,GMM,ANN和SVM
- 线性
-
维度语音情感预测器
- Linear Regression
- KNN
- ANN
- SVR
Triplet Loss
triplet loss是深度学习中的一种损失函数,用于训练差异性较小的样本,送入的数据包括锚正例(anchor)
、正例(positive)
和负例(negative)
。通过优化锚正例与正例距离小于锚正例与负例距离,实现样本相似度计算。
其中,\(f(x^a),f(x^p),f(x^n)\)分别为锚正例、正例和负例;\(\alpha\)为距离常数,超参数。
tf.gradients()
及tf.stop_gradient()
-
Tensorflow中有一个计算梯度的函数
tf.gradients(xs,ys)
,注意:xs
和ys
必须相关,不相关则会报错。import tensorflow as tf w1=tf.Variable([[1,2]]) w2=tf.Variable([[3,4]]) # 定义了两个变量w1,w2,但result只和w1相关。否则报错:Fetch argument None has invalid type res=tf.matmul(w1,[[2],[1]]) grads=tf.gradients(res,[w1,w2]) with tf.Session() as sess: tf.global_variables_initializer() # 将报错,因为res只和w1相关。TypeError: Fetch argument None has invalid type <class 'NoneType'> re=sess.run(grads)
-
tf.stop_gradients()
:阻挡节点BP的梯度import tensorflow as tf w1=tf.Variable([[2.]]) a=tf.matmul(w1,[[3.]]) a_stopped=tf.stop_gradient(a) w2=tf.Variable(2.) b=tf.multiply(a_stopped,w2) # b=w1*3.*w2 gradients=tf.gradients(b,xs=[w1,w2]) print(gradients) ''' 输出: [None, <tf.Tensor 'gradients/Mul_grad/Reshape_1:0' shape=() dtype=float32>] '''
可见,一个节点被stop之后,这个节点上的梯度就无法在向前BP了。由于w1变量的梯度只能来自于a节点,所以其对应的节点计算梯度返回的是None.
对应的,
a=tf.Variable(1.) b=tf.Variable(1.) c=tf.add(a,b) c_stopped=tf.stop_gradient(c) d=tf.add(a,b) e=tf.add(c_stopped,d) gradients=tf.gradients(e,xs=[a,b]) with tf.Session() as sess: tf.global_variables_initializer().run() # 输出[1.,1.] print(sess.run(gradients))
虽然c节点被stop了,但是a、b还有从d传回的梯度,因此还是可以输出梯度的。
另外一个例子:
w1=tf.Variable(2.) a_stopped=tf.stop_gradient(a) # b=w1*3.*w2 w2=tf.Variable(2.) opt=tf.train.GradientDescentOptimizer(0.1) # 注意:tf.trainable_variables(): w1&w2 gradients=tf.gradients(b,xs=tf.trainable_variables()) # 输出:[None,Tensor] print(gradients)
-
高阶导数
Tensorflow求高阶导数可以用
tf.gradients()
实现with tf.Session() as sess,tf.device('/cpu:0'): a=tf.constant(2.) b=tf.pow(a,2) # b=a^2 grad=tf.gradients(ys=b,xs=a) # 一阶导数, 4. grad_2=tf.gradients(ys=grad[0],xs=a) # 二阶导数, 2. grad_3=tf.gradients(ys=grad_2[0],xs=a) # 三阶导数, 0. print(sess.run([grad,grad_2,grad_3]))
注意:有些op,Tensorflow没有实现其对应的高阶导计算,如
tf.add()
如果计算了一个没有实现高阶导的op的高阶导数,tf.gradients()
会返回None.
注意力机制
注意力机制可以理解为一种文本聚集方法,基本思想是对文本分配注意力权重,把注意力集中在相关的文本内容上,增加这部分的贡献。
-
注意力形式
- 计算区域
- soft attention: 最为常见的Attention形式,对所有key求权重概率,每个key都有一个对应的权重,是一种全局的计算方式(也可以叫做Global Attention)。这种方式比较理性,参考了所有key的内容,再进行加权,但计算量大。
- hard attention: 这种方式直接精准定位到某个key,其余key全部忽略。即这个key的权重为1,其余key的权重为0。这种对齐方式要求很高,如果没有正确对齐,会带来很大影响。另一方面,因为不可导,一般需要用强化学习的方法进行训练。
- local attention: 上述两者的折中,对一个窗口区域进行计算,先用hard方式定位到某个地方,以该点为中心可以得到一个窗口区域,在这个窗口区域使用soft形式计算attention。
- 计算区域
-
所用信息:假设对一段原文计算Attention,所用信息包括内部信息和外部信息。内部信息是原文本身的信息,而外部信息指原文之外的信息。
-
General attention:这种方式利用了外部信息,常用于构建两个文本之间的关系,query一般包含了额外信息,根据外部query对原文进行对齐。
比如在阅读理解任务中,需要构建问题和文章的关联,先要对问题计算出一个问题向量\(q\),把这个\(q\)和文章所有词向量拼接起来,输入到LSTM进行建模。在这个模型中,文章所有词向量共享同一个问题向量,这里问题属于原文,文章词向量就属于外部信息。
-
Local Attention:只使用内部信息,key、value和query只和输入原文有关,在self attention中,key=value=query。既然没有外部信息,那么在原文中每个词都可以和句子中的每个词进行Attention计算,相当于求序列内部的联系。
I love China [0.5,0.7] [0.3,0.1] [0.3,0.5] \[alignment=\begin{bmatrix} 0.5 & 0.7 \\ 0.3 & 0.1\\ 0.3 & 0.5 \end{bmatrix}_{3\times 2} \begin{bmatrix} 0.5 & 0.3 & 0.3 \\ 0.7 & 0.1 & 0.5 \end{bmatrix}_{2\times 3} \]
-
-
结构层次
-
单层Attention:普遍做法,用一个query对一段原文进行一次attention
-
多层Attention:一般用于文本具有层次关系的模型,假设将一个文章划分为多个句子,在第一层对一个句子使用attention,计算出一个句子向量(也即是单层attention),在第二层对所有句子向量再做一次attention,计算一个文章向量(也是单层attention),最后用这个文章向量进行下游任务。
-
多头Attention:重复h头次数:先对query、key和value乘参数矩阵,然后做attention。
\[head_i=Attention(q^i,k^i,v^i) \]再拼接起来:
\[MultiHead(k,v)=concat(head_1,head_2,...,head_h)W^c \]
-
-
注意力中求query和key相似度的方法有很多,如:
-
点乘
\[s(q,k)=q^Tk \] -
矩阵相乘
\[s(q,k)=q^Twk \] -
cos相似度
\[s(q,k)=\frac{q^Tk}{||q||\cdot ||k||} \] -
串联方式
\[s(q,k)=w[q;k] \] -
MLP
\[s(q,k)=v_a^T\mathop{tanh}(wq+uk) \]
-
生成模型
- GAN
- VAEs
- 自回归模型
- RNNs
- 普通RNN
- 门:LSTM、GRU,双向RNN
- 自回归模型
- RNNs
常见的生成模型:
- RNNs
- 普通RNN
- 门:LSTM,GRU,双向
- seq2seq+attention
- 带洞卷积
- WaveNet
- ByteNet
- PixelRNN
- PixelCNN
音频表示
-
原始波形
无压缩,一维,幅度-时间
-
线性谱
二维,频率桶(frequency bins)-时间(1025 bins)
梅尔谱
易于训练神经网络,有损,需要压缩但也保持充足的特征。
能量集中在线性谱的小部分自己bins
梅尔频谱特征:
-
低频更重要:低频排布紧密的滤波器
-
高频不重要
\[M=1125\mathop{ln}(1+\frac{f}{700}) \]低频部分,bins排布更紧密
-
-
幅度谱
二维,指数压缩表示(80bins)
自编码器
自编码器由encoder和decoder两部分组成。encoder将输入进行编码,得到隐表达(latent representation)\(z\),然后decoder对\(z\)进行解码得到输入\(x\),即重建\(x\)。
通常中间潜在表达的维度比输入小,中间层要对输入\(x\)进行压缩,提取输入\(x\)的主要信息,然后利用得到的\(z\)进行重建,得到原来的\(x\)。在重建过程中,从低维到高维势必产生一定的误差,这样可以保证重建数据和输入数据不完全相像。
如果抹去encoder,剩下的decoder就是一个生成器,可以输入\(z\)得到想生成的数据。
变分自编码器(VAE)
VAE不像标准的auto-encoder中encoder产生一个单一数值来描述潜在表达\(z\)的分布,而是用概率来表达产生的数值。
VAE的encoder会将图片编码成一个个概率分布,然后decoder会从这个分布中随机采样作为decoder的输入。
不同时刻的输出都是从潜在表达的概率分布中生成的,因此希望生成的输出尽可能相似。
在贝叶斯公式中,
其中,\(p(x)\)并不一定好算,\(p(x)=\int p(x|z)p(z)dz\),如果\(z\)是一个高维的,就会出现多次积分。一个替代方法就是用变分推断(varitational inference)来估计这一个值。
假如有另外一个分布\(q(z|x)\),\(q(z|x)\)可以用于拟合\(p(z|x)\),而\(q(z|x)\)有很好的性质,可以很好的计算,这样就可以间接的计算\(p\),可以最小化\(p\)和\(q\)的KL散度,使得\(q\)来模拟出\(p\)。
其中,\(\mathop{log}p(x)\)是一个常数,因此减少\(KL(q||p)\)等同于增大\(\sum_z q(z|x)\mathop{log}\frac{p(x,z)}{q(z|x)}\)。\(\sum_z q(z|x)\mathop{log}\frac{p(x,z)}{q(z|x)}\)被称为变分下界。
因此需要增大\(E_{q(z|x)}\mathop{log}p(x|z)-KL(q(z|x)||p(z))\)
其中,第一部分表示重建可能性,第二部分确保学习到的\(q\)相似于\(p\)。因此可以用\(q\)来推测产生的隐变量\(p\)。
Loss function由两部分组成,一部分是重建误差,另一个是我们学习到的分布\(q(z|x)\)应相似于默认潜在空间的分布\(p(z)\)。