我建立了一个模型,该模型由提供LSTM的CNN组成。我已经将CNN包裹在TimeDistributed包装器中。我已经将训练集(x值)配置为具有5D形状(batch_size,num_steps,image_height,image_width,channels)。尝试训练模型时,出现以下错误:ValueError:检查输入时出错:预期time_distributed_input具有5个维度,但数组的形状为(4,28,28,1)。
我尝试了许多不同的模型配置,并调试了代码。我可以看到ValueError被抛出的位置,但是我看不到任何防止这种情况发生的方法。代码详细信息。
我的模型构建代码:
def build_cnn(input_shape=None):
print('Building the CNN')
model = tfkm.Sequential()
if input_shape:
model.add(tfkl.Conv2D(64, (3, 3), activation='relu', input_shape=input_shape))
else:
model.add(tfkl.Conv2D(64, (3, 3), activation='relu'))
model.add(tfkl.MaxPooling2D((2, 2), strides=(1, 1)))
model.add(tfkl.Conv2D(128, (4, 4), activation='relu'))
model.add(tfkl.MaxPooling2D((2, 2), strides=(2, 2)))
model.add(tfkl.Conv2D(256, (4, 4), activation='relu'))
model.add(tfkl.MaxPooling2D((2, 2), strides=(2, 2)))
# extract features and dropout
model.add(tfkl.Flatten())
return model
def build_lstm(units, return_sequences, dropout):
print('Building the LSTM model')
model = tfkm.Sequential()
model.add(tfkl.LSTM(units, return_sequences=return_sequences, dropout=dropout))
return model
def build_classification_layer(num_classes):
print('Building the classification-layer model')
model = tfkm.Sequential()
# classifier with sigmoid activation for multilabel
model.add(tfkl.Dense(num_classes, activation='sigmoid'))
return model
cnn = build_cnn(input_shape=(28, 28, 1))
lstm = build_lstm(256, False, 0.5)
classification_layer = build_classification_layer(2)
combined_model = tfkm.Sequential()
#combined_model.add(tfkl.TimeDistributed(cnn, batch_input_shape=(20, 4, 28, 28, 1)))
#combined_model.add(tfkl.TimeDistributed(cnn, input_shape=(4, 28, 28, 1), batch_size=20))
combined_model.add(tfkl.TimeDistributed(cnn, input_shape=(4, 28, 28, 1)))
combined_model.add(lstm)
combined_model.add(classification_layer)
combined_model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy'])
.
.
.
data-set building: creating 20 individual records, each containing a sequence of 4 28x28x1 images and the associated labels list.
.
.
.
print('train_input shape: {} train_labels shape: {}'.format(np.array(train_input).shape, np.array(train_labels).shape))
print('Training the model')
combined_model.fit(train_input, train_labels, epochs=2)
训练尝试的输出:
train_input shape: (20, 4, 28, 28, 1) train_labels shape: (20,)
Training the model
Traceback (most recent call last):
File "/Users/scott/sandbox/CNN-LSTM-sandbox/build_and_train.py", line 184, in <module>
combined_model.fit(train_input, train_labels, epochs=2)
File "/anaconda3/envs/TF2_py36/lib/python3.6/site-packages/tensorflow/python/keras/engine/training.py", line 806, in fit
shuffle=shuffle)
File "/anaconda3/envs/TF2_py36/lib/python3.6/site-packages/tensorflow/python/keras/engine/training.py", line 2596, in _standardize_user_data
exception_prefix='input')
File "/anaconda3/envs/TF2_py36/lib/python3.6/site-packages/tensorflow/python/keras/engine/training_utils.py", line 340, in standardize_input_data
'with shape ' + str(data_shape))
ValueError: Error when checking input: expected time_distributed_input to have 5 dimensions, but got array with shape (4, 28, 28, 1)
Process finished with exit code 1
请注意,无论我的代码中有三个combined_model.add(tfkl.TimeDistributed(cnn...
版本中的哪个版本,我都会得到相同的结果。
我不期望模型提供的内容与提供的内容之间存在差异。我正在提供5D数据集,这就是它想要的,但是它声称我只提供4D数据集。
在调试时,我发现了抛出ValueError的地方。它位于training_utils.py
的第336行-if len(data_shape) != len(shape):
(为上下文显示了第303-350行):
lines 303-350 of training_utils.py:
if len(data) != len(names):
if data and hasattr(data[0], 'shape'):
raise ValueError('Error when checking model ' + exception_prefix +
': the list of Numpy arrays that you are passing to '
'your model is not the size the model expected. '
'Expected to see ' + str(len(names)) + ' array(s), '
'but instead got the following list of ' +
str(len(data)) + ' arrays: ' + str(data)[:200] + '...')
elif len(names) > 1:
raise ValueError('Error when checking model ' + exception_prefix +
': you are passing a list as input to your model, '
'but the model expects a list of ' + str(len(names)) +
' Numpy arrays instead. The list you passed was: ' +
str(data)[:200])
elif len(data) == 1 and not hasattr(data[0], 'shape'):
raise TypeError('Error when checking model ' + exception_prefix +
': data should be a Numpy array, or list/dict of '
'Numpy arrays. Found: ' + str(data)[:200] + '...')
elif len(names) == 1:
data = [np.asarray(data)]
# Check shapes compatibility.
if shapes:
for i in range(len(names)):
if shapes[i] is not None:
if tensor_util.is_tensor(data[i]):
tensorshape = data[i].get_shape()
if not tensorshape:
continue
data_shape = tuple(tensorshape.as_list())
else:
data_shape = data[i].shape
shape = shapes[i]
if len(data_shape) != len(shape):
raise ValueError('Error when checking ' + exception_prefix +
': expected ' + names[i] + ' to have ' +
str(len(shape)) + ' dimensions, but got array '
'with shape ' + str(data_shape))
if not check_batch_axis:
data_shape = data_shape[1:]
shape = shape[1:]
for dim, ref_dim in zip(data_shape, shape):
if ref_dim != dim and ref_dim is not None and dim is not None:
raise ValueError('Error when checking ' + exception_prefix +
': expected ' + names[i] + ' to have shape ' +
str(shape) + ' but got array with shape ' +
str(data_shape))
return data
调试器命中336行时的状态是:
np.array(data).shape = <class 'tuple'>: (1, 4, 28, 28, 1)
data_shape = <class 'tuple'>: (4, 28, 28, 1)
name = <class 'list'>: ['time_distributed_input']
shapes = <class 'list'>: [(None, 4, 28, 28, 1)]
由此,可以看到到达这一点的数据形状是正确的,但是代码提取了批处理中的第一条记录,并将其形状与TimeDistributed层期望的形状进行了比较。问题在于,TimeDistributed层期望以(None, 4, 28, 28, 1)
的形式进行批处理表示,但在b / c中,代码只在该批处理位置data_shape = data[i].shape
处提取了输入记录。
从我的角度来看,批次尺寸不应该在用于为InputLayer建立数据预期形状的元组中表示,批次长度比较需要忽略形状元组中的None
,否则比较应为if len(np.array(data).shape) != len(shape):