روز جامعه ML 9 نوامبر است! برای به روز رسانی از TensorFlow، JAX به ما بپیوندید، و بیشتر بیشتر بدانید

ساخت لایه ها و مدل های جدید از طریق طبقه بندی فرعی

مشاهده در TensorFlow.org در Google Colab اجرا کنید مشاهده منبع در GitHub دانلود دفترچه یادداشت

برپایی

import tensorflow as tf
from tensorflow import keras

Layer کلاس: ترکیبی از دولت (وزن) و برخی از محاسبات

یکی از انتزاع مرکزی در Keras است Layer کلاس. یک لایه هم یک حالت ("وزن" لایه) و هم تبدیل از ورودی به خروجی را در بر می گیرد (یک "تماس" ، پاس رو به جلو لایه).

در اینجا یک لایه متراکم متصل شده است. از آن است که دولت: متغیرهای w و b .

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

شما می توانید از یک لایه با فراخوانی آن بر روی برخی ورودی های تانسور استفاده کنید ، درست مانند عملکرد پایتون.

x = tf.ones((2, 2))
linear_layer = Linear(4, 2)
y = linear_layer(x)
print(y)
tf.Tensor(
[[ 0.03029768 -0.05972501  0.00586849 -0.1109921 ]
 [ 0.03029768 -0.05972501  0.00586849 -0.1109921 ]], shape=(2, 4), dtype=float32)

توجه داشته باشید که وزن w و b به طور خودکار توسط لایه ردیابی بر بودن مجموعه ای به عنوان ویژگی لایه:

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

توجه داشته باشید شما همچنین دسترسی به یک میانبر سریعتر برای اضافه کردن وزن به یک لایه داشته باشد: add_weight() روش:

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.05004499  0.01081884 -0.12212791  0.01023131]
 [ 0.05004499  0.01081884 -0.12212791  0.01023131]], shape=(2, 4), dtype=float32)

لایه ها می توانند وزنه های غیر قابل تمرین داشته باشند

علاوه بر وزنه های قابل تمرین ، می توانید وزنه های غیر قابل تمرین را نیز به یک لایه اضافه کنید. چنین وزنه هایی در حین انتشار در پشت ، هنگام آموزش لایه مورد توجه قرار نمی گیرد.

در اینجا نحوه اضافه کردن و استفاده از یک وزنه غیر قابل تمرین وجود دارد:

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 ، اما آن را می شود به عنوان یک وزن غیر تربیت شدنی طبقه بندی:

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: []

بهترین روش: به تعویق انداختن وزن تا مشخص شدن شکل ورودی ها

ما Linear لایه بالاتر در زمان input_dim استدلال که برای محاسبه به شکل وزن مورد استفاده قرار گرفت w و b در __init__() :

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

در بسیاری از موارد ، شما ممکن است اندازه ورودی های خود را از قبل ندانید و دوست دارید وقتی مقدار آن مشخص می شود ، به صورت تنبلی وزنی ایجاد کنید ، مدتی پس از ایجاد لایه.

در API Keras، توصیه می کنیم ایجاد وزن لایه در build(self, inputs_shape) روش لایه خود را. مثل این:

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__() روش لایه خود را به طور خودکار اجرا ساخت اولین بار آن را به نام. اکنون یک لایه تنبل دارید و بنابراین استفاده از آن آسان تر است:

# 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)

لایه ها بصورت بازگشتی ترکیب پذیر هستند

اگر یک نمونه Layer را به عنوان ویژگی لایه دیگر اختصاص دهید ، لایه بیرونی شروع به ردیابی وزن لایه داخلی می کند.

ما توصیه می کنیم ایجاد چنین زیر لایه در __init__() روش (از زیر لایه های معمولا یک روش ایجاد خواهد شد که، آنها ساخته شده خواهد شد زمانی که لایه بیرونی ساخته شده می شود).

# 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() روش

هنگام نوشتن call() روش از یک لایه، شما می توانید از دست دادن تانسورها ایجاد می کند که شما می خواهید به استفاده از بعد، هنگام نوشتن حلقه های آموزشی خود را. این شدنی است با تماس با self.add_loss(value) :

# 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

این زیان (از جمله کسانی ایجاد شده توسط هر لایه داخلی) می تواند از طریق بازیابی layer.losses . این ویژگی تنظیم مجدد در آغاز هر است __call__() به لایه های سطح بالا، به طوری که layer.losses همیشه شامل ارزش از دست دادن ایجاد شده در طول آخرین پاس رو به جلو.

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

علاوه بر این، loss اموال را نیز شامل زیان تنظیم ایجاد شده برای وزن هر لایه داخلی:

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.0016696099>]

این ضررها هنگام نوشتن حلقه های آموزشی مانند موارد زیر باید در نظر گرفته شوند:

# 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))

