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