如何在Keras中构建含图像与数值双输入的神经网络?
结合图像与数值输入的Keras多分支模型实现
嘿,你的思路完全正确!当需要同时利用图像视觉特征和结构化数值特征时,单靠CNN确实搞不定,把数值输入接入全连接层(或者和CNN提取的特征融合后再走全连接)是这类多模态任务的标准操作。Keras的Functional API正好能完美支持这种多输入架构,我给你一步步拆解实现:
1. 改造现有CNN为图像分支
你给出的代码是Sequential风格的,首先咱们把它转成Functional API的图像分支(Sequential只能处理单输入,多输入必须用Functional):
from keras.models import Model from keras.layers import Input, Lambda, Conv2D, MaxPooling2D, Flatten, Dense, Concatenate from keras.optimizers import Adam # 图像分支:沿用你原来的归一化逻辑和后续CNN层 image_input = Input(shape=(66, 200, 3), name='image_input') # 你原来的像素归一化Lambda层 x = Lambda(lambda x: x/127.5 - 1.0)(image_input) # 这里补全你未写完的CNN层(示例参考常见的自动驾驶图像特征提取结构) x = Conv2D(24, (5,5), activation='relu', strides=(2,2))(x) x = Conv2D(36, (5,5), activation='relu', strides=(2,2))(x) x = Conv2D(48, (5,5), activation='relu', strides=(2,2))(x) x = Conv2D(64, (3,3), activation='relu')(x) x = Conv2D(64, (3,3), activation='relu')(x) # 把CNN的2D输出展平为一维特征向量(也可用GlobalAveragePooling2D替代,按需选择) image_features = Flatten()(x)
2. 构建数值特征分支
假设你的数值输入是N个连续型特征(比如速度、角度、环境参数等),咱们单独做一个轻量分支:
# 数值输入:假设输入是5维的结构化数值 numeric_input = Input(shape=(5,), name='numeric_input') # 可选:给数值特征加几层全连接做特征变换(如果数值维度高或需要非线性变换) y = Dense(16, activation='relu')(numeric_input) y = Dense(8, activation='relu')(y) numeric_features = y
3. 融合分支并构建输出层
把图像特征和数值特征拼接后,接入全连接层,最后用tanh激活匹配你需要的-1到1输出范围:
# 拼接两个分支的特征向量 combined_features = Concatenate()([image_features, numeric_features]) # 后续全连接层,可根据任务复杂度调整层数和神经元数 z = Dense(100, activation='relu')(combined_features) z = Dense(50, activation='relu')(z) z = Dense(10, activation='relu')(z) # 输出层:tanh激活刚好输出-1到1的数值 output = Dense(1, activation='tanh', name='output')(z) # 定义完整模型:输入为图像+数值,输出为预测结果 model = Model(inputs=[image_input, numeric_input], outputs=output)
4. 编译与训练
编译和训练逻辑和普通模型一致,只是需要同时传入图像和数值两类输入:
# 编译模型,回归任务用MSE损失,搭配Adam优化器 model.compile(optimizer=Adam(learning_rate=0.0001), loss='mse') # 假设你的训练数据结构如下: # X_img:形状为(样本数, 66, 200, 3)的图像数组 # X_num:形状为(样本数, 5)的数值数组 # y:形状为(样本数, 1)的标签数组(取值-1到1) model.fit([X_img, X_num], y, epochs=50, batch_size=32, validation_split=0.2)
额外小提示
- 如果数值特征维度极小(比如1-2个),可以跳过数值分支的Dense层,直接把原始数值和图像特征拼接
- 可以给两个分支分别加Dropout层,降低过拟合风险
- 推理时需同时传入图像和数值输入,比如:
model.predict([test_img_batch, test_num_batch])
内容的提问来源于stack exchange,提问作者KatharsisHerbie




