Bu sayfa, Cloud Translation API ile çevrilmiştir.
Switch to English

Alt sınıflandırma yoluyla yeni Katmanlar ve Modeller oluşturma

TensorFlow.org'da görüntüleyin Google Colab'de çalıştırın Kaynağı GitHub'da görüntüleyin Defteri indirin

Kurmak

import tensorflow as tf
from tensorflow import keras

Layer sınıfı: durum (ağırlıklar) ve bazı hesaplamaların kombinasyonu

Keras'taki temel soyutlamalardan biri Layer sınıfıdır. Bir katman, hem bir durumu (katmanın "ağırlıkları") hem de girdilerden çıktılara bir dönüşümü (bir "çağrı", katmanın ileri geçişi) içerir.

İşte yoğun bağlantılı bir katman. Bir durumu vardır: w ve b değişkenleri.

class Linear(keras.layers.Layer):
    def __init__(self, units=32, input_dim=32):
        super(Linear, self).__init__()
        w_init = tf.random_normal_initializer()
        self.w = tf.Variable(
            initial_value=w_init(shape=(input_dim, units), dtype="float32"),
            trainable=True,
        )
        b_init = tf.zeros_initializer()
        self.b = tf.Variable(
            initial_value=b_init(shape=(units,), dtype="float32"), trainable=True
        )

    def call(self, inputs):
        return tf.matmul(inputs, self.w) + self.b

Bir Python işlevi gibi, bazı tensör girdilerinde çağırarak bir katman kullanırsınız.

x = tf.ones((2, 2))
linear_layer = Linear(4, 2)
y = linear_layer(x)
print(y)
tf.Tensor(
[[0.06229124 0.02534804 0.00851583 0.00457605]
 [0.06229124 0.02534804 0.00851583 0.00457605]], shape=(2, 4), dtype=float32)

w ve b ağırlıklarının, katman özellikleri olarak ayarlandıktan sonra katman tarafından otomatik olarak izlendiğini unutmayın:

assert linear_layer.weights == [linear_layer.w, linear_layer.b]

Ayrıca, bir katmana ağırlık eklemek için daha hızlı bir kısayola erişiminiz olduğunu unutmayın: add_weight() yöntemi:

class Linear(keras.layers.Layer):
    def __init__(self, units=32, input_dim=32):
        super(Linear, self).__init__()
        self.w = self.add_weight(
            shape=(input_dim, units), initializer="random_normal", trainable=True
        )
        self.b = self.add_weight(shape=(units,), initializer="zeros", trainable=True)

    def call(self, inputs):
        return tf.matmul(inputs, self.w) + self.b


x = tf.ones((2, 2))
linear_layer = Linear(4, 2)
y = linear_layer(x)
print(y)
tf.Tensor(
[[ 0.06930272  0.03181376 -0.07157768  0.07838295]
 [ 0.06930272  0.03181376 -0.07157768  0.07838295]], shape=(2, 4), dtype=float32)

Katmanlar eğitilemez ağırlıklara sahip olabilir

Eğitilebilir ağırlıkların yanı sıra, bir katmana eğitilemeyen ağırlıklar da ekleyebilirsiniz. Bu tür ağırlıkların, katmanı eğitirken geri yayılım sırasında dikkate alınmaması amaçlanmıştır.

Eğitilemez bir ağırlığın nasıl ekleneceği ve kullanılacağı aşağıda açıklanmıştır:

class ComputeSum(keras.layers.Layer):
    def __init__(self, input_dim):
        super(ComputeSum, self).__init__()
        self.total = tf.Variable(initial_value=tf.zeros((input_dim,)), trainable=False)

    def call(self, inputs):
        self.total.assign_add(tf.reduce_sum(inputs, axis=0))
        return self.total


x = tf.ones((2, 2))
my_sum = ComputeSum(2)
y = my_sum(x)
print(y.numpy())
y = my_sum(x)
print(y.numpy())
[2. 2.]
[4. 4.]

layer.weights parçasıdır, ancak layer.weights bir ağırlık olarak kategorize edilir:

print("weights:", len(my_sum.weights))
print("non-trainable weights:", len(my_sum.non_trainable_weights))

# It's not included in the trainable weights:
print("trainable_weights:", my_sum.trainable_weights)
weights: 1
non-trainable weights: 1
trainable_weights: []

En iyi uygulama: girdilerin şekli bilinene kadar ağırlık oluşumunu ertelemek

