2017-01-25 1 views
0

Ich habe Caltech101 heruntergeladen. Seine Struktur ist:Schreiben Sie auf HDF5 und mischen Sie große Datenfelder

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

Mein Problem ist, dass ich nicht im Speicher zwei np Arrays x und y der Form (9144, 240, 180, 3) und (9144) halten kann. Meine Lösung besteht also darin, ein h5py-Dataset zu verteilen, sie in 2 Chunks zu laden und sie nacheinander in die Datei zu schreiben. Genau:

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) 

Das funktioniert ganz gut, und auch das Lesen ist eigentlich schnell genug. Das Problem ist, dass ich den Datensatz mischen muss.

Beobachtungen:

  • die Daten-Set Objekte Schlurfen: offensichtlich seeeehr langsam, weil sie auf der Festplatte sind.

  • Erstellen Sie ein Array von gemischten Indizes und verwenden Sie erweiterte Indexerstellung. Dies bedeutet ein langsameres Lesen der Datei.

  • Mischen vor dem Schreiben in die Datei wäre nett, Problem: Ich habe immer nur etwa die Hälfte des Datensatzes im Speicher. Ich würde ein falsches Mischen bekommen.

Können Sie sich einen Weg vorstellen, vor dem Schreiben zu mischen? Ich bin auch offen für Lösungen, die den Schreibprozess überdenken, solange sie nicht viel Speicher verbrauchen.

Antwort

2

Sie können die Dateipfade mischen, bevor Sie die Bilddaten lesen.

Anstatt die Bilddaten im Speicher zu mischen, erstellen Sie eine Liste aller Dateipfade, die zum Datensatz gehören. Dann mische die Liste der Dateipfade. Jetzt können Sie Ihre HDF5-Datenbank wie zuvor erstellen.

Sie zum Beispiel glob verwenden könnte die Liste der Dateien für Schlurfen zu erstellen:

import glob 
import random 

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

Sie könnten dann rufen Sie das Klassenlabel und Bildnamen aus dem Pfad:

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] 
+0

Das Problem dieser Ansatz ist, dass der Name der Verzeichnisse meine Etiketten sind, sollte ich ein Kartenbild erstellen -> Label. Ok, du antwortest mir gleich nach: D – iacolippo

+0

Ich habe ein Beispiel hinzugefügt, wie du die ID und das Label vom Pfad abrufen kannst. Habe gerade gemerkt, dass du die Labels auch (natürlich) speichern willst :) – thertweck

+0

Es funktioniert! Vielen Dank – iacolippo

Verwandte Themen