I've been at my wits end trying to solve this issue with Conv1D in Keras. Basically, I have a vector bathyZ that is 100 x 1. I'd like to do some convolution on it before merging it with 2 scalar inputs Tperiod and AMP_WK to predict another 100 x 1 vector. (bathyZ has spatial variability I'm looking to pick up). This is my first time using tensorflow datasets and parsing/deserializing. I consistently run into shape errors that I can't seem to understand though.
Mainly, it seems like the first dense layer isn't receiving the correct dimensions in its inputs, and I can't figure out why, since the input dimensions for everything seem to make sense to me. Why is it expecting 6402 and getting (None, 165)? I'm debugging on a single record, hence the small batch size, if that was a concern. It should work regardless though, right? My understanding is that my input should be (None,100,1) to allow for different batch sizes for a 100 x 1 sequence. I've tried reshaping a few ways, but none of them have seemed to work, so maybe I'm missing something more fundamental
Error message:
ValueError: Exception encountered when calling Functional.call().
Input 0 of layer "dense_110" is incompatible with the layer: expected axis -1 of input shape to have value 6402, but received input with shape (None, 165)
Arguments received by Functional.call():
• inputs={'bathyZ': 'tf.Tensor(shape=(None, 100, 1), dtype=float32)', 'AMP_WK': 'tf.Tensor(shape=(None, 1), dtype=float32)', 'Tperiod': 'tf.Tensor(shape=(None, 1), dtype=float32)'}
• training=True
• mask={'bathyZ': 'None', 'AMP_WK': 'None', 'Tperiod': 'None'}
Code:
feature_description = {
'bathyZ': tf.io.FixedLenFeature([], tf.string),
'bathyZ_shape': tf.io.FixedLenFeature([3], tf.int64),
'AMP_WK': tf.io.FixedLenFeature([], tf.float32),
'Tperiod': tf.io.FixedLenFeature([], tf.float32),
'skew': tf.io.FixedLenFeature([], tf.string),
'skew_shape': tf.io.FixedLenFeature([3], tf.int64),
}
def _parse_function(proto):
# Parse
parsed_features = tf.io.parse_single_example(proto, feature_description)
# Decode/reshape the serialized tensors
bathyZ = parsed_features['bathyZ']
bathyZ = tf.io.parse_tensor(bathyZ, out_type=tf.float32)
bathyZ = tf.reshape(bathyZ, [100, 1])
skew = parsed_features['skew']
skew = tf.io.parse_tensor(skew, out_type=tf.float32)
skew = tf.reshape(skew, [100, 1])
# Get other inputs, reshape
AMP_WK = parsed_features['AMP_WK']
Tperiod = parsed_features['Tperiod']
AMP_WK = tf.reshape(AMP_WK, [1])
Tperiod = tf.reshape(Tperiod, [1])
# Create tuple
inputs = {'bathyZ': bathyZ, 'AMP_WK': AMP_WK, 'Tperiod': Tperiod}
outputs = {'skew': skew}
return inputs, outputs
# Create a TFRecordDataset and map the parsing function
tfrecord_path = 'ML_0004.tfrecord'
dataset = tf.data.TFRecordDataset(tfrecord_path)
dataset = dataset.map(_parse_function)
# Model
def create_model():
# Tensor input branch (shape: 100 timesteps, 1 feature)
bathyZ = Input(shape=(100, 1), name='bathyZ')
x = layers.Conv1D(32, 3, activation='relu', padding='same')(bathyZ)
x = layers.Conv1D(64, 3, activation='relu', padding='same')(x)
x = layers.Flatten()(x)
# Scalar inputs
AMP_WK = Input(shape=(1,), name='AMP_WK')
Tperiod = Input(shape=(1,), name='Tperiod')
# Combine all branches
combined = layers.concatenate([x, AMP_WK, Tperiod])
# Fully connected layer
z = layers.Dense(64, activation='relu')(combined)
z = layers.Dense(128, activation='relu')(z)
# Output layer (tensor output, same shape as input tensor)
skew = layers.Dense(100, activation='linear', name='skew')(z)
# Create the model
model = models.Model(inputs=[bathyZ, AMP_WK, Tperiod], outputs=skew)
return model
# Example usage:
model = create_model()
model.compile(optimizer='adam', loss='mse')
model.summary()
dataset = dataset.batch(1)
model.fit(dataset)
I tried reshaping various input tensors in the parsing and preprocessing steps to different versions of [1,100], [1,100,1] and so on, and tracking how the shape evolves. But I always run into some sort of dimension error
For some reason, despite the inputs being stored as a key-value, the order in which they are given to model = models.Model
matters. If you reverse the order, and make it model = models.Model(inputs=[Tperiod, AMP_WK, bathyZ], outputs=skew)
, it works.