Dokumentation | Beispiele
Sonnet ist eine auf TensorFlow 2 basierende Bibliothek, die einfache, zusammensetzbare Abstraktionen für die maschinelle Lernforschung bereitstellen soll.
Sonnet wurde von Forschern bei DeepMind entworfen und gebaut. Es kann zum Aufbau neuronaler Netze für viele verschiedene Zwecke verwendet werden (unüberwachtes Lernen, verstärkendes Lernen usw.). Wir finden, dass es eine erfolgreiche Idee für unsere Organisation ist, vielleicht auch für Sie!
Genauer gesagt bietet Sonnet ein einfaches, aber leistungsstarkes Programmiermodell, das auf einem einzigen Konzept basiert: snt.Module
. Module können Verweise auf Parameter, andere Module und Methoden enthalten, die eine Funktion auf die Benutzereingabe anwenden. Sonnet wird mit vielen vordefinierten Modulen (z. B. snt.Linear
, snt.Conv2D
, snt.BatchNorm
) und einigen vordefinierten Modulnetzwerken (z. B. snt.nets.MLP
) ausgeliefert. Benutzer werden jedoch auch dazu ermutigt, ihre eigenen Module zu erstellen.
Im Gegensatz zu vielen anderen Frameworks hat Sonnet keinerlei Meinung darüber, wie Sie Ihre Module verwenden werden. Die Module sind so konzipiert, dass sie in sich geschlossen und vollständig voneinander entkoppelt sind. Sonnet wird nicht mit einem Schulungs-Framework ausgeliefert und Benutzer werden ermutigt, ihr eigenes zu erstellen oder die von anderen erstellten zu übernehmen.
Sonnet ist außerdem so konzipiert, dass es einfach zu verstehen ist. Unser Code ist (hoffentlich!) klar und zielgerichtet. Wo wir Standardwerte ausgewählt haben (z. B. Standardwerte für anfängliche Parameterwerte), versuchen wir darauf hinzuweisen, warum.
Der einfachste Weg, Sonnet auszuprobieren, ist die Verwendung von Google Colab, das ein kostenloses Python-Notebook anbietet, das an eine GPU oder TPU angeschlossen ist.
snt.distribute
Um zu beginnen, installieren Sie TensorFlow 2.0 und Sonnet 2:
$ pip install tensorflow tensorflow-probability
$ pip install dm-sonnet
Sie können Folgendes ausführen, um zu überprüfen, ob die Dinge korrekt installiert wurden:
import tensorflow as tf
import sonnet as snt
print ( "TensorFlow version {}" . format ( tf . __version__ ))
print ( "Sonnet version {}" . format ( snt . __version__ ))
Sonnet wird mit einer Reihe integrierter Module geliefert, die Sie problemlos verwenden können. Um beispielsweise ein MLP zu definieren, können wir das Modul snt.Sequential
verwenden, um eine Folge von Modulen aufzurufen und die Ausgabe eines bestimmten Moduls als Eingabe für das nächste Modul zu übergeben. Wir können snt.Linear
und tf.nn.relu
verwenden, um unsere Berechnung tatsächlich zu definieren:
mlp = snt . Sequential ([
snt . Linear ( 1024 ),
tf . nn . relu ,
snt . Linear ( 10 ),
])
Um unser Modul nutzen zu können, müssen wir es „aufrufen“. Das Sequential
-Modul (und die meisten Module) definieren eine __call__
Methode, was bedeutet, dass Sie sie nach Namen aufrufen können:
logits = mlp ( tf . random . normal ([ batch_size , input_size ]))
Es ist auch sehr üblich, alle Parameter für Ihr Modul anzufordern. Die meisten Module in Sonnet erstellen ihre Parameter beim ersten Aufruf mit einer Eingabe (da die Form der Parameter in den meisten Fällen eine Funktion der Eingabe ist). Sonnet-Module bieten zwei Eigenschaften für den Zugriff auf Parameter.
Die variables
Eigenschaft gibt alle tf.Variable
s zurück, auf die das angegebene Modul verweist:
all_variables = mlp . variables
Es ist erwähnenswert, dass tf.Variable
s nicht nur für Parameter Ihres Modells verwendet werden. Sie werden beispielsweise verwendet, um den Status in Metriken zu speichern, die in snt.BatchNorm
verwendet werden. In den meisten Fällen rufen Benutzer die Modulvariablen ab, um sie zur Aktualisierung an einen Optimierer zu übergeben. In diesem Fall sollten nicht trainierbare Variablen normalerweise nicht in dieser Liste enthalten sein, da sie über einen anderen Mechanismus aktualisiert werden. TensorFlow verfügt über einen integrierten Mechanismus, um Variablen als „trainierbar“ (Parameter Ihres Modells) und nicht trainierbar (andere Variablen) zu markieren. Sonnet bietet einen Mechanismus zum Sammeln aller trainierbaren Variablen aus Ihrem Modul, was Sie wahrscheinlich an einen Optimierer übergeben möchten:
model_parameters = mlp . trainable_variables
Sonnet empfiehlt Benutzern dringend, snt.Module
in Unterklassen zu unterteilen, um ihre eigenen Module zu definieren. Beginnen wir mit der Erstellung einer einfachen Linear
Ebene namens MyLinear
:
class MyLinear ( snt . Module ):
def __init__ ( self , output_size , name = None ):
super ( MyLinear , self ). __init__ ( name = name )
self . output_size = output_size
@ snt . once
def _initialize ( self , x ):
initial_w = tf . random . normal ([ x . shape [ 1 ], self . output_size ])
self . w = tf . Variable ( initial_w , name = "w" )
self . b = tf . Variable ( tf . zeros ([ self . output_size ]), name = "b" )
def __call__ ( self , x ):
self . _initialize ( x )
return tf . matmul ( x , self . w ) + self . b
Die Verwendung dieses Moduls ist trivial:
mod = MyLinear ( 32 )
mod ( tf . ones ([ batch_size , input_size ]))
Durch die Unterklasse snt.Module
erhalten Sie viele schöne Eigenschaften kostenlos. Zum Beispiel eine Standardimplementierung von __repr__
, die Konstruktorargumente anzeigt (sehr nützlich für Debugging und Selbstbeobachtung):
>> > print ( repr ( mod ))
MyLinear ( output_size = 10 )
Sie erhalten auch die Eigenschaften variables
und trainable_variables
:
>> > mod . variables
( < tf . Variable 'my_linear/b:0' shape = ( 10 ,) ...) > ,
< tf . Variable 'my_linear/w:0' shape = ( 1 , 10 ) ...) > )
Möglicherweise fällt Ihnen das Präfix my_linear
bei den oben genannten Variablen auf. Dies liegt daran, dass Sonnet-Module bei jedem Methodenaufruf auch in den Modulnamensbereich gelangen. Durch die Eingabe des Modulnamenbereichs stellen wir ein viel nützlicheres Diagramm bereit, das Tools wie TensorBoard nutzen können (z. B. befinden sich alle Operationen, die innerhalb von my_linear stattfinden, in einer Gruppe namens my_linear).
Darüber hinaus unterstützt Ihr Modul jetzt TensorFlow-Checkpointing und gespeicherte Modelle, bei denen es sich um erweiterte Funktionen handelt, die später behandelt werden.
Sonnet unterstützt mehrere Serialisierungsformate. Das einfachste Format, das wir unterstützen, ist Pythons pickle
. Alle integrierten Module werden getestet, um sicherzustellen, dass sie im selben Python-Prozess über pickle gespeichert/geladen werden können. Im Allgemeinen raten wir von der Verwendung von Pickle ab, da es von vielen Teilen von TensorFlow nicht gut unterstützt wird und unserer Erfahrung nach recht spröde sein kann.
Referenz: https://www.tensorflow.org/alpha/guide/checkpoints
TensorFlow-Checkpointing kann verwendet werden, um den Wert von Parametern während des Trainings regelmäßig zu speichern. Dies kann nützlich sein, um den Trainingsfortschritt zu speichern, falls Ihr Programm abstürzt oder gestoppt wird. Sonnet ist so konzipiert, dass es sauber mit TensorFlow-Checkpointing funktioniert:
checkpoint_root = "/tmp/checkpoints"
checkpoint_name = "example"
save_prefix = os . path . join ( checkpoint_root , checkpoint_name )
my_module = create_my_sonnet_module () # Can be anything extending snt.Module.
# A `Checkpoint` object manages checkpointing of the TensorFlow state associated
# with the objects passed to it's constructor. Note that Checkpoint supports
# restore on create, meaning that the variables of `my_module` do **not** need
# to be created before you restore from a checkpoint (their value will be
# restored when they are created).
checkpoint = tf . train . Checkpoint ( module = my_module )
# Most training scripts will want to restore from a checkpoint if one exists. This
# would be the case if you interrupted your training (e.g. to use your GPU for
# something else, or in a cloud environment if your instance is preempted).
latest = tf . train . latest_checkpoint ( checkpoint_root )
if latest is not None :
checkpoint . restore ( latest )
for step_num in range ( num_steps ):
train ( my_module )
# During training we will occasionally save the values of weights. Note that
# this is a blocking call and can be slow (typically we are writing to the
# slowest storage on the machine). If you have a more reliable setup it might be
# appropriate to save less frequently.
if step_num and not step_num % 1000 :
checkpoint . save ( save_prefix )
# Make sure to save your final values!!
checkpoint . save ( save_prefix )
Referenz: https://www.tensorflow.org/alpha/guide/saved_model
Mit in TensorFlow gespeicherten Modellen können Sie eine Kopie Ihres Netzwerks speichern, die von der Python-Quelle dafür entkoppelt ist. Dies wird durch das Speichern eines TensorFlow-Diagramms, das die Berechnung beschreibt, und eines Prüfpunkts mit den Werten der Gewichtungen ermöglicht.
Um ein gespeichertes Modell zu erstellen, müssen Sie zunächst ein snt.Module
erstellen, das Sie speichern möchten:
my_module = snt . nets . MLP ([ 1024 , 1024 , 10 ])
my_module ( tf . ones ([ 1 , input_size ]))
Als nächstes müssen wir ein weiteres Modul erstellen, das die spezifischen Teile unseres Modells beschreibt, die wir exportieren möchten. Wir empfehlen, dies zu tun (anstatt das ursprüngliche Modell direkt zu ändern), damit Sie eine genaue Kontrolle darüber haben, was tatsächlich exportiert wird. Dies ist normalerweise wichtig, um das Erstellen sehr großer gespeicherter Modelle zu vermeiden und um sicherzustellen, dass Sie nur die Teile Ihres Modells freigeben, die Sie möchten (z. B. möchten Sie nur den Generator für ein GAN freigeben, aber den Diskriminator privat halten).
@ tf . function ( input_signature = [ tf . TensorSpec ([ None , input_size ])])
def inference ( x ):
return my_module ( x )
to_save = snt . Module ()
to_save . inference = inference
to_save . all_variables = list ( my_module . variables )
tf . saved_model . save ( to_save , "/tmp/example_saved_model" )
Wir haben jetzt ein gespeichertes Modell im Ordner /tmp/example_saved_model
:
$ ls -lh /tmp/example_saved_model
total 24K
drwxrwsr-t 2 tomhennigan 154432098 4.0K Apr 28 00:14 assets
-rw-rw-r-- 1 tomhennigan 154432098 14K Apr 28 00:15 saved_model.pb
drwxrwsr-t 2 tomhennigan 154432098 4.0K Apr 28 00:15 variables
Das Laden dieses Modells ist einfach und kann auf einem anderen Computer ohne den Python-Code durchgeführt werden, der das gespeicherte Modell erstellt hat:
loaded = tf . saved_model . load ( "/tmp/example_saved_model" )
# Use the inference method. Note this doesn't run the Python code from `to_save`
# but instead uses the TensorFlow Graph that is part of the saved model.
loaded . inference ( tf . ones ([ 1 , input_size ]))
# The all_variables property can be used to retrieve the restored variables.
assert len ( loaded . all_variables ) > 0
Beachten Sie, dass es sich bei dem geladenen Objekt nicht um ein Sonnet-Modul, sondern um ein Containerobjekt handelt, das über die spezifischen Methoden (z. B. inference
) und Eigenschaften (z. B. all_variables
) verfügt, die wir im vorherigen Block hinzugefügt haben.
Beispiel: https://github.com/deepmind/sonnet/blob/v2/examples/distributed_cifar10.ipynb
Sonnet unterstützt verteiltes Training mithilfe benutzerdefinierter TensorFlow-Verteilungsstrategien.
Ein wesentlicher Unterschied zwischen Sonnet und verteiltem Training mit tf.keras
besteht darin, dass sich Sonnet-Module und -Optimierer nicht anders verhalten, wenn sie unter Verteilungsstrategien ausgeführt werden (z. B. mitteln wir Ihre Gradienten nicht und synchronisieren Ihre Batch-Normstatistiken nicht). Wir glauben, dass Benutzer die volle Kontrolle über diese Aspekte ihrer Schulung haben sollten und sie nicht in die Bibliothek eingebunden werden sollten. Der Nachteil hierbei ist, dass Sie diese Funktionen in Ihrem Trainingsskript implementieren müssen (normalerweise sind dies nur zwei Codezeilen, um alle Ihre Farbverläufe zu reduzieren, bevor Sie Ihren Optimierer anwenden) oder Module austauschen müssen, die explizit verteilungsbewusst sind (z. B. snt.distribute.CrossReplicaBatchNorm
).
Unser verteiltes Cifar-10-Beispiel führt Sie durch das Multi-GPU-Training mit Sonnet.