Ich habe ein Verzeichnis mit rund einer Million Bildern. Ich möchte einen batch_generator erstellen, damit ich mein CNN trainieren kann, da ich nicht alle diese Bilder gleichzeitig im Speicher halten kann.

Also schrieb ich eine Generatorfunktion, um dies zu tun.

def batch_generator(image_paths, batch_size, isTraining):
    while True:
        batch_imgs = []
        batch_labels = []

        type_dir = 'train' if isTraining else 'test'

        for i in range(len(image_paths)):
            print(i)
            print(os.path.join(data_dir_base, type_dir, image_paths[i]))
            img = cv2.imread(os.path.join(data_dir_base, type_dir, image_paths[i]), 0)
            img  = np.divide(img, 255)
            img = img.reshape(28, 28, 1)
            batch_imgs.append(img)
            label = image_paths[i].split('_')[1].split('.')[0]
            batch_labels.append(label)
            if len(batch_imgs) == batch_size:
                yield (np.asarray(batch_imgs), np.asarray(batch_labels))
                batch_imgs = []
        if batch_imgs:
            yield batch_imgs

Wenn ich diese Aussage nenne-

index = next(batch_generator(train_dataset, 10, True))

Es druckt dieselben Indexwerte und Pfade und gibt daher bei jedem Aufruf von next () denselben Stapel zurück. Wie behebe ich das?

Ich habe diese Frage als Referenz für den Code verwendet, wie man eine aufteilt iterabel in Blöcken konstanter Größe

1
user8187389 18 Jän. 2019 im 10:25

3 Antworten

Beste Antwort

Generatorfunktionen sind keine Generatoren selbst, sondern "Generatorfabriken". Jedes Mal, wenn Sie batch_generator(...) aufrufen, wird ein neuer Generator zurückgegeben, der erneut gestartet werden kann. IOW, du willst:

gen = batch_generator(...)
for batch in gen:       
    do_something_with(batch)

Ebenfalls:

1 / Die Art und Weise, wie Sie Ihre Generatorfunktion geschrieben haben, erzeugt einen unendlichen Generator - die äußere while-Schleife wird sich für immer wiederholen - was möglicherweise das ist, was Sie erwartet haben oder nicht (ich dachte, ich warne Sie besser).

2 / Ihr Code enthält zwei logische Fehler: Erstens setzen Sie die batch_labels -Liste nicht zurück, und beim letzten yield geben Sie nur batch_imgs aus, was nicht mit dem übereinstimmt inneres yield. FWIW, anstatt zwei Listen zu verwalten (eine für die Bilder und die andere für die Beschriftungen), ist es vielleicht besser, eine einzige Liste von (img, label) Tupeln zu verwenden.

Und als letzte Randnotiz: Sie müssen nicht range(len(lst)) verwenden, um eine Liste zu iterieren - Pythons for -Schleife ist vom Typ foreach und iteriert direkt über die Elemente des Iterables. dh:

for path image_paths:
    print(path)

Funktioniert trotzdem, ist besser lesbar und etwas schneller ...

0
bruno desthuilliers 18 Jän. 2019 im 08:07

Mir scheint, Sie versuchen etwas in dieser Richtung zu erreichen:

def batch_generator(image_paths, batch_size, isTraining):
    your_code_here

Generator anrufen - statt was Sie haben:

index = next(batch_generator(train_dataset, 10, True))

Du kannst es versuchen:

index = iter(batch_generator(train_dataset, 10, True))
index.__next__()
0
kerwei 18 Jän. 2019 im 07:59
# batch generator
def get_batches(dataset, batch_size):
    X, Y = dataset
    n_samples = X.shape[0]

    # Shuffle at the start of epoch
    indices = np.arange(n_samples)
    np.random.shuffle(indices)

    for start in range(0, n_samples, batch_size):
        end = min(start + batch_size, n_samples)

        batch_idx = indices[start:end]

        yield X[batch_idx], Y[batch_idx]
0
David Buck 22 Apr. 2020 im 20:15