Yukarıdaki Linear katmanımız __init__() deki w ve b ağırlıklarının şeklini hesaplamak için kullanılan bir input_dim bağımsız değişkeni aldı:

class Linear(keras.layers.Layer):
    def __init__(self, units=32, input_dim=32):
        super(Linear, self).__init__()
        self.w = self.add_weight(
            shape=(input_dim, units), initializer="random_normal", trainable=True
        )
        self.b = self.add_weight(shape=(units,), initializer="zeros", trainable=True)

    def call(self, inputs):
        return tf.matmul(inputs, self.w) + self.b

Çoğu durumda, girdilerinizin boyutunu önceden bilemeyebilirsiniz ve katmanı somutlaştırdıktan bir süre sonra bu değer bilindiğinde tembel ağırlıklar oluşturmak isteyebilirsiniz.

Keras API'sinde, katmanınızın build(self, inputs_shape) yönteminde katman ağırlıkları oluşturmanızı öneririz. Bunun gibi:

class Linear(keras.layers.Layer):
    def __init__(self, units=32):
        super(Linear, self).__init__()
        self.units = units

    def build(self, input_shape):
        self.w = self.add_weight(
            shape=(input_shape[-1], self.units),
            initializer="random_normal",
            trainable=True,
        )
        self.b = self.add_weight(
            shape=(self.units,), initializer="random_normal", trainable=True
        )

    def call(self, inputs):
        return tf.matmul(inputs, self.w) + self.b

__call__() yöntemi, ilk çağrıldığında derlemeyi otomatik olarak çalıştıracaktır. Artık tembel ve dolayısıyla kullanımı daha kolay bir katmanınız var:

# At instantiation, we don't know on what inputs this is going to get called
linear_layer = Linear(32)

# The layer's weights are created dynamically the first time the layer is called
y = linear_layer(x)

Katmanlar yinelemeli olarak oluşturulabilir

Bir Katman örneğini başka bir Katmanın niteliği olarak atarsanız, dış katman iç katmanın ağırlıklarını izlemeye başlar.

__init__() yönteminde bu tür alt katmanlar oluşturmanızı öneririz (alt katmanlar genellikle bir inşa yöntemine sahip olduklarından, dış katman oluşturulduğunda bunlar oluşturulacaktır).

# Let's assume we are reusing the Linear class
# with a `build` method that we defined above.


class MLPBlock(keras.layers.Layer):
    def __init__(self):
        super(MLPBlock, self).__init__()
        self.linear_1 = Linear(32)
        self.linear_2 = Linear(32)
        self.linear_3 = Linear(1)

    def call(self, inputs):
        x = self.linear_1(inputs)
        x = tf.nn.relu(x)
        x = self.linear_2(x)
        x = tf.nn.relu(x)
        return self.linear_3(x)


mlp = MLPBlock()
y = mlp(tf.ones(shape=(3, 64)))  # The first call to the `mlp` will create the weights
print("weights:", len(mlp.weights))
print("trainable weights:", len(mlp.trainable_weights))
weights: 6
trainable weights: 6

add_loss() yöntemi

Bir katmanın call() yöntemini yazarken, eğitim döngünüzü yazarken daha sonra kullanmak isteyeceğiniz kayıp tensörleri oluşturabilirsiniz. Bu, self.add_loss(value) çağırarak yapılabilir:

# A layer that creates an activity regularization loss
class ActivityRegularizationLayer(keras.layers.Layer):
    def __init__(self, rate=1e-2):
        super(ActivityRegularizationLayer, self).__init__()
        self.rate = rate

    def call(self, inputs):
        self.add_loss(self.rate * tf.reduce_sum(inputs))
        return inputs

Bu kayıplar (herhangi bir iç katman tarafından oluşturulanlar dahil) layer.losses aracılığıyla geri alınabilir. Bu özellik, her __call__() başlangıcında üst düzey katmana layer.losses , böylece layer.losses her zaman son ileri geçiş sırasında oluşturulan kayıp değerlerini içerir.

class OuterLayer(keras.layers.Layer):
    def __init__(self):
        super(OuterLayer, self).__init__()
        self.activity_reg = ActivityRegularizationLayer(1e-2)

    def call(self, inputs):
        return self.activity_reg(inputs)


layer = OuterLayer()
assert len(layer.losses) == 0  # No losses yet since the layer has never been called

_ = layer(tf.zeros(1, 1))
assert len(layer.losses) == 1  # We created one loss value

