用于多标签图像分类的大型 Numpy.Array(CelebA 数据集)

数据挖掘 机器学习 图像分类 美国有线电视新闻网 多标签分类 麻木的
2022-01-19 23:21:26

任务:构建 CNN 模型(最好是 Keras 或 TensorFlow)来预测与CelebA 数据集中每个图像相关的标签(多标签图像分类)

过去,对于大多数多类/二值图像分类问题,我曾经使用 Keras 有效地提供图像ImageDataGenerator.flow_from_directory然后将图像正确组织在每个类的单独目录中。因此,在输入模型之前,我从来没有费心将图像转换为 numpy.arrary,除非我必须这样做,当然数据集很小,以便我可以在本地机器上轻松完成。

然而,CelebA 是一个多标签图像分类,每个图像有 40 个标签(属性,如微笑、眼镜、年轻等),这意味着我不能像以前那样将它们组织在子类中,所以.flow_from_directory不在桌面上(到目前为止我所知!)。我仍然设法通过以下简单循环将图像转换为 numpy.array:

import numpy as np
import skimage.transform

images_path='../img_align_celeba/'

train_images=[]
from skimage import data

for filename in train['Images'].tolist()):
    tmp=np.array(skimage.transform.resize(io.imread(os.path.join(images_path,filename))/255., (64, 64)))
    train_images.append(tmp)

x_train=np.array(train_images)
del train_images

好吧,这不是一项不可能完成的任务。CelebA 数据集很大,与许多其他图像数据集相比并不是很大(>200K RGB 图像,总共 1.4GB 大小,每张图像约 8 KB)。然而令人惊讶的是,将这些图像转换为 numpy 数组需要花费大量时间,甚至在运行一个小型 CNN 模型时会卡住。

我的电脑规格:MacBook Pro (2015),内存:8GB,硬盘:128 GB。

即使有几乎超过 4GM 的可用内存和 20 GB 的可用硬盘,我也无法在本地计算机上管理它。

更新:通过Keras 中.flow_from_directory的方法似乎很有可能而且效率更高。ImageDataGenerator虽然手头的这个多标签分类不是那个选项,但我只是做了一些虚拟子类,它起作用了,模型运行得更快!

我的问题(终于!!):

  • 也许我没有有效地进行图像到 numpy 的转换?请建议我如何以更有效的方法构造数组!

    更新:一年前我在 stackoverflow 中发现了一个非常相似的问题,但答案似乎没有提供更好的选择。

    也许它就是这样,我只需要更好的硬件就可以在本地完成它!?

  • 那么 Keras 如何在后台有效地进行转换呢?

最后(正如我们所说的那样),我只对 20% 的图像进行了采样,以便至少有一个模型原型启动并运行,尽管准确性并不令人印象深刻!

1个回答

我最终编写了一个 python 生成器,它实际上工作得很好,用于手动将所需数量的图像逐块输入到我的 CNN 模型中,如下所示:

def image_batch_generator(df,images_path, batch_size):

    '''
    A generator that takes a dataframe (for image names) and
    with a given image path goes to conver images to numpy array over
    batch (chunk by chunk).

    "df": is the "Attributes Annotations" text file from CelebA dataset.
    It has a column for image names, and another 40 attributes columns 
    (binary) for each image. 

    "images_path": it is the path to CelebA dataset image files.

    "batch_size": the batch size by which image will be read chunk by chunk.
    '''

    L = df.shape[0]
    files = df['Images'].tolist()

    #this line is just to make the generator infinite, keras needs that    
    while True:

        batch_start = 0
        batch_end = batch_size

        while batch_start < L:
            limit = min(batch_end, L)

            X= np.array([np.array(skimage.transform.resize(io.imread(os.path.join(images_path,fname))/255., (64, 64))) for fname in files[batch_start:limit]])
            y=df.loc[df["Images"].isin(files[batch_start:limit]), :].drop(['Images'],axis=1).values

            yield (X,y) #a tuple with two numpy arrays with batch_size samples     

            batch_start += batch_size   
            batch_end += batch_size

希望它会帮助那里的人。