Как обработать последнюю партию с помощью keras fit_generator - PullRequest
1 голос
/ 28 апреля 2019

Я использую настраиваемый генератор партий, чтобы решить проблему несовместимых фигур (ошибка BroadcastGradientArgs) при использовании стандартной функции model.fit () из-за небольшого размера последней партии в обучающих данных.Я использовал упомянутый генератор пакетов здесь с функцией model.fit_generator ():

class Generator(Sequence):
    # Class is a dataset wrapper for better training performance
    def __init__(self, x_set, y_set, batch_size=256):
        self.x, self.y = x_set, y_set
        self.batch_size = batch_size
        self.indices = np.arange(self.x.shape[0])

    def __len__(self):
        return math.floor(self.x.shape[0] / self.batch_size) 

    def __getitem__(self, idx):
        inds = self.indices[idx * self.batch_size:(idx + 1) * self.batch_size] #Line A
        batch_x = self.x[inds]
        batch_y = self.y[inds]
        return batch_x, batch_y

    def on_epoch_end(self):
        np.random.shuffle(self.indices)

Но, похоже, он отбрасывает последнюю партию, если ее размер меньше указанного размера партии,Как я могу обновить его, чтобы включить последний пакет и расширить его (например) несколькими повторными выборками?

Кроме того, каким-то образом я не понимаю, как работает «Линия А»!

Обновление: вот как я использую генератор с моей моделью:

# dummy model
input_1 = Input(shape=(None,))
...
dense_1 = Dense(10, activation='relu')(input_1)
output_1 = Dense(1, activation='sigmoid')(dense_1)

model = Model(input_1, output_1)
print(model.summary())

#Compile and fit_generator
model.compile(optimizer='adam', loss='binary_crossentropy')

train_data_gen = Generator(x1_train, y_train, batch_size)
test_data_gen = Generator(x1_test, y_test, batch_size)

model.fit_generator(generator=train_data_gen, validation_data = test_data_gen, epochs=epochs, shuffle=False, verbose=1)

 loss, accuracy = model.evaluate_generator(generator=test_data_gen)
print('Test Loss: %0.5f Accuracy: %0.5f' % (loss, accuracy))

1 Ответ

3 голосов
/ 28 апреля 2019

Мне кажется, виновником является эта линия

    return math.floor(self.x.shape[0] / self.batch_size)

Замените это на это может сработать

    return math.ceil(self.x.shape[0] / self.batch_size) 

Представьте, что у вас 100 образцов и размер партии 32. Он должен быть разделен на 3.125 партий. Но если вы используете math.floor, оно станет 3 и диссонанс 0,125.

Что касается строки A, если размер партии равен 32, а индекс равен 1, [idx * self.batch_size:(idx + 1) * self.batch_size] станет [32:64], другими словами, выберите с 33-го по 64-й элементы self.indices

** Обновление 2, измените вход, чтобы иметь форму None, используйте LSTM и добавьте оценку

import os
os.environ['CUDA_VISIBLE_DEVICES'] = ""
import math
import numpy as np
from keras.models import Model
from keras.utils import Sequence
from keras.layers import Input, Dense, LSTM


class Generator(Sequence):
    # Class is a dataset wrapper for better training performance
    def __init__(self, x_set, y_set, batch_size=256):
        self.x, self.y = x_set, y_set
        self.batch_size = batch_size
        self.indices = np.arange(self.x.shape[0])

    def __len__(self):
        return math.ceil(self.x.shape[0] / self.batch_size)

    def __getitem__(self, idx):
        inds = self.indices[idx * self.batch_size:(idx + 1) * self.batch_size]  # Line A
        batch_x = self.x[inds]
        batch_y = self.y[inds]
        return batch_x, batch_y

    def on_epoch_end(self):
        np.random.shuffle(self.indices)


# dummy model
input_1 = Input(shape=(None, 10))
x = LSTM(90)(input_1)
x = Dense(10)(x)
x = Dense(1, activation='sigmoid')(x)

model = Model(input_1, x)
print(model.summary())

# Compile and fit_generator
model.compile(optimizer='adam', loss='binary_crossentropy')

x1_train = np.random.rand(1590, 20, 10)
x1_test = np.random.rand(90, 20, 10)
y_train = np.random.rand(1590, 1)
y_test = np.random.rand(90, 1)

train_data_gen = Generator(x1_train, y_train, 256)
test_data_gen = Generator(x1_test, y_test, 256)

model.fit_generator(generator=train_data_gen,
                    validation_data=test_data_gen,
                    epochs=5,
                    shuffle=False,
                    verbose=1)

loss = model.evaluate_generator(generator=test_data_gen)
print('Test Loss: %0.5f' % loss)

Этот прогон без проблем.

...