# `layer.losses` gets reset at the start of each __call__
_ = layer(tf.zeros(1, 1))
assert len(layer.losses) == 1  # This is the loss created during the call above

Ek olarak, loss özelliği ayrıca herhangi bir iç katmanın ağırlıkları için oluşturulan düzenlilik kayıplarını da içerir:

class OuterLayerWithKernelRegularizer(keras.layers.Layer):
    def __init__(self):
        super(OuterLayerWithKernelRegularizer, self).__init__()
        self.dense = keras.layers.Dense(
            32, kernel_regularizer=tf.keras.regularizers.l2(1e-3)
        )

    def call(self, inputs):
        return self.dense(inputs)


layer = OuterLayerWithKernelRegularizer()
_ = layer(tf.zeros((1, 1)))

# This is `1e-3 * sum(layer.dense.kernel ** 2)`,
# created by the `kernel_regularizer` above.
print(layer.losses)
[<tf.Tensor: shape=(), dtype=float32, numpy=0.002361052>]

Bu kayıplar, aşağıdaki gibi eğitim döngüleri yazılırken dikkate alınmalıdır:

# Instantiate an optimizer.
optimizer = tf.keras.optimizers.SGD(learning_rate=1e-3)
loss_fn = keras.losses.SparseCategoricalCrossentropy(from_logits=True)

# Iterate over the batches of a dataset.
for x_batch_train, y_batch_train in train_dataset:
  with tf.GradientTape() as tape:
    logits = layer(x_batch_train)  # Logits for this minibatch
    # Loss value for this minibatch
    loss_value = loss_fn(y_batch_train, logits)
    # Add extra losses created during this forward pass:
    loss_value += sum(model.losses)

  grads = tape.gradient(loss_value, model.trainable_weights)
  optimizer.apply_gradients(zip(grads, model.trainable_weights))

Eğitim döngüleri yazma hakkında ayrıntılı bir kılavuz için sıfırdan bir eğitim döngüsü yazma kılavuzuna bakın.

Bu kayıplar aynı zamanda fit() ile sorunsuz bir fit() otomatik olarak toplanır ve varsa ana kayba eklenirler):

import numpy as np

inputs = keras.Input(shape=(3,))
outputs = ActivityRegularizationLayer()(inputs)
model = keras.Model(inputs, outputs)

# If there is a loss passed in `compile`, thee regularization
# losses get added to it
model.compile(optimizer="adam", loss="mse")
model.fit(np.random.random((2, 3)), np.random.random((2, 3)))

# It's also possible not to pass any loss in `compile`,
# since the model already has a loss to minimize, via the `add_loss`
# call during the forward pass!
model.compile(optimizer="adam")
model.fit(np.random.random((2, 3)), np.random.random((2, 3)))
1/1 [==============================] - 0s 1ms/step - loss: 0.2552
1/1 [==============================] - 0s 893us/step - loss: 0.0427

<tensorflow.python.keras.callbacks.History at 0x7ff6586c3588>

add_metric() yöntemi

add_loss() benzer şekilde, katmanlar eğitim sırasında bir miktarın hareketli ortalamasını izlemek için bir add_metric() yöntemine de sahiptir.

Şu katmanı düşünün: "lojistik uç nokta" katmanı. Girişler tahminler & hedefler, bunun aracılığıyla izleyen bir kayıp hesaplar gibi sürer add_loss() ve bunun aracılığıyla izleyen bir doğruluk sayıl, hesaplar add_metric() .

class LogisticEndpoint(keras.layers.Layer):
    def __init__(self, name=None):
        super(LogisticEndpoint, self).__init__(name=name)
        self.loss_fn = keras.losses.BinaryCrossentropy(from_logits=True)
        self.accuracy_fn = keras.metrics.BinaryAccuracy()

    def call(self, targets, logits, sample_weights=None):
        # Compute the training-time loss value and add it
        # to the layer using `self.add_loss()`.
        loss = self.loss_fn(targets, logits, sample_weights)
        self.add_loss(loss)

        # Log accuracy as a metric and add it
        # to the layer using `self.add_metric()`.
        acc = self.accuracy_fn(targets, logits, sample_weights)
        self.add_metric(acc, name="accuracy")

        # Return the inference-time prediction tensor (for `.predict()`).
        return tf.nn.softmax(logits)

Bu şekilde izlenen metriklere layer.metrics aracılığıyla erişilebilir:

