forked from baidu-research/warp-ctc
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add mandarin tutorial - not quite finished
- Loading branch information
Erich Elsen
committed
Jan 19, 2016
1 parent
a470da0
commit b2b61d2
Showing
1 changed file
with
176 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,176 @@ | ||
## Torch教程 | ||
|
||
确保您有安装并运行’Wrap-ctc’ ‘’Luarocks在最顶层目录创建了torch_binding/rocks/warp-ctc-scm-1.rockspec | ||
|
||
使用Torch绑定/平台 (?),以便交互试验CTC | ||
|
||
假如你的编译没有GPU支持,请用`torch.Tensor(...):float()`替代`torch.Tensor(...):cuda()`,用`cpu_ctc`取代`gpu_ctc` | ||
|
||
CTC算法给出了输入序列与目标输出序列之间的损失。由于CTC普遍运用于神经网络,我们称输入序列为激活序列。目标输出序列是从一个固定的字母表中得出的。 | ||
为了在此讨论, 我们选择了四个字母‘a,b,c,d’. 算法需要一个`<BLANK>`符号区别于字母。这就意味着激活序列会是一个五维向量序列(字母的数量加<BLANK>)。这个向量将会被转化成字母以及<BLANK>上的概率分布,包含一个SoftMax函数。所以比如一个长度为7的序列就会是(向量的组成部分是任意的) | ||
```{<2,0,0,0,0>, <1,3,0,0,0>, <1,4,1,0,0>, <1,1,5,6,0>, <1,1,1,1,1>, <1,1,7,1,1>, <9,1,1,1,1>}``` | ||
得到的有效输出序列即`daceba`. | ||
|
||
一开始我们会举一个非常简单的例子。在这个例子中我们会用一个长度为1的激活序列,以及一个长度为1的目标输出序列。 | ||
为了指定这个激活序列,我们必须写下每一个五维向量的组成部分。我们使用`<0,0,0,0,0>`作为激活序列的单一向量,得到的概率分布及`0.2,0.2,0.2,0.2,0.2`. | ||
对于目标输出,我们会用一个单一标签`a`. | ||
|
||
首先,我们如何将数据展现给算法? 像平时使用Torch一样,激活表示要在一个2维张量中放入行。目标标签需要放入lua目录/表格 (?), 每个目标标签序列都有一个对应的目录。 | ||
我们每一个标签仅有一个序列,因此当标签`a`有指数1时,目录即`{{1}}` (指数0预留给空白符号)。因为我们允许输入不同长度的激活序列的可能性,我们需要指定 | ||
输入激活序列的长度,在这个例子即带有一个lua目录`{1}`的1. | ||
|
||
|
||
为了计算以上问题(单一元素输入序列,单一输出标签)的CTC损失函数的价值, 只有一种可能的映射/对齐方式(?),所以符号必须在第一个时间步(time step)发出。 | ||
发出符号的概率为`0.2`。 算法返回的负对数似然值为`-ln(0.2)=1.6094`. | ||
|
||
|
||
现在让我们通过代码来做计算。先从Torch部分开始,需要代码库。 | ||
|
||
假如你有GPU的支持 | ||
|
||
``` | ||
th>require 'cutorch' | ||
``` | ||
|
||
如果仅有CPU | ||
|
||
``` | ||
th>require 'warp_ctc' | ||
``` | ||
|
||
请将激活输入行-- 注意用两个大括号 | ||
|
||
``` | ||
th>acts = torch.Tensor({{0,0,0,0,0}}):cuda() | ||
``` | ||
|
||
假如一个空梯度张量通过,梯度计算则不能完成。 | ||
|
||
``` | ||
th>grads = torch.Tensor():cuda() | ||
``` | ||
|
||
对于目标标签以及输入序列的大小 | ||
``` | ||
th>labels = {{1}} | ||
th>sizes ={1} | ||
``` | ||
|
||
如果你有CUDA支持,请使用`gpu_ctc` ,否则请使用`cpu_ctc` | ||
|
||
``` | ||
th> gpu_ctc(acts, grads, labels, sizes) | ||
{ | ||
1 : 1.6094379425049 | ||
} | ||
``` | ||
|
||
对每一组序列,函数会返回CTC损失的一个lua目录 | ||
|
||
现在,我们来看一个更有意思的例子。假如我们有一个长度为3的输入序列,激活后: | ||
|
||
`1,2,3,4,5`,`6,7,8,9,10` and `11,12,13,14,15`. | ||
|
||
对应这些帧(?)的概率则为 | ||
|
||
`0.0117, 0.0317, 0.0861, 0.2341, 0.6364` | ||
|
||
(在这个特殊例子中,每一帧的概率都一样) | ||
对于目标符号,我们将使用序列`c,c`. | ||
|
||
``` | ||
th>acts = torch.Tensor({{1,2,3,4,5},{6,7,8,9,10},{11,12,13,14,15}}):cuda() | ||
th>labels = {{3,3}} | ||
th>sizes = {3} | ||
``` | ||
CTC calculates the probability of all the possible alignments. Note that the targets | ||
contain the repeated symbol `c`. CTC cannot emit a repeated symbol on consecutive timesteps | ||
(for more details consult http://www.cs.toronto.edu/~graves/icml_2006.pdf) it must separate | ||
the repeated symbol with a blank and so the only possible aligned sequence is | ||
`c <BLANK> c`. | ||
CTC计算了所有可能映射的概率。请注意目标包涵了重复的符号`c`.CTC不能在连续的时间步上发出一个重复的符号(更多细节,请见 http://www.cs.toronto.edu/~graves/icml_2006.pdf)。 | ||
对于重复的符号必须用一个空白分开,所以唯一可能的映射序列为`c <BLANK> c`. | ||
|
||
CTC假设,在给定数据的情况下,标签概率是有条件独立的,所以我们期待的答案即`Pr(c at frame 1)*Pr(<BLANK> at frame 2)*Pr(c at frame 3) = 0.2341*0.0117*0.2341` | ||
and `-ln(0.2341*0.0117*0.2341) = 7.3522`. | ||
``` | ||
th> gpu_ctc(acts, grads, labels, sizes) | ||
{ | ||
1 : 7.355742931366 | ||
} | ||
``` | ||
|
||
小的数值差由于其中一个计算人工完成。 | ||
|
||
假设目标序列为`b,c`,激活序列则为 | ||
|
||
`-5,-4,-3,-2,-1`,`-10,-9,-8,-7,-6` and `-15,-14,-13,-12,-11`. | ||
|
||
对应这些帧的概率则为 | ||
|
||
`0.0117, 0.0317, 0.0861, 0.2341, 0.6364`. | ||
|
||
由于重复的符号被折叠(?),空白被取消,现在有五种可能的映射 | ||
`<BLANK> b c`, `b <BLANK> c`, `b c <BLANK>`, `b b c` and `b c c`. | ||
|
||
结果应当是 | ||
`-ln(3*0.0117*0.0861*0.2341 + 0.0861*0.0861*0.2341 + 0.0861*0.2341*0.2341) = 4.9390` | ||
``` | ||
th>acts = torch.Tensor({{-5,-4,-3,-2,-1},{-10,-9,-8,-7,-6},{-15,-14,-13,-12,-11}}):cuda() | ||
th>labels = {{2,3}} | ||
th>sizes = {3} | ||
th>gpu_ctc(acts, grads, labels, sizes) | ||
{ | ||
1 : 4.938850402832 | ||
} | ||
``` | ||
|
||
因此,我们有三个例子。最后一个例子显示如果通过算法将3个例子做迷你批处理 (minibatch). 标签现在是`{{1}, {3,3}, {2,3}}`,输入序列的长度是`{1,3,3}`. | ||
我们必须将输入序列放入一个单独的两维矩阵。通过交织输入序列的元素,我们的输入矩阵如下: | ||
为了清楚起见,我们从前两个输入序列开始 | ||
|
||
| entries | col1 | col2 | col3 | col4 | col5 | | ||
|---------|------|------|------|------|------| | ||
|seq1 item 1|0|0|0|0|0| | ||
|seq2 item 1|1|2|3|4|5| | ||
|seq1 item 2|P|P|P|P|P| | ||
|seq2 item 2|6|7|8|9|10| | ||
|seq1 item 3|P|P|P|P|P| | ||
|seq2 item 3|11|12|13|14|15| | ||
|
||
由于第一个序列没有第二个或第三个元素,我们用0填入矩阵(在上面一个表格中显示为`P`)。 现在我们将第三个序列放入表格中 | ||
|
||
| entries | col1 | col2 | col3 | col4 | col5 | | ||
|---------|------|------|------|------|------| | ||
|seq1 item 1|0|0|0|0|0| | ||
|seq2 item 1|1|2|3|4|5| | ||
|seq3 item 1|-5|-4|-3|-2|-1| | ||
|seq1 item 2|P|P|P|P|P| | ||
|seq2 item 2|6|7|8|9|10| | ||
|seq3 item 2|-10|-9|-8|7|-6| | ||
|seq1 item 3|P|P|P|P|P| | ||
|seq2 item 3|11|12|13|14|15| | ||
|seq3 item 3|-15|-14|-13|-12|-11| | ||
|
||
|
||
在Torch中完整的例子如下 | ||
``` | ||
th>acts = torch.Tensor({{0,0,0,0,0},{1,2,3,4,5},{-5,-4,-3,-2,-1}, | ||
{0,0,0,0,0},{6,7,8,9,10},{-10,-9,-8,-7,-6}, | ||
{0,0,0,0,0},{11,12,13,14,15},{-15,-14,-13,-12,-11}}):cuda() | ||
th>labels = {{1}, {3,3}, {2,3}} | ||
th>sizes = {1,3,3} | ||
th>gpu_ctc(acts, grads, labels, sizes) | ||
{ | ||
1 : 1.6094379425049 | ||
2 : 7.355742931366 | ||
3 : 4.938850402832 | ||
} | ||
``` | ||
|
||
为了获得梯度wrt, 接下来的激活序列仅通过一个相同大小的张量作为激活张量即可(?) | ||
如果想看更多例子,请见`torch_binding/tests/test.lua`。 |