तिथि को रक्षित करें! Google I / O 18-20 मई को पंजीकृत करता है
इस पेज का अनुवाद Cloud Translation API से किया गया है.
Switch to English

उप-आवरण के माध्यम से नए परत और मॉडल बनाना

TensorFlow.org पर देखें Google Colab में चलाएं GitHub पर स्रोत देखें नोटबुक डाउनलोड करें

सेट अप

import tensorflow as tf
from tensorflow import keras

Layer वर्ग: राज्य (भार) और कुछ संगणना का संयोजन

केरस में केंद्रीय अमूर्त में से एक 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(
[[ 8.9605771e-02 -5.8132906e-02 -2.3558782e-02 -5.9220940e-05]
 [ 8.9605771e-02 -5.8132906e-02 -2.3558782e-02 -5.9220940e-05]], 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.00164011 -0.02662886  0.00616307  0.0370644 ]
 [-0.00164011 -0.02662886  0.00616307  0.0370644 ]], 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 तर्क लिया, input_dim उपयोग __init__() में भार w और b के आकार की गणना करने के लिए किया गया था:

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

कई मामलों में, आप अपने इनपुट्स के आकार को पहले से नहीं जान सकते हैं, और जब आप उस मूल्य के बारे में जान जाते हैं, तो कुछ समय के लिए लेयर को इंस्टेंट करने के बाद आपको आलसी बनाना चाहेंगे।

केरस एपीआई में, हम आपकी परत के 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)

परतें पुनरावर्ती रूप से रचना योग्य हैं

यदि आप किसी अन्य लेयर की विशेषता के रूप में एक लेयर इंस्टेंस असाइन करते हैं, तो बाहरी लेयर आंतरिक परत के भार को ट्रैक करना शुरू कर देगी।

हम __init__() विधि में ऐसे __init__() बनाने की सलाह देते हैं (क्योंकि __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) कहकर 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.001774033>]

इन नुकसानों को प्रशिक्षण लूप लिखते समय ध्यान में रखा जाना चाहिए:

# 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 111ms/step - loss: 0.3057
1/1 [==============================] - 0s 44ms/step - loss: 0.0246
<tensorflow.python.keras.callbacks.History at 0x7f557862c4e0>

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

add_loss() लिए की तरह, ये मीट्रिक fit() द्वारा ट्रैक किए गए 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 248ms/step - loss: 0.8016 - binary_accuracy: 0.0000e+00
<tensorflow.python.keras.callbacks.History at 0x7f557860d470>

आप वैकल्पिक रूप से अपनी परतों पर क्रमबद्धता को सक्षम कर सकते हैं

यदि आपको एक कार्यात्मक मॉडल के भाग के रूप में अपनी कस्टम लेयर को क्रमबद्ध करने की आवश्यकता है, तो आप वैकल्पिक रूप से एक 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}

ध्यान दें कि आधार Layer वर्ग की __init__() विधि कुछ कीवर्ड तर्क लेती है, विशेष रूप से एक name और एक dtype । इन तर्कों को __init__() और __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}

यदि आपको इसके from_config() से from_config() को from_config() करते समय अधिक लचीलेपन की आवश्यकता है, तो आप from_config() क्लास मेथड को भी ओवरराइड कर सकते हैं। यह from_config() का आधार कार्यान्वयन है:

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

क्रमांकन और बचत के बारे में अधिक जानने के लिए, मॉडल को सहेजने और क्रमबद्ध करने के लिए संपूर्ण मार्गदर्शिका देखें।

call() पद्धति में विशेषाधिकार training तर्क

कुछ परतें, विशेष रूप से BatchNormalization लेयर और Dropout लेयर, में प्रशिक्षण और अनुमान के दौरान अलग-अलग व्यवहार होते हैं। ऐसी परतों के लिए, call() विधि में एक training (बूलियन) तर्क को उजागर करना मानक अभ्यास है।

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

call() विधि में विशेषाधिकार प्राप्त mask तर्क

call() द्वारा समर्थित अन्य विशेषाधिकार प्राप्त तर्क call() mask तर्क है।

आप इसे सभी केरस आरएनएन परतों में पाएंगे। एक मुखौटा एक बूलियन टेंसर (इनपुट में टाइमस्टेप प्रति एक बूलियन मूल्य) है जिसका उपयोग कुछ इनपुट टाइमस्टेप्स को छोड़ता है जब समय डेटा को संसाधित करता है।

Keras स्वचालित रूप से सही पारित करेंगे mask करने के लिए तर्क __call__() परतों है कि यह समर्थन करते हैं, जब एक मुखौटा एक पूर्व परत द्वारा उत्पन्न होता है के लिए। मास्क जेनरेट होने परतें हैं Embedding परत के साथ विन्यस्त mask_zero=True है, और Masking परत।

मास्किंग-सक्षम परतों को लिखने के तरीके के बारे में अधिक जानने के लिए, कृपया "पैडिंग और मास्किंग को समझना" गाइड देखें

Model वर्ग

सामान्य तौर पर, आप आंतरिक गणना ब्लॉकों को परिभाषित करने के लिए Layer वर्ग का उपयोग करेंगे, और बाहरी मॉडल को परिभाषित करने के लिए Model वर्ग का उपयोग करेंगे - जिस वस्तु को आप प्रशिक्षित करेंगे।

