前言

最近在看这个论文,本来想要写一个翻译,但是鉴于本人英语的渣水平,再加上论文本身一些说明,虽然能够看懂,但是很难翻译过来,所以还是写个阅读笔记好了。在这篇文章,我会跟着论文的思路大致说明论文的内容和自己的理解。

CTC解决什么问题

在许多的训练任务中,我们需要输入一个序列,这个序列有可能有噪声,并不是我们需要的信息都连续存在。比如声音的识别之类的,对于一个语音,假设我们要翻译成文字,但是声音中的信息并不是连续的,说了一个字可能要停顿个1秒才会说下个字:

  1. 我~~~~要吃饭
  2. 我要~~~~吃饭
  3. 我要吃~~~~饭

像上面这三种情况,显然结果都是我要吃饭。想要让RNN做到这一点,我们要解决两个问题,一个是,如何将RNN的输出翻译成同一句话,另一个问题,如何训练这样一个网络。CTC就这两个问题提供了一个可行的方案,使得训练这样的网络成为可能。

2.时序分类器(Temporal Classification)

论文的第二节,实际上是定义了一些基础的概念和问题,这个小标题大概是这么翻译吧……

这里提到了一大堆符号,不过有一些都是为了后面少说几个字~

SS:表示训练集
χ=(Rm)∗\chi = (\mathbb{R}^m)^*:输入空间,表示m维的所有序列(这里的m就是输入序列长度)
LL:字符集
Z=L∗Z=L^*:输出空间,是字符集中的字符的组合序列。
(x,z)(x,z):表示训练集中的一个训练样例。
x=(x1,x2,...,xT)x=(x_1,x_2,...,x_T):一个训练样例中的输入的序列。
z=(z1,z2,...,zU)z=(z_1,z_2,...,z_U):一个训练样例中的label的序列(就是应该输出的结果)。
U≤TU \leq T:这里要说明的是,输出序列长度要小于等于输入序列的长度(RNN对于序列的每个元素都有个输出,但是我们要做一些操作吧这些输出转化成真正的结果)。

说了这么多,终于可以说训练的目标了,我们的目标是训练一个时序分类器hh来将输入转换(映射)成我们需要的结果:

h:χ↦Z

h : \chi \mapsto Z

2.1 label的错误率计算

在论文里,评价标签的错误率使用了最小编辑距离的方法,也就是说,想要把一个串变成目标串最少需要几步(可用的操作包括添加、修改、删除一个字符)。最小编辑距离用ED(p,q)ED(p,q)表示,这里的p,qp,q就是要计算的两个字符串。

论文里还是用符号和公式来表达了最终测试的评价结果:

S′S':表示测试集
LERLER:标签的错误率(label error rate)

LER(h,S′)=1|S′|∑(x,z)∈S′ED(h(x),z)|z|a(1)

