ImageDataGenerator.flow_from_directory 到可以在 Kfold 中使用的数据集

ImageDataGenerator.flow_from_directory to a dataset that can be used in Kfold

我正在尝试对我用于 class 将图像转换为 3 class 的模型使用交叉验证方法。我使用以下代码导入图像:

train_datagen = ImageDataGenerator(rescale=1./255)
data = train_datagen.flow_from_directory(directory=train_path,
                                       target_size=(300,205), batch_size=8, 
                                       color_mode='grayscale',class_mode='categorical')

在我尝试使用 sklearn.model_selectionKFold 之前训练和测试模型效果很好。我在互联网上找到的所有示例都是简单的 numpy 数组,而我有一个 classification 数组。这意味着图像数组有标签,我无法解决将这个 DirectoryIterator(flow_from_directory returns DirectoryIterator)转换为可与 kfold.split 一起使用的数组功能。

我尝试了以下方法,请记住我是 class化模型的新手:

np_data = data.next()

num_folds = 5
kfold = KFold(n_splits=num_folds, shuffle=True)
for train, test in kfold.split(np_data):

然后我得到: ValueError:分割数 n_splits=5 不能大于样本数:n_samples=2.

我相信我得到这个值错误是因为 np_array 内部有 2 个嵌套数组,第一个用于图像,第二个用于它们的 classes。

我会尝试仅对图像进行洗牌和折叠,但是如果没有信息 class 它们属于什么,我将无法正确训练我的模型。我已尝试按照 this link but the data for their testing and training seem to be imported in a different way than I have my data. Then I came across also this 中的指南进行操作,但它对我的情况并没有真正帮助。

我不知道我错过了什么,任何额外的帮助将不胜感激。

最后我试过:

x, y = data.next()
for train, test in kfold.split(x, y):
     ...

当它开始第一次折叠的第一个纪元时,这给了我以下错误:

ValueError:没有为任何变量提供梯度:['conv2d/kernel:0'、'conv2d/bias:0'、'conv2d_1/kernel:0'、'conv2d_1/bias:0'、'conv2d_2/kernel:0'、 'conv2d_2/bias:0', 'conv2d_3/kernel:0', 'conv2d_3/bias:0', 'dense/kernel:0', 'dense/bias:0', 'dense_1/kernel:0', 'dense_1/bias:0'].

我得到最后一个ValueError的原因是因为我在使用model.fit()时没有包含y[test]。以下对我来说效果很好。

使用 ImageDataGenerator.flow_from_directory(...) 导入图像后,x, y = data.next() 将图像及其标签生成到 x 和 y 数组中。今后:

kfold = KFold(n_splits=num_folds, shuffle=True)

fold_no = 1
for train, test in kfold.split(x, y):
   model = keras.models.Sequential(.....)
   model.fit(x[train], y[train], epochs=epochs)
   ...
   scores = model.evaluate(x[test], y[test], verbose=0)
   ...
   fold_no = fold_no + 1

我也用这个打印行来记录分数:

print(f'Score for fold {fold_no}: {network.metrics_names[0]} of {scores[0]}; {network.metrics_names[1]} of {scores[1]*100}%')

此外,损失和准确性结果可以存储在两个单独的数组中,并在折叠结束时得到平均值。

acc_per_fold.append(scores[1] * 100)
loss_per_fold.append(scores[0])

以上两行必须在 for 循环内 (for train, test in kfold.split(x, y):),下面两行必须在循环外。

print("\n\n Overall accuracy: " + str(np.average(acc_per_fold)))
print("Overall loss: " + str(np.average(loss_per_fold)))