TL;DR
enable_backprop wird beim Erstellen des Vorwärtsgraphen angewendet, nicht wenn backward () ausgeführt wird.enable_backprop nicht mehrmals im Diagramm zu ändern.Als ich endlich mein Gewicht hob und versuchte, die Chainer- und Oreore-Hilfsbibliothek auf v2 zu erhöhen, bemerkte ich, dass das Verhalten von "enable_backprop" spürbar wurde. Berücksichtigen Sie insbesondere die folgenden Fragen.
train auf False gesetzt ist, wird enable_backprop dann auch automatisch auf False gesetzt?chainer.extensions.Evaluator zu vertrauen und sie zu verwenden?Dieser Beitrag ist übrigens ab v2.0.0.
Bei der Implementierung mit dem Kontextmanager bin ich sehr gespannt, was passiert, wenn sich "enable_backprop" in der Mitte des Diagramms ändert. Wenn "no_backprop_mode" einen Effekt hat, wenn "backward ()" ausgeführt wird und "no_backprop_mode" zum Zeitpunkt der Vorwärtsberechnung verwendet wird, die Rückwärtsberechnung jedoch vergessen wird, in "no_backprop_mode" eingeschlossen zu sein, ist die Genauigkeit ungewöhnlich gut. Ich bin in Schwierigkeiten [^ 1].
[^ 1]: Natürlich ändern sich die Daten nur, wenn Sie den Optimierer aufrufen. Daher ist es in Ordnung, diesen Fehler in der Praxis zu machen.
Die Antwort finden Sie unter function_node.py. Wie hier beschrieben, bewirkt no_backprop_mode, dass das übergeordnete Element beim Erstellen des Berechnungsdiagramms nicht registriert wird, sodass der ** Effekt innerhalb des Bereichs liegt, der während der ** Vorwärtsberechnung angegeben wurde.
Normale Ausführung
a = chainer.Variable(np.array([0.1], dtype=np.float32))
with chainer.configuration.using_config('enable_backprop', True):
    chainer.config.show()
    b = a * 2.0
b.backward()
print a.grad
Ausgabe
cudnn_deterministic  False
debug                False
enable_backprop      True
keep_graph_on_report False
train                True
type_check           True
use_cudnn            auto
[ 2.]
Sie können sehen, dass es auch dann wirksam ist, wenn der Rückwärtsbereich außerhalb der Reichweite liegt.
a = chainer.Variable(np.array([0.1], dtype=np.float32))
with chainer.configuration.using_config('enable_backprop', False):
    chainer.config.show()
    b = a * 2.0
b.backward()
print a.grad
Ausgabe
cudnn_deterministic  False
debug                False
enable_backprop      False
keep_graph_on_report False
train                True
type_check           True
use_cudnn            auto
None
Wie oben erwähnt, wird enable_backprop auch vom ** übergeordneten ** getrennt. Daher ist der Gradient des übergeordneten Elements 0 und nicht die neu erstellte Variable im Kontextmanager.
a = chainer.Variable(np.array([0.1], dtype=np.float32))
with chainer.configuration.using_config('enable_backprop', False):
    b = a * 2.0
c = b + 0.5
c.backward()
print a.grad  # None
print b.grad  # [ 1.]
Außerdem ist ** nicht vollständig von der Konfiguration abhängig, wenn Rückwärts aufgerufen wird? Nicht **. Daher scheint es besser, "unchain_backward ()" gehorsam zu verwenden, als es so zu implementieren, dass "enable_backprop" in einem Berechnungsgraphen mehrmals verwendet wird.
train auf False gesetzt ist, wird enable_backprop dann automatisch auch auf False gesetzt?** Nein. ** ** **
a = chainer.Variable(np.array([0.1], dtype=np.float32))
with chainer.configuration.using_config('train', False):
    chainer.config.show()
    b = a * 2.0
b.backward()
print a.grad
Ausgabe
cudnn_deterministic  False
debug                False
enable_backprop      True
keep_graph_on_report False
train                False
type_check           True
use_cudnn            auto
[ 2.]
Wenn Sie also Ihren eigenen Code wie "extensions.Evaluator" schreiben, müssen Sie sowohl "enable_backprop" als auch "train" auf "False" setzen.
** Es sieht okay aus. ** Sowohl enable_backprop als auch train sind auf False gesetzt.
import chainer
import chainer.functions as F
import chainer.links as L
from chainer import training
from chainer.training import extensions
# Network definition
class MLP(chainer.Chain):
    def __init__(self, n_out):
        super(MLP, self).__init__()
        with self.init_scope():
            self.l1 = L.Linear(None, n_out)
    def __call__(self, x):
        chainer.config.show()
        print ""
        return self.l1(x)
model = L.Classifier(MLP(10))
optimizer = chainer.optimizers.Adam()
optimizer.setup(model)
# Load the MNIST dataset
train, test = chainer.datasets.get_mnist()
test = chainer.datasets.split_dataset(test, 1)[0]
train_iter = chainer.iterators.SerialIterator(train, 32)
test_iter = chainer.iterators.SerialIterator(test, 1,
                                             repeat=False, shuffle=False)
# Set up a trainer
updater = training.StandardUpdater(train_iter, optimizer)
trainer = training.Trainer(updater, (1, 'iteration'))
trainer.extend(extensions.Evaluator(test_iter, model), trigger=(1, 'iteration'))
# Run the training
trainer.run()
Ausgabe
cudnn_deterministic  False
debug                False
enable_backprop      True
keep_graph_on_report False
train                True
type_check           True
use_cudnn            auto
cudnn_deterministic  False
debug                False
enable_backprop      False
keep_graph_on_report False
train                False
type_check           True
use_cudnn            auto
Wie Sie sehen können, sind sowohl "enable_backprop" als auch "train" "False". In Bezug auf Code ist hier anwendbar.
Recommended Posts