I am implementing the following model:
def ConnectomeCNNAutoencoder(input_shape, keep_pr=0.65, n_filter=32, n_dense1=64, n_classes=2,
mode="autoencoder", sign="neg"):
input_1 = Input(shape=input_shape)
# Convolutional Encoder
bias_init = tf.constant_initializer(value=0.001)
conv1 = Conv2D(filters=n_filter , kernel_size=(1,input_shape[1]), strides=(1, 1),
padding= "valid", activation="selu", # "selu"
kernel_initializer="glorot_uniform",
bias_initializer=bias_init, name="conv1")(input_1)
dropout1 = Dropout(keep_pr, name="dropout1")(conv1)
conv2 = Conv2D(filters=n_filter*2 , kernel_size=(input_shape[1],1), strides=(1, 1),
padding= "valid", activation="selu",
kernel_initializer="glorot_uniform",
bias_initializer=bias_init, name="conv2")(dropout1)
encoded = Dropout(keep_pr, name="dropout2")(conv2)
# Classification
reshape = Reshape((n_filter*2,), name="reshape1")(encoded)
dense1 = Dense(n_dense1, activation="selu", name="dense1", kernel_regularizer=keras.regularizers.l1_l2())(reshape)
if n_classes == 1:
activation = "sigmoid"
else:
activation = "softmax"
output = Dense(n_classes, activation=activation, name="output")(dense1)
# Decoder
dense2 = Dense(n_dense1, activation="selu", name="dense2")(output)
dim_reconstruct = tuple(encoded.get_shape().as_list())
reshape2 = Reshape(dim_reconstruct[1:], name="reshape2")(dense2)
conv3 = Conv2DTranspose(filters=n_filter*2 , kernel_size=(1,1), strides=(1, 1),
padding= "valid", activation="selu", # "selu"
kernel_initializer="glorot_uniform",
bias_initializer=bias_init, name="conv3")(reshape2)
conv4 = Conv2DTranspose(filters=n_filter , kernel_size=(input_shape[1],1), strides=(1, 1),
padding= "valid", activation="selu", # "selu"
kernel_initializer="glorot_uniform",
bias_initializer=bias_init, name="conv4")(conv3)
if sign == "pos":
reconstructed_activation = "sigmoid"
elif sign == "neg":
reconstructed_activation = "tanh"
reconstructed_input = Conv2DTranspose(filters=input_shape[-1], kernel_size=(1,input_shape[1]), strides=(1, 1),
padding= "valid", activation=reconstructed_activation,
kernel_initializer="glorot_uniform",
bias_initializer=bias_init, name='autoencoder')(conv4)
if mode == "autoencoder":
model = keras.models.Model(inputs=input_1, outputs=[output, reconstructed_input])
elif mode =="encoder":
model = keras.models.Model(inputs=input_1, outputs=encoded)
elif mode == "decoder":
model = keras.models.Model(inputs=input_1, outputs=reconstructed_input)
return model
The model works fine when n_filter=32
and n_dense1=64
, but when I change these variable for other values, this error pops up: "ValueError: total size of new array must be unchanged"
.
I know that is related tothe use of Reshape in reshape2
, but I don't know how to solve this.
How can I solve this?
Thanks!
The problem appears in this line:
reshape2 = Reshape(dim_reconstruct[1:], name="reshape2")(dense2)
Tensor dense2
should be of the shape that could be 'transformed' into shape of dim_reconstruct[1:]
. It means that the product of values of dim_reconstruct[1:]
should be equal to the shape of dense2
(excluding zeroth dimension - batch size, because keras
doesn't count it when derives dimensionalities of tensors).
If n_filters = 30
, dim_reconstruct[1:]
will be [1, 1, 60]
- because you multiplied n_filters
by 2. But number of dense filters has to be equal to the product of values from [1, 1, 60]
, i.e., 60.
I couldn't find any image with transformation of 1d into 3d array. But there's and example with 2d arrays: one can't fit array [1,2,3,4,5]
into 2x3 2d array, but can transform [1,2,3,4,5,6]
into something like [[1, 2, 3], [4, 5, 6]]
So, you could set n_units1
to 60 when call ConnectomeCNNAutoencoder
, or you could derive it automatically instead:
# Decoder
dim_reconstruct = tuple(encoded.get_shape().as_list()) # say, (1, 1, 60)
n_dense2 = np.product(dim_reconstruct[1:]) # will be 60
dense2 = Dense(n_dense2, activation="selu", name="dense2")(output)
reshape2 = Reshape(dim_reconstruct[1:], name="reshape2")(dense2)
Complete example (I removed some arguments that were equal to default values):
import numpy as np
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import Input
from tensorflow.keras.layers import Conv2D, Dropout, Reshape, Dense, Conv2DTranspose
def ConnectomeCNNAutoencoder(input_shape,
keep_pr=0.65,
n_filter=32,
n_dense1=64,
n_classes=2,
mode="autoencoder",
sign="neg"):
input_1 = Input(shape=input_shape)
# Convolutional Encoder
bias_init = tf.constant_initializer(value=0.001)
conv1 = Conv2D(filters=n_filter,
kernel_size=(1, input_shape[1]),
strides=(1, 1),
activation="selu", # "selu"
bias_initializer=bias_init,
name="conv1")(input_1)
dropout1 = Dropout(keep_pr, name="dropout1")(conv1)
conv2 = Conv2D(filters=n_filter * 2,
kernel_size=(input_shape[1], 1),
strides=(1, 1),
activation="selu",
bias_initializer=bias_init,
name="conv2")(dropout1)
encoded = Dropout(keep_pr, name="dropout2")(conv2)
# Classification
reshape = Reshape((n_filter * 2,), name="reshape1")(encoded)
dense1 = Dense(n_dense1,
activation="selu",
name="dense1",
kernel_regularizer=keras.regularizers.l1_l2())(reshape)
if n_classes == 1:
activation = "sigmoid"
else:
activation = "softmax"
output = Dense(n_classes, activation=activation, name="output")(dense1)
# Decoder - Changes here
dim_reconstruct = tuple(encoded.get_shape().as_list())
n_dense2 = np.product(dim_reconstruct[1:])
dense2 = Dense(n_dense2, activation="selu", name="dense2")(output)
reshape2 = Reshape(dim_reconstruct[1:], name="reshape2")(dense2)
conv3 = Conv2DTranspose(filters=n_filter * 2,
kernel_size=(1, 1),
strides=(1, 1),
activation="selu", # "selu"
bias_initializer=bias_init,
name="conv3")(reshape2)
conv4 = Conv2DTranspose(filters=n_filter,
kernel_size=(input_shape[1], 1),
strides=(1, 1),
activation="selu", # "selu"
bias_initializer=bias_init,
name="conv4")(conv3)
if sign == "pos":
reconstructed_activation = "sigmoid"
elif sign == "neg":
reconstructed_activation = "tanh"
reconstructed_input = Conv2DTranspose(filters=input_shape[-1],
kernel_size=(1, input_shape[1]),
strides=(1, 1),
activation=reconstructed_activation,
bias_initializer=bias_init,
name='autoencoder')(conv4)
if mode == "autoencoder":
model = keras.models.Model(inputs=input_1, outputs=[output, reconstructed_input])
elif mode == "encoder":
model = keras.models.Model(inputs=input_1, outputs=encoded)
elif mode == "decoder":
model = keras.models.Model(inputs=input_1, outputs=reconstructed_input)
else:
raise ValueError("Unexpected mode: %s" % mode)
return model
model = ConnectomeCNNAutoencoder((32, 32, 3), n_filter=30, n_dense1=65)