Benutzerdefinierte Ebenen

Auf TensorFlow.org ansehen In Google Colab ausführen Quelle auf GitHub anzeigen Notizbuch herunterladen

Wir empfehlen die Verwendung von tf.keras als High-Level-API zum Aufbau neuronaler Netze. Die meisten TensorFlow-APIs können jedoch mit Eifer-Ausführung verwendet werden.

import tensorflow as tf
print(tf.test.is_gpu_available())
WARNING:tensorflow:From <ipython-input-1-ae932be897c3>:1: is_gpu_available (from tensorflow.python.framework.test_util) is deprecated and will be removed in a future version.
Instructions for updating:
Use `tf.config.list_physical_devices('GPU')` instead.
True

Ebenen: allgemeine Sätze nützlicher Operationen

Wenn Sie Code für Machine-Learning-Modelle schreiben, möchten Sie meistens auf einer höheren Abstraktionsebene arbeiten als einzelne Operationen und die Manipulation einzelner Variablen.

Viele Modelle des maschinellen Lernens lassen sich als Komposition und Stapelung relativ einfacher Ebenen ausdrücken, und TensorFlow bietet sowohl einen Satz vieler gängiger Ebenen als auch einfache Möglichkeiten für Sie, Ihre eigenen anwendungsspezifischen Ebenen entweder von Grund auf neu zu schreiben oder als Zusammensetzung von write vorhandene Schichten.

TensorFlow enthält die vollständige Keras- API im tf.keras-Paket, und die Keras-Ebenen sind beim Erstellen eigener Modelle sehr nützlich.

# In the tf.keras.layers package, layers are objects. To construct a layer,
# simply construct the object. Most layers take as a first argument the number
# of output dimensions / channels.
layer = tf.keras.layers.Dense(100)
# The number of input dimensions is often unnecessary, as it can be inferred
# the first time the layer is used, but it can be provided if you want to
# specify it manually, which is useful in some complex models.
layer = tf.keras.layers.Dense(10, input_shape=(None, 5))

Die vollständige Liste der bereits vorhandenen Layer finden Sie in der Dokumentation . Es umfasst Dense (eine vollständig verbundene Ebene), Conv2D, LSTM, BatchNormalization, Dropout und viele andere.

# To use a layer, simply call it.
layer(tf.zeros([10, 5]))
<tf.Tensor: shape=(10, 10), dtype=float32, numpy=
array([[0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]], dtype=float32)>
# Layers have many useful methods. For example, you can inspect all variables
# in a layer using `layer.variables` and trainable variables using
# `layer.trainable_variables`. In this case a fully-connected layer
# will have variables for weights and biases.
layer.variables
[<tf.Variable 'dense_1/kernel:0' shape=(5, 10) dtype=float32, numpy=
 array([[ 0.41612893,  0.00680858, -0.15176293, -0.00973207,  0.59399027,
         -0.21253625, -0.1478551 ,  0.27604955, -0.45228451,  0.46626216],
        [-0.5034984 ,  0.57823354, -0.16178468,  0.06708157, -0.4363411 ,
         -0.2542489 ,  0.1391185 , -0.04650295, -0.56672245, -0.5115522 ],
        [ 0.6028014 ,  0.62964135, -0.3306328 ,  0.53295714, -0.3689586 ,
         -0.19429362,  0.5127184 , -0.52880275, -0.38910007,  0.5512075 ],
        [-0.24163917,  0.14351976,  0.0895347 ,  0.5721167 , -0.35562444,
          0.15277112, -0.42938113, -0.02248359, -0.36540297,  0.434869  ],
        [-0.01469213, -0.3137877 , -0.5943229 ,  0.37445801,  0.55643815,
         -0.5431152 , -0.5895129 ,  0.508768  , -0.34295392, -0.33140907]],
       dtype=float32)>,
 <tf.Variable 'dense_1/bias:0' shape=(10,) dtype=float32, numpy=array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0.], dtype=float32)>]
