LSTM与DENSE层维度不匹配报错:输入3D不符合≤2D要求
问题描述
在为算法调优超参数时,使用LSTM+DENSE两层结构,当LSTM后接DENSE层时出现报错:ValueError: Found array with dim 3. None expected <=2。使用两层DENSE+2D输入时正常,问题出在LSTM层的输出维度上。
训练数据X_entrainement与Y_entrainement形状为(1416, 24, 1),尝试过用flatten()修改LSTM输出、调整输入形状声明语法,但仍未解决,需要了解如何设置LSTM参数适配DENSE层。
原代码如下:
def create_model(): # create model model = Sequential() model.add(LSTM(24, input_dim=24, activation='relu',return_sequences=True)) model.add(Dense(24, activation='sigmoid')) # Compile model model.compile(optimizer='adam', loss='mse') print(model.summary()) return model modelk = KerasRegressor(model=create_model, verbose = 0) batch_size = [24,64] epochs = [10, 50, 100] optimizer = ['SGD', 'RMSprop', 'Adagrad', 'Adadelta', 'Adam', 'Adamax', 'Nadam'] param_grid = dict(batch_size=batch_size, epochs=epochs, optimizer=optimizer) grid = GridSearchCV(estimator=modelk, param_grid=param_grid, cv=3, verbose = 3, error_score = 'raise') grid_result = grid.fit(X_entrainement, Y_entrainement) print("Best: %f using %s" % (grid_result.best_score_, grid_result.best_params_)) means = grid_result.cv_results_['mean_test_score'] stds = grid_result.cv_results_['std_test_score'] params = grid_result.cv_results_['params'] for mean, stdev, param in zip(means, stds, params): print("%f (%f) with: %r" % (mean, stdev, param))
解决方案
报错的核心原因是LSTM层设置了return_sequences=True,输出是3D张量(batch_size, timesteps, units),而DENSE层只能接收≤2D的输入。针对这个问题,有两种可行的解决方式:
方式1:关闭LSTM的return_sequences参数
如果你的任务不需要LSTM输出每个时间步的结果(比如单步回归预测),直接将return_sequences设为False(默认就是False,可直接省略该参数),此时LSTM会输出最后一个时间步的2D张量(batch_size, units),可直接对接DENSE层:
def create_model(): model = Sequential() # 去掉return_sequences=True,或显式设为False,同时修正输入形状声明 model.add(LSTM(24, input_shape=(24, 1), activation='relu')) model.add(Dense(24, activation='sigmoid')) model.compile(optimizer='adam', loss='mse') print(model.summary()) return model
注意:这里把input_dim=24改为input_shape=(24, 1),更符合Keras对时序输入的形状规范((timesteps, features)),与你的输入(1416,24,1)匹配。
方式2:在LSTM和DENSE之间添加Flatten层
如果必须保留return_sequences=True(比如需要利用所有时间步的输出),可以在LSTM之后加一个Flatten()层,把3D张量展平成2D:
def create_model(): model = Sequential() model.add(LSTM(24, input_shape=(24, 1), activation='relu', return_sequences=True)) model.add(Flatten()) # 将(None,24,24)的3D张量转为(None,576)的2D张量 model.add(Dense(24, activation='sigmoid')) model.compile(optimizer='adam', loss='mse') print(model.summary()) return model
这种方式会把LSTM每个时间步的输出拼接起来,作为DENSE层的输入。
补充说明
- 需确认
Y_entrainement形状与模型输出匹配:若用方式1,模型输出形状为(None,24),则Y_entrainement需为(1416,24);如果是单值回归,最后一层DENSE的units应设为1,同时Y_entrainement形状为(1416,1)。 - 超参数调优部分无需改动,只要模型结构正确,
GridSearchCV即可正常运行。
内容的提问来源于stack exchange,提问作者SneakeSausage

