TensorFlow中融合图像与Landmark坐标两种不同形状输入的方法
多输入模型融合与训练解决方案
问题分析
你之前的尝试存在几个关键问题:
- 关键点输入层的形状错误:
landmarks_x_train的形状是(120,478,3),但你定义的Input(shape=(landmarks_x_train.shape[1],))只对应了478这个维度,漏掉了坐标的3个通道 - 关键点输入未做维度压缩:ResNet的输出是二维向量
(batch_size, features),而原始关键点输入是三维(batch_size,478,3),两者维度不匹配,无法直接拼接 - 融合后缺少最终分类层:你把拼接后的结果直接作为输出,但原来的任务是7分类,需要在拼接后添加全连接层完成分类
- 训练时输入格式错误:多输入模型需要传入对应输入列表,而不是单一输入
完整实现步骤
1. 调整ResNet模型,获取特征输出
首先修改ResNet50模型,去掉顶层的分类层,保留特征提取部分:
# 重新定义模型,只保留特征提取部分,输出特征向量 def get_resnet_feature_model(): base_model = ResNet50(include_top=False, input_shape=(224,224,1), weights=None) x = base_model.output # 全局平均池化得到特征向量 x = GlobalAveragePooling2D()(x) # 可选:加全连接层增强特征表达 x = Dense(256, activation='relu')(x) return Model(inputs=base_model.input, outputs=x) # 获取特征提取模型 image_model = get_resnet_feature_model()
2. 构建关键点输入分支
对关键点输入进行处理,将三维数据压缩为二维特征向量:
from tensorflow.keras.layers import Input, Flatten, Dense, concatenate from tensorflow.keras.models import Model # 关键点输入层,匹配(478,3)的形状 landmarks_input = Input(shape=(478,3), name='landmarks_input') # 压平三维数据,也可以用GlobalAveragePooling1D替代 x = Flatten()(landmarks_input) # 加全连接层提取关键点特征 x = Dense(128, activation='relu')(x) landmarks_feature = Dense(64, activation='relu')(x)
3. 融合两个分支并构建完整模型
将图像特征和关键点特征拼接,添加最终分类层:
# 获取图像分支的输出 image_feature = image_model.output # 拼接两个特征向量 combined = concatenate([image_feature, landmarks_feature], name='combined_features') # 添加分类层 x = Dense(128, activation='relu')(combined) output = Dense(7, activation='softmax', name='classification_output')(x) # 构建多输入模型 final_model = Model(inputs=[image_model.input, landmarks_input], outputs=output)
4. 编译模型
final_model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', # 标签是整数用这个,one-hot编码用categorical_crossentropy metrics=['accuracy'])
5. 训练模型(两种场景)
场景1:直接使用numpy数组训练
如果你的标签是y_train(形状(120,)或(120,7)),直接传入输入列表:
# 假设y_train是训练标签,y_val是验证标签 final_model.fit( [X_train, landmarks_x_train], y_train, validation_data=([X_val, landmarks_x_val], y_val), epochs=20, batch_size=8 )
场景2:结合ImageDataGenerator处理图像增强
如果需要用ImageDataGenerator做图像增强,需要自定义生成器来同时输出图像和关键点数据:
from tensorflow.keras.preprocessing.image import ImageDataGenerator import numpy as np # 初始化图像生成器 datagen = ImageDataGenerator(rotation_range=10, width_shift_range=0.1, height_shift_range=0.1) # 自定义生成器,结合图像增强和关键点数据 def multi_input_generator(image_generator, x_images, x_landmarks, y): gen = image_generator.flow(x_images, y, batch_size=8) while True: image_batch, y_batch = next(gen) # 获取当前batch的索引,取出对应的关键点数据 idx = gen.batch_index if idx == 0: indices = np.arange(len(x_images)) np.random.shuffle(indices) batch_indices = indices[idx*gen.batch_size : (idx+1)*gen.batch_size] landmarks_batch = x_landmarks[batch_indices] yield [image_batch, landmarks_batch], y_batch # 创建训练和验证生成器 train_gen = multi_input_generator(datagen, X_train, landmarks_x_train, y_train) val_gen = multi_input_generator(ImageDataGenerator(), X_val, landmarks_x_val, y_val) # 训练 final_model.fit( train_gen, steps_per_epoch=len(X_train)//8, validation_data=val_gen, validation_steps=len(X_val)//8, epochs=20 )
注意事项
- 如果你的原始ResNet模型已经包含顶层分类层,需要先移除,否则特征维度会是
(None,7),拼接后特征表达能力不足 - 关键点分支的结构可以根据任务调整,比如用LSTM、1D卷积代替Flatten,更适合序列类的关键点数据
- 训练时要确保输入列表的顺序和模型定义的
inputs顺序完全一致
内容的提问来源于stack exchange,提问作者Alexander
相关产品推荐
相关产品推荐

