We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
ctc loss compatibility
i think this error is a bug in ctc implementation:

```
  File "/usr/local/lib/python2.7/dist-packages/chainer/functions/loss/ctc.py", line 223, in connectionist_temporal_classification
    assert blank_symbol < x[0].data.shape[1]
TypeError: 'Variable' object does not support indexing
```

x is Variable from output of relu function.


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `chainer/functions/loss/ctc.py`
Content:
```
1 import numpy
2 import six
3 
4 from chainer import cuda
5 from chainer import function
6 from chainer import utils
7 from chainer.utils import type_check
8 
9 
10 def _logsumexp(a, xp, axis=None):
11     vmax = xp.amax(a, axis=axis, keepdims=True)
12     vmax += xp.log(xp.sum(xp.exp(a - vmax),
13                           axis=axis, keepdims=True, dtype=a.dtype))
14     return xp.squeeze(vmax, axis=axis)
15 
16 
17 def _softmax(x, xp):
18     val = xp.exp(x - xp.amax(x, axis=1, keepdims=True))
19     val /= xp.sum(val, axis=1, keepdims=True)
20     return val
21 
22 
23 def _label_to_path(labels, blank_symbol, xp):
24     path = xp.full((len(labels), labels.shape[1] * 2 + 1),
25                    blank_symbol, dtype=numpy.int32)
26     path[:, 1::2] = labels
27     return path
28 
29 
30 def _log_dot(prob, rr, xp):
31     return _logsumexp(prob + xp.swapaxes(rr, 1, 2), xp, axis=2)
32 
33 
34 def _activate(yseq, xp):
35     return [_softmax(y, xp) for y in yseq]
36 
37 
38 class ConnectionistTemporalClassification(function.Function):
39 
40     """The implementation of Connectionist Temporal Classfication loss functions.
41 
42     To make it usable for real-world cases, this class has two policies below.
43     1. This class computes forward and backward variables in the log domain.
44     2. This class applies the softmax function to inputs. The Backward
45     values of CTC loss is often overflows. This is avoided by computing
46     backward values before the activation function is applied.
47     """
48 
49     def __init__(self, blank_symbol):
50         self.blank_symbol = blank_symbol
51         self.zero_padding = -10000000000.0
52 
53     def check_type_forward(self, in_types):
54         type_check.expect(in_types.size() > 1)
55         l_type = in_types[0]
56         type_check.expect(l_type.dtype == numpy.int32)
57 
58         x_basetype = in_types[1]
59 
60         for i in six.moves.range(2, len(in_types)):
61             x_type = in_types[i]
62             type_check.expect(
63                 x_type.dtype == numpy.float32,
64                 x_type.shape == x_basetype.shape,
65             )
66 
67     def log_matrix(self, x, xp):
68         if xp == numpy:
69             res = numpy.ma.log(x).filled(fill_value=self.zero_padding)
70         else:
71             create_recurrence_relation = cuda.cupy.ElementwiseKernel(
72                 'T x, T e', 'T y',
73                 'y = x == 0 ? e : log(x)',
74                 'create_recurrence_relation')
75             res = create_recurrence_relation(x, self.zero_padding)
76         return res
77 
78     def recurrence_relation(self, size, dtype, xp):
79         """Transition in forword and backword algorithms is represented as matrix.
80 
81         See also
82         https://blog.wtf.sg/2014/10/06/connectionist-temporal-classification-ctc-with-theano/
83         """
84 
85         rr = (xp.eye(size, dtype=dtype) +
86               xp.eye(size, k=1, dtype=dtype) +
87               xp.eye(size, k=2, dtype=dtype) *
88               (xp.arange(size, dtype=dtype) % dtype(2)))
89         return self.log_matrix(rr, xp)
90 
91     # path probablity to label probability
92     def label_probability(self, label_size, path, multiply, xp):
93         labels_prob = self.log_matrix(xp.zeros((len(path), label_size),
94                                                dtype=multiply.dtype), xp)
95         if xp == numpy:
96             for b in six.moves.range(len(path)):
97                 chars = {c for c in path[b]}
98                 for c in chars:
99                     labels_prob[b, c] = _logsumexp(
100                         multiply[b, path[b] == c], numpy)
101         else:
102             cuda.cupy.ElementwiseKernel(
103                 'raw T x, raw I y, I b_max, I c_max',
104                 'T z',
105                 '''
106                 T value = z;
107                 I c = i % b_max, b = i / b_max;
108                 int ind[2] = {b, -1};
109                 for (int index = 0; index < c_max; ++index) {
110                     ind[1] = index;
111                     if (y[ind] == c) {
112                         T xvalue = x[ind];
113                         if (value > xvalue) {
114                             value = value + log(1 + exp(xvalue - value));
115                         } else {
116                             value = xvalue + log(1 + exp(value - xvalue));
117                         }
118                     }
119                     z = value;
120                 }
121                 ''',
122                 'reduce_probability')(multiply, path, labels_prob.shape[1],
123                                       path.shape[1], labels_prob)
124         return labels_prob
125 
126     def calc_trans(self, path, yseq, rr, xp):
127         forward_prob = self.log_matrix(
128             xp.eye(path.shape[1], dtype='f')[0], xp)[None, :]
129         backward_prob = forward_prob
130         offset = xp.arange(
131             0, yseq[0].size, yseq[0].shape[1], dtype=path.dtype)[:, None]
132 
133         # prob[i] := forward[i] + backward[-i-1]
134         prob = []
135         index = offset + path
136         for y in yseq:
137             # calc forward probability in log scale
138             forward_prob = xp.take(y, index) + _log_dot(
139                 forward_prob[:, None, :], rr, xp)
140             prob.append(forward_prob)
141 
142         r_index = offset + path[:, ::-1]
143         for i, y_inv in enumerate(yseq[::-1]):
144             # calc backward probability
145             backward_prob = _log_dot(backward_prob[:, None, :], rr, xp)
146             prob[-i - 1] += backward_prob[:, ::-1]
147             backward_prob = xp.take(y_inv, r_index) + backward_prob
148         return prob
149 
150     def forward(self, inputs):
151         xp = cuda.get_array_module(inputs[0])
152         batch_size = len(inputs[0])
153         self.yseq = _activate(inputs[1::], xp)
154         log_yseq = [self.log_matrix(y, xp) for y in self.yseq]
155         self.path = _label_to_path(inputs[0], self.blank_symbol, xp)
156         rr = self.recurrence_relation(
157             self.path.shape[1], numpy.float32, xp)[None, :, :]
158         self.prob_trans = self.calc_trans(self.path, log_yseq, rr, xp)
159 
160         loss = utils.force_array(xp.sum(
161             _logsumexp(self.prob_trans[-1], xp, axis=1)))
162         loss /= -batch_size
163         return loss,
164 
165     def backward(self, inputs, grad_output):
166         xp = cuda.get_array_module(inputs[0])
167         batch_size = len(inputs[0])
168 
169         total_probability = _logsumexp(self.prob_trans[0], xp, axis=1)
170         scale = grad_output[0] / batch_size
171         for y, prob in zip(self.yseq, self.prob_trans):
172             label_prob = self.label_probability(
173                 y.shape[1], self.path, prob, xp)
174             y -= xp.exp(label_prob - total_probability[:, None])
175             y *= scale
176         return (None,) + tuple(self.yseq)
177 
178 
179 def connectionist_temporal_classification(x, t, blank_symbol):
180     """Connectionist Temporal Classification loss function.
181 
182     Connectionist Temporal Classification(CTC) [Graves2006]_ is a loss function
183     of sequence labeling where the alignment between the inputs and target is
184     unknown. See also [Graves2012]_
185 
186     Args:
187         x (Variable): RNN output at each time.
188                       (ex. :math:`(y_1, y_2, ..., y_T)`)
189         t (Variable): Expected label sequence.
190         blank_symbol (int): Index of blank_symbol.
191                             This value must be non-negative.
192 
193     Returns:
194         Variable: A variable holding a scalar value of the CTC loss.
195 
196     .. note::
197        You need to input ``x`` without applying to activation functions(e.g.
198        softmax function), because this function applies softmax functions
199        to ``x`` before calculating CTC loss to avoid numerical limitations.
200        You also need to apply softmax function to fowarded values before you
201        decode it.
202 
203     .. note::
204        This function is differentiable only by ``x``.
205 
206     .. note::
207        This function supports (batch, sequence, 1-dimensional input)-data.
208 
209     .. [Graves2006] Alex Graves, Santiago Fernandez,\
210     Faustino Gomez, Jurgen Schmidhuber,\
211     `Connectionist Temporal Classification: Labelling Unsegmented\
212     Sequence Data with Recurrent Neural Networks\
213     <ftp://ftp.idsia.ch/pub/juergen/icml2006.pdf>`_
214 
215     .. [Graves2012] Alex Graves,\
216     `Supervised Sequence Labelling with Recurrent Neural Networks\
217     <http://www.cs.toronto.edu/~graves/preprint.pdf>`_
218 
219     """
220     if not isinstance(blank_symbol, int):
221         raise TypeError('blank_symbol must be non-negative integer.')
222     assert blank_symbol >= 0
223     assert blank_symbol < x[0].data.shape[1]
224     # This implementation only supports 1-dimensional data.
225     # TODO(jnishi): Support d(>1)-dimentinal inputs.
226     assert(len(x[0].data.shape) == 2)
227 
228     return ConnectionistTemporalClassification(blank_symbol)(t, *x)
229
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/chainer/functions/loss/ctc.py b/chainer/functions/loss/ctc.py
--- a/chainer/functions/loss/ctc.py
+++ b/chainer/functions/loss/ctc.py
@@ -1,3 +1,4 @@
+import collections
 import numpy
 import six
 
@@ -184,8 +185,10 @@
     unknown. See also [Graves2012]_
 
     Args:
-        x (Variable): RNN output at each time.
-                      (ex. :math:`(y_1, y_2, ..., y_T)`)
+        x (sequence of Variable): RNN output at each time. ``x`` must be a list
+            of :class:`~chianer.Variable` s. Each element of ``x``, ``x[i]``
+            is a :class:`~chainer.Variable` representing output of RNN at time
+            ``i``.
         t (Variable): Expected label sequence.
         blank_symbol (int): Index of blank_symbol.
                             This value must be non-negative.
@@ -217,6 +220,8 @@
     <http://www.cs.toronto.edu/~graves/preprint.pdf>`_
 
     """
+    if not isinstance(x, collections.Sequence):
+        raise TypeError('x must be a list of Variables')
     if not isinstance(blank_symbol, int):
         raise TypeError('blank_symbol must be non-negative integer.')
     assert blank_symbol >= 0

{"golden_diff": "diff --git a/chainer/functions/loss/ctc.py b/chainer/functions/loss/ctc.py\n--- a/chainer/functions/loss/ctc.py\n+++ b/chainer/functions/loss/ctc.py\n@@ -1,3 +1,4 @@\n+import collections\n import numpy\n import six\n \n@@ -184,8 +185,10 @@\n     unknown. See also [Graves2012]_\n \n     Args:\n-        x (Variable): RNN output at each time.\n-                      (ex. :math:`(y_1, y_2, ..., y_T)`)\n+        x (sequence of Variable): RNN output at each time. ``x`` must be a list\n+            of :class:`~chianer.Variable` s. Each element of ``x``, ``x[i]``\n+            is a :class:`~chainer.Variable` representing output of RNN at time\n+            ``i``.\n         t (Variable): Expected label sequence.\n         blank_symbol (int): Index of blank_symbol.\n                             This value must be non-negative.\n@@ -217,6 +220,8 @@\n     <http://www.cs.toronto.edu/~graves/preprint.pdf>`_\n \n     \"\"\"\n+    if not isinstance(x, collections.Sequence):\n+        raise TypeError('x must be a list of Variables')\n     if not isinstance(blank_symbol, int):\n         raise TypeError('blank_symbol must be non-negative integer.')\n     assert blank_symbol >= 0\n", "issue": "ctc loss compatibility\ni think this error is a bug in ctc implementation:\n\n```\n  File \"/usr/local/lib/python2.7/dist-packages/chainer/functions/loss/ctc.py\", line 223, in connectionist_temporal_classification\n    assert blank_symbol < x[0].data.shape[1]\nTypeError: 'Variable' object does not support indexing\n```\n\nx is Variable from output of relu function.\n\n", "before_files": [{"content": "import numpy\nimport six\n\nfrom chainer import cuda\nfrom chainer import function\nfrom chainer import utils\nfrom chainer.utils import type_check\n\n\ndef _logsumexp(a, xp, axis=None):\n    vmax = xp.amax(a, axis=axis, keepdims=True)\n    vmax += xp.log(xp.sum(xp.exp(a - vmax),\n                          axis=axis, keepdims=True, dtype=a.dtype))\n    return xp.squeeze(vmax, axis=axis)\n\n\ndef _softmax(x, xp):\n    val = xp.exp(x - xp.amax(x, axis=1, keepdims=True))\n    val /= xp.sum(val, axis=1, keepdims=True)\n    return val\n\n\ndef _label_to_path(labels, blank_symbol, xp):\n    path = xp.full((len(labels), labels.shape[1] * 2 + 1),\n                   blank_symbol, dtype=numpy.int32)\n    path[:, 1::2] = labels\n    return path\n\n\ndef _log_dot(prob, rr, xp):\n    return _logsumexp(prob + xp.swapaxes(rr, 1, 2), xp, axis=2)\n\n\ndef _activate(yseq, xp):\n    return [_softmax(y, xp) for y in yseq]\n\n\nclass ConnectionistTemporalClassification(function.Function):\n\n    \"\"\"The implementation of Connectionist Temporal Classfication loss functions.\n\n    To make it usable for real-world cases, this class has two policies below.\n    1. This class computes forward and backward variables in the log domain.\n    2. This class applies the softmax function to inputs. The Backward\n    values of CTC loss is often overflows. This is avoided by computing\n    backward values before the activation function is applied.\n    \"\"\"\n\n    def __init__(self, blank_symbol):\n        self.blank_symbol = blank_symbol\n        self.zero_padding = -10000000000.0\n\n    def check_type_forward(self, in_types):\n        type_check.expect(in_types.size() > 1)\n        l_type = in_types[0]\n        type_check.expect(l_type.dtype == numpy.int32)\n\n        x_basetype = in_types[1]\n\n        for i in six.moves.range(2, len(in_types)):\n            x_type = in_types[i]\n            type_check.expect(\n                x_type.dtype == numpy.float32,\n                x_type.shape == x_basetype.shape,\n            )\n\n    def log_matrix(self, x, xp):\n        if xp == numpy:\n            res = numpy.ma.log(x).filled(fill_value=self.zero_padding)\n        else:\n            create_recurrence_relation = cuda.cupy.ElementwiseKernel(\n                'T x, T e', 'T y',\n                'y = x == 0 ? e : log(x)',\n                'create_recurrence_relation')\n            res = create_recurrence_relation(x, self.zero_padding)\n        return res\n\n    def recurrence_relation(self, size, dtype, xp):\n        \"\"\"Transition in forword and backword algorithms is represented as matrix.\n\n        See also\n        https://blog.wtf.sg/2014/10/06/connectionist-temporal-classification-ctc-with-theano/\n        \"\"\"\n\n        rr = (xp.eye(size, dtype=dtype) +\n              xp.eye(size, k=1, dtype=dtype) +\n              xp.eye(size, k=2, dtype=dtype) *\n              (xp.arange(size, dtype=dtype) % dtype(2)))\n        return self.log_matrix(rr, xp)\n\n    # path probablity to label probability\n    def label_probability(self, label_size, path, multiply, xp):\n        labels_prob = self.log_matrix(xp.zeros((len(path), label_size),\n                                               dtype=multiply.dtype), xp)\n        if xp == numpy:\n            for b in six.moves.range(len(path)):\n                chars = {c for c in path[b]}\n                for c in chars:\n                    labels_prob[b, c] = _logsumexp(\n                        multiply[b, path[b] == c], numpy)\n        else:\n            cuda.cupy.ElementwiseKernel(\n                'raw T x, raw I y, I b_max, I c_max',\n                'T z',\n                '''\n                T value = z;\n                I c = i % b_max, b = i / b_max;\n                int ind[2] = {b, -1};\n                for (int index = 0; index < c_max; ++index) {\n                    ind[1] = index;\n                    if (y[ind] == c) {\n                        T xvalue = x[ind];\n                        if (value > xvalue) {\n                            value = value + log(1 + exp(xvalue - value));\n                        } else {\n                            value = xvalue + log(1 + exp(value - xvalue));\n                        }\n                    }\n                    z = value;\n                }\n                ''',\n                'reduce_probability')(multiply, path, labels_prob.shape[1],\n                                      path.shape[1], labels_prob)\n        return labels_prob\n\n    def calc_trans(self, path, yseq, rr, xp):\n        forward_prob = self.log_matrix(\n            xp.eye(path.shape[1], dtype='f')[0], xp)[None, :]\n        backward_prob = forward_prob\n        offset = xp.arange(\n            0, yseq[0].size, yseq[0].shape[1], dtype=path.dtype)[:, None]\n\n        # prob[i] := forward[i] + backward[-i-1]\n        prob = []\n        index = offset + path\n        for y in yseq:\n            # calc forward probability in log scale\n            forward_prob = xp.take(y, index) + _log_dot(\n                forward_prob[:, None, :], rr, xp)\n            prob.append(forward_prob)\n\n        r_index = offset + path[:, ::-1]\n        for i, y_inv in enumerate(yseq[::-1]):\n            # calc backward probability\n            backward_prob = _log_dot(backward_prob[:, None, :], rr, xp)\n            prob[-i - 1] += backward_prob[:, ::-1]\n            backward_prob = xp.take(y_inv, r_index) + backward_prob\n        return prob\n\n    def forward(self, inputs):\n        xp = cuda.get_array_module(inputs[0])\n        batch_size = len(inputs[0])\n        self.yseq = _activate(inputs[1::], xp)\n        log_yseq = [self.log_matrix(y, xp) for y in self.yseq]\n        self.path = _label_to_path(inputs[0], self.blank_symbol, xp)\n        rr = self.recurrence_relation(\n            self.path.shape[1], numpy.float32, xp)[None, :, :]\n        self.prob_trans = self.calc_trans(self.path, log_yseq, rr, xp)\n\n        loss = utils.force_array(xp.sum(\n            _logsumexp(self.prob_trans[-1], xp, axis=1)))\n        loss /= -batch_size\n        return loss,\n\n    def backward(self, inputs, grad_output):\n        xp = cuda.get_array_module(inputs[0])\n        batch_size = len(inputs[0])\n\n        total_probability = _logsumexp(self.prob_trans[0], xp, axis=1)\n        scale = grad_output[0] / batch_size\n        for y, prob in zip(self.yseq, self.prob_trans):\n            label_prob = self.label_probability(\n                y.shape[1], self.path, prob, xp)\n            y -= xp.exp(label_prob - total_probability[:, None])\n            y *= scale\n        return (None,) + tuple(self.yseq)\n\n\ndef connectionist_temporal_classification(x, t, blank_symbol):\n    \"\"\"Connectionist Temporal Classification loss function.\n\n    Connectionist Temporal Classification(CTC) [Graves2006]_ is a loss function\n    of sequence labeling where the alignment between the inputs and target is\n    unknown. See also [Graves2012]_\n\n    Args:\n        x (Variable): RNN output at each time.\n                      (ex. :math:`(y_1, y_2, ..., y_T)`)\n        t (Variable): Expected label sequence.\n        blank_symbol (int): Index of blank_symbol.\n                            This value must be non-negative.\n\n    Returns:\n        Variable: A variable holding a scalar value of the CTC loss.\n\n    .. note::\n       You need to input ``x`` without applying to activation functions(e.g.\n       softmax function), because this function applies softmax functions\n       to ``x`` before calculating CTC loss to avoid numerical limitations.\n       You also need to apply softmax function to fowarded values before you\n       decode it.\n\n    .. note::\n       This function is differentiable only by ``x``.\n\n    .. note::\n       This function supports (batch, sequence, 1-dimensional input)-data.\n\n    .. [Graves2006] Alex Graves, Santiago Fernandez,\\\n    Faustino Gomez, Jurgen Schmidhuber,\\\n    `Connectionist Temporal Classification: Labelling Unsegmented\\\n    Sequence Data with Recurrent Neural Networks\\\n    <ftp://ftp.idsia.ch/pub/juergen/icml2006.pdf>`_\n\n    .. [Graves2012] Alex Graves,\\\n    `Supervised Sequence Labelling with Recurrent Neural Networks\\\n    <http://www.cs.toronto.edu/~graves/preprint.pdf>`_\n\n    \"\"\"\n    if not isinstance(blank_symbol, int):\n        raise TypeError('blank_symbol must be non-negative integer.')\n    assert blank_symbol >= 0\n    assert blank_symbol < x[0].data.shape[1]\n    # This implementation only supports 1-dimensional data.\n    # TODO(jnishi): Support d(>1)-dimentinal inputs.\n    assert(len(x[0].data.shape) == 2)\n\n    return ConnectionistTemporalClassification(blank_symbol)(t, *x)\n", "path": "chainer/functions/loss/ctc.py"}], "after_files": [{"content": "import collections\nimport numpy\nimport six\n\nfrom chainer import cuda\nfrom chainer import function\nfrom chainer import utils\nfrom chainer.utils import type_check\n\n\ndef _logsumexp(a, xp, axis=None):\n    vmax = xp.amax(a, axis=axis, keepdims=True)\n    vmax += xp.log(xp.sum(xp.exp(a - vmax),\n                          axis=axis, keepdims=True, dtype=a.dtype))\n    return xp.squeeze(vmax, axis=axis)\n\n\ndef _softmax(x, xp):\n    val = xp.exp(x - xp.amax(x, axis=1, keepdims=True))\n    val /= xp.sum(val, axis=1, keepdims=True)\n    return val\n\n\ndef _label_to_path(labels, blank_symbol, xp):\n    path = xp.full((len(labels), labels.shape[1] * 2 + 1),\n                   blank_symbol, dtype=numpy.int32)\n    path[:, 1::2] = labels\n    return path\n\n\ndef _log_dot(prob, rr, xp):\n    return _logsumexp(prob + xp.swapaxes(rr, 1, 2), xp, axis=2)\n\n\ndef _activate(yseq, xp):\n    return [_softmax(y, xp) for y in yseq]\n\n\nclass ConnectionistTemporalClassification(function.Function):\n\n    \"\"\"The implementation of Connectionist Temporal Classfication loss functions.\n\n    To make it usable for real-world cases, this class has two policies below.\n    1. This class computes forward and backward variables in the log domain.\n    2. This class applies the softmax function to inputs. The Backward\n    values of CTC loss is often overflows. This is avoided by computing\n    backward values before the activation function is applied.\n    \"\"\"\n\n    def __init__(self, blank_symbol):\n        self.blank_symbol = blank_symbol\n        self.zero_padding = -10000000000.0\n\n    def check_type_forward(self, in_types):\n        type_check.expect(in_types.size() > 1)\n        l_type = in_types[0]\n        type_check.expect(l_type.dtype == numpy.int32)\n\n        x_basetype = in_types[1]\n\n        for i in six.moves.range(2, len(in_types)):\n            x_type = in_types[i]\n            type_check.expect(\n                x_type.dtype == numpy.float32,\n                x_type.shape == x_basetype.shape,\n            )\n\n    def log_matrix(self, x, xp):\n        if xp == numpy:\n            res = numpy.ma.log(x).filled(fill_value=self.zero_padding)\n        else:\n            create_recurrence_relation = cuda.cupy.ElementwiseKernel(\n                'T x, T e', 'T y',\n                'y = x == 0 ? e : log(x)',\n                'create_recurrence_relation')\n            res = create_recurrence_relation(x, self.zero_padding)\n        return res\n\n    def recurrence_relation(self, size, dtype, xp):\n        \"\"\"Transition in forword and backword algorithms is represented as matrix.\n\n        See also\n        https://blog.wtf.sg/2014/10/06/connectionist-temporal-classification-ctc-with-theano/\n        \"\"\"\n\n        rr = (xp.eye(size, dtype=dtype) +\n              xp.eye(size, k=1, dtype=dtype) +\n              xp.eye(size, k=2, dtype=dtype) *\n              (xp.arange(size, dtype=dtype) % dtype(2)))\n        return self.log_matrix(rr, xp)\n\n    # path probablity to label probability\n    def label_probability(self, label_size, path, multiply, xp):\n        labels_prob = self.log_matrix(xp.zeros((len(path), label_size),\n                                               dtype=multiply.dtype), xp)\n        if xp == numpy:\n            for b in six.moves.range(len(path)):\n                chars = {c for c in path[b]}\n                for c in chars:\n                    labels_prob[b, c] = _logsumexp(\n                        multiply[b, path[b] == c], numpy)\n        else:\n            cuda.cupy.ElementwiseKernel(\n                'raw T x, raw I y, I b_max, I c_max',\n                'T z',\n                '''\n                T value = z;\n                I c = i % b_max, b = i / b_max;\n                int ind[2] = {b, -1};\n                for (int index = 0; index < c_max; ++index) {\n                    ind[1] = index;\n                    if (y[ind] == c) {\n                        T xvalue = x[ind];\n                        if (value > xvalue) {\n                            value = value + log(1 + exp(xvalue - value));\n                        } else {\n                            value = xvalue + log(1 + exp(value - xvalue));\n                        }\n                    }\n                    z = value;\n                }\n                ''',\n                'reduce_probability')(multiply, path, labels_prob.shape[1],\n                                      path.shape[1], labels_prob)\n        return labels_prob\n\n    def calc_trans(self, path, yseq, rr, xp):\n        forward_prob = self.log_matrix(\n            xp.eye(path.shape[1], dtype='f')[0], xp)[None, :]\n        backward_prob = forward_prob\n        offset = xp.arange(\n            0, yseq[0].size, yseq[0].shape[1], dtype=path.dtype)[:, None]\n\n        # prob[i] := forward[i] + backward[-i-1]\n        prob = []\n        index = offset + path\n        for y in yseq:\n            # calc forward probability in log scale\n            forward_prob = xp.take(y, index) + _log_dot(\n                forward_prob[:, None, :], rr, xp)\n            prob.append(forward_prob)\n\n        r_index = offset + path[:, ::-1]\n        for i, y_inv in enumerate(yseq[::-1]):\n            # calc backward probability\n            backward_prob = _log_dot(backward_prob[:, None, :], rr, xp)\n            prob[-i - 1] += backward_prob[:, ::-1]\n            backward_prob = xp.take(y_inv, r_index) + backward_prob\n        return prob\n\n    def forward(self, inputs):\n        xp = cuda.get_array_module(inputs[0])\n        batch_size = len(inputs[0])\n        self.yseq = _activate(inputs[1::], xp)\n        log_yseq = [self.log_matrix(y, xp) for y in self.yseq]\n        self.path = _label_to_path(inputs[0], self.blank_symbol, xp)\n        rr = self.recurrence_relation(\n            self.path.shape[1], numpy.float32, xp)[None, :, :]\n        self.prob_trans = self.calc_trans(self.path, log_yseq, rr, xp)\n\n        loss = utils.force_array(xp.sum(\n            _logsumexp(self.prob_trans[-1], xp, axis=1)))\n        loss /= -batch_size\n        return loss,\n\n    def backward(self, inputs, grad_output):\n        xp = cuda.get_array_module(inputs[0])\n        batch_size = len(inputs[0])\n\n        total_probability = _logsumexp(self.prob_trans[0], xp, axis=1)\n        scale = grad_output[0] / batch_size\n        for y, prob in zip(self.yseq, self.prob_trans):\n            label_prob = self.label_probability(\n                y.shape[1], self.path, prob, xp)\n            y -= xp.exp(label_prob - total_probability[:, None])\n            y *= scale\n        return (None,) + tuple(self.yseq)\n\n\ndef connectionist_temporal_classification(x, t, blank_symbol):\n    \"\"\"Connectionist Temporal Classification loss function.\n\n    Connectionist Temporal Classification(CTC) [Graves2006]_ is a loss function\n    of sequence labeling where the alignment between the inputs and target is\n    unknown. See also [Graves2012]_\n\n    Args:\n        x (sequence of Variable): RNN output at each time. ``x`` must be a list\n            of :class:`~chianer.Variable` s. Each element of ``x``, ``x[i]``\n            is a :class:`~chainer.Variable` representing output of RNN at time\n            ``i``.\n        t (Variable): Expected label sequence.\n        blank_symbol (int): Index of blank_symbol.\n                            This value must be non-negative.\n\n    Returns:\n        Variable: A variable holding a scalar value of the CTC loss.\n\n    .. note::\n       You need to input ``x`` without applying to activation functions(e.g.\n       softmax function), because this function applies softmax functions\n       to ``x`` before calculating CTC loss to avoid numerical limitations.\n       You also need to apply softmax function to fowarded values before you\n       decode it.\n\n    .. note::\n       This function is differentiable only by ``x``.\n\n    .. note::\n       This function supports (batch, sequence, 1-dimensional input)-data.\n\n    .. [Graves2006] Alex Graves, Santiago Fernandez,\\\n    Faustino Gomez, Jurgen Schmidhuber,\\\n    `Connectionist Temporal Classification: Labelling Unsegmented\\\n    Sequence Data with Recurrent Neural Networks\\\n    <ftp://ftp.idsia.ch/pub/juergen/icml2006.pdf>`_\n\n    .. [Graves2012] Alex Graves,\\\n    `Supervised Sequence Labelling with Recurrent Neural Networks\\\n    <http://www.cs.toronto.edu/~graves/preprint.pdf>`_\n\n    \"\"\"\n    if not isinstance(x, collections.Sequence):\n        raise TypeError('x must be a list of Variables')\n    if not isinstance(blank_symbol, int):\n        raise TypeError('blank_symbol must be non-negative integer.')\n    assert blank_symbol >= 0\n    assert blank_symbol < x[0].data.shape[1]\n    # This implementation only supports 1-dimensional data.\n    # TODO(jnishi): Support d(>1)-dimentinal inputs.\n    assert(len(x[0].data.shape) == 2)\n\n    return ConnectionistTemporalClassification(blank_symbol)(t, *x)\n", "path": "chainer/functions/loss/ctc.py"}]}