layer = LogisticEndpoint()

targets = tf.ones((2, 2))
logits = tf.ones((2, 2))
y = layer(targets, logits)

print("layer.metrics:", layer.metrics)
print("current accuracy value:", float(layer.metrics[0].result()))
layer.metrics: [<tensorflow.python.keras.metrics.BinaryAccuracy object at 0x7ff68cc73208>]
current accuracy value: 1.0

Tıpkı add_loss() için olduğu gibi, bu metrikler fit() tarafından izlenir:

inputs = keras.Input(shape=(3,), name="inputs")
targets = keras.Input(shape=(10,), name="targets")
logits = keras.layers.Dense(10)(inputs)
predictions = LogisticEndpoint(name="predictions")(logits, targets)

model = keras.Model(inputs=[inputs, targets], outputs=predictions)
model.compile(optimizer="adam")

data = {
    "inputs": np.random.random((3, 3)),
    "targets": np.random.random((3, 10)),
}
model.fit(data)
1/1 [==============================] - 0s 2ms/step - loss: 1.0043 - binary_accuracy: 0.0000e+00

<tensorflow.python.keras.callbacks.History at 0x7ff658522b00>

Katmanlarınızda isteğe bağlı olarak serileştirmeyi etkinleştirebilirsiniz

Özel katmanlarınızın bir İşlevsel modelin parçası olarak serileştirilebilir olmasına ihtiyacınız varsa, isteğe bağlı olarak bir get_config() yöntemi uygulayabilirsiniz:

class Linear(keras.layers.Layer):
    def __init__(self, units=32):
        super(Linear, self).__init__()
        self.units = units

    def build(self, input_shape):
        self.w = self.add_weight(
            shape=(input_shape[-1], self.units),
            initializer="random_normal",
            trainable=True,
        )
        self.b = self.add_weight(
            shape=(self.units,), initializer="random_normal", trainable=True
        )

    def call(self, inputs):
        return tf.matmul(inputs, self.w) + self.b

    def get_config(self):
        return {"units": self.units}


# Now you can recreate the layer from its config:
layer = Linear(64)
config = layer.get_config()
print(config)
new_layer = Linear.from_config(config)
{'units': 64}

Temel Layer sınıfının __init__() yönteminin bazı anahtar kelime bağımsız değişkenleri, özellikle bir name ve bir dtype . Bu argümanları __init__() içindeki ana sınıfa geçirmek ve bunları katman yapılandırmasına dahil etmek iyi bir uygulamadır:

class Linear(keras.layers.Layer):
    def __init__(self, units=32, **kwargs):
        super(Linear, self).__init__(**kwargs)
        self.units = units

    def build(self, input_shape):
        self.w = self.add_weight(
            shape=(input_shape[-1], self.units),
            initializer="random_normal",
            trainable=True,
        )
        self.b = self.add_weight(
            shape=(self.units,), initializer="random_normal", trainable=True
        )

    def call(self, inputs):
        return tf.matmul(inputs, self.w) + self.b

    def get_config(self):
        config = super(Linear, self).get_config()
        config.update({"units": self.units})
        return config


layer = Linear(64)
config = layer.get_config()
print(config)
new_layer = Linear.from_config(config)
{'name': 'linear_8', 'trainable': True, 'dtype': 'float32', 'units': 64}

Katmanı konfigürasyonundan from_config() daha fazla esnekliğe ihtiyacınız varsa, from_config() sınıf yöntemini de geçersiz kılabilirsiniz. Bu, from_config() temel uygulamasıdır:

def from_config(cls, config):
  return cls(**config)

Serileştirme ve kaydetme hakkında daha fazla bilgi edinmek için modelleri kaydetme ve serileştirme kılavuzunun tamamına bakın.

call() yönteminde ayrıcalıklı training bağımsız değişkeni

Bazı katmanlar, özellikle BatchNormalization katmanı ve Dropout katmanı, eğitim ve çıkarım sırasında farklı davranışlara sahiptir. Bu tür katmanlar için call() yönteminde bir training (boolean) argümanını açığa çıkarmak standart uygulamadır.

Bu argümanı call() içinde açığa çıkararak, yerleşik eğitim ve değerlendirme döngülerinin (örneğin, fit() ) katmanı eğitimde ve çıkarımda doğru şekilde kullanmasını sağlarsınız.

