如何将输入层连接到深度神经网络的每一层?
问题与解决方案
需求描述
现有一个Keras Sequential模型,希望保留原有的Dropout、BatchNormalization、LeakyReLU等层操作,同时修改结构,让每个深层Dense层同时接收前一层输出和原始输入层的输出(即每个深层都直接连接输入层)。
原模型代码如下:
from tensorflow.keras import initializers INNER_LAYER_SIZE=x.shape[1] drouout_fraction=.0 #set_seeds(123456) model = keras.models.Sequential([ keras.layers.InputLayer(input_shape=[x.shape[1],]), keras.layers.Dense(INNER_LAYER_SIZE, kernel_initializer=tf.keras.initializers.RandomUniform()), tf.keras.layers.BatchNormalization(), keras.layers.LeakyReLU(), #tf.keras.layers.Dropout(drouout_fraction), ]) for i in range(15): model.add(keras.layers.Dense(int(INNER_LAYER_SIZE/2), kernel_initializer=tf.keras.initializers.RandomUniform())) model.add(tf.keras.layers.BatchNormalization()) model.add(keras.layers.LeakyReLU()) model.add(tf.keras.layers.Dropout(drouout_fraction)) model.add(tf.keras.layers.BatchNormalization()) model.add(keras.layers.Dense(y.shape[1], kernel_initializer=tf.keras.initializers.RandomUniform())) model.add(keras.layers.LeakyReLU()) model.compile(loss="mse", metrics=["mean_absolute_error"], optimizer=tf.keras.optimizers.SGD( learning_rate=0.1, momentum=0.25, nesterov=True#, decay=.001#/x.shape[0] ))# last_loss=1 model.summary()
之前尝试的两种写法均报错:
- 直接在
model.add()里调用层:model.add(keras.layers.Dense(...)(input)) - 尝试用
tf.concat([previous, input], axis=1)拼接输入和前层输出,但未成功
解决方案
Sequential模型只能处理线性层结构,无法实现这种多分支的连接逻辑,必须改用Keras函数式API来构建模型。核心思路是:
- 定义输入层并保存其引用
- 每一层计算前,先把当前前层的输出和原始输入拼接
- 将拼接后的张量作为下一个Dense层的输入
- 保留原有的BatchNormalization、LeakyReLU、Dropout等操作
完整实现代码如下:
import tensorflow as tf from tensorflow.keras import layers, initializers INNER_LAYER_SIZE = x.shape[1] dropout_fraction = .0 # 1. 定义输入层并保存引用 inputs = layers.Input(shape=[INNER_LAYER_SIZE,]) # 2. 第一层处理(和原逻辑一致) x = layers.Dense(INNER_LAYER_SIZE, kernel_initializer=initializers.RandomUniform())(inputs) x = layers.BatchNormalization()(x) x = layers.LeakyReLU()(x) # x = layers.Dropout(dropout_fraction)(x) # 原代码注释掉的部分,可按需启用 # 3. 循环构建15层,每层都拼接原始输入和前层输出 for i in range(15): # 拼接原始输入和当前前层输出 concat = layers.concatenate([inputs, x], axis=1) # 后续层处理和原逻辑一致 x = layers.Dense(int(INNER_LAYER_SIZE/2), kernel_initializer=initializers.RandomUniform())(concat) x = layers.BatchNormalization()(x) x = layers.LeakyReLU()(x) x = layers.Dropout(dropout_fraction)(x) # 4. 最后输出层处理 concat_final = layers.concatenate([inputs, x], axis=1) x = layers.BatchNormalization()(concat_final) x = layers.Dense(y.shape[1], kernel_initializer=initializers.RandomUniform())(x) outputs = layers.LeakyReLU()(x) # 5. 构建模型并编译 model = tf.keras.Model(inputs=inputs, outputs=outputs) model.compile(loss="mse", metrics=["mean_absolute_error"], optimizer=tf.keras.optimizers.SGD( learning_rate=0.1, momentum=0.25, nesterov=True )) last_loss = 1 model.summary()
关键说明
- 使用
layers.concatenate()替代tf.concat(),更符合Keras函数式API的使用习惯(两者功能一致,但前者是层对象,便于构建模型图) - 每次进入新的Dense层前,先拼接原始输入和前一层的输出,确保深层能同时获取原始特征和前层提取的特征
- 所有原有的层操作(BatchNormalization、LeakyReLU、Dropout)都完整保留,逻辑和原模型一致
内容的提问来源于stack exchange,提问作者Arsen Zahray
相关产品推荐
相关产品推荐

