Repository: chainer/chainer

Issue:
Creating ``ideep.array`` without checking ndim and dtype in ``chianer.Variable.to_intel64``.
When running the below command, it outputs error.
It seems that creating ``ideep.array`` without checking ndim and dtype in ``chianer.Variable.to_intel64``.

```
$ python snipet.py 
terminate called after throwing an instance of 'mkldnn::error'
  what():  std::exception
Aborted (core dumped)
```

snipet.py
```
import os                                                                         
os.environ["CHAINER_USE_IDEEP"] = "auto"

import numpy as np
import chainer
from chainer import cuda, Function, gradient_check, report, training, utils, Variable
from chainer import datasets, iterators, optimizers, serializers
from chainer import Link, Chain, ChainList
import chainer.functions as F
import chainer.links as L
from chainer.training import extensions
from chainer.datasets import mnist

class Conv1D(chainer.Chain):
    def __init__(self, in_channels, out_channels, ksize=3, stride=1, pad=1):
        super(Conv1D, self).__init__()
        with self.init_scope():
            self.conv=L.ConvolutionND(1, in_channels, out_channels, ksize, stride=stride, pad=pad)

    def __call__(self, x):
        return F.relu(self.conv(x))

model = Conv1D(3, 32)

gpu_id = -1  # Set to -1 if you use CPU
if gpu_id >= 0:
    model.to_gpu(gpu_id)
if os.environ["CHAINER_USE_IDEEP"] == "auto":
    model.to_intel64()

print('reached end')
```


Discussion:

Resolving patch:
diff --git a/chainer/link.py b/chainer/link.py
--- a/chainer/link.py
+++ b/chainer/link.py
@@ -389,9 +389,11 @@ def to_intel64(self):
             value = d[name]
             if isinstance(value, cuda.ndarray):
                 value = value.get()  # to numpy.ndarray
-            if isinstance(value, numpy.ndarray):
-                d[name] = intel64.ideep.array(
+            if (isinstance(value, numpy.ndarray) and
+                    intel64.inputs_all_ready((value,))):
+                value = intel64.ideep.array(
                     value, itype=intel64.ideep.wgt_array)
+            d[name] = value
         self._cpu = True
         self._device_id = None
         return self
diff --git a/chainer/variable.py b/chainer/variable.py
--- a/chainer/variable.py
+++ b/chainer/variable.py
@@ -776,16 +776,16 @@ def to_intel64(self):
         intel64.check_ideep_available()
         data = self.data
         if data is not None:
-            if isinstance(data, numpy.ndarray):
-                # numpy.ndarray to ideep
-                self._data = [
-                    intel64.ideep.array(
-                        data, itype=intel64.ideep.wgt_array)]
-            elif isinstance(data, cuda.ndarray):
-                # cupy.ndarray to ideep
-                self._data = [
-                    intel64.ideep.array(
-                        data.get(), itype=intel64.ideep.wgt_array)]
+            if isinstance(data, cuda.ndarray):
+                # cupy.ndarray to numpy.ndarray
+                data = data.get()
+            if (isinstance(data, numpy.ndarray) and
+                    intel64.inputs_all_ready((data,))):
+                # numpy.ndarray to ideep.mdarray
+                data = intel64.ideep.array(
+                    data, itype=intel64.ideep.wgt_array)
+            self._data = [data]
+
         if self._grad_var is not None:
             self._grad_var.to_intel64()
             # ensure that the node tracks the device migration


Test patch:
diff --git a/tests/chainer_tests/test_link.py b/tests/chainer_tests/test_link.py
--- a/tests/chainer_tests/test_link.py
+++ b/tests/chainer_tests/test_link.py
@@ -1152,7 +1152,7 @@ class TestIntel64(unittest.TestCase):
 
     def setUp(self):
         self.link = chainer.Link()
-        shape = (2,)
+        shape = (2, 2)
         dtype = numpy.float32
         y_array = numpy.random.rand(*shape).astype(dtype)
         pa_array = numpy.random.rand(*shape).astype(dtype)
@@ -1284,5 +1284,22 @@ def test_intel64_to_cpu(self):
         # Persistent scalar
         assert link.ps == self.ps_scalar
 
+    def test_cpu_to_intel64_unsupported(self):
+        # Test for persistents that cannot be transferred to iDeep.
+        with self.link.init_scope():
+            self.link.no_ideep = numpy.ones((2, 2, 2), numpy.float32)
+            self.link.register_persistent('no_ideep')
+        self.link.to_intel64()
+        assert isinstance(self.link.no_ideep, numpy.ndarray)
+
+    @attr.gpu
+    def test_gpu_to_intel64_unsupported(self):
+        # Test for persistents that cannot be transferred to iDeep.
+        with self.link.init_scope():
+            self.link.no_ideep = cuda.cupy.ones((2, 2, 2), numpy.float32)
+            self.link.register_persistent('no_ideep')
+        self.link.to_intel64()
+        assert isinstance(self.link.no_ideep, numpy.ndarray)
+
 
 testing.run_module(__name__, __file__)
diff --git a/tests/chainer_tests/test_variable.py b/tests/chainer_tests/test_variable.py
--- a/tests/chainer_tests/test_variable.py
+++ b/tests/chainer_tests/test_variable.py
@@ -1696,8 +1696,7 @@ def test_loss_scale_gpu(self):
 
 
 @testing.parameterize(*testing.product({
-    # TODO(niboshi): shape () is not supported
-    'shape': [(0,), (3, 2)],
+    'shape': [(3, 2), (2, 3, 4, 3)],
     'dtype': [
         np.int8, np.int16, np.int32, np.int64, np.uint8, np.uint16, np.uint32,
         np.uint64, np.float16, np.float32, np.float64],
@@ -1773,6 +1772,35 @@ def test_intel64_to_cpu(self):
         self._check_variable_shape_and_dtype(x)
 
 
+@testing.parameterize(*testing.product({
+    'shape': [(), (0,), (3, 2, 3), (4, 4, 3, 2, 3)],
+    'dtype': [
+        np.int8, np.int16, np.int32, np.int64,
+        np.uint8, np.uint16, np.uint32, np.uint64,
+        np.float16, np.float32, np.float64,
+    ],
+}))
+@attr.ideep
+class TestIntel64Unsupported(unittest.TestCase):
+
+    """Tests for arrays that should not be converted to iDeep array."""
+
+    def setUp(self):
+        self.x_data = np.random.uniform(-1, 1, self.shape).astype(self.dtype)
+
+    def test_cpu_to_intel64(self):
+        x = chainer.Variable(self.x_data)
+        x.to_intel64()
+        assert isinstance(x.data, np.ndarray)
+
+    @attr.gpu
+    def test_gpu_to_intel64(self):
+        x = chainer.Variable(self.x_data)
+        x.to_gpu()
+        x.to_intel64()
+        assert isinstance(x.data, np.ndarray)
+
+
 @testing.parameterize(*testing.product({
     'shape': [(3,), (3, 2), (3, 2, 2), (3, 2, 2, 3)],
     'dtype': [