在图像回归任务中,DenseNet121可以自动提取图像的深层语义特征,而手工特征如颜色直方图、纹理特征等能够补充模型对特定先验信息的感知,构建双输入融合模型可以充分发挥两者的优势,提升回归预测的准确性。

模型整体结构设计
融合DenseNet121与手工特征的双输入回归模型包含两个独立输入分支,分别是图像输入分支和手工特征输入分支,两个分支提取的特征经过融合后输入全连接层完成回归预测,整体结构如下:
- 图像输入分支:使用预训练的DenseNet121作为特征提取器,去除顶层分类层,输出图像的高维特征
- 手工特征输入分支:对输入的手工特征进行维度变换和特征增强,适配后续融合操作
- 特征融合模块:将图像分支和手工特征分支的输出进行拼接,得到融合特征
- 回归输出层:通过全连接层将融合特征映射到最终的回归预测值
数据预处理步骤
图像数据预处理
图像数据需要统一尺寸、归一化,并适配DenseNet121的输入要求,预处理代码如下:
import numpy as np
from tensorflow.keras.applications.densenet import preprocess_input
from tensorflow.keras.preprocessing.image import ImageDataGenerator
# 定义图像数据生成器,进行归一化和增强
image_datagen = ImageDataGenerator(
preprocessing_function=preprocess_input,
rotation_range=20,
width_shift_range=0.2,
height_shift_range=0.2,
horizontal_flip=True
)
# 加载图像数据,统一尺寸为DenseNet121要求的224x224
train_image_generator = image_datagen.flow_from_directory(
'train_image_dir',
target_size=(224, 224),
batch_size=32,
class_mode=None # 回归任务不需要类别标签
)
手工特征预处理
手工特征需要根据具体任务提取,比如颜色、纹理、形状等特征,提取完成后进行标准化处理,示例代码如下:
from sklearn.preprocessing import StandardScaler
import pandas as pd
# 假设手工特征存储在csv文件中,每一行对应一张图像的手工特征
handcraft_df = pd.read_csv('handcraft_features.csv')
handcraft_features = handcraft_df.values.astype(np.float32)
# 标准化手工特征
scaler = StandardScaler()
scaled_handcraft = scaler.fit_transform(handcraft_features)
双输入模型构建实现
图像分支构建
使用TensorFlow Keras构建DenseNet121图像分支,代码如下:
from tensorflow.keras.applications import DenseNet121 from tensorflow.keras.layers import Input, GlobalAveragePooling2D, Dense from tensorflow.keras.models import Model # 定义图像输入 image_input = Input(shape=(224, 224, 3), name='image_input') # 加载预训练DenseNet121,去除顶层 base_model = DenseNet121(weights='imagenet', include_top=False, input_tensor=image_input) # 添加全局平均池化层,输出图像特征 x = GlobalAveragePooling2D()(base_model.output) image_features = Dense(256, activation='relu')(x) # 降维到256维 image_branch = Model(inputs=image_input, outputs=image_features, name='image_branch')
手工特征分支构建
手工特征分支对输入的手工特征进行维度适配,代码如下:
from tensorflow.keras.layers import Input, Dense, Dropout # 假设手工特征维度为50,定义手工特征输入 handcraft_input = Input(shape=(50,), name='handcraft_input') # 手工特征分支处理 y = Dense(128, activation='relu')(handcraft_input) y = Dropout(0.3)(y) y = Dense(64, activation='relu')(y) handcraft_features = Dense(256, activation='relu')(y) # 输出256维,和图像分支维度一致 handcraft_branch = Model(inputs=handcraft_input, outputs=handcraft_features, name='handcraft_branch')
特征融合与模型组装
将两个分支的特征拼接后接入回归输出层,完成模型组装:
from tensorflow.keras.layers import Concatenate
# 拼接两个分支的特征
merged = Concatenate(name='feature_merge')([image_branch.output, handcraft_branch.output])
# 融合特征后接入全连接层
z = Dense(128, activation='relu')(merged)
z = Dropout(0.4)(z)
z = Dense(64, activation='relu')(z)
# 回归输出层,输出1个预测值
output = Dense(1, activation='linear', name='regression_output')(z)
# 构建最终双输入模型
dual_input_model = Model(
inputs=[image_branch.input, handcraft_branch.input],
outputs=output,
name='densenet_handcraft_regression_model'
)
模型编译与训练
模型编译时选择适合回归任务的损失函数和优化器,训练时同时输入图像数据和手工特征数据:
# 编译模型
dual_input_model.compile(
optimizer='adam',
loss='mse', # 回归任务常用均方误差损失
metrics=['mae'] # 监控平均绝对误差
)
# 打印模型结构
dual_input_model.summary()
# 准备训练数据,假设标签为train_labels
# 图像数据通过生成器获取,手工特征为预处理后的scaled_handcraft
train_handcraft = scaled_handcraft[:len(train_image_generator.filenames)]
train_labels = np.load('train_labels.npy') # 加载回归标签
# 训练模型
history = dual_input_model.fit(
[train_image_generator, train_handcraft],
train_labels,
epochs=50,
batch_size=32,
validation_split=0.2,
shuffle=True
)
模型优化建议
为了进一步提升模型性能,可以尝试以下优化策略:
- 对DenseNet121的顶层部分层进行微调,解冻最后几层卷积层参与训练,适配当前任务的特征分布
- 尝试不同的特征融合方式,比如加权融合、逐元素相加等,替代简单的拼接操作
- 对手工特征进行筛选,去除冗余特征,降低手工特征分支的维度,减少过拟合风险
- 调整两个分支的输出维度,根据实际任务效果选择最优的特征维度配比
常见问题解答
问:两个输入分支的数据量需要一致吗?
答:需要一致,每个样本必须同时对应一张图像和一组手工特征,否则会出现维度不匹配的问题。
问:预训练DenseNet121的权重需要冻结吗?
答:初期可以冻结所有预训练层,仅训练新增的全连接层,待模型收敛后再逐步解冻部分层微调,避免预训练权重被破坏。
DenseNet121双输入回归模型手工特征特征融合深度学习修改时间:2026-07-13 07:03:26