LER(h,S')=\frac{1}{|S'|} \sum_{(x,z)\in S'} \frac{ED(h(x),z)}{|z|} a \qquad (1)
使用分类器hh在测试集S′S'上测试的标签错误率,计算方法是,对于每个样例,计算分类器的输出与label的最小编辑距离,然后除label的长度,把这些求和除测试集的长度~

3. Connectionist Temporal Classification

也不知道具体如何翻译,就这样吧。这一节是说,要把RNN的输出使用CTC来描述,最重要的一步是把网络的输出转化成标签上每个字符的独立的条件概率,然后网络就可以根据对应的最有可能的label来训练分类器。

3.1 从网络输出到标签

这里大概说了一下CTC网络的结构,首先是有一个softmax的输出层,输出层除了字符集LL还有一个额外的单元,论文里称为’blank’,可以看作是一个特殊符号,表示这个输出不对应的字符集的元素。这些输出通过排列组合就可以得到所有可能的输出。
接下来,又是惯例的公式时间:

Nw:(Rm)T↦(Rn)TN_w : (\mathbb{R}^m)^T \mapsto (\mathbb{R^n})^T:这里对于一个长度为TT的输入序列xx,定义了一个mm个输入,nn个输出,权重向量为ww的RNN网络作为映射函数。这里m,nm,n指的是网络的输入输出,而TT指的一个输入序列的长度,有些绕,就是一个输入到输出的定义,大概理解就好了。
y=Nw(x)y = N_w(x) :这里yy就是网络的输出序列。
ytky_k^t:这个就是在tt时刻,网络输出的kk元素的值(概率)。
L′=L∪{blank}L' = L \cup \{blank\}:也就是说L′L'是网络的所有输出元素的集合。
L′TL'^T:一个长度为TT的输出序列。

p(π|x)=∏t=1Tytπt,∀π∈L′Ta(2)

p(\pi | x) = \prod_{t=1}^{T} y_{\pi_t}^t ,\forall{\pi} \in L'^T a \qquad (2)论文中说,把L′TL'^T中的元素称之为paths,并用π\pi表示。这个公式就是定义了在输入为xx的时候,输出为某个路径π\pi的概率,这个概率的算法,就是把对应的每个时刻的网络输出的对应元素的概率乘起来。

论文里说,(2)式假设了不同时刻网络的输出概率是条件独立的,并且这一点通过给定的网络的输出层与网络不存在反馈连接来保证:

This is ensured by requiring that no feedback connections exist from the output layer to itself or the network.

我看的时候还是有些疑惑的,因为RNN的输出在时间上是存在依赖性的,这里说不同时刻是独立的,总觉得哪里不太对。我的理解是,当RNN的输出确定之后,这时候对于CTC网络来说,每个时刻的输出是独立的,这样似乎可以解释得通。

然后又讲了一下从网络的输出映射为一个唯一的label的方法,其实就是把输出串的blank删掉,并且相邻的相同字符合并起来就好了。下面说一下相关的公式表示:

B:L′T↦L≤TB : L'^T \mapsto L^{\le T}:这个就是上面说的映射函数,方法就向上面说的那样。(如:B(a−ab−)=B(−aa−−abb)=aabB(a-ab-)=B(-aa--abb)=aab)

p(l|x)=∑π∈B−1(l)p(π|x)(3)

p(l|x)=\sum_{\pi \in B^-1(l)}p(\pi|x) \qquad (3)这个公式定义了在输入为xx的时候,输出一个给定label的值ll的概率,计算方法就是把所有可以用BB函数映射为ll的路径的概率相加。

3.2 构造分类器

根据上面说的,就可以很容易得出结论,最终我们的结果就是概率最大的那个labelling:

h(x)=argmaxl∈L≤T p(l|x)

h(x) = \underset{l \in L^{\le T}}{argmax} \ p(l|x)
不过,这个东西是没有一个好的解法的,因为要枚举所有的可能的 ll的话,时间复杂度就爆炸了。所以论文中给出了两个求近似的解法。
第一种:
叫作best path decoding。其实就是把每个时刻的输出的argmax作为最终的输出,用这个输出序列来求出最后的label:

h(x)≈B(π∗) where π∗=argmaxπ∈Nt p(π|x)(4)

h(x) \approx B(\pi^*) \ where \ \pi^* = \underset{\pi\in N^t}{argmax} \ p(\pi | x) \qquad (4)
第二种:
叫作prefix search decoding。这里论文讲的节奏有点不太好,论文提到了用后面的前向后向算法,用同样的方法来做一个前缀计算。这里先简单说一下前向后向算法在这里的作用,具体后面再说,这个算法利用动态规划,可以算出输出为某个前缀的概率的值,prefix search decoding的想法就是,我每次给当前的串添加一个字符(最开始是空),算出用哪个字符得到的概率最大,一个一个添上去,就得到了最终的答案:

这里我还是有个疑问,就是输出串的长度是如何确定的,我猜应该是不断续上字符,然后所有的结果中取一个最大值吧。
但是呢,这么算还是有个bug,就是说,当最优解向下图中的实线部分那样分布,用这个方法是算不出来的。

然后呢,论文的作者就加了一个黑科技,先把输出序列分段,在每一段的内部使用这个方法得到答案,然后把这些结果拼起来作为最终答案。而分段的依据就是通过判断每个时刻输出的blank的概率值大于某个阈值。这个方法表现的还是挺好的,但是在一个被分好的一段序列的内部再出现上面的情况,那就没办法了。

4. 训练网络

这里说了现在描述了一个用CTC来表示RNN的输出的方法,然后根据目标函数就可以开始愉快的训练了balabala~

4.1 CTC的前向后向算法

这一节讲了计算p(l|x)p(l|x)的算法,因为我们不可能枚举所有的可能性,所以这里采用了一个动态规划的方法来计算,作为搞过acm的人来说,动态规划就很熟悉啦,不说也知道怎么算了。这里就简单讲一下,主要是这里公式挺多的,也需要列一下。

简单来说呢,这个方法是基于这样一个结论:t时刻的一个前缀s,可以通过t-1时刻算出的前缀的结果推导出来。

下面会列一下论文中的公式和推导:

αt(s)=def∑π∈NT:B(π1:t)=l1:s∏t′=1tyt′πt′(5)

\alpha_t(s) \overset{def}{=} \sum_{\pi \in N^T:B(\pi_{1:t})=l_{1:s}}{\prod_{t'=1}^{t}{y_{\pi_{t'}}^{t'}}} \qquad (5)
这个公式看起来很复杂,其实也不难懂啦,其实就是定义了对于特定的 ll的前缀l1:sl_{1:s}来说, αt(s)\alpha_t(s)就是在t时刻可以转化成这个前缀的路径的概率总和。后面不会用到这个公式来计算啦,所以只要知道 αt(s)\alpha_t(s)是个什么东西就行了,它的值会用动态规划的算法算出来。

就像前面所说的:αt(s)\alpha_t(s)是可以根据αt−1(s)\alpha_{t-1}(s) 和αt−1(s−1)\alpha_{t-1} (s-1)来推导出来的。这个应该是比较容易理解的,如果是αt−1(s)\alpha_{t-1}(s)这种情况,那么只需要在后面乘上一个blank或者lsl_s的概率就行了,如果是αt−1(s−1)\alpha_{t-1}(s-1)这种情况,就要乘一个lsl_s的概率,这两种情况的结果加起来就行了。

大概的意思就是上面所说的,但是实际实现的时候,还是有一些不同的。论文里,把给定的ll做了一些修改,把每个字符之间还有前后两端插入了一个blank,得到了l′l',它的长度是2|l|+12|l| + 1。这样做的好处,一个是便于计算,另一个是可以保证每一步得到的结果是合法的,因为blank是具体区分每个字符的依据。

接下来,首先定义一下初始值:

α1(1)=y1bα1(2)=y1l1α1(s)=0,∀s>2

\alpha_1(1)=y_b^1 \\ \alpha_1(2)=y_{l_1}^1 \\ \alpha_1(s)=0,\forall {s>2}

然后是状态转移方程:

αt(s)=⎧⎩⎨α¯t(s)ytl′s(α¯t(s)+α¯t−1(s−2))ytl′sif l′s=b or l′s−2=l′sotherwise(6)

\alpha_t(s)=\left\{\begin{matrix}&\bar{\alpha}_t(s)y_{l'_s}^t &if \ l'_s=b \ or \ l'_{s-2}=l'_s \\ &(\bar{\alpha}_t(s) + \bar{\alpha}_{t-1}(s-2))y_{l'_s}^t &otherwise \end{matrix}\right. (6)

α¯t(s)=defαt−1(s)+αt−1(s−1)(7)

\bar{\alpha}_t(s) \overset{def}{=} \alpha_{t-1}(s) + \alpha_{t-1}(s-1) \qquad (7)
这个公式把 α¯t(s)\bar{\alpha}_t(s)带入展开以后还是比较好懂的,需要注意的就是,当前一个字符是blank的时候,后面插入字符是任意的,但是如果目标有两个字符连在一起的时候,它们中间必须间隔一个blank,但是如果两个字符不同,就可以直接连接,另外, ss的最长长度在时刻tt是有限制的。

根据上面的公式,我们就能得到p(l|x)p(l|x)的结果了:

p(l|x)=αT(|l′|)+αT(|l′|−1)(8)

p(l|x) = \alpha_T(|l'|) + \alpha_T(|l'|-1) \qquad (8)

然后,我们可以用相似的方法定义后缀的概率βt(s)\beta_t(s),这里的ss指的就是从第ss个字符到最后。这个公式我就不写了,直接放个图好了:

接下来还有一个问题,就是这个计算有可能溢出,因为每一步都要进行乘法。所以,论文里在计算的时候加了一个缩放的操作:

Ct=def∑sαt(s),α^t(s)=defαt(s)Ct

C_t \overset {def}{=} \sum_{s}\alpha_t(s), \qquad \hat{\alpha}_t(s)\overset{def}{=} \frac{\alpha_t(s)}{C_t}
在(6)(7)式中用 α^\hat{\alpha}代替 α\alpha。
后向的结果也一样:

Dt=def∑sβt(s),β^t(s)=defβt(s)Ct

D_t \overset {def}{=} \sum_{s}\beta_t(s), \qquad \hat{\beta}_t(s)\overset{def}{=} \frac{\beta_t(s)}{C_t}

这节的最后,提了一个最大似然误差的计算,但是我没看懂公式是怎么算出来的,后面貌似也没有用到。这里就贴个图吧,后面看懂再说。

4.2 最大似然训练

这一节基本就是训练的各种公式,求导之类的。
首先,定义目标函数,涉及的符号前面都有提及:

OML(S,Nw)=−∑(x,z)∈Sln(p(z|x))(12)

O^{ML}(S,N_w)=-\sum_{(x,z) \in S} ln (p(z|x)) \qquad (12)
然后是对于每个网络(字符)的输出,可以单独地进行求导:

∂OML({(x,z)},Nw)∂ytk=−∂ln(p(z|x))∂ytk(13)

\frac{\partial O^{ML}(\{(x,z)\},N_w)}{\partial y_k^t} = - \frac{\partial ln(p(z|x))}{\partial y_k^t} \qquad (13)

接下来用上一节提到的前向后向算法来计算(13),对于一个特定的时刻tt和位置ss来说:

αt(s)βt(s)=∑π∈B−1(l):πt=lsytls∏t=1Tytπt

\alpha_t(s) \beta_t(s) = \sum_{\pi \in B^{-1}(l):\pi_t=l_s}y_{l_s}^t \prod_{t=1}^T y_{\pi_t}^t
联合公式(2),得到:

αt(s)βt(s)ytls=∑π∈B−1(l):πt=lsp(π|x)

\frac{\alpha_t(s) \beta_t(s)}{y_{l_s}^t}= \sum_{\pi \in B^{-1}(l):\pi_t=l_s} p(\pi | x)
可以看出来,上面这个式子由特定的时刻和位置决定的,我们想要计算 p(l|x)p(l|x),可以把这些情况全都加起来:

p(l|x)=∑t=1T∑s=1|l|αt(s)βt(s)ytls(14)

p(l|x) = \sum_{t=1}^{T} \sum_{s=1}^{|l|} \frac{\alpha_t(s) \beta_t(s)}{y_{l_s}^t} \qquad (14)

在前面也说过,ctc网络输出是独立概率的,所以对于在tt时刻,字符为kk的一个路径的概率可以用上面的式子进行计算,也就是可以对ytky_k^t进行求导。然后需要注意的是,一个字符有可能在一个串中出现了很多次,所以我们定义一个集合来表示字符kk出现的位置:lab(l,k)={s:ls=k}lab(l,k) = \{s:l_s=k\}。当然,这个集合也有可能是空的(有些字符没有在串中出现)。然后通过(14),可以推导出来:

∂p(l|x)∂ytk=−1yt2k∑s∈lab(l,k)αt(s)βt(s)(15)

\frac{\partial p(l|x)}{\partial y_k^t} = - \frac{1}{y_k^{t^2}}\sum_{s \in lab(l,k)} \alpha_t(s) \beta_t(s) \qquad (15)
显然:

∂ln(p(l|x))∂ytk=1p(l|x)∂p(l|x)∂ytk

\frac{\partial ln(p(l|x))}{\partial y_k^t} = \frac{1}{p(l|x)} \frac{\partial p(l|x)}{\partial y_k^t}

然后,论文里说令l=zl=z,然后把(8)和(15)带入到(13)中,就可以求解了。这个的确可以推出来,但是和论文最后导出的公式不一样,不知道用了些什么骚操作,所以,这里我还是贴图吧。

结语

这文章还是有一些细节没太看懂,希望了解的大佬可以讲解一下。不过整体的思路应该说的还是比较清晰的~

CTC算法论文阅读笔记:Connectionist Temporal Classification: Labelling Unsegmented Sequence Data with Recurren相关推荐

  1. 造球粒径检测算法论文阅读笔记

    造球粒径检测算法论文阅读笔记 1.图像感兴趣区域的划分 2.生球区图像高斯滤波 3.生球区域与阴影区域的分割 4.对生球区域的分类标记(区分上下层球) 1.图像感兴趣区域的划分 依据光照的不同,将图像 ...

  2. CTC的直观理解(Connectionist Temporal Classification连接时序分类),单行文本时序分类识别的端到端方法

    CTC(Connectionist Temporal Classification), ctc擅长单行验证码识别: 两组谷歌验证码示例 ctc可以提高单行文本识别鲁棒性(不同长度不同位置 ).本文用几 ...

  3. keras cnn注意力机制_2019 SSA-CNN(自注意力机制)目标检测算法论文阅读笔记

    背景 <SSA-CNN Semantic Self-Attention CNN for Pedestrian Detection>是2019 的工作,其作者来自于南洋理工.这篇文章主要是做 ...

  4. 《Rigging the Lottery》 RigL算法 论文阅读笔记

    Rigging the Lottery: Making All Tickets Winners authors: Utku Evci Trevor Gale Jacob Menick Pablo Sa ...

  5. 长尾推荐算法论文阅读笔记合集(papers / literatures for long tail recommendation)

    写在前面: (1)我将长尾推荐系统相关论文做了一个整理,主要包括:论文题目.发表的会议/期刊(出处).发表时间.被引量(主要是google scholar),有的论文将对其内容进行简单介绍.最后提供这 ...

  6. [论文阅读笔记44]Named Entity Recognition without Labelled Data:A Weak Supervision Approach

    一,题目 Named Entity Recognition without Labelled Data:A Weak Supervision Approach 无标记数据的命名实体识别: 一种弱监督方 ...

  7. 联结主义时间分类(Connectionist temporal classification)的论文笔记

    前言: { 最近在github上更新了一些代码,但没在这里更新文章,这次就在这写一篇论文的阅读笔记. 论文是<Connectionist temporal classification: Lab ...

  8. CTC介绍(connectionist temporal classification论文翻译)

    1.摘要 我基本是基于论文<Connectionist Temporal Classification: Labelling Unsegmented Sequence Data with Rec ...

  9. CTC 论文阅读笔记

    Sayre's paradox 读语音识别的论文Towards End-to-End Speech Recognition with Recurrent Neural Networks时,看到了这个名 ...

  10. 一文读懂CRNN+CTC(Connectionist Temporal Classification)文字识别

    先总结一把CTC,下面文档太长: CTC是一种Loss计算方法,用CTC代替Softmax Loss,TF和pytorch都有对CTC的实现,从而解决OCR或者语音识别中序列对齐的问题.CTC特点: ...

最新文章

  1. 继承QTreeWidgetItem发生error: 'staticMetaObject' is not a member of 'QTreeWidgetItem' 错误
  2. 第一届中国三维视觉大会China3DV论文展示
  3. [转]掌握Ajax 第 2 部分: 使用 JavaScript 和 Ajax 发出异步请求 [IBM]
  4. 【网络】解决‘ipconfig不是内部或外部命令,也不是可运行的程序
  5. iQOO3Android11稳定版,vivo安卓11来了iQOO3 NEX3S尝鲜Androi11测试版!
  6. 匆匆那年之Java程序员之最近两周的面试总结:
  7. html 嵌入 excel_用了这么久Excel,你了解它的前世今生吗?
  8. i7处理器好吗_笔记本电脑处理器是i5好还是i7好?为什么?
  9. 软件工程第一周预备作业
  10. 针式PKM的设计原则
  11. vivado.2019.1 安装教程
  12. html播放韰 寸 频,asp.net 汉字转换拼音及首字母实现代码
  13. Thrift交流(二)thrift服务端和客户端实现 Nifty
  14. centos安装五笔与拼音的办法
  15. 操作系统简介及编程语言
  16. OpenSSH创建秘钥的4种格式以及git多秘钥配置
  17. RISC_V(0) 指令集架构
  18. CVPR 2020 开幕!最佳论文奖等揭晓!
  19. 3d打印光固化好还是热固化好_光固化3D打印机的优势在哪里?
  20. 王兴:为什么中国的To B企业都活得这么惨?

热门文章

  1. 数据库中查找某个字段
  2. python之Unitest框架
  3. 磁珠 符号_超实用理解磁珠
  4. PHP GD库 教程
  5. 瞬时功率与有功功率计算公式
  6. 股票量化交易系统的指标和策略有哪些?
  7. 物联网共享单车有什么物联技术?
  8. Mybatis使用order by语句
  9. 研发 | Unity资源商店里的免费资源,你一定要知道!
  10. 国内外游戏运营模式区别