class CustomDropout(keras.layers.Layer):
    def __init__(self, rate, **kwargs):
        super(CustomDropout, self).__init__(**kwargs)
        self.rate = rate

    def call(self, inputs, training=None):
        if training:
            return tf.nn.dropout(inputs, rate=self.rate)
        return inputs

call() yöntemindeki ayrıcalıklı mask argümanı

call() tarafından desteklenen diğer ayrıcalıklı argüman mask argümanıdır.

Bunu tüm Keras RNN katmanlarında bulacaksınız. Maske, zaman serisi verilerini işlerken belirli giriş zaman adımlarını atlamak için kullanılan bir boole tensörüdür (girişteki zaman adımı başına bir boole değeri).

__call__() , önceki katman tarafından bir maske oluşturulduğunda, kendisini destekleyen katmanlar için doğru mask argümanını __call__() e otomatik olarak __call__() . Maske üreten katmanlar, mask_zero=True ile yapılandırılan Embedding katmanı ve Masking katmanıdır.

Maskeleme ve maskeleme özellikli katmanların nasıl yazılacağı hakkında daha fazla bilgi edinmek için lütfen "dolgu ve maskelemeyi anlama" kılavuzuna bakın.

Model sınıfı

Genel olarak, iç hesaplama bloklarını tanımlamak için Layer sınıfını ve eğiteceğiniz nesne olan dış modeli tanımlamak için Model sınıfını kullanacaksınız.

Örneğin, bir ResNet50 modelinde, Layer alt sınıflara ayıran birkaç ResNet bloğunuz ve tüm ResNet50 ağını kapsayan tek bir Model .

Model sınıfı, aşağıdaki farklılıklarla Layer ile aynı API'ye sahiptir:

  • model.fit() eğitim, değerlendirme ve tahmin döngülerini ( model.fit() , model.evaluate() , model.predict() ) ortaya model.predict() .
  • model.layers özelliği aracılığıyla iç katmanlarının listesini gösterir.
  • Kaydetme ve serileştirme API'lerini ortaya çıkarır ( save() , save_weights() ...)

Etkili olarak, Layer sınıfı, literatürde "katman" ("evrişim katmanı" veya "tekrarlayan katman" gibi) veya "blok" ("ResNet bloğu" veya "Başlangıç ​​bloğu" gibi) olarak bahsettiğimiz şeye karşılık gelir. ).

Bu arada Model sınıfı, literatürde bir "model" ("derin öğrenme modeli" nde olduğu gibi) veya bir "ağ" ("derin sinir ağı" gibi) olarak anılan şeye karşılık gelir.

Öyleyse, " Layer sınıfını mı yoksa Model sınıfını mı kullanmalıyım?" Diye merak ediyorsanız, kendinize sorun: bunun için fit() çağırmam gerekecek mi? Bunun için save() çağırmam gerekecek mi? Eğer öyleyse, Model ile gidin. Değilse (ya sınıfınız daha büyük bir sistemde sadece bir blok olduğu için ya da kendiniz eğitim yazıp kod kaydettiğiniz için) Layer kullanın.

Örneğin, yukarıdaki mini resnet örneğimizi alıp fit() ile save_weights() ve save_weights() ile tasarruf edebileceğimiz bir Model oluşturmak için kullanabiliriz:

class ResNet(tf.keras.Model):

    def __init__(self):
        super(ResNet, self).__init__()
        self.block_1 = ResNetBlock()
        self.block_2 = ResNetBlock()
        self.global_pool = layers.GlobalAveragePooling2D()
        self.classifier = Dense(num_classes)

    def call(self, inputs):
        x = self.block_1(inputs)
        x = self.block_2(x)
        x = self.global_pool(x)
        return self.classifier(x)


resnet = ResNet()
dataset = ...
resnet.fit(dataset, epochs=10)
resnet.save(filepath)

Hepsini bir araya getirmek: uçtan uca bir örnek

Şimdiye kadar öğrendikleriniz:

  • Bir Layer bir durumu ( __init__() veya build() ) ve bazı hesaplamaları ( call() içinde tanımlanmış) kapsamaktadır.
  • Katmanlar, yeni, daha büyük hesaplama blokları oluşturmak için yinelemeli olarak yuvalanabilir.
  • Katmanlar, add_loss() ve add_metric() aracılığıyla kayıplar (tipik olarak düzenleme kayıpları) ve ölçümler oluşturabilir ve izleyebilir.
  • Dış kap, eğitmek istediğiniz şey bir Model . Bir Model tıpkı bir Layer , ancak ek eğitim ve serileştirme araçları içerir.

