【问题标题】:Write to HDF5 and shuffle big arrays of data写入 HDF5 并打乱大数据数组
【发布时间】:2017-06-10 12:26:58
【问题描述】:

我已经下载了 Caltech101。它的结构是:

#Caltech101 dir #class1 dir #images of class1 jpgs #class2 dir #images of class2 jpgs ... #class100 dir #images of class100 jpgs

我的问题是我无法在内存中保存两个形状为(9144, 240, 180, 3)(9144) 的np 数组xy。所以我的解决方案是过度分配一个 h5py 数据集,将它们加载到 2 个块中,然后将它们一个接一个地写入文件。准确地说:

from __future__ import print_function
import os
import glob
from scipy.misc import imread, imresize
from sklearn.utils import shuffle
import numpy as np
import h5py
from time import time


def load_chunk(images_dset, labels_dset, chunk_of_classes, counter, type_key, prev_chunk_length):
    # getting images and processing
    xtmp = []
    ytmp = []
    for label in chunk_of_classes:
        img_list = sorted(glob.glob(os.path.join(dir_name, label, "*.jpg")))
        for img in img_list:
            img = imread(img, mode='RGB')
            img = imresize(img, (240, 180))
            xtmp.append(img)
            ytmp.append(label)
        print(label, 'done')

    x = np.concatenate([arr[np.newaxis] for arr in xtmp])
    y = np.array(ytmp, dtype=type_key)
    print('x: ', type(x), np.shape(x), 'y: ', type(y), np.shape(y))

    # writing to dataset
    a = time()
    images_dset[prev_chunk_length:prev_chunk_length+x.shape[0], :, :, :] = x
    print(labels_dset.shape)
    print(y.shape, y.shape[0])
    print(type(y), y.dtype)
    print(prev_chunk_length)
    labels_dset[prev_chunk_length:prev_chunk_length+y.shape[0]] = y
    b = time()
    print('Chunk', counter, 'written in', b-a, 'seconds')
    return prev_chunk_length+x.shape[0]


def write_to_file(remove_DS_Store):
    if os.path.isfile('caltech101.h5'):
        print('File exists already')
        return
    else:
        # the name of each dir is the name of a class
        classes = os.listdir(dir_name)
        if remove_DS_Store:
            classes.pop(0)  # removes .DS_Store - may not be used on other terminals

        # need the dtype of y in order to initialize h5 dataset
        s = ''
        key_type_y = s.join(['S', str(len(max(classes, key=len)))])
        classes = np.array(classes, dtype=key_type_y)

        # number of chunks in which the dataset must be divided
        nb_chunks = 2
        nb_chunks_loaded = 0
        prev_chunk_length = 0
        # open file and allocating a dataset
        f = h5py.File('caltech101.h5', 'a')
        imgs = f.create_dataset('images', shape=(9144, 240, 180, 3), dtype='uint8')
        labels = f.create_dataset('labels', shape=(9144,), dtype=key_type_y)
        for class_sublist in np.array_split(classes, nb_chunks):
            # loading chunk by chunk in a function to avoid memory overhead
            prev_chunk_length = load_chunk(imgs, labels, class_sublist, nb_chunks_loaded, key_type_y, prev_chunk_length)
            nb_chunks_loaded += 1
        f.close()
        print('Images and labels saved to \'caltech101.h5\'')
    return

dir_name = '../Datasets/Caltech101'
write_to_file(remove_DS_Store=True)

这很好用,而且阅读速度也足够快。问题是我需要对数据集进行洗牌。

观察:

  • 洗牌数据集对象:显然非常慢,因为它们在磁盘上。

  • 创建一个随机索引数组并使用高级 numpy 索引。这意味着从文件中读取速度较慢。

  • 在写入文件之前洗牌会很好,问题:我每次只有大约一半的数据集在内存中。我会得到不正确的洗牌。

你能想出一种在写作前洗牌的方法吗?我也愿意重新考虑编写过程的解决方案,只要它不使用大量内存。

【问题讨论】:

    标签: python memory hdf5 h5py


    【解决方案1】:

    您可以在读取图像数据之前对文件路径进行洗牌。

    创建属于数据集的所有文件路径的列表,而不是打乱内存中的图像数据。然后打乱文件路径列表。现在您可以像以前一样创建 HDF5 数据库了。

    例如,您可以使用glob 来创建文件列表以进行混洗:

    import glob
    import random
    
    files = glob.glob('../Datasets/Caltech101/*/*.jpg')
    shuffeled_files = random.shuffle(files)
    

    然后您可以从路径中检索类标签和图像名称:

    import os
    
    for file_path in shuffeled_files:
        label = os.path.basename(os.path.dirname(file_path))
        image_id = os.path.splitext(os.path.basename(file_path))[0]
    

    【讨论】:

    • 这种方法的问题是目录的名字是我的标签,我应该创建一个地图图像->标签。好的,你刚刚回答了我:D
    • 我添加了一个示例,您可以如何从路径中检索 id 和标签。刚刚意识到,您也想存储标签(当然):)
    猜你喜欢
    • 2017-09-16
    • 2020-07-31
    • 2012-03-04
    • 1970-01-01
    • 1970-01-01
    • 2018-04-20
    • 2017-10-29
    • 2016-04-04
    • 2015-11-14
    相关资源
    最近更新 更多