Skip to content

Commit

Permalink
add mandarin tutorial - not quite finished
Browse files Browse the repository at this point in the history
  • Loading branch information
Erich Elsen committed Jan 19, 2016
1 parent a470da0 commit b2b61d2
Showing 1 changed file with 176 additions and 0 deletions.
176 changes: 176 additions & 0 deletions torch_binding/TUTORIAL.zh_cn.md
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`

0 comments on commit b2b61d2

Please sign in to comment.