Tüm bunları uçtan uca bir örnekle bir araya getirelim: Bir Varyasyonel Otomatik Kodlayıcı (VAE) uygulayacağız. MNIST basamaklarına göre eğiteceğiz.

VAE'miz, Layer alt Layer katmanların iç içe yerleştirilmiş bir bileşimi olarak oluşturulmuş bir Model alt sınıfı olacaktır. Bir düzenlilik kaybına (KL sapması) sahip olacaktır.

from tensorflow.keras import layers


class Sampling(layers.Layer):
    """Uses (z_mean, z_log_var) to sample z, the vector encoding a digit."""

    def call(self, inputs):
        z_mean, z_log_var = inputs
        batch = tf.shape(z_mean)[0]
        dim = tf.shape(z_mean)[1]
        epsilon = tf.keras.backend.random_normal(shape=(batch, dim))
        return z_mean + tf.exp(0.5 * z_log_var) * epsilon


class Encoder(layers.Layer):
    """Maps MNIST digits to a triplet (z_mean, z_log_var, z)."""

    def __init__(self, latent_dim=32, intermediate_dim=64, name="encoder", **kwargs):
        super(Encoder, self).__init__(name=name, **kwargs)
        self.dense_proj = layers.Dense(intermediate_dim, activation="relu")
        self.dense_mean = layers.Dense(latent_dim)
        self.dense_log_var = layers.Dense(latent_dim)
        self.sampling = Sampling()

    def call(self, inputs):
        x = self.dense_proj(inputs)
        z_mean = self.dense_mean(x)
        z_log_var = self.dense_log_var(x)
        z = self.sampling((z_mean, z_log_var))
        return z_mean, z_log_var, z


class Decoder(layers.Layer):
    """Converts z, the encoded digit vector, back into a readable digit."""

    def __init__(self, original_dim, intermediate_dim=64, name="decoder", **kwargs):
        super(Decoder, self).__init__(name=name, **kwargs)
        self.dense_proj = layers.Dense(intermediate_dim, activation="relu")
        self.dense_output = layers.Dense(original_dim, activation="sigmoid")

    def call(self, inputs):
        x = self.dense_proj(inputs)
        return self.dense_output(x)


class VariationalAutoEncoder(keras.Model):
    """Combines the encoder and decoder into an end-to-end model for training."""

    def __init__(
        self,
        original_dim,
        intermediate_dim=64,
        latent_dim=32,
        name="autoencoder",
        **kwargs
    ):
        super(VariationalAutoEncoder, self).__init__(name=name, **kwargs)
        self.original_dim = original_dim
        self.encoder = Encoder(latent_dim=latent_dim, intermediate_dim=intermediate_dim)
        self.decoder = Decoder(original_dim, intermediate_dim=intermediate_dim)

    def call(self, inputs):
        z_mean, z_log_var, z = self.encoder(inputs)
        reconstructed = self.decoder(z)
        # Add KL divergence regularization loss.
        kl_loss = -0.5 * tf.reduce_mean(
            z_log_var - tf.square(z_mean) - tf.exp(z_log_var) + 1
        )
        self.add_loss(kl_loss)
        return reconstructed

MNIST üzerinde basit bir eğitim döngüsü yazalım:

original_dim = 784
vae = VariationalAutoEncoder(original_dim, 64, 32)

optimizer = tf.keras.optimizers.Adam(learning_rate=1e-3)
mse_loss_fn = tf.keras.losses.MeanSquaredError()

loss_metric = tf.keras.metrics.Mean()

(x_train, _), _ = tf.keras.datasets.mnist.load_data()
x_train = x_train.reshape(60000, 784).astype("float32") / 255

train_dataset = tf.data.Dataset.from_tensor_slices(x_train)
train_dataset = train_dataset.shuffle(buffer_size=1024).batch(64)

epochs = 2

# Iterate over epochs.
for epoch in range(epochs):
    print("Start of epoch %d" % (epoch,))

    # Iterate over the batches of the dataset.
    for step, x_batch_train in enumerate(train_dataset):
        with tf.GradientTape() as tape:
            reconstructed = vae(x_batch_train)
            # Compute reconstruction loss
            loss = mse_loss_fn(x_batch_train, reconstructed)
            loss += sum(vae.losses)  # Add KLD regularization loss

        grads = tape.gradient(loss, vae.trainable_weights)
        optimizer.apply_gradients(zip(grads, vae.trainable_weights))

        loss_metric(loss)

        if step % 100 == 0:
            print("step %d: mean loss = %.4f" % (step, loss_metric.result()))