برای یک راهنمای دقیق در مورد نوشتن حلقه آموزش، نگاه کنید به راهنمایی برای نوشتن یک حلقه آموزش از ابتدا .

این زیان نیز یکپارچه با کار fit() (آنها به طور خودکار خلاصه و اضافه شده به از دست دادن اصلی، در صورت وجود):

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`, the 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 103ms/step - loss: 0.3750
1/1 [==============================] - 0s 44ms/step - loss: 0.0230
<keras.callbacks.History at 0x7fd0f80b3290>

add_metric() روش

به طور مشابه به add_loss() ، لایه نیز دارند add_metric() روش برای ردیابی از میانگین متحرک یک مقدار در طول آموزش.

لایه زیر را در نظر بگیرید: یک لایه "نقطه پایانی لجستیک". طول می کشد تا به عنوان ورودی پیش بینی و اهداف، آن را محاسبه از دست دادن که آن را از طریق آهنگ add_loss() ، و آن را محاسبه اسکالر دقت، که آن را از طریق آهنگ 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)

متریک ردیابی در این راه از طریق در دسترس هستند layer.metrics :

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: [<keras.metrics.BinaryAccuracy object at 0x7fd1b0214810>]
current accuracy value: 1.0

درست مثل برای add_loss() ، این معیارها توسط ردیابی fit() :

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 242ms/step - loss: 0.9954 - binary_accuracy: 0.0000e+00
<keras.callbacks.History at 0x7fd0f80b3110>

به صورت اختیاری می توانید سریال سازی را در لایه های خود فعال کنید

اگر شما نیاز به لایه های سفارشی خود را به serializable عنوان بخشی از یک مدل کاربردی ، شما به صورت اختیاری می تواند پیاده سازی get_config() روش:

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}

توجه داشته باشید که __init__() روش از پایه Layer کلاس برخی از آرگومان های کلیدی طول می کشد، در یک خاص name و dtype . این تمرین خوبی به تصویب این استدلال به کلاس پدر و مادر در این __init__() و آن ها را در پیکربندی لایه:

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}

اگر شما نیاز به انعطاف پذیری بیشتر در هنگام deserializing لایه از پیکربندی آن، شما همچنین می توانید نادیده گرفتن from_config() روش کلاس. این اجرای پایه است from_config() :

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

برای کسب اطلاعات بیشتر در مورد ترتیب و صرفه جویی، کامل را ببینید راهنمای صرفه جویی در و serialize کردن مدل .

ممتاز training استدلال در call() روش

برخی لایه ها، به ویژه BatchNormalization لایه و Dropout لایه، دارای رفتار های مختلف در طول آموزش و استنتاج است. برای چنین لایه، آن عمل استاندارد به افشای یک است training برهان (بولین) در call() روش.

با افشای این استدلال در call() ، شما در ساخته شده در حلقه آموزش و ارزیابی (به عنوان مثال قادر fit() ) لایه به درستی استفاده در آموزش و استنتاج است.

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

ممتاز mask استدلال در call() روش

استدلال دیگر ممتاز پشتیبانی شده توسط call() است mask استدلال است.

آن را در تمام لایه های Keras RNN پیدا خواهید کرد. ماسک یک تانسور بولی است (یک مقدار بولین در هر مرحله زمانی در ورودی) که برای رد کردن برخی از بازه های زمانی ورودی هنگام پردازش داده های زمان سنجی استفاده می شود.

Keras به طور خودکار درست خواهد عبور mask آرگومان به __call__() برای لایه های که از آن حمایت، زمانی که یک ماسک توسط یک لایه قبل تولید شده است. ماسک تولید لایه هستند Embedding لایه پیکربندی شده با mask_zero=True و Masking لایه.

برای کسب اطلاعات بیشتر در مورد پوشش و نحوه ارسال لایه پوشش را فعال کنید، لطفا به راهنمای "درک padding و پوشش" .

Model کلاس

به طور کلی، شما را به استفاده از Layer کلاس برای تعریف بلوکهای محاسبات داخلی، خواهد شد و استفاده از Model کلاس به تعریف مدل بیرونی - شی به شما آموزش خواهد داد.

به عنوان مثال، در یک مدل ResNet50، شما می توانید چندین بلوک RESNET subclassing دارند Layer ، و یک Model جامع و فراگیر در کل شبکه ResNet50.

Model کلاس است API همان Layer ، با تفاوت های زیر:

  • آن را در معرض ساخته شده در حلقه آموزش، ارزیابی و پیش بینی ( model.fit() ، model.evaluate() ، model.predict() ).
  • آن را در معرض لیست لایه های درونی آن، از طریق model.layers اموال.
  • آن را در معرض صرفه جویی و API ترتیب ( save() ، save_weights() ...)

به طور موثر، Layer مربوط کلاس به آنچه که ما به عنوان "لایه" مراجعه کنید در ادبیات (همانطور که در "لایه پیچیدگی" یا "لایه های مکرر") و یا به عنوان یک "بلاک" (همانطور که در "RESNET بلوک" یا "بلوک آغاز به کار" )

در همین حال، Model مربوط کلاس به آنچه که در ادبیات به عنوان یک "مدل" اشاره (همانطور که در "مدل یادگیری عمیق") و یا به عنوان یک "شبکه" (همانطور که در "شبکه های عصبی عمیق").

بنابراین اگر شما می پرسیم "باید استفاده کنم Layer کلاس و یا Model کلاس؟"، از خودتان بپرسید: آیا من به پاسخ نیاز fit() بر روی آن؟ آیا من نیاز به پاسخ save() بر روی آن؟ اگر چنین است، با رفتن Model . اگر نه (یا به دلیل کلاس خود را فقط یک بلوک در یک سیستم بزرگتر است، و یا اینکه شما در حال نوشتن آموزش و صرفه جویی در کد خود را)، استفاده Layer .

به عنوان مثال، ما می تواند ما را به عنوان مثال مینی RESNET بالا، و استفاده از آن برای ساخت یک Model که ما می تواند با آموزش fit() ، و که ما می تواند با صرفه جویی save_weights() :

class ResNet(tf.keras.Model):

    def __init__(self, num_classes=1000):
        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)

جمع بندی همه چیز: یک مثال سرتاسری

در اینجا چیزی است که تا کنون آموخته اید:

  • Layer محفظهای قرار دادن یک دولت (در ایجاد __init__() و یا build() ) و برخی از محاسبات (تعریف شده در call() ).
  • لایه ها را می توان بصورت بازگشتی برای ایجاد بلوک های جدید و بزرگتر محاسبه کرد.
  • لایه می تواند ایجاد و زیان مسیر (معمولا زیان تنظیم) و همچنین معیارهای، از طریق add_loss() و add_metric()
  • ظرف بیرونی، چیزی که شما می خواهید برای آموزش، یک است Model . Model درست مثل یک Layer ، اما با آموزش و ترتیب آب و برق اضافه شده است.

بیایید همه این موارد را با هم در یک مثال سرتاسری قرار دهیم: ما قصد داریم یک Vodation AutoEncoder (VAE) را پیاده سازی کنیم. ما آن را بر روی ارقام MNIST آموزش خواهیم داد.

VAE ما این خواهد بود یک زیر کلاس از Model ، ساخته شده به عنوان یک ترکیب تو در تو از لایه هایی که زیر کلاس Layer . این از دست دادن منظم (واگرایی KL) را نشان می دهد.

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 بنویسیم:

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.3729
step 100: mean loss = 0.1265
step 200: mean loss = 0.0996
step 300: mean loss = 0.0895
step 400: mean loss = 0.0844
step 500: mean loss = 0.0810
step 600: mean loss = 0.0789
step 700: mean loss = 0.0773
step 800: mean loss = 0.0761
step 900: mean loss = 0.0751
Start of epoch 1
step 0: mean loss = 0.0748
step 100: mean loss = 0.0741
step 200: mean loss = 0.0736
step 300: mean loss = 0.0731
step 400: mean loss = 0.0728
step 500: mean loss = 0.0724
step 600: mean loss = 0.0721
step 700: mean loss = 0.0718
step 800: mean loss = 0.0715
step 900: mean loss = 0.0713

توجه داشته باشید که پس از VAE است subclassing Model ، ویژگی های آن ساخته شده است در حلقه آموزش. بنابراین شما همچنین می توانید آن را به این صورت آموزش دهید:

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 [==============================] - 3s 3ms/step - loss: 0.0747
Epoch 2/2
938/938 [==============================] - 2s 3ms/step - loss: 0.0676
<keras.callbacks.History at 0x7fcd2ad6bed0>

فراتر از توسعه شی گرا: API عملکردی

آیا این مثال برای شما توسعه شی گرا بیش از حد بود؟ شما همچنین می توانید مدل با استفاده از ساخت API کاربردی . نکته مهم این است که انتخاب یک سبک یا سبک دیگر مانع از استفاده از اجزای نوشته شده در سبک دیگر نمی شود: شما همیشه می توانید ترکیب و مطابقت داشته باشید.

به عنوان مثال، به عنوان مثال API کاربردی زیر استفاده مجدد همان Sampling لایه ما در مثال بالا تعریف می شود:

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 [==============================] - 3s 3ms/step - loss: 0.0749
Epoch 2/3
938/938 [==============================] - 2s 3ms/step - loss: 0.0676
Epoch 3/3
938/938 [==============================] - 2s 3ms/step - loss: 0.0675
<keras.callbacks.History at 0x7fcd2b3a37d0>

برای کسب اطلاعات بیشتر، مطمئن شوید که به خواندن راهنمای API کاربردی .