Visualizza su TensorFlow.org | Esegui in Google Colab | Visualizza l'origine su GitHub | Scarica quaderno |
Si consiglia di utilizzare tf.keras
come API di alto livello per la creazione di reti neurali. Detto questo, la maggior parte delle API TensorFlow sono utilizzabili con un'esecuzione ansiosa.
import tensorflow as tf
print(tf.config.list_physical_devices('GPU'))
[PhysicalDevice(name='/physical_device:GPU:0', device_type='GPU')]
Livelli: insiemi comuni di operazioni utili
Nella maggior parte dei casi, quando si scrive codice per modelli di apprendimento automatico, si desidera operare a un livello di astrazione più elevato rispetto alle singole operazioni e alla manipolazione di singole variabili.
Molti modelli di apprendimento automatico sono esprimibili come la composizione e l'impilamento di livelli relativamente semplici e TensorFlow fornisce sia un insieme di molti livelli comuni sia metodi semplici per scrivere i propri livelli specifici dell'applicazione da zero o come composizione di strati esistenti.
TensorFlow include l'API Keras completa nel pacchetto tf.keras e i livelli Keras sono molto utili quando si creano i propri modelli.
# 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))
L'elenco completo dei layer preesistenti può essere visualizzato nella documentazione . Include Dense (un livello completamente connesso), Conv2D, LSTM, BatchNormalization, Dropout e molti altri.
# 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.4370762 , 0.6231566 , -0.44082257, -0.48535 , 0.17860883, -0.521853 , -0.45774594, -0.5409817 , 0.29194772, -0.18690601], [ 0.3304953 , -0.27142242, -0.48322448, -0.19328138, -0.14415592, 0.05973059, 0.56227285, 0.5323917 , -0.4914217 , 0.62182254], [-0.5313885 , 0.54680306, 0.1632638 , -0.10741419, -0.04727739, -0.35414204, 0.07529551, -0.06515282, -0.19732419, 0.25217015], [ 0.49743277, 0.31172627, 0.04989761, 0.1200847 , 0.42642146, 0.5887727 , 0.5771937 , 0.08720696, 0.43024355, -0.17298424], [-0.07610255, 0.04131562, 0.3136508 , -0.6197298 , 0.2331146 , 0.04888463, -0.54215366, 0.41208786, 0.27439958, 0.08524591]], 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.4370762 , 0.6231566 , -0.44082257, -0.48535 , 0.17860883, -0.521853 , -0.45774594, -0.5409817 , 0.29194772, -0.18690601], [ 0.3304953 , -0.27142242, -0.48322448, -0.19328138, -0.14415592, 0.05973059, 0.56227285, 0.5323917 , -0.4914217 , 0.62182254], [-0.5313885 , 0.54680306, 0.1632638 , -0.10741419, -0.04727739, -0.35414204, 0.07529551, -0.06515282, -0.19732419, 0.25217015], [ 0.49743277, 0.31172627, 0.04989761, 0.1200847 , 0.42642146, 0.5887727 , 0.5771937 , 0.08720696, 0.43024355, -0.17298424], [-0.07610255, 0.04131562, 0.3136508 , -0.6197298 , 0.2331146 , 0.04888463, -0.54215366, 0.41208786, 0.27439958, 0.08524591]], 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)>)
Implementazione di livelli personalizzati
Il modo migliore per implementare il tuo livello è estendere la classe tf.keras.Layer e implementare:
-
__init__
, dove puoi eseguire tutte le inizializzazioni indipendenti dall'input -
build
, dove conosci le forme dei tensori di input e puoi fare il resto dell'inizializzazione -
call
, dove esegui il calcolo in avanti
Nota che non devi aspettare fino a quando build
non viene chiamato per creare le tue variabili, puoi anche crearle in __init__
. Tuttavia, il vantaggio di crearli in build
è che consente la creazione tardiva di variabili in base alla forma degli input su cui opererà il livello. D'altra parte, la creazione di variabili in __init__
significherebbe che le forme richieste per creare le variabili dovranno essere specificate in modo esplicito.
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']
Il codice generale è più facile da leggere e mantenere se utilizza livelli standard quando possibile, poiché altri lettori avranno familiarità con il comportamento dei livelli standard. Se vuoi utilizzare un livello che non è presente in tf.keras.layers
, considera di presentare un problema con github o, ancora meglio, inviandoci una richiesta pull!
Modelli: Comporre strati
Molte cose interessanti simili a livelli nei modelli di apprendimento automatico vengono implementate componendo livelli esistenti. Ad esempio, ogni blocco residuo in un resnet è una composizione di convoluzioni, normalizzazioni batch e una scorciatoia. I livelli possono essere nidificati all'interno di altri livelli.
In genere erediti da keras.Model
quando hai bisogno dei metodi del modello come: Model.fit
, Model.evaluate
e Model.save
(vedi Livelli e modelli Keras personalizzati per i dettagli).
Un'altra caratteristica fornita da keras.Model
(invece di keras.layers.Layer
) è che oltre a tracciare le variabili, un keras.Model
traccia anche i suoi livelli interni, rendendoli più facili da ispezionare.
Ad esempio, ecco un blocco ResNet:
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
[<keras.layers.convolutional.Conv2D at 0x7fc7e439bf90>, <keras.layers.normalization.batch_normalization.BatchNormalization at 0x7fc7dc1e5dd0>, <keras.layers.convolutional.Conv2D at 0x7fc7dc1a1cd0>, <keras.layers.normalization.batch_normalization.BatchNormalization at 0x7fc7dc12c490>, <keras.layers.convolutional.Conv2D at 0x7fc7dc12c8d0>, <keras.layers.normalization.batch_normalization.BatchNormalization at 0x7fc7dc12cf50>]
len(block.variables)
18
block.summary()
Model: "" _________________________________________________________________ Layer (type) Output Shape Param # ================================================================= conv2d (Conv2D) multiple 4 batch_normalization (BatchN multiple 4 ormalization) conv2d_1 (Conv2D) multiple 4 batch_normalization_1 (Batc multiple 8 hNormalization) conv2d_2 (Conv2D) multiple 9 batch_normalization_2 (Batc multiple 12 hNormalization) ================================================================= Total params: 41 Trainable params: 29 Non-trainable params: 12 _________________________________________________________________
La maggior parte delle volte, tuttavia, i modelli che compongono molti livelli richiamano semplicemente uno strato dopo l'altro. Questo può essere fatto in pochissimo codice usando 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 (Batc (None, None, None, 1) 4 hNormalization) conv2d_4 (Conv2D) (None, None, None, 2) 4 batch_normalization_4 (Batc (None, None, None, 2) 8 hNormalization) conv2d_5 (Conv2D) (None, None, None, 3) 9 batch_normalization_5 (Batc (None, None, None, 3) 12 hNormalization) ================================================================= Total params: 41 Trainable params: 29 Non-trainable params: 12 _________________________________________________________________
Prossimi passi
Ora puoi tornare al taccuino precedente e adattare l'esempio di regressione lineare per utilizzare livelli e modelli per essere strutturati meglio.