Start of epoch 0
step 0: mean loss = 0.3187
step 100: mean loss = 0.1247
step 200: mean loss = 0.0987
step 300: mean loss = 0.0888
step 400: mean loss = 0.0840
step 500: mean loss = 0.0807
step 600: mean loss = 0.0786
step 700: mean loss = 0.0770
step 800: mean loss = 0.0759
step 900: mean loss = 0.0749
Start of epoch 1
step 0: mean loss = 0.0746
step 100: mean loss = 0.0739
step 200: mean loss = 0.0734
step 300: mean loss = 0.0730
step 400: mean loss = 0.0726
step 500: mean loss = 0.0722
step 600: mean loss = 0.0720
step 700: mean loss = 0.0717
step 800: mean loss = 0.0714
step 900: mean loss = 0.0712

VAE, Model alt sınıflandırma olduğundan, yerleşik eğitim döngüleri içerdiğini unutmayın. Yani bunu şu şekilde de eğitebilirdiniz:

vae = VariationalAutoEncoder(784, 64, 32)

optimizer = tf.keras.optimizers.Adam(learning_rate=1e-3)

vae.compile(optimizer, loss=tf.keras.losses.MeanSquaredError())
vae.fit(x_train, x_train, epochs=2, batch_size=64)
Epoch 1/2
938/938 [==============================] - 2s 2ms/step - loss: 0.0747
Epoch 2/2
938/938 [==============================] - 2s 2ms/step - loss: 0.0676

<tensorflow.python.keras.callbacks.History at 0x7ff6583b2588>

Nesne yönelimli geliştirmenin ötesinde: Fonksiyonel API

Bu örnek sizin için çok fazla nesne yönelimli gelişme miydi? İşlevsel API'yi kullanarak da modeller oluşturabilirsiniz. Önemli olarak, bir stili veya diğerini seçmek, diğer stilde yazılmış bileşenlerden yararlanmanızı engellemez: Her zaman karıştırıp eşleştirebilirsiniz.

Örneğin, aşağıdaki Fonksiyonel API örneği, yukarıdaki örnekte tanımladığımız aynı Sampling katmanını yeniden kullanır:

original_dim = 784
intermediate_dim = 64
latent_dim = 32

# Define encoder model.
original_inputs = tf.keras.Input(shape=(original_dim,), name="encoder_input")
x = layers.Dense(intermediate_dim, activation="relu")(original_inputs)
z_mean = layers.Dense(latent_dim, name="z_mean")(x)
z_log_var = layers.Dense(latent_dim, name="z_log_var")(x)
z = Sampling()((z_mean, z_log_var))
encoder = tf.keras.Model(inputs=original_inputs, outputs=z, name="encoder")

# Define decoder model.
latent_inputs = tf.keras.Input(shape=(latent_dim,), name="z_sampling")
x = layers.Dense(intermediate_dim, activation="relu")(latent_inputs)
outputs = layers.Dense(original_dim, activation="sigmoid")(x)
decoder = tf.keras.Model(inputs=latent_inputs, outputs=outputs, name="decoder")

# Define VAE model.
outputs = decoder(z)
vae = tf.keras.Model(inputs=original_inputs, outputs=outputs, name="vae")

# Add KL divergence regularization loss.
kl_loss = -0.5 * tf.reduce_mean(z_log_var - tf.square(z_mean) - tf.exp(z_log_var) + 1)
vae.add_loss(kl_loss)

# Train.
optimizer = tf.keras.optimizers.Adam(learning_rate=1e-3)
vae.compile(optimizer, loss=tf.keras.losses.MeanSquaredError())
vae.fit(x_train, x_train, epochs=3, batch_size=64)
Epoch 1/3
938/938 [==============================] - 2s 2ms/step - loss: 0.0746
Epoch 2/3
938/938 [==============================] - 2s 2ms/step - loss: 0.0676
Epoch 3/3
938/938 [==============================] - 2s 2ms/step - loss: 0.0676

<tensorflow.python.keras.callbacks.History at 0x7ff658204588>

Daha fazla bilgi için, Fonksiyonel API kılavuzunu okuduğunuzdan emin olun.