उदाहरण के लिए, एक ResNet50 मॉडल में, आपके पास कई ResNet ब्लॉक होंगे जो Layer उपवर्गित करते हैं, और एक Model पूरे ResNet50 नेटवर्क को शामिल करता है।

Model वर्ग में निम्न अंतर के साथ Layer के समान API है:

  • यह अंतर्निहित प्रशिक्षण, मूल्यांकन और भविष्यवाणी छोरों ( model.fit() , model.evaluate() , model.predict() ) को model.predict()
  • यह model.layers संपत्ति के माध्यम से अपनी आंतरिक परतों की सूची को उजागर करता है।
  • यह बचत और क्रमांकन API ( save() , save_weights() ...) को उजागर करता है

प्रभावी रूप से, Layer क्लास उस चीज़ से मेल खाती है जिसे हम साहित्य में "लेयर" (जैसा कि "कनवल्शन लेयर" या "रीक्रिएट लेयर") या "ब्लॉक" ("रेनेट ब्लॉक" या "इंसेप्शन ब्लॉक" के रूप में संदर्भित करते हैं) ) का है।

इस बीच, Model वर्ग साहित्य में एक "मॉडल" ("गहन शिक्षा मॉडल" के रूप में) या एक "नेटवर्क" ("गहरे तंत्रिका नेटवर्क के रूप में) के रूप में संदर्भित होता है।

इसलिए यदि आप सोच रहे हैं, "क्या मुझे Layer क्लास या Model क्लास का उपयोग करना चाहिए?", अपने आप से पूछें: क्या मुझे इसके लिए fit() कॉल करने की आवश्यकता होगी? क्या मुझे इस पर save() कॉल करना होगा? यदि हां, तो Model साथ जाएं। यदि नहीं (या तो क्योंकि आपकी कक्षा एक बड़ी प्रणाली में सिर्फ एक ब्लॉक है, या क्योंकि आप प्रशिक्षण और बचत कोड स्वयं लिख रहे हैं), तो Layer उपयोग करें।

उदाहरण के लिए, हम अपने मिनी-रेसनेट उदाहरण को ऊपर ले जा सकते हैं, और इसका उपयोग एक 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() में परिभाषित call() ) में बनाया गया है।
  • नए, बड़े संगणना ब्लॉक बनाने के लिए परतों को पुनरावर्ती रूप से नेस्ट किया जा सकता है।
  • लेयर्स add_loss() और add_metric() माध्यम से नुकसान और (आमतौर पर नियमितीकरण के नुकसान) और साथ ही मैट्रिक्स को ट्रैक कर सकते हैं
  • बाहरी कंटेनर, जिस चीज को आप प्रशिक्षित करना चाहते हैं, वह एक Model । एक Model एक Layer तरह है, लेकिन अतिरिक्त प्रशिक्षण और क्रमिक उपयोगिताओं के साथ।

आइए इन सभी चीजों को एक साथ एक एंड-टू-एंड उदाहरण में डालें: हम एक वैरिएशनल ऑटोइंकोडर (वीए) लागू करने जा रहे हैं। हम इसे MNIST अंकों पर प्रशिक्षित करेंगे।

हमारे VAE का एक उपवर्ग हो जाएगा Model , कि उपवर्ग परतों के एक नेस्टेड संरचना के रूप में बनाया गया Layer । इसमें एक नियमितीकरण हानि (केएल विचलन) की सुविधा होगी।

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()))
Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/mnist.npz
11493376/11490434 [==============================] - 0s 0us/step
Start of epoch 0
step 0: mean loss = 0.3603
step 100: mean loss = 0.1262
step 200: mean loss = 0.0997
step 300: mean loss = 0.0895
step 400: mean loss = 0.0845
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.0750
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 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 2ms/step - loss: 0.0945
Epoch 2/2
938/938 [==============================] - 2s 2ms/step - loss: 0.0678
<tensorflow.python.keras.callbacks.History at 0x7f54dc15f550>

वस्तु-उन्मुख विकास से परे: कार्यात्मक एपीआई

क्या यह उदाहरण आपके लिए बहुत अधिक वस्तु-उन्मुख विकास था? आप कार्यात्मक एपीआई का उपयोग करके मॉडल भी बना सकते हैं। महत्वपूर्ण रूप से, एक शैली या किसी अन्य को चुनने से आप अन्य शैली में लिखे गए घटकों का लाभ उठाने से नहीं बचते हैं: आप हमेशा मिश्रण-और-मैच कर सकते हैं।

उदाहरण के लिए, नीचे दी गई कार्यात्मक 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 2ms/step - loss: 0.0950
Epoch 2/3
938/938 [==============================] - 2s 2ms/step - loss: 0.0677
Epoch 3/3
938/938 [==============================] - 2s 2ms/step - loss: 0.0676
<tensorflow.python.keras.callbacks.History at 0x7f54d00b9630>

अधिक जानकारी के लिए, कार्यात्मक एपीआई गाइड को पढ़ना सुनिश्चित करें।