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

自定义DataGenerator训练InceptionV4时形状不兼容问题解决咨询

问题描述

使用8通道npy格式数据,自定义Keras的CustomDataGenerator读取数据,训练InceptionV4模型时触发错误:

ValueError: Shapes (None, None, None, None) and (None, 6) are incompatible

已知InceptionV4输入形状为(batch_size, height, width, channel),自定义生成器输出符合该形状,标签已转one-hot格式,且该生成器此前用于Unet训练无问题。相关代码及模型结构如下:

自定义生成器代码

params = {'dim': (299,299),
          'batch_size': 1,
          'n_classes': 6,
          'n_channels': 8,}
class CustomDataGenerator(Sequence):
    def __init__(self, image_folders, label_folders, dir, dim=(299,299),  batch_size=1,n_classes=6,n_channels=8,shuffle=True):
        self.image_folders = image_folders
        ...
        self.on_epoch_end()

    def __len__(self):
        return int(np.ceil(len(self.image_paths) / self.batch_size))  

    def __getitem__(self, index):
        batch_image_paths = self.image_paths[index * self.batch_size: (index + 1) * self.batch_size]
        batch_label_paths = self.label_paths[index * self.batch_size: (index + 1) * self.batch_size]
        batch = zip(batch_image_paths, batch_label_paths)

        return self.get_data(batch)

    def on_epoch_end(self):
        self.image_paths = []
        self.label_paths = []
        for folder in self.image_folders:
            image_folder_path = os.path.join(self.dir, folder)
            image_files = os.listdir(image_folder_path)
            for file_name in image_files:
                self.image_paths.append(os.path.join(image_folder_path, file_name))

        for folder in self.label_folders:
            ...

        if self.shuffle:
            ...

    def get_data(self, batch):
        X = np.empty((self.batch_size, *self.dim, self.n_channels))
        y = np.empty((self.batch_size, *self.dim, self.n_classes))

        for i, (image_path, label_path) in enumerate(batch):
            image = np.load(image_path)
            label = np.load(label_path)
            self.y_true.append(label)

            label_grayscale = np.mean(label, axis=-1)
            min_val = label_grayscale.min()
            max_val = label_grayscale.max()
            scaled_label = (label_grayscale - min_val) / (max_val - min_val)  # Scale to [0, 1]
            scaled_label = (scaled_label * (self.n_classes - 1)).astype(int)  # Scale to [0, n_classes-1]
            label_one_hot = to_categorical(scaled_label, num_classes=self.n_classes)

            X[i,] = image
            y[i,] = label_one_hot

        return X, y
train_datagen = CustomDataGenerator(image_folders, label_folders, train_dir, **params, shuffle = True)

model = model_incetionV4
model.compile(optimizer=Adam(lr=0.0001), loss=categorical_crossentropy, metrics=['accuracy'])
model_checkpoint = ModelCheckpoint('weight/123467_InceptionV4_test1.hdf5', monitor='loss',verbose=1, save_best_only=True)
model.fit(train_datagen, steps_per_epoch=30, epochs=500, validation_data=val_datagen, callbacks=[model_checkpoint])

InceptionV4模型代码

class InceptionV4(tf.keras.Model):
    def __init__(self,blocksList,num_classes):
        ...
    def call(self,inputs,training=None):
        x=self.stem(inputs)

        x=self.inceptionA(x)
        x=self.redA(x)
        x=self.inceptionB(x)
        x=self.redB(x)
        x=self.inceptionC(x)

        x=self.avgpool(x)
        x=self.dropout(x)
        x=self.dense(x)
        x=self.softmax(x)

model_incetionV4=InceptionV4(blocksList=[4,7,3],num_classes=6)
batch_size = 1
model_incetionV4.build(input_shape=(batch_size,299,299,8))
model_incetionV4.summary()

模型结构摘要

Model: "inception_v4"
_________________________________________________________________
Layer (type)                 Output Shape              Param #
=================================================================
stem (Sequential)            (1, 35, 35, 384)          609760
_________________________________________________________________
inceptionA (Sequential)      (1, 35, 35, 384)          1277824   
_________________________________________________________________
reducetionA (Sequential)     (1, 17, 17, 1024)         2309280
_________________________________________________________________
inceptionB (Sequential)      (1, 17, 17, 1024)         18135040  
_________________________________________________________________
reducetionB (Sequential)     (1, 8, 8, 1536)           2571456
_________________________________________________________________
inceptionC (Sequential)      (1, 8, 8, 1536)           31940160  
_________________________________________________________________
global_average_pooling2d (Gl multiple                  0
_________________________________________________________________
dropout (Dropout)            multiple                  0
_________________________________________________________________
dense (Dense)                multiple                  9222
_________________________________________________________________
activation_21 (Activation)   multiple                  0
=================================================================
问题根源与解决方案

错误核心是生成器输出的标签形状与模型输出形状不匹配:

  • InceptionV4是图像分类模型,最终输出为(batch_size, num_classes)(即(1,6)),对应全局池化后接全连接层的单样本单类别输出。
  • 自定义生成器中标签y被定义为(batch_size, *self.dim, self.n_classes)(即(1,299,299,6)),这是图像分割任务的像素级标签格式(适配Unet),完全不符合分类模型的输入要求。

需要修改自定义生成器,将标签从像素级one-hot调整为样本级one-hot:

修改生成器的关键代码

在get_data方法中,调整标签形状和处理逻辑:

def get_data(self, batch):
    # 输入X的定义保持不变
    X = np.empty((self.batch_size, *self.dim, self.n_channels))
    # 修改y的形状:从像素级转为样本级
    y = np.empty((self.batch_size, self.n_classes))

    for i, (image_path, label_path) in enumerate(batch):
        image = np.load(image_path)
        label = np.load(label_path)
        self.y_true.append(label)

        label_grayscale = np.mean(label, axis=-1)
        min_val = label_grayscale.min()
        max_val = label_grayscale.max()
        scaled_label = (label_grayscale - min_val) / (max_val - min_val)
        scaled_label = (scaled_label * (self.n_classes - 1)).astype(int)
        
        # 从像素级标签提取样本级标签:示例为取出现次数最多的类别,可根据任务需求调整
        sample_label = np.bincount(scaled_label.flatten()).argmax()
        # 转换为样本级one-hot编码
        label_one_hot = to_categorical(sample_label, num_classes=self.n_classes)

        X[i,] = image
        y[i,] = label_one_hot

    return X, y

模型部分无需修改

从模型结构摘要可知,InceptionV4经过全局平均池化后,将(1,8,8,1536)的特征转为(1,1536),再通过全连接层输出(1,6),完全符合分类任务的输出形状,无需调整。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 12:31:07