![]() | ![]() | ![]() | ![]() |
Thiết lập
import tensorflow as tf
from tensorflow import keras
Layer
: sự kết hợp của trạng thái (trọng số) và một số tính toán
Một trong những trừu tượng trung tâm trong Keras là Layer
. Một lớp đóng gói cả trạng thái ("trọng số" của lớp) và sự chuyển đổi từ đầu vào thành đầu ra ("lệnh gọi", chuyển tiếp của lớp).
Đây là một lớp được kết nối dày đặc. Nó có một trạng thái: các biến w
và 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
Bạn sẽ sử dụng một lớp bằng cách gọi nó trên một số (các) đầu vào tensor, giống như một hàm Python.
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)
Lưu ý rằng trọng số w
và b
được lớp tự động theo dõi khi được đặt làm thuộc tính lớp:
assert linear_layer.weights == [linear_layer.w, linear_layer.b]
Lưu ý rằng bạn cũng có quyền truy cập vào một phím tắt nhanh hơn để thêm trọng lượng vào một lớp: phương thức 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)
Các lớp có thể có trọng lượng không thể đào tạo
Bên cạnh trọng lượng có thể huấn luyện, bạn cũng có thể thêm các trọng lượng không thể huấn luyện vào một lớp. Trọng lượng như vậy có nghĩa là không được tính đến trong quá trình nhân giống ngược, khi bạn đang đào tạo lớp.
Dưới đây là cách thêm và sử dụng trọng lượng không thể đào tạo:
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.]
Nó là một phần của layer.weights
, nhưng nó được phân loại là trọng lượng không thể đào tạo:
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: []
Phương pháp hay nhất: trì hoãn việc tạo trọng lượng cho đến khi biết hình dạng của các đầu vào
Lớp Linear
của chúng tôi ở trên đã lấy một đối số input_dim
được sử dụng để tính hình dạng của trọng số w
và b
trong __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
Trong nhiều trường hợp, bạn có thể không biết trước kích thước đầu vào của mình và bạn muốn tạo trọng số một cách lười biếng khi biết giá trị đó, một thời gian sau khi khởi tạo lớp.
Trong API Keras, chúng tôi khuyên bạn nên tạo trọng số lớp trong phương thức build(self, inputs_shape)
của lớp của bạn. Như thế này:
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
Phương thức __call__()
của lớp của bạn sẽ tự động chạy bản dựng lần đầu tiên nó được gọi. Bây giờ bạn có một lớp lười biếng và do đó dễ sử dụng hơn:
# 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)
Các lớp có thể kết hợp đệ quy
Nếu bạn chỉ định một cá thể Lớp làm thuộc tính của một Lớp khác, thì lớp bên ngoài sẽ bắt đầu theo dõi trọng số của lớp bên trong.
Chúng tôi khuyên bạn nên tạo các lớp con như vậy trong phương thức __init__()
(vì các lớp con thường sẽ có một phương thức xây dựng, chúng sẽ được tạo khi lớp ngoài được tạo).
# 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
Phương thức add_loss()
Khi viết phương thức call()
của một lớp, bạn có thể tạo các hàm giảm tổn thất mà bạn sẽ muốn sử dụng sau này, khi viết vòng lặp đào tạo của mình. Điều này có thể thực hiện được bằng cách gọi 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
Những tổn thất này (bao gồm cả những tổn thất được tạo ra bởi bất kỳ lớp bên trong nào) có thể được truy xuất thông qua layer.losses
. Thuộc tính này được đặt lại ở đầu mỗi __call__()
cho lớp cấp cao nhất, do đó layer.losses
luôn chứa các giá trị mất mát được tạo trong lần chuyển tiếp cuối cùng.
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
Ngoài ra, thuộc tính loss
cũng chứa các tổn thất chính quy được tạo ra cho trọng lượng của bất kỳ lớp bên trong nào:
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>]
Những tổn thất này có nghĩa là được tính đến khi viết các vòng lặp đào tạo, như sau:
# 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))
Để có hướng dẫn chi tiết về cách viết vòng lặp huấn luyện, hãy xem hướng dẫn viết vòng lặp huấn luyện từ đầu .
Các khoản lỗ này cũng hoạt động trơn tru với fit()
(chúng được tự động tổng hợp và cộng vào khoản lỗ chính, nếu có):
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>
Phương thức add_metric()
Tương tự như add_loss()
, các lớp cũng có một phương thức add_metric()
để theo dõi đường trung bình của một số lượng trong quá trình huấn luyện.
Hãy xem xét lớp sau: lớp "điểm cuối logistic". Nó có vai trò là các dự đoán & mục tiêu đầu vào, nó tính toán tổn thất mà nó theo dõi thông qua add_loss()
và nó tính toán một đại lượng vô hướng chính xác, nó theo dõi thông qua 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)
Các chỉ số được theo dõi theo cách này có thể truy cập được qua 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
Cũng giống như đối với add_loss()
, các chỉ số này được theo dõi bởi 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>
Bạn có thể tùy chọn bật tuần tự hóa trên các lớp của mình
Nếu bạn cần các lớp tùy chỉnh của mình có thể tuần tự hóa như một phần của mô hình Chức năng , bạn có thể tùy chọn triển khai phương thức 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}
Lưu ý rằng phương thức __init__()
của Layer
cơ sở nhận một số đối số từ khóa, đặc biệt là name
và kiểu dtype
. Bạn nên chuyển các đối số này cho lớp cha trong __init__()
và đưa chúng vào cấu hình lớp:
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}
Nếu bạn cần linh hoạt hơn khi giải mã lớp từ cấu hình của nó, bạn cũng có thể ghi đè phương thức lớp from_config()
. Đây là cách triển khai cơ bản của from_config()
:
def from_config(cls, config):
return cls(**config)
Để tìm hiểu thêm về tuần tự hóa và lưu, hãy xem hướng dẫn đầy đủ về cách lưu và tuần tự hóa mô hình .
Đối số training
đặc quyền trong phương thức call()
Một số lớp, đặc biệt là lớp BatchNormalization
và lớp Dropout
, có các hành vi khác nhau trong quá trình đào tạo và suy luận. Đối với các lớp như vậy, thông lệ tiêu chuẩn là hiển thị đối số training
(boolean) trong phương thức call()
.
Bằng cách hiển thị đối số này trong call()
, bạn cho phép các vòng đào tạo và đánh giá được tích hợp sẵn (ví dụ: fit()
) để sử dụng chính xác lớp trong đào tạo và suy luận.
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
Đối số mask
đặc quyền trong phương thức call()
Đối số đặc quyền khác được hỗ trợ bởi call()
là đối số mask
.
Bạn sẽ tìm thấy nó trong tất cả các lớp Keras RNN. Mặt nạ là một tensor boolean (một giá trị boolean cho mỗi bước thời gian trong đầu vào) được sử dụng để bỏ qua các bước thời gian đầu vào nhất định khi xử lý dữ liệu thời gian.
Keras sẽ tự động chuyển đối số mask
chính xác cho __call__()
cho các lớp hỗ trợ nó, khi một mặt nạ được tạo bởi một lớp trước. Các lớp tạo mặt nạ là lớp Embedding
định cấu hình với mask_zero=True
và lớp Mặt Masking
.
Để tìm hiểu thêm về tạo mặt nạ và cách viết các lớp hỗ trợ tạo mặt nạ, vui lòng xem hướng dẫn "hiểu về đệm và tạo mặt nạ" .
Lớp người Model
Nói chung, bạn sẽ sử dụng Layer
để xác định các khối tính toán bên trong và sẽ sử dụng lớp Model
để định nghĩa mô hình bên ngoài - đối tượng mà bạn sẽ đào tạo.
Ví dụ, trong mô hình ResNet50, bạn sẽ có một số Layer
phân lớp con của khối ResNet và một Model
duy nhất bao gồm toàn bộ mạng ResNet50.
Lớp Model
có cùng API như Layer
, với những điểm khác biệt sau:
- Nó hiển thị các vòng đào tạo, đánh giá và dự đoán được tích hợp sẵn (
model.fit()
,model.evaluate()
,model.predict()
). - Nó hiển thị danh sách các lớp bên trong của nó, thông qua thuộc tính
model.layers
. - Nó hiển thị các API lưu và tuần tự hóa (
save()
,save_weights()
...)
Về mặt hiệu quả, Layer
tương ứng với những gì chúng tôi đề cập đến trong tài liệu là một "lớp" (như trong "lớp tích chập" hoặc "lớp lặp lại") hoặc như một "khối" (như trong "Khối ResNet" hoặc "Khối khởi động" ).
Trong khi đó, lớp Model
tương ứng với những gì được gọi trong tài liệu là "mô hình" (như trong "mô hình học sâu") hoặc là "mạng" (như trong "mạng nơ-ron sâu").
Vì vậy, nếu bạn đang tự hỏi, "tôi nên sử dụng Layer
hay lớp Model
?", Hãy tự hỏi: liệu tôi có cần gọi fit()
trên đó không? Tôi có cần gọi save()
trên đó không? Nếu vậy, hãy đi với Model
. Nếu không (vì lớp của bạn chỉ là một khối trong một hệ thống lớn hơn hoặc vì bạn đang tự viết mã đào tạo và lưu mã), hãy sử dụng Layer
.
Ví dụ: chúng ta có thể lấy ví dụ về mini-resnet ở trên và sử dụng nó để xây dựng một Model
mà chúng ta có thể đào tạo với fit()
và chúng ta có thể lưu với 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)
Tổng hợp tất cả lại với nhau: một ví dụ từ đầu đến cuối
Đây là những gì bạn đã học được cho đến nay:
- Một
Layer
đóng gói một trạng thái (được tạo trong__init__()
hoặcbuild()
) và một số tính toán (được định nghĩa trongcall()
). - Các lớp có thể được lồng vào nhau một cách đệ quy để tạo ra các khối tính toán mới, lớn hơn.
- Các lớp có thể tạo và theo dõi các khoản lỗ (thường là các khoản lỗ theo quy định) cũng như các chỉ số, thông qua
add_loss()
vàadd_metric()
- Vật chứa bên ngoài, thứ bạn muốn đào tạo, là một
Model
. MộtModel
cũng giống như mộtLayer
, nhưng có thêm các tiện ích đào tạo và tuần tự hóa.
Hãy ghép tất cả những điều này lại với nhau thành một ví dụ từ đầu đến cuối: chúng ta sẽ triển khai Bộ mã hóa tự động biến thể (VAE). Chúng tôi sẽ đào tạo nó trên các chữ số MNIST.
VAE của chúng ta sẽ là một lớp con của Model
, được xây dựng như một thành phần lồng vào nhau của các lớp mà lớp con Layer
. Nó sẽ có đặc điểm là mất điều hòa (phân kỳ 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
Hãy viết một vòng lặp đào tạo đơn giản trên 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
Lưu ý rằng vì VAE là Model
phân lớp nên nó có các vòng huấn luyện tích hợp sẵn. Vì vậy, bạn cũng có thể đã đào tạo nó như thế này:
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>
Ngoài phát triển hướng đối tượng: API chức năng
Ví dụ này có quá nhiều phát triển hướng đối tượng đối với bạn không? Bạn cũng có thể xây dựng các mô hình bằng cách sử dụng API chức năng . Quan trọng là, việc chọn kiểu này hay kiểu khác không ngăn cản bạn tận dụng các thành phần được viết theo kiểu khác: bạn luôn có thể mix-and-match.
Ví dụ: ví dụ API chức năng bên dưới sử dụng lại cùng một lớp Sampling
mà chúng tôi đã xác định trong ví dụ trên:
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>
Để biết thêm thông tin, hãy nhớ đọc hướng dẫn API chức năng .