首页 文章

用于大型hdf5文件的Keras自定义数据生成器,不适合内存

提问于
浏览
3

我正在尝试使用预训练的InceptionV3模型对food-101 dataset进行分类,其中包含101个类别的食物图像,每个类别1000个 . 我已经将这个数据集预处理成一个单独的hdf5文件(我认为这比在训练时加载图像相比是有益的)到目前为止,其中包含以下表格:

Food-101 hdf5 file structure

数据拆分是标准的70%列车,20%验证,10%测试,因此例如valid_img的大小为20200 * 299 * 299 * 3 . 标签是针对Keras的一个编码,因此valid_labels的大小为20200 * 101 .

This hdf5 file has a size of 27.1 GB ,所以它不适合我的记忆 . (有8 GB,虽然在运行Ubuntu时实际上只有4-5演出可用 . 而且我的GPU是带有2 GB VRAM的GTX 960,到目前为止,当我尝试启动时,它似乎有1.5 GB可用于python训练脚本) . 我正在使用Tensorflow后端 .

我的第一个想法是使用带有双嵌套for循环的 model.train_on_batch() ,如下所示:

#Loading InceptionV3, adding my fully connected layers, compiling model...    

dataset = h5py.File('/home/uzoltan/PycharmProjects/food-101/food-101_299x299.hdf5', 'r')
    epoch = 50
    for i in range(epoch):
        for i in range(100): #1000 images can fit in the memory easily, this could probably be range(10) too
            train_images = dataset["train_img"][i * 706:(i + 1) * 706, ...]
            train_labels = dataset["train_labels"][i * 706:(i + 1) * 706, ...]
            val_images = dataset["valid_img"][i * 202:(i + 1) * 202, ...]
            val_labels = dataset["valid_labels"][i * 202:(i + 1) * 202, ...]
            model.train_on_batch(x=train_images, y=train_labels, class_weight=None,
                                 sample_weight=None, )

我对这种方法的问题是 train_on_batch 为验证或批量洗牌提供了0支持,因此每个时期的批次不是相同的顺序 .

所以我看向 model.fit_generator() ,它具有提供与 fit() 相同功能的优点,加上内置的 ImageDataGenerator 你可以与CPU同时进行图像增强(旋转,水平翻转等),这样你的模型可以更健壮 . 我的问题是,如果我理解正确, ImageDataGenerator.flow(x,y) 方法需要一次所有的样本和标签,但我的训练/验证数据不适合我的RAM .

以下是我认为自定义数据生成器出现在图片中的内容,但在广泛查看了我可以在Keras GitHub / Issues页面上找到的一些示例之后, I still dont really get how should I implement a custom generator, which would read in batches of data from my hdf5 file. 有人可以为我提供一个很好的示例或指针吗?如何将自定义批处理生成器与图像扩充相结合?或者也许更容易实现 train_on_batch() 的某种手动验证和批量洗牌?如果是这样,我也可以使用一些指针 .

3 回答

  • -1

    如果我理解正确,您希望使用HDF5中的数据(不适合内存),同时在其上使用数据扩充 .

    我和你的情况相同,我发现这些代码可能对一些修改有所帮助:

    https://gist.github.com/wassname/74f02bc9134897e3fe4e60784f5aaa15

  • -1

    你想写一个函数,它从HDF5加载图像然后 yield s(而不是 return s)它们作为一个numpy数组 . 下面是一个简单的示例,它使用OpenCV直接从给定目录中的.png / .jpg文件加载图像:

    def generate_data(directory, batch_size):
        """Replaces Keras' native ImageDataGenerator."""
        i = 0
        file_list = os.listdir(directory)
        while True:
            image_batch = []
            for b in range(batch_size):
                if i == len(file_list):
                    i = 0
                    random.shuffle(file_list)
                sample = file_list[i]
                i += 1
                image = cv2.resize(cv2.imread(sample[0]), INPUT_SHAPE)
                image_batch.append((image.astype(float) - 128) / 128)
    
            yield np.array(image_batch)
    

    显然你必须修改它才能从HDF5读取 .

    编写完功能后,用法很简单:

    model.fit_generator(
    generate_data('~/my_data', batch_size),
    steps_per_epoch=len(os.listdir('~/my_data')) // batch_size)
    

    再次修改以反映您正在从HDF5而不是目录中读取的事实 .

  • 1

    这是我用h5文件每个时代的随机数据的解决方案 . 指数表示火车或val指数列表 .

    def generator(h5path, indices, batchSize=128, is_train=True, aug=None):
    
        db = h5py.File(h5path, "r")
        with open("mean.json") as f:
            mean = json.load(f)
        meanV = np.array([mean["R"], mean["G"], mean["B"]])
    
        while True:
    
            np.random.shuffle(indices)
            for i in range(0, len(indices), batchSize):
                t0 = time()
                batch_indices = indices[i:i+batchSize]
                batch_indices.sort()
    
                by = db["labels"][batch_indices,:]
                bx = db["images"][batch_indices,:,:,:]
    
                bx[:,:,:,0] -= meanV[0]
                bx[:,:,:,1] -= meanV[1]
                bx[:,:,:,2] -= meanV[2]
                t1=time()
    
                if is_train:
    
                    #bx = random_crop(bx, (224,224))
                    if aug is not None:
                        bx,by = next(aug.flow(bx,by,batchSize))
    
                yield (bx,by)
    
    
    h5path='all_224.hdf5'   
    model.fit_generator(generator(h5path, train_indices, batchSize=batchSize, is_train=True, aug=aug),
                    steps_per_epoch = 20000//batchSize,
                    validation_data= generator(h5path, test_indices, is_train=False, batchSize=batchSize), 
                    validation_steps = 2424//batchSize,
                    epochs=args.epoch, 
                    max_queue_size=100,
                    callbacks=[checkpoint, early_stop])
    

相关问题