Repository: chainer/chainer

Issue:
Add strict option in load_npz
https://github.com/pfnet/chainer/blob/master/chainer/serializers/npz.py#L118
`serializers.load_npz` can not use useful `strict` option of `serializers.NpzDeserializer` just due to the absence in its input arguments. We have to add it.


Discussion:

Resolving patch:
diff --git a/chainer/serializers/npz.py b/chainer/serializers/npz.py
--- a/chainer/serializers/npz.py
+++ b/chainer/serializers/npz.py
@@ -118,7 +118,7 @@ def __call__(self, key, value):
         return value
 
 
-def load_npz(filename, obj, path=''):
+def load_npz(filename, obj, path='', strict=True):
     """Loads an object from the file in NPZ format.
 
     This is a short-cut function to load from an `.npz` file that contains only
@@ -127,11 +127,14 @@ def load_npz(filename, obj, path=''):
     Args:
         filename (str): Name of the file to be loaded.
         obj: Object to be deserialized. It must support serialization protocol.
-        path: The path in the hierarchy of the serialized data under which the
-            data is to be loaded. The default behavior (blank) will load all
-            data under the root path.
+        path (str): The path in the hierarchy of the serialized data under
+            which the data is to be loaded. The default behavior (blank) will
+            load all data under the root path.
+        strict (bool): If ``True``, the deserializer raises an error when an
+            expected value is not found in the given NPZ file. Otherwise,
+            it ignores the value and skip deserialization.
 
     """
     with numpy.load(filename) as f:
-        d = NpzDeserializer(f, path=path)
+        d = NpzDeserializer(f, path=path, strict=strict)
         d.load(obj)


Test patch:
diff --git a/tests/chainer_tests/serializers_tests/test_npz.py b/tests/chainer_tests/serializers_tests/test_npz.py
--- a/tests/chainer_tests/serializers_tests/test_npz.py
+++ b/tests/chainer_tests/serializers_tests/test_npz.py
@@ -284,13 +284,23 @@ def tearDown(self):
         if hasattr(self, 'temp_file_path'):
             os.remove(self.temp_file_path)
 
-    def test_load(self):
+    def test_load_with_strict(self):
         obj = mock.MagicMock()
         npz.load_npz(self.temp_file_path, obj)
 
         self.assertEqual(obj.serialize.call_count, 1)
         (serializer,), _ = obj.serialize.call_args
         self.assertIsInstance(serializer, npz.NpzDeserializer)
+        self.assertTrue(serializer.strict)
+
+    def test_load_without_strict(self):
+        obj = mock.MagicMock()
+        npz.load_npz(self.temp_file_path, obj, strict=False)
+
+        self.assertEqual(obj.serialize.call_count, 1)
+        (serializer,), _ = obj.serialize.call_args
+        self.assertFalse(serializer.strict)
+        self.assertIsInstance(serializer, npz.NpzDeserializer)
 
     def test_load_with_path(self):
         target = link.Chain()
@@ -387,7 +397,7 @@ def test_save_optimizer2(self):
         with numpy.load(self.temp_file_path) as f:
             self._check_optimizer_group(f, ('Wp/msg', 'Wp/msdx', 'epoch', 't'))
 
-    def test_load_optimizer(self):
+    def test_load_optimizer_with_strict(self):
         for param in self.parent.params():
             param.data.fill(1)
         npz.save_npz(self.temp_file_path, self.parent, self.compress)
@@ -397,5 +407,18 @@ def test_load_optimizer(self):
         for param in self.parent.params():
             self.assertTrue((param.data == 1).all())
 
+    def test_load_optimizer_without_strict(self):
+        for param in self.parent.params():
+            param.data.fill(1)
+        npz.save_npz(self.temp_file_path, self.parent, self.compress)
+        # Remove a param
+        del self.parent.child.linear.b
+        for param in self.parent.params():
+            param.data.fill(0)
+        npz.load_npz(self.temp_file_path, self.parent, strict=False)
+        for param in self.parent.params():
+            self.assertTrue((param.data == 1).all())
+        self.assertFalse(hasattr(self.parent.child.linear, 'b'))
+
 
 testing.run_module(__name__, __file__)