![]() | ![]() | ![]() | ![]() |
برپایی
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.00962844 -0.01307489 -0.1452128 0.0538918 ] [ 0.00962844 -0.01307489 -0.1452128 0.0538918 ]], 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.05790994 0.060931 -0.0402256 -0.09450993] [ 0.05790994 0.060931 -0.0402256 -0.09450993]], 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)
پیاده سازی build()
به طور جداگانه به عنوان بالا به خوبی نشان داده شده است از هم جدا ایجاد وزن فقط یک بار از با استفاده از وزن در هر تماس. با این حال، برای برخی از لایه های سفارشی پیشرفته، جداسازی ایجاد حالت و محاسبه می تواند غیرعملی باشد. مجریان لایه مجاز به تسلیم ایجاد وزن به اولین __call__()
، اما نیاز به مراقبت است که تماس های بعد از استفاده از وزن است. علاوه بر این، از آنجا که __call__()
است به احتمال زیاد برای اولین بار در داخل یک اجرا شود tf.function
، هر گونه ایجاد متغیر است که می گیرد در __call__()
باید در یک پیچیده tf.init_scope
.
لایه ها به صورت بازگشتی ترکیب می شوند
اگر یک نمونه لایه را به عنوان ویژگی لایه دیگر اختصاص دهید، لایه بیرونی شروع به ردیابی وزن های ایجاد شده توسط لایه داخلی می کند.
ما توصیه می کنیم ایجاد چنین زیر لایه در __init__()
روش و ترک آن را به اولین __call__()
را به دنبال ساخت وزن آنها.
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.0024520475>]
این تلفات باید در هنگام نوشتن حلقه های آموزشی در نظر گرفته شوند، مانند:
# 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 209ms/step - loss: 0.1948 1/1 [==============================] - 0s 49ms/step - loss: 0.0298 <keras.callbacks.History at 0x7fce9052d290>
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 0x7fce90578490>] 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 274ms/step - loss: 0.9291 - binary_accuracy: 0.0000e+00 <keras.callbacks.History at 0x7fce90448c50>
شما به صورت اختیاری می توانید سریال سازی را در لایه های خود فعال کنید
اگر شما نیاز به لایه های سفارشی خود را به 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
، اما با آموزش و ترتیب آب و برق اضافه شده است.
بیایید همه این موارد را در یک مثال سرتاسر کنار هم قرار دهیم: ما یک رمزگذار خودکار متغیر (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.3184 step 100: mean loss = 0.1252 step 200: mean loss = 0.0989 step 300: mean loss = 0.0890 step 400: mean loss = 0.0841 step 500: mean loss = 0.0807 step 600: mean loss = 0.0787 step 700: mean loss = 0.0771 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.0740 step 200: mean loss = 0.0735 step 300: mean loss = 0.0730 step 400: mean loss = 0.0727 step 500: mean loss = 0.0723 step 600: mean loss = 0.0720 step 700: mean loss = 0.0717 step 800: mean loss = 0.0715 step 900: mean loss = 0.0712
توجه داشته باشید که پس از 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.0745 Epoch 2/2 938/938 [==============================] - 3s 3ms/step - loss: 0.0676 <keras.callbacks.History at 0x7fce90282750>
فراتر از توسعه شی گرا: Functional 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.0748 Epoch 2/3 938/938 [==============================] - 3s 3ms/step - loss: 0.0676 Epoch 3/3 938/938 [==============================] - 3s 3ms/step - loss: 0.0676 <keras.callbacks.History at 0x7fce90233cd0>
برای کسب اطلاعات بیشتر، مطمئن شوید که به خواندن راهنمای API کاربردی .