# The variables are also accessible through nice accessors
layer.kernel, layer.bias
(<tf.Variable 'dense_1/kernel:0' shape=(5, 10) dtype=float32, numpy=
 array([[ 0.41612893,  0.00680858, -0.15176293, -0.00973207,  0.59399027,
         -0.21253625, -0.1478551 ,  0.27604955, -0.45228451,  0.46626216],
        [-0.5034984 ,  0.57823354, -0.16178468,  0.06708157, -0.4363411 ,
         -0.2542489 ,  0.1391185 , -0.04650295, -0.56672245, -0.5115522 ],
        [ 0.6028014 ,  0.62964135, -0.3306328 ,  0.53295714, -0.3689586 ,
         -0.19429362,  0.5127184 , -0.52880275, -0.38910007,  0.5512075 ],
        [-0.24163917,  0.14351976,  0.0895347 ,  0.5721167 , -0.35562444,
          0.15277112, -0.42938113, -0.02248359, -0.36540297,  0.434869  ],
        [-0.01469213, -0.3137877 , -0.5943229 ,  0.37445801,  0.55643815,
         -0.5431152 , -0.5895129 ,  0.508768  , -0.34295392, -0.33140907]],
       dtype=float32)>,
 <tf.Variable 'dense_1/bias:0' shape=(10,) dtype=float32, numpy=array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0.], dtype=float32)>)

Implementieren von benutzerdefinierten Ebenen

Der beste Weg, um einen eigenen Layer zu implementieren, besteht darin, die tf.keras.Layer-Klasse zu erweitern und Folgendes zu implementieren:

  1. __init__ , wo Sie alle __init__ Initialisierungen durchführen können
  2. build , wo Sie die Formen der Eingabetensoren kennen und den Rest der Initialisierung durchführen können
  3. call , wo du die Vorwärtsberechnung durchführst

Beachten Sie, dass Sie nicht warten müssen, bis build aufgerufen wird, um Ihre Variablen zu erstellen, Sie können sie auch in __init__ erstellen. Der Vorteil der Erstellung im build besteht jedoch darin, dass eine späte Variablenerstellung basierend auf der Form der Eingaben ermöglicht wird, mit denen der Layer arbeiten wird. Andererseits würde das Erstellen von Variablen in __init__ bedeuten, dass die zum Erstellen der Variablen erforderlichen Formen explizit angegeben werden müssen.

class MyDenseLayer(tf.keras.layers.Layer):
  def __init__(self, num_outputs):
    super(MyDenseLayer, self).__init__()
    self.num_outputs = num_outputs

  def build(self, input_shape):
    self.kernel = self.add_weight("kernel",
                                  shape=[int(input_shape[-1]),
                                         self.num_outputs])

  def call(self, inputs):
    return tf.matmul(inputs, self.kernel)

layer = MyDenseLayer(10)
_ = layer(tf.zeros([10, 5])) # Calling the layer `.builds` it.
print([var.name for var in layer.trainable_variables])
['my_dense_layer/kernel:0']

Der gesamte Code ist einfacher zu lesen und zu warten, wenn er nach Möglichkeit Standard-Layer verwendet, da andere Leser mit dem Verhalten von Standard-Layern vertraut sind. Wenn Sie einen Layer verwenden möchten, der nicht intf.keras.layers , sollten Sie ein Github-Problem einreichen oder uns noch besser einen Pull-Request senden!

Modelle: Komponieren von Ebenen

Viele interessante schichtartige Dinge in Modellen für maschinelles Lernen werden durch das Zusammensetzen bestehender Schichten implementiert. Jeder Restblock in einem Resnet ist beispielsweise eine Komposition aus Faltungen, Stapelnormalisierungen und einer Verknüpfung. Layer können in anderen Layern verschachtelt werden.

Normalerweise erben Sie von keras.Model wenn Sie die Modellmethoden wie: Model.fit , Model.evaluate und Model.save (weitere Model.save Sie unter Benutzerdefinierte Keras-Layer und -Modelle ).

Eine weitere Funktion von keras.Model (anstelle von keras.layers.Layer ) besteht darin, dass ein keras.Model Variablen verfolgt, keras.Model auch seine internen Layer verfolgt, wodurch sie leichter zu überprüfen sind.

Hier ist zum Beispiel ein ResNet-Block:

