Repository: chainer/chainer

Issue:
Remove trigger option of snapshot and snapshot_object
They have the same functionality as the trigger argument of Trainer.extend and are redundant. I think they confuse users and they might misunderstand the trigger feature, and so they should be removed in the next major update.


Discussion:

Resolving patch:
diff --git a/chainer/training/extensions/_snapshot.py b/chainer/training/extensions/_snapshot.py
--- a/chainer/training/extensions/_snapshot.py
+++ b/chainer/training/extensions/_snapshot.py
@@ -6,15 +6,19 @@
 from chainer.training import extension
 
 
-def snapshot_object(target, filename, savefun=npz.save_npz,
-                    trigger=(1, 'epoch')):
+def snapshot_object(target, filename, savefun=npz.save_npz):
     """Returns a trainer extension to take snapshots of a given object.
 
     This extension serializes the given object and saves it to the output
     directory.
 
-    This extension is called once for each epoch by default. The default
-    priority is -100, which is lower than that of most built-in extensions.
+    This extension is called once per epoch by default. To take a
+    snapshot at a different interval, a trigger object specifying the
+    required interval can be passed along with this extension
+    to the `extend()` method of the trainer.
+
+    The default priority is -100, which is lower than that of most
+    built-in extensions.
 
     Args:
         target: Object to serialize.
@@ -25,17 +29,12 @@ def snapshot_object(target, filename, savefun=npz.save_npz,
             ``'snapshot_10000'`` at the 10,000th iteration.
         savefun: Function to save the object. It takes two arguments: the
             output file path and the object to serialize.
-        trigger: Trigger that decides when to take snapshot. It can be either
-            an already built trigger object (i.e., a callable object that
-            accepts a trainer object and returns a bool value), or a tuple in
-            the form ``<int>, 'epoch'`` or ``<int>, 'iteration'``. In latter
-            case, the tuple is passed to IntervalTrigger.
 
     Returns:
         An extension function.
 
     """
-    @extension.make_extension(trigger=trigger, priority=-100)
+    @extension.make_extension(trigger=(1, 'epoch'), priority=-100)
     def snapshot_object(trainer):
         _snapshot_object(trainer, target, filename.format(trainer), savefun)
 
@@ -43,16 +42,20 @@ def snapshot_object(trainer):
 
 
 def snapshot(savefun=npz.save_npz,
-             filename='snapshot_iter_{.updater.iteration}',
-             trigger=(1, 'epoch')):
+             filename='snapshot_iter_{.updater.iteration}'):
     """Returns a trainer extension to take snapshots of the trainer.
 
     This extension serializes the trainer object and saves it to the output
     directory. It is used to support resuming the training loop from the saved
     state.
 
-    This extension is called once for each epoch by default. The default
-    priority is -100, which is lower than that of most built-in extensions.
+    This extension is called once per epoch by default. To take a
+    snapshot at a different interval, a trigger object specifying the
+    required interval can be passed along with this extension
+    to the `extend()` method of the trainer.
+
+    The default priority is -100, which is lower than that of most
+    built-in extensions.
 
     .. note::
        This extension first writes the serialized object to a temporary file
@@ -66,14 +69,9 @@ def snapshot(savefun=npz.save_npz,
         filename (str): Name of the file into which the trainer is serialized.
             It can be a format string, where the trainer object is passed to
             the :meth:`str.format` method.
-        trigger: Trigger that decides when to take snapshot. It can be either
-            an already built trigger object (i.e., a callable object that
-            accepts a trainer object and returns a bool value), or a tuple in
-            the form ``<int>, 'epoch'`` or ``<int>, 'iteration'``. In latter
-            case, the tuple is passed to IntervalTrigger.
 
     """
-    @extension.make_extension(trigger=trigger, priority=-100)
+    @extension.make_extension(trigger=(1, 'epoch'), priority=-100)
     def snapshot(trainer):
         _snapshot_object(trainer, trainer, filename.format(trainer), savefun)
 


Test patch:
diff --git a/tests/chainer_tests/training_tests/extensions_tests/test_snapshot.py b/tests/chainer_tests/training_tests/extensions_tests/test_snapshot.py
--- a/tests/chainer_tests/training_tests/extensions_tests/test_snapshot.py
+++ b/tests/chainer_tests/training_tests/extensions_tests/test_snapshot.py
@@ -4,35 +4,21 @@
 
 from chainer import testing
 from chainer.training import extensions
-from chainer.training import trigger
 
 
-@testing.parameterize(
-    {'trigger': ('epoch', 2)},
-    {'trigger': ('iteration', 10)},
-    {'trigger': trigger.IntervalTrigger(5, 'epoch')},
-    {'trigger': trigger.IntervalTrigger(20, 'iteration')},
-)
 class TestSnapshotObject(unittest.TestCase):
 
     def test_trigger(self):
         target = mock.MagicMock()
-        snapshot_object = extensions.snapshot_object(target, 'myfile.dat',
-                                                     trigger=self.trigger)
-        self.assertEqual(snapshot_object.trigger, self.trigger)
+        snapshot_object = extensions.snapshot_object(target, 'myfile.dat')
+        self.assertEqual(snapshot_object.trigger, (1, 'epoch',))
 
 
-@testing.parameterize(
-    {'trigger': ('epoch', 2)},
-    {'trigger': ('iteration', 10)},
-    {'trigger': trigger.IntervalTrigger(5, 'epoch')},
-    {'trigger': trigger.IntervalTrigger(20, 'iteration')},
-)
 class TestSnapshot(unittest.TestCase):
 
     def test_trigger(self):
-        snapshot = extensions.snapshot(trigger=self.trigger)
-        self.assertEqual(snapshot.trigger, self.trigger)
+        snapshot = extensions.snapshot()
+        self.assertEqual(snapshot.trigger, (1, 'epoch'))
 
 
 testing.run_module(__name__, __file__)