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

使用ImageDataGenerator时无需调整文件夹如何修改分类数量?

问题:无需修改文件夹结构实现哺乳类/非哺乳类二分类

我现在用的自定义数据集包含4个类别(猫、狗、老鼠、金枪鱼),已经能很好完成这4类的分类任务。现在想把任务改成区分哺乳类与非哺乳类,但找不到不用修改图像存储文件夹结构的实现方法。

我目前想到的低效方法

我写了一个逐样本处理的生成器,但效率较低:

def to2Clases(image_generator,batch_size):
  noMammal= (0,0,0,1,)
  for x, y in image_generator:
    for i in range(len(y)):
      
      if all(y[i]==noMammal): y[i] = (0,1,0,0,)
      else: y[i] = (1,0,0,0,)
  yield x, y

注:原代码存在逻辑错误,yield 应放在外层循环内部,否则只会返回最后一个batch的数据。

我也考虑过先按原类别预测再转换结果,但本质和这个方法一样,效率不高。

参考过但不适用的方法

我找到一个基于MNIST数据集转奇偶二分类的方案,但它不适用于我的场景:

even=[0,2,4,6,8]

# Converting Train labels from numbers to even/odd
Y_trainbinary= np.empty(Y_train.shape[0],dtype=object)     
for idx, item in enumerate(Y_train):                     
      if np.nonzero(item)[0] in even:
            Y_trainbinary[idx] = 0     # even number
      else:
            Y_trainbinary[idx] = 1     # odd number

Y_trainmodel = np_utils.to_categorical(Y_trainbinary)

这个方案针对的是标签编码的场景,而我的训练生成器采用的是One-Hot编码,无法直接复用。

补充信息

我的训练生成器定义如下:

train_datagen = ImageDataGenerator(
    rescale = 1./255,
    horizontal_flip = True,
    vertical_flip = True,
    validation_split = 0.1)

train_generator = train_datagen.flow_from_directory(
    data_train,
    target_size = (img_height, img_width),
    batch_size = batch_size,
    shuffle = True,
    class_mode = 'categorical',
    subset = 'training',
    seed = 42)

打印标签形状的代码及输出:

x,y = train_generator.next()

print(len(y))
print(len(y[0]))
print(y[0])

输出:

32  # batch size
4   # number of classes
[0. 1. 0. 0.]  # 单样本One-Hot标签

更优的实现方法

可以利用Numpy的向量化操作替代逐样本循环,大幅提升效率,同时无需修改文件夹结构:

方法1:生成器层面转换标签(推荐)

import numpy as np

def convert_to_mammal_binary(generator):
    # 定义原类别到哺乳类的映射:原类别索引 -> 1(哺乳类)/0(非哺乳类)
    # 需与`train_generator.class_indices`的顺序对应,假设顺序为猫、狗、老鼠、金枪鱼
    class_mapping = np.array([1, 1, 1, 0])
    
    for x, y in generator:
        # 获取每个样本的原类别索引(从One-Hot编码转换)
        original_class_indices = np.argmax(y, axis=1)
        # 映射为二分类标签
        binary_labels = class_mapping[original_class_indices]
        # 转换为One-Hot编码(若模型输出层为2分类的softmax)
        binary_one_hot = np.stack([1 - binary_labels, binary_labels], axis=1)
        # 若模型用sigmoid做二分类,直接返回binary_labels即可
        yield x, binary_one_hot

使用时直接包装原生成器:

train_binary_generator = convert_to_mammal_binary(train_generator)

方法2:修改模型输出层(适合微调场景)

如果想复用原有模型的权重,可以在原4分类输出层后添加一个全连接层,将4维输出映射为2维:

from tensorflow.keras.models import Model
from tensorflow.keras.layers import Dense

# 假设原模型为`original_model`,输出层名为`dense_4`
base_model = Model(inputs=original_model.input, outputs=original_model.get_layer('dense_4').output)
# 添加二分类输出层
output_layer = Dense(2, activation='softmax')(base_model.output)
binary_model = Model(inputs=base_model.input, outputs=output_layer)

# 编译并训练
binary_model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])
binary_model.fit(train_generator, epochs=10)

这种方法无需修改生成器,直接在模型层面完成类别映射,适合基于原有模型进行微调的场景。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 14:20:36