Tensorflow:通过子类化的卷积自动编码器
Tensorflow : convolutional autoencoder via subclassing
我正在玩一些 Keras 示例,通过子类定义模型,但我无法让它工作。
from keras import layers, Model
from keras.datasets import mnist
from keras.callbacks import TensorBoard
import numpy as np
import datetime
import os
class Encoder(Model):
def __init__(self, name: str = "encoder"):
super(Encoder, self).__init__(name=name)
self._conv16 = layers.Conv2D(16, (3, 3), activation='relu', padding='same', name="conv16")
self._conv8 = layers.Conv2D(8, (3, 3), activation='relu', padding='same', name="conv8")
self._max_pool = layers.MaxPooling2D((2, 2), padding='same', name="max_pool")
def call(self, inputs: np.ndarray):
x = layers.Conv2D(16, (3, 3), activation='relu', padding='same')(inputs)
x = layers.MaxPooling2D((2, 2), padding='same')(x)
x = layers.Conv2D(8, (3, 3), activation='relu', padding='same')(x)
x = layers.MaxPooling2D((2, 2), padding='same')(x)
x = layers.Conv2D(8, (3, 3), activation='relu', padding='same')(x)
encoded = layers.MaxPooling2D((2, 2), padding='same')(x)
# x = self._conv16(inputs)
# x = self._max_pool(x)
# x = self._conv8(x)
# x = self._max_pool(x)
# x = self._conv8(x)
# encoded = self._max_pool(x)
return encoded
class Decoder(Model):
def __init__(self, name: str = "decoder"):
super(Decoder, self).__init__(name=name)
self._conv16 = layers.Conv2D(16, (3, 3), activation='relu', padding='same', name="conv16")
self._conv8 = layers.Conv2D(8, (3, 3), activation='relu', padding='same', name="conv8")
self._conv1 = layers.Conv2D(1, (3, 3), activation='sigmoid', padding='same', name="conv1")
self._up_sampling = layers.UpSampling2D((2, 2), name="up_samp")
def call(self, inputs: np.ndarray):
x = layers.Conv2D(8, (3, 3), activation='relu', padding='same')(inputs)
x = layers.UpSampling2D((2, 2))(x)
x = layers.Conv2D(8, (3, 3), activation='relu', padding='same')(x)
x = layers.UpSampling2D((2, 2))(x)
x = layers.Conv2D(16, (3, 3), activation='relu')(x)
x = layers.UpSampling2D((2, 2))(x)
decoded = layers.Conv2D(1, (3, 3), activation='sigmoid', padding='same')(x)
# x = self._conv8(inputs)
# x = self._up_sampling(x)
# x = self._conv8(x)
# x = self._up_sampling(x)
# x = self._conv16(x)
# x = self._up_sampling(x)
# decoded = self._conv1(x)
return decoded
class Autoencoder(Model):
def __init__(self, name: str = "autoencoder"):
super(Autoencoder, self).__init__(name=name)
self.encoder = Encoder()
self.decoder = Decoder()
def call(self, inputs: np.ndarray):
encoded = self.encoder(inputs)
reconstructed = self.decoder(encoded)
return reconstructed
(x_train, _), (x_test, _) = mnist.load_data()
x_train = x_train.astype('float32') / 255.
x_test = x_test.astype('float32') / 255.
x_train = np.reshape(x_train, (len(x_train), 28, 28, 1))
x_test = np.reshape(x_test, (len(x_test), 28, 28, 1))
print(x_train.shape)
print(x_test.shape)
autoencoder = Autoencoder()
autoencoder.compile(optimizer='adam', loss='binary_crossentropy')
autoencoder.fit(x_train, x_train,
epochs=50,
batch_size=128,
shuffle=True,
validation_data=(x_test, x_test)
首先,我无法使注释代码正常工作。每当我尝试使用它时,我都会收到这样的错误:“ValueError:层“conv8”的输入 0 与层不兼容:输入形状的预期轴 -1 的值为 1,但收到的输入形状为(60000、56、56, 8)”。我无法在模型定义中发现差异。
其次,运行上面的代码给了我:
ValueError: tf.function only supports singleton tf.Variables created on the first call. Make sure the tf.Variable is only created once or created outside tf.function. See https://www.tensorflow.org/guide/function#creating_tfvariables for more information.
我不确定我做错了什么。
在您的代码中,有许多问题需要解决。例如,
- 问题 1:在
call
方法中,inputs
参数应该是张量而不是 numpy 数组。
- 问题 2:在模型子类化中,您应该在
init
方法或 [=18] 中启动 可训练层 =] 方法并使用 call
函数中的实例。这是您收到以下错误的原因。
ValueError: tf.function only supports singleton tf.Variables were created on the first call. Make sure the tf. Variable is only created once or created outside tf. function. See https://www.tensorflow.org/guide/function#creating_tfvariables for more information.
- 问题 3:在您的编码器块中,您似乎使用了两次
self._conv8
,这也发生在解码器块中。不应该是这样的。如果需要调用它们两次(或多次),则需要在 init
(或 build
)方法中分别启动它们。我认为这是子类化方法的 so-called 缺点之一,您需要在 init
中启动 N 次层并在 call
方法中再转发它们的实例 N 次。这是您收到以下错误的原因。 (旁注,将相同的输入传递到相同的可训练层也称为权重共享,我认为这不是这里的意图。)
ValueError: Input 0 of layer "conv8" is incompatible with the layer: expected axis -1of input shape to have value 1, but received input with shape (60000, 56, 56, 8)
解决方案
通过解决上述问题,这里是工作代码。另外,请注意,从 tensorflow
.
导入 keras
更好更合适
编码器
from tensorflow.keras import layers, Model
from tensorflow.keras.datasets import mnist
from tensorflow.keras.callbacks import TensorBoard
import numpy as np
class Encoder(Model):
def __init__(self, name: str = "encoder"):
super().__init__(name=name)
self._conv16 = layers.Conv2D(16, (3, 3), activation='relu',
padding='same', name="conv16")
self._conv8 = layers.Conv2D(8, (3, 3), activation='relu',
padding='same', name="conv8")
self._max_pool = layers.MaxPooling2D((2, 2), padding='same',
name="max_pool")
def call(self, inputs):
x = self._conv16(inputs)
x = self._max_pool(x)
encoded = self._conv8(x)
return encoded
解码器
class Decoder(Model):
def __init__(self, name: str = "decoder"):
super(Decoder, self).__init__(name=name)
self._conv16 = layers.Conv2D(16, (3, 3),
activation='relu',
padding='same', name="conv16")
self._conv8 = layers.Conv2D(8, (3, 3),
activation='relu',
padding='same', name="conv8")
self._conv1 = layers.Conv2D(1, (3, 3),
activation='sigmoid',
padding='same', name="conv1")
self._up_sampling = layers.UpSampling2D((2, 2), name="up_samp")
def call(self, inputs):
x = self._conv8(inputs)
x = self._up_sampling(x)
x = self._conv16(x)
decoded = self._conv1(x)
return decoded
自编码器
class Autoencoder(Model):
def __init__(self, name: str = "autoencoder"):
super(Autoencoder, self).__init__(name=name)
self.encoder = Encoder()
self.decoder = Decoder()
def call(self, inputs):
encoded = self.encoder(inputs)
reconstructed = self.decoder(encoded)
return reconstructed
执行
(x_train, _), (x_test, _) = mnist.load_data()
x_train = x_train.astype('float32') / 255.
x_test = x_test.astype('float32') / 255.
x_train = np.reshape(x_train, (len(x_train), 28, 28, 1))
x_test = np.reshape(x_test, (len(x_test), 28, 28, 1))
print(x_train.shape)
print(x_test.shape)
autoencoder = Autoencoder()
autoencoder.compile(optimizer='adam', loss='binary_crossentropy')
autoencoder.fit(x_train, x_train,
epochs=50,
batch_size=128,
shuffle=True,
validation_data=(x_test, x_test))
Epoch 1/5
12ms/step - loss: 0.1100 - val_loss: 0.0676
Epoch 2/5
12ms/step - loss: 0.0666 - val_loss: 0.0651
Epoch 3/5
12ms/step - loss: 0.0649 - val_loss: 0.0641
Epoch 4/5
12ms/step - loss: 0.0642 - val_loss: 0.0635
Epoch 5/5
11ms/step - loss: 0.0636 - val_loss: 0.0631
预测
import matplotlib.pyplot as plt
fig, ax = plt.subplots(1, 2)
y_pred = autoencoder.predict(x_test)
ax[0].imshow(x_test[10, :,:, 0])
ax[1].imshow(y_pred[10, :,:, 0])
我正在玩一些 Keras 示例,通过子类定义模型,但我无法让它工作。
from keras import layers, Model
from keras.datasets import mnist
from keras.callbacks import TensorBoard
import numpy as np
import datetime
import os
class Encoder(Model):
def __init__(self, name: str = "encoder"):
super(Encoder, self).__init__(name=name)
self._conv16 = layers.Conv2D(16, (3, 3), activation='relu', padding='same', name="conv16")
self._conv8 = layers.Conv2D(8, (3, 3), activation='relu', padding='same', name="conv8")
self._max_pool = layers.MaxPooling2D((2, 2), padding='same', name="max_pool")
def call(self, inputs: np.ndarray):
x = layers.Conv2D(16, (3, 3), activation='relu', padding='same')(inputs)
x = layers.MaxPooling2D((2, 2), padding='same')(x)
x = layers.Conv2D(8, (3, 3), activation='relu', padding='same')(x)
x = layers.MaxPooling2D((2, 2), padding='same')(x)
x = layers.Conv2D(8, (3, 3), activation='relu', padding='same')(x)
encoded = layers.MaxPooling2D((2, 2), padding='same')(x)
# x = self._conv16(inputs)
# x = self._max_pool(x)
# x = self._conv8(x)
# x = self._max_pool(x)
# x = self._conv8(x)
# encoded = self._max_pool(x)
return encoded
class Decoder(Model):
def __init__(self, name: str = "decoder"):
super(Decoder, self).__init__(name=name)
self._conv16 = layers.Conv2D(16, (3, 3), activation='relu', padding='same', name="conv16")
self._conv8 = layers.Conv2D(8, (3, 3), activation='relu', padding='same', name="conv8")
self._conv1 = layers.Conv2D(1, (3, 3), activation='sigmoid', padding='same', name="conv1")
self._up_sampling = layers.UpSampling2D((2, 2), name="up_samp")
def call(self, inputs: np.ndarray):
x = layers.Conv2D(8, (3, 3), activation='relu', padding='same')(inputs)
x = layers.UpSampling2D((2, 2))(x)
x = layers.Conv2D(8, (3, 3), activation='relu', padding='same')(x)
x = layers.UpSampling2D((2, 2))(x)
x = layers.Conv2D(16, (3, 3), activation='relu')(x)
x = layers.UpSampling2D((2, 2))(x)
decoded = layers.Conv2D(1, (3, 3), activation='sigmoid', padding='same')(x)
# x = self._conv8(inputs)
# x = self._up_sampling(x)
# x = self._conv8(x)
# x = self._up_sampling(x)
# x = self._conv16(x)
# x = self._up_sampling(x)
# decoded = self._conv1(x)
return decoded
class Autoencoder(Model):
def __init__(self, name: str = "autoencoder"):
super(Autoencoder, self).__init__(name=name)
self.encoder = Encoder()
self.decoder = Decoder()
def call(self, inputs: np.ndarray):
encoded = self.encoder(inputs)
reconstructed = self.decoder(encoded)
return reconstructed
(x_train, _), (x_test, _) = mnist.load_data()
x_train = x_train.astype('float32') / 255.
x_test = x_test.astype('float32') / 255.
x_train = np.reshape(x_train, (len(x_train), 28, 28, 1))
x_test = np.reshape(x_test, (len(x_test), 28, 28, 1))
print(x_train.shape)
print(x_test.shape)
autoencoder = Autoencoder()
autoencoder.compile(optimizer='adam', loss='binary_crossentropy')
autoencoder.fit(x_train, x_train,
epochs=50,
batch_size=128,
shuffle=True,
validation_data=(x_test, x_test)
首先,我无法使注释代码正常工作。每当我尝试使用它时,我都会收到这样的错误:“ValueError:层“conv8”的输入 0 与层不兼容:输入形状的预期轴 -1 的值为 1,但收到的输入形状为(60000、56、56, 8)”。我无法在模型定义中发现差异。
其次,运行上面的代码给了我:
ValueError: tf.function only supports singleton tf.Variables created on the first call. Make sure the tf.Variable is only created once or created outside tf.function. See https://www.tensorflow.org/guide/function#creating_tfvariables for more information.
我不确定我做错了什么。
在您的代码中,有许多问题需要解决。例如,
- 问题 1:在
call
方法中,inputs
参数应该是张量而不是 numpy 数组。 - 问题 2:在模型子类化中,您应该在
init
方法或 [=18] 中启动 可训练层 =] 方法并使用call
函数中的实例。这是您收到以下错误的原因。
ValueError: tf.function only supports singleton tf.Variables were created on the first call. Make sure the tf. Variable is only created once or created outside tf. function. See https://www.tensorflow.org/guide/function#creating_tfvariables for more information.
- 问题 3:在您的编码器块中,您似乎使用了两次
self._conv8
,这也发生在解码器块中。不应该是这样的。如果需要调用它们两次(或多次),则需要在init
(或build
)方法中分别启动它们。我认为这是子类化方法的 so-called 缺点之一,您需要在init
中启动 N 次层并在call
方法中再转发它们的实例 N 次。这是您收到以下错误的原因。 (旁注,将相同的输入传递到相同的可训练层也称为权重共享,我认为这不是这里的意图。)
ValueError: Input 0 of layer "conv8" is incompatible with the layer: expected axis -1of input shape to have value 1, but received input with shape (60000, 56, 56, 8)
解决方案
通过解决上述问题,这里是工作代码。另外,请注意,从 tensorflow
.
keras
更好更合适
编码器
from tensorflow.keras import layers, Model
from tensorflow.keras.datasets import mnist
from tensorflow.keras.callbacks import TensorBoard
import numpy as np
class Encoder(Model):
def __init__(self, name: str = "encoder"):
super().__init__(name=name)
self._conv16 = layers.Conv2D(16, (3, 3), activation='relu',
padding='same', name="conv16")
self._conv8 = layers.Conv2D(8, (3, 3), activation='relu',
padding='same', name="conv8")
self._max_pool = layers.MaxPooling2D((2, 2), padding='same',
name="max_pool")
def call(self, inputs):
x = self._conv16(inputs)
x = self._max_pool(x)
encoded = self._conv8(x)
return encoded
解码器
class Decoder(Model):
def __init__(self, name: str = "decoder"):
super(Decoder, self).__init__(name=name)
self._conv16 = layers.Conv2D(16, (3, 3),
activation='relu',
padding='same', name="conv16")
self._conv8 = layers.Conv2D(8, (3, 3),
activation='relu',
padding='same', name="conv8")
self._conv1 = layers.Conv2D(1, (3, 3),
activation='sigmoid',
padding='same', name="conv1")
self._up_sampling = layers.UpSampling2D((2, 2), name="up_samp")
def call(self, inputs):
x = self._conv8(inputs)
x = self._up_sampling(x)
x = self._conv16(x)
decoded = self._conv1(x)
return decoded
自编码器
class Autoencoder(Model):
def __init__(self, name: str = "autoencoder"):
super(Autoencoder, self).__init__(name=name)
self.encoder = Encoder()
self.decoder = Decoder()
def call(self, inputs):
encoded = self.encoder(inputs)
reconstructed = self.decoder(encoded)
return reconstructed
执行
(x_train, _), (x_test, _) = mnist.load_data()
x_train = x_train.astype('float32') / 255.
x_test = x_test.astype('float32') / 255.
x_train = np.reshape(x_train, (len(x_train), 28, 28, 1))
x_test = np.reshape(x_test, (len(x_test), 28, 28, 1))
print(x_train.shape)
print(x_test.shape)
autoencoder = Autoencoder()
autoencoder.compile(optimizer='adam', loss='binary_crossentropy')
autoencoder.fit(x_train, x_train,
epochs=50,
batch_size=128,
shuffle=True,
validation_data=(x_test, x_test))
Epoch 1/5
12ms/step - loss: 0.1100 - val_loss: 0.0676
Epoch 2/5
12ms/step - loss: 0.0666 - val_loss: 0.0651
Epoch 3/5
12ms/step - loss: 0.0649 - val_loss: 0.0641
Epoch 4/5
12ms/step - loss: 0.0642 - val_loss: 0.0635
Epoch 5/5
11ms/step - loss: 0.0636 - val_loss: 0.0631
预测
import matplotlib.pyplot as plt
fig, ax = plt.subplots(1, 2)
y_pred = autoencoder.predict(x_test)
ax[0].imshow(x_test[10, :,:, 0])
ax[1].imshow(y_pred[10, :,:, 0])