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

从tf.keras.preprocessing.image迁移至image_dataset_from_directory提取特征遇异常

问题:新方案提取的图像特征检索效果异常,与原方案差异巨大

公共代码部分

两种方案共用的代码如下:

BATCH_SIZE = 32
IM_DIR = '/content/drive/My Drive/101_ObjectCategories/'
IM_HEIGHT = 224
IM_WIDTH = 224
NUM_IM = 8686
NUM_EPOCHS = int(math.ceil(NUM_IM / BATCH_SIZE))

# 加载预训练基础模型
model = ResNet50(weights='imagenet',
                 include_top=False,
                 input_shape=(IM_WIDTH, IM_HEIGHT, CH),
                 pooling='max')

原有效方案

我曾用tf.keras.preprocessing.image模块成功提取图像特征,代码如下:

datagen = tf.keras.preprocessing.image.ImageDataGenerator(preprocessing_function=preprocess_input)
dataset = datagen.flow_from_directory(IM_DIR,
                                      target_size=(IM_HEIGHT, IM_WIDTH),
                                      class_mode=None,
                                      shuffle=False)

feature_list = []
feature_list = model.predict(dataset, num_epochs)

基于该特征训练暴力近邻模型后,能准确检索到相似图像。

新方案(效果异常)

由于tf.keras.preprocessing.image已废弃,我按文档建议改用tf.keras.utils.image_dataset_from_directory加载数据并转换,代码如下:

# 加载图像
dataset = tf.keras.utils.image_dataset_from_directory(
  IM_DIR,
  labels='inferred', # 'inferred', None
  label_mode='categorical',  # 'int', 'categorical', 'binary' or None
  class_names=None,
  color_mode='rgb',  # 'grayscale', 'rgb' or 'rgba'
  batch_size=BATCH_SIZE,
  image_size=(IM_HEIGHT, IM_WIDTH),
  shuffle=True,
  seed=51719,
  validation_split=None,
  subset=None,                # 'training', 'validation' or 'both'
  interpolation='bilinear',   # 'bilinear', 'nearest', 'bicubic', 'area', 'lanczos3', 'lanczos5', 'gaussian' or 'mitchellcubic'
  follow_links=False,
  crop_to_aspect_ratio=False
)

# "用预处理层转换输出"
# 缩放(归一化)数据集
rescale_layer = tf.keras.layers.Rescaling(1./255)

rescaled_dataset = dataset.map(lambda x, y: (rescale_layer(x), y))
im_batch, labels_batch = next(iter(rescaled_dataset))


# 配置数据集以提升性能
AUTOTUNE = tf.data.AUTOTUNE
tuned_dataset = dataset.cache().prefetch(buffer_size=AUTOTUNE)

特征提取代码:

# 特征提取
feature_list = []

feature_list = model.predict(
    tuned_dataset,
    batch_size=None,
    verbose='auto',
    steps=None,
    callbacks=None,
    max_queue_size=10,
    workers=1,
    use_multiprocessing=False
)

# 保存特征
pickle.dump(
    feature_list,
    open(DATA_DIR + 'features.pickle', 'wb'))

但基于该特征训练的近邻模型检索效果极差。

补充对比

使用同一查询图像,原方案的近邻距离为:

0.0
185.60701
185.75049
195.71657
196.4056

新方案的近邻距离为:

0.0
0.81401
0.88622
0.92734
0.9346

新方案的距离数值不符合预期,相似图像距离未趋近于0。

请问我哪里操作错误导致结果差异如此之大?


解答

问题出在图像预处理不匹配和数据集使用错误两个核心点,具体分析及修复步骤如下:

1. 核心问题:未遵循ResNet的预处理要求

原方案中使用preprocess_input作为预处理函数,这是为预训练ResNet专门设计的逻辑——它会将[0,255]区间的像素值转换为[-1,1]区间(完全匹配ImageNet训练时的输入标准)。

而新方案仅做了Rescaling(1./255),把像素值缩到[0,1],完全不符合模型的输入要求。预训练模型只有在输入匹配训练时的预处理逻辑时,才能输出有效的特征向量,这直接导致新方案提取的特征失效。

2. 额外问题:特征提取用了未预处理的原始数据集

你创建了rescaled_dataset但未实际使用,反而基于未做任何预处理的原始dataset生成tuned_dataset,最后用这个原始数据集喂给模型提取特征,进一步加剧了特征的无效性。

3. 次要问题:数据集打乱破坏特征与图像的对应关系

原方案设置shuffle=False,特征列表顺序与图像目录顺序完全对应,这对后续近邻检索的标签匹配至关重要。但新方案开启shuffle=True,若未同步记录标签顺序,会导致检索时特征与标签不对应,进一步影响效果。

修复步骤

步骤1:替换预处理逻辑,使用preprocess_input

from tensorflow.keras.applications.resnet50 import preprocess_input

# 对数据集应用ResNet要求的预处理
preprocessed_dataset = dataset.map(lambda x, y: (preprocess_input(x), y))

注意:preprocess_input会自动处理[0,255]的像素值,无需提前做Rescaling(1./255)。

步骤2:使用预处理后的数据集做特征提取

# 配置性能优化时使用预处理后的数据集
AUTOTUNE = tf.data.AUTOTUNE
tuned_dataset = preprocessed_dataset.cache().prefetch(buffer_size=AUTOTUNE)

# 提取特征
feature_list = model.predict(tuned_dataset)

步骤3:关闭数据集打乱(可选但建议)

若需要保持特征与图像顺序一致,修改加载数据集的参数:

dataset = tf.keras.utils.image_dataset_from_directory(
  # 其他参数不变
  shuffle=False,  # 关闭打乱
  # seed=51719,  # 关闭打乱后可注释种子参数
)

修复后,提取的特征分布会与原方案一致,近邻距离也会回到正常范围,检索效果即可恢复。


内容的提问来源于stack exchange,提问作者Aloysia de Argenteuil

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 05:50:26