Repository: chainer/chainer

Issue:
Cannot report int value
I couldn't report int value. We need to check type of an input value here:
https://github.com/pfnet/chainer/blob/master/chainer/reporter.py#L244



Discussion:
I encountered the similar problem. Here is the small code that causes the problem.

```
from chainer import training
from chainer.training import extensions

def trigger(trainer):
    return True

class DummyUpdater(training.Updater):

    def __init__(self):
        self.iteration = 0

    def finalize(self):
        pass

    def get_all_optimizers(self):
        return {}

    def update(self):
        self.iteration += 1

    @property
    def epoch(self):
        return 1

    @property
    def is_new_epoch(self):
        return False

l = extensions.LogReport(trigger=trigger)
u = DummyUpdater()
t = training.Trainer(u)
# The integer value reported will be interpreted
# as the device ID by get_device function.
# So large number will raise invalid device ID error.
t.observation = {'key': 100}
l(t)
```

log

```
Traceback (most recent call last):
  File "test.py", line 40, in <module>
    l(t)
  File "/home/delta/dev/chainer/chainer/training/extensions/log_report.py", line 69, in __call__
    summary.add(observation)
  File "/home/delta/dev/chainer/chainer/reporter.py", line 297, in add
    summaries[k].add(v)
  File "/home/delta/dev/chainer/chainer/reporter.py", line 244, in add
    with cuda.get_device(value) as d:
  File "cupy/cuda/device.pyx", line 64, in cupy.cuda.device.Device.__enter__ (cupy/cuda/device.cpp:1503)
  File "cupy/cuda/device.pyx", line 79, in cupy.cuda.device.Device.use (cupy/cuda/device.cpp:1753)
  File "cupy/cuda/runtime.pyx", line 152, in cupy.cuda.runtime.setDevice (cupy/cuda/runtime.cpp:2531)
  File "cupy/cuda/runtime.pyx", line 111, in cupy.cuda.runtime.check_status (cupy/cuda/runtime.cpp:1924)
```


Resolving patch:
diff --git a/chainer/reporter.py b/chainer/reporter.py
--- a/chainer/reporter.py
+++ b/chainer/reporter.py
@@ -221,6 +221,13 @@ def report_scope(observation):
     current.observation = old
 
 
+def _get_device(x):
+    if numpy.isscalar(x):
+        return cuda.DummyDevice
+    else:
+        return cuda.get_device(x)
+
+
 class Summary(object):
 
     """Online summarization of a sequence of scalars.
@@ -241,7 +248,7 @@ def add(self, value):
                 a zero-dimensional array (on CPU or GPU).
 
         """
-        with cuda.get_device(value):
+        with _get_device(value):
             self._x += value
             self._x2 += value * value
             self._n += 1
@@ -249,7 +256,7 @@ def add(self, value):
     def compute_mean(self):
         """Computes the mean."""
         x, n = self._x, self._n
-        with cuda.get_device(x):
+        with _get_device(x):
             return x / n
 
     def make_statistics(self):
@@ -261,10 +268,10 @@ def make_statistics(self):
         """
         x, n = self._x, self._n
         xp = cuda.get_array_module(x)
-        with cuda.get_device(x):
+        with _get_device(x):
             mean = x / n
             var = self._x2 / n - mean * mean
-            std = xp.sqrt(var, var)
+            std = xp.sqrt(var)
             return mean, std
 
 


Test patch:
diff --git a/tests/chainer_tests/test_reporter.py b/tests/chainer_tests/test_reporter.py
--- a/tests/chainer_tests/test_reporter.py
+++ b/tests/chainer_tests/test_reporter.py
@@ -1,7 +1,11 @@
 import unittest
 
+import numpy
+
 import chainer
+from chainer import cuda
 from chainer import testing
+from chainer.testing import attr
 
 
 class TestReporter(unittest.TestCase):
@@ -115,4 +119,58 @@ def test_report_scope(self):
         self.assertNotIn('x', reporter.observation)
 
 
+class TestSummary(unittest.TestCase):
+
+    def setUp(self):
+        self.summary = chainer.reporter.Summary()
+
+    def test_numpy(self):
+        self.summary.add(numpy.array(1, 'f'))
+        self.summary.add(numpy.array(-2, 'f'))
+
+        mean = self.summary.compute_mean()
+        testing.assert_allclose(mean, numpy.array(-0.5, 'f'))
+
+        mean, std = self.summary.make_statistics()
+        testing.assert_allclose(mean, numpy.array(-0.5, 'f'))
+        testing.assert_allclose(std, numpy.array(1.5, 'f'))
+
+    @attr.gpu
+    def test_cupy(self):
+        xp = cuda.cupy
+        self.summary.add(xp.array(1, 'f'))
+        self.summary.add(xp.array(-2, 'f'))
+
+        mean = self.summary.compute_mean()
+        testing.assert_allclose(mean, numpy.array(-0.5, 'f'))
+
+        mean, std = self.summary.make_statistics()
+        testing.assert_allclose(mean, numpy.array(-0.5, 'f'))
+        testing.assert_allclose(std, numpy.array(1.5, 'f'))
+
+    def test_int(self):
+        self.summary.add(1)
+        self.summary.add(2)
+        self.summary.add(3)
+
+        mean = self.summary.compute_mean()
+        testing.assert_allclose(mean, 2)
+
+        mean, std = self.summary.make_statistics()
+        testing.assert_allclose(mean, 2)
+        testing.assert_allclose(std, numpy.sqrt(2 / 3))
+
+    def test_float(self):
+        self.summary.add(1.)
+        self.summary.add(2.)
+        self.summary.add(3.)
+
+        mean = self.summary.compute_mean()
+        testing.assert_allclose(mean, 2.)
+
+        mean, std = self.summary.make_statistics()
+        testing.assert_allclose(mean, 2.)
+        testing.assert_allclose(std, numpy.sqrt(2. / 3.))
+
+
 testing.run_module(__name__, __file__)