class ResnetIdentityBlock(tf.keras.Model):
  def __init__(self, kernel_size, filters):
    super(ResnetIdentityBlock, self).__init__(name='')
    filters1, filters2, filters3 = filters

    self.conv2a = tf.keras.layers.Conv2D(filters1, (1, 1))
    self.bn2a = tf.keras.layers.BatchNormalization()

    self.conv2b = tf.keras.layers.Conv2D(filters2, kernel_size, padding='same')
    self.bn2b = tf.keras.layers.BatchNormalization()

    self.conv2c = tf.keras.layers.Conv2D(filters3, (1, 1))
    self.bn2c = tf.keras.layers.BatchNormalization()

  def call(self, input_tensor, training=False):
    x = self.conv2a(input_tensor)
    x = self.bn2a(x, training=training)
    x = tf.nn.relu(x)

    x = self.conv2b(x)
    x = self.bn2b(x, training=training)
    x = tf.nn.relu(x)

    x = self.conv2c(x)
    x = self.bn2c(x, training=training)

    x += input_tensor
    return tf.nn.relu(x)


block = ResnetIdentityBlock(1, [1, 2, 3])
_ = block(tf.zeros([1, 2, 3, 3]))
block.layers
[<tensorflow.python.keras.layers.convolutional.Conv2D at 0x7fcda4a91390>,
 <tensorflow.python.keras.layers.normalization_v2.BatchNormalization at 0x7fccf78d2390>,
 <tensorflow.python.keras.layers.convolutional.Conv2D at 0x7fccf412ea10>,
 <tensorflow.python.keras.layers.normalization_v2.BatchNormalization at 0x7fccf40ea4d0>,
 <tensorflow.python.keras.layers.convolutional.Conv2D at 0x7fccf412e0d0>,
 <tensorflow.python.keras.layers.normalization_v2.BatchNormalization at 0x7fccf40eaf50>]
len(block.variables)
18
block.summary()
Model: "resnet_identity_block"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d (Conv2D)              multiple                  4         
_________________________________________________________________
batch_normalization (BatchNo multiple                  4         
_________________________________________________________________
conv2d_1 (Conv2D)            multiple                  4         
_________________________________________________________________
batch_normalization_1 (Batch multiple                  8         
_________________________________________________________________
conv2d_2 (Conv2D)            multiple                  9         
_________________________________________________________________
batch_normalization_2 (Batch multiple                  12        
=================================================================
Total params: 41
Trainable params: 29
Non-trainable params: 12
_________________________________________________________________

Modelle, die aus vielen Schichten bestehen, rufen jedoch meistens einfach eine Schicht nach der anderen auf. Dies kann in sehr wenig Code mit tf.keras.Sequential :

my_seq = tf.keras.Sequential([tf.keras.layers.Conv2D(1, (1, 1),
                                                    input_shape=(
                                                        None, None, 3)),
                             tf.keras.layers.BatchNormalization(),
                             tf.keras.layers.Conv2D(2, 1,
                                                    padding='same'),
                             tf.keras.layers.BatchNormalization(),
                             tf.keras.layers.Conv2D(3, (1, 1)),
                             tf.keras.layers.BatchNormalization()])
my_seq(tf.zeros([1, 2, 3, 3]))
<tf.Tensor: shape=(1, 2, 3, 3), dtype=float32, numpy=
array([[[[0., 0., 0.],
         [0., 0., 0.],
         [0., 0., 0.]],

        [[0., 0., 0.],
         [0., 0., 0.],
         [0., 0., 0.]]]], dtype=float32)>
my_seq.summary()
Model: "sequential"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d_3 (Conv2D)            (None, None, None, 1)     4         
_________________________________________________________________
batch_normalization_3 (Batch (None, None, None, 1)     4         
_________________________________________________________________
conv2d_4 (Conv2D)            (None, None, None, 2)     4         
_________________________________________________________________
batch_normalization_4 (Batch (None, None, None, 2)     8         
_________________________________________________________________
conv2d_5 (Conv2D)            (None, None, None, 3)     9         
_________________________________________________________________
batch_normalization_5 (Batch (None, None, None, 3)     12        
=================================================================
Total params: 41
Trainable params: 29
Non-trainable params: 12
_________________________________________________________________

Nächste Schritte

Jetzt können Sie zum vorherigen Notebook zurückkehren und das Beispiel der linearen Regression anpassen, um Layer und Modelle besser zu strukturieren.