Repository: chainer/chainer

Issue:
double backprop with embed_id raises an error
Code to reproduce:
```python
import numpy as np                                                                                                                                                                                                                                                                                                                                                                     
import chainer                                                                                                                                                                                                                                                                                                                                                                         
from chainer import Variable                                                                                                                                                                                                                                                                                                                                                           
import chainer.functions as F                                                                                                                                                                                                                                                                                                                                                          
                                                                                                                                                                                                                                                                                                                                                                                       
mat = Variable(np.random.uniform(size=(16, 32)).astype(np.float32))                                                                                                                                                                                                                                                                                                                    
x = F.embed_id(Variable(np.array([1, 2], dtype=np.int32)), mat)                                                                                                                                                                                                                                                                                                                        
l = F.sum(x)                                                                                                                                                                                                                                                                                                                                                                           
grad, = chainer.grad([l], [mat], enable_double_backprop=True)
```
This gives the following error:
```
Traceback (most recent call last):                                                                                                                                                                                                                                                                                                                                                     
  File "test_embed.py", line 11, in <module>                                                                                                                                                                                                                                                                                                                                           
    grad, = chainer.grad([l], [mat], enable_double_backprop=True)                                                                                                                                                                                                                                                                                                                      
  File "/home/murawaki/local3/lib/python3.6/site-packages/chainer/function_node.py", line 763, in grad                                                                                                                                                                                                                                                                                 
    _backprop(outputs, inputs, grad_required, retain_grad, grads)                                                                                                                                                                                                                                                                                                                      
  File "/home/murawaki/local3/lib/python3.6/site-packages/chainer/function_node.py", line 822, in _backprop                                                                                                                                                                                                                                                                            
    new_gxs = func.backward_accumulate(input_indexes, gys, gxs)                                                                                                                                                                                                                                                                                                                        
  File "/home/murawaki/local3/lib/python3.6/site-packages/chainer/function_node.py", line 514, in backward_accumulate                                                                                                                                                                                                                                                                  
    gxs = self.backward(target_input_indexes, grad_outputs)                                                                                                                                                                                                                                                                                                                            
  File "/home/murawaki/local3/lib/python3.6/site-packages/chainer/functions/connection/embed_id.py", line 55, in backward                                                                                                                                                                                                                                                              
    self._w_shape, self.ignore_label).apply(inputs + grad_outputs)[0]                                                                                                                                                                                                                                                                                                                  
TypeError: can only concatenate tuple (not "list") to tuple 
```
Replacing 
```
inputs + grad_outputs
```
with
```
inputs + tuple(grad_outputs)
```
eliminates the error, but I am not sure if this is an elegant way to solve the problem.



Discussion:
The error has been confirmed. Thank you for reporting!

Resolving patch:
diff --git a/chainer/function_node.py b/chainer/function_node.py
--- a/chainer/function_node.py
+++ b/chainer/function_node.py
@@ -536,6 +536,10 @@ def backward_accumulate(self, target_input_indexes, grad_outputs,
            This behavior might be changed in a future version.
 
         """
+        assert isinstance(target_input_indexes, tuple)
+        assert isinstance(grad_outputs, tuple)
+        assert isinstance(grad_inputs, tuple)
+
         # The default implementation uses backward(). You can override this
         # method without using backward().
         gxs = self.backward(target_input_indexes, grad_outputs)
@@ -821,6 +825,7 @@ def _backprop(outputs, inputs, grad_required, retain_grad, grads):
                 gys.append(None)
                 continue
             gys.append(grads.get(y, None))
+        gys = tuple(gys)
 
         # Collect the gradients w.r.t. the inputs
         #
@@ -841,6 +846,8 @@ def _backprop(outputs, inputs, grad_required, retain_grad, grads):
             else:
                 gxs.append(grads.get(x, None))
                 selected_inputs.add(x)
+        gxs = tuple(gxs)
+        input_indexes = tuple(input_indexes)
 
         if not input_indexes:
             continue
diff --git a/chainer/variable.py b/chainer/variable.py
--- a/chainer/variable.py
+++ b/chainer/variable.py
@@ -932,9 +932,9 @@ def get_grad(node):
         while cand_funcs:
             _, _, func = heapq.heappop(cand_funcs)
             inputs = func.inputs
-            target_input_indexes = [
+            target_input_indexes = tuple([
                 i for i, x in enumerate(inputs) if x.requires_grad
-            ]
+            ])
             if not target_input_indexes:
                 continue
             outputs = [y() for y in func.outputs]  # access via weak ref
@@ -984,6 +984,7 @@ def get_grad(node):
                 else:
                     gx = None
                 in_grad.append(gx)
+            in_grad = tuple(in_grad)
 
             gxs = func.backward_accumulate(
                 target_input_indexes, out_grad, in_grad)


Test patch: