You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Keras实现结合图像与预提取特征的CNN分类模型?

Got it! 要实现这种同时用图像和预提取结构化特征的分类模型,Keras的函数式API是最佳选择——它天生支持多输入多输出的模型架构。下面我给你一步步拆解实现过程,代码都给你写好,细节也给你讲清楚:

1. 数据准备:先把图像和特征数据处理好

首先得把两类数据都整理成模型能接受的格式:

  • 图像数据:加载后归一化到0-1区间,形状为(样本数, 64, 64, 3)
  • 结构化特征:用pandas读取CSV后,用标准化工具(比如StandardScaler)统一特征尺度,最终形状为(样本数, 14)

示例代码片段:

import numpy as np
import pandas as pd
from PIL import Image
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import train_test_split

# 加载图像数据(假设图像路径存在CSV的'image_path'列里)
df = pd.read_csv('your_features.csv')
images = []
for img_path in df['image_path']:
    img = Image.open(img_path).resize((64,64))
    images.append(np.array(img)/255.0)  # 归一化到0-1
images = np.array(images)

# 加载并标准化结构化特征
features = df.drop(['image_path', 'label'], axis=1).values  # 去掉路径和标签列
scaler = StandardScaler()
features = scaler.fit_transform(features)

# 加载标签并处理(假设是多分类,转成独热编码)
labels = pd.get_dummies(df['label']).values

# 划分训练测试集
images_train, images_test, features_train, features_test, labels_train, labels_test = train_test_split(
    images, features, labels, test_size=0.2, random_state=42
)
2. 构建双分支模型

我们需要分别搭建图像特征提取分支和结构化特征分支,最后把两个分支的输出融合:

图像分支(CNN特征提取)

针对64x64的RGB图像,用卷积+池化层提取视觉特征:

from keras.layers import Input, Conv2D, MaxPooling2D, GlobalAveragePooling2D, Dense, Dropout, concatenate
from keras.models import Model
from keras.optimizers import Adam

# 图像输入层
image_input = Input(shape=(64, 64, 3), name='image_input')
x = Conv2D(32, (3,3), activation='relu', padding='same')(image_input)
x = MaxPooling2D((2,2))(x)
x = Conv2D(64, (3,3), activation='relu', padding='same')(x)
x = MaxPooling2D((2,2))(x)
x = Conv2D(128, (3,3), activation='relu', padding='same')(x)
x = GlobalAveragePooling2D()(x)  # 用全局平均池化替代Flatten,减少参数避免过拟合
x = Dropout(0.3)(x)  # 加Dropout防止过拟合
image_branch = Model(inputs=image_input, outputs=x)

结构化特征分支(全连接层处理)

针对14维的预提取特征,用全连接层做特征变换:

# 特征输入层
feature_input = Input(shape=(14,), name='feature_input')
y = Dense(64, activation='relu')(feature_input)
y = Dropout(0.2)(y)
y = Dense(32, activation='relu')(y)
feature_branch = Model(inputs=feature_input, outputs=y)

融合分支+最终分类层

把两个分支的输出拼接,再通过全连接层输出分类结果:

# 融合两个分支的特征
combined_features = concatenate([image_branch.output, feature_branch.output])
z = Dense(64, activation='relu')(combined_features)
output = Dense(labels.shape[1], activation='softmax')(z)  # labels.shape[1]是分类类别数

# 定义完整模型
model = Model(inputs=[image_branch.input, feature_branch.input], outputs=output)
3. 编译与训练模型

训练时需要同时传入图像和特征两类输入:

# 编译模型(多分类用categorical_crossentropy,二分类换binary_crossentropy+激活sigmoid)
model.compile(optimizer=Adam(learning_rate=0.001),
              loss='categorical_crossentropy',
              metrics=['accuracy'])

# 开始训练
history = model.fit(
    [images_train, features_train],
    labels_train,
    batch_size=32,
    epochs=20,
    validation_data=([images_test, features_test], labels_test)
)
4. 预测新样本

预测时同样需要传入图像和对应特征:

# 示例:预测单个样本
sample_image = np.expand_dims(images_test[0], axis=0)  # 加batch维度
sample_feature = np.expand_dims(features_test[0], axis=0)
pred_probs = model.predict([sample_image, sample_feature])
pred_class = np.argmax(pred_probs, axis=1)[0]  # 取概率最大的类别
关键注意事项
  • 特征标准化:结构化特征一定要做标准化,不然尺度差异会让模型忽略小数值特征
  • 过拟合防控:可以在分支或融合层后加Dropout,或者用L2正则化
  • 大数据场景:如果25000张图内存装不下,自定义一个数据生成器,每次yield([batch_images, batch_features], batch_labels)
  • 模型调优:可以尝试调整卷积层数量、全连接层神经元数,或者用预训练模型(比如ResNet50)作为图像分支的基础

内容的提问来源于stack exchange,提问作者Sreeram TP

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 03:48:37