Keras的predict_generator没有返回正确数量的样本

时间:2018-01-31 20:48:14

标签: python pandas tensorflow keras

我正在尝试实现一个自定义数据生成器,它使用pandas.read_csv以块的形式从csv文件中读取数据。我用model.predict_generator测试了它,但返回的预测数量少于预期(在我的情况下,253457中的248192)。

自定义生成器

class TestDataGenerator:

def __init__(self, directory, batch_size=1024):
    self.directory = directory
    self.batch_size = batch_size
    self.chunk_size=10000
    self.samples = 0

def _to_movie_id(self, ids):
    ids = ast.literal_eval(ids)
    if ids == []:
        return [EMB_MATRIX_SIZE-1]
    else:
        return [movie2idx[str(movie_id)] for movie_id in ids]

def generate(self):
    csv_files = glob.glob(self.directory + '/*.csv')
    while True:
        for file in csv_files:
            df = pd.read_csv(file, chunksize=self.chunk_size)
            for df_chunk in df:
                chunk_steps = math.ceil(len(df_chunk) / self.batch_size)
                for i in range(chunk_steps):
                    batch = df_chunk[i * self.batch_size:(i + 1) * self.batch_size]
                    X_batch, y_batch = self.preprocess(batch)
                    self.samples += len(batch)
                    yield X_batch, y_batch


def preprocess(self, df):
    X_user = df['user'].apply(lambda x: user2idx[str(x)]).values
    X_watched = df['watched'].apply(self._to_movie_id).values
    X_watched_padded = pad_sequences(X_watched, maxlen=SEQ_LENGTH, value=0)

    ohe = df['movie'].apply(lambda x: to_categorical(movie2idx[x], num_classes=len(movie2idx)))
    X = [X_user, X_watched_padded]
    y = np.array([o.tolist() for o in ohe])

    return X, y

运行model.predict_generator

batch_size=1024
n_samples_test = 253457
test_dir = 'folder/'
test_gen = TestDataGenerator(test_dir, batch_size=batch_size)
next_test_gen = test_gen.generate()
preds = model.predict_generator(next_test_gen, steps=math.ceil(n_samples_test/batch_size))

运行model.predict_generator后,preds的行数为248192,小于实际的253457。看起来它缺少了几个时代。我还单独测试了generate而没有与Keras进行交互,并且它按预期运行,在csv文件中返回正确数量的样本。此外,在generate生成值之前,我会跟踪使用samples处理的样本数。令人惊讶的是,samples的值是250000.所以,我很确定我可能会对Keras做过一些事情。

请注意,我还尝试设置max_queue_size=1,并使generate线程安全,但没有运气。为简单起见,我在test_dir下只放置了1个csv文件。我正在使用Tensorflow 1.5.0中嵌入的Keras 2.1.2-tf。

我做了一些关于如何做到这一点的研究,但还没有找到一个有用的例子。这个实现有什么问题?

由于

Peeranat F。

1 个答案:

答案 0 :(得分:2)

嗯,这很棘手。让我们深入研究这个问题:

  1. 当提供的批次小于fit_generator 时,batch_size的工作原理:您可能会看到 - 您向fit_generator提供的许多批次属于大小小于batch_size。每次从每个文件中取出最后一批时都会发生这种情况。通常 - 许多文本不能被批量大小整除,因此没有足够的文本来填充批次。这最终会为模型提供更少的例子。

    这是一个棘手的部分 - keras忽略较小的尺寸,将其视为有效的生成器步骤并返回不完整批次的值。

  2. 那么为什么缺少文字:让我通过示例向您展示。假设您有2个文件,每个文件有5个文本,batch_size为4.这就是您的批次的样子:

    [1t1, 1t2, 1t3, 1t4], [1t5,], [2t1, 2t2, 2t3, 2t4], [2t5].
    

    正如您所看到的 - 所需的实际步数等于4,它不等于3,它是通过以下方式获得的:math.ceil(10 / 4)。这种方式适用于这些批次:

    [1t1, 1t2, 1t3, 1t4], [1t5, 2t1, 2t2, 2t3], [2t4, 2t5]
    

    但是从您的发电机返回的批次不是这些。

  3. 如何解决问题? - 您需要让您的生成器计算所需的实际步骤数:

    def steps_needed(self):
        steps = 0
        csv_files = glob.glob(self.directory + '/*.csv')
        for file in csv_files:
        df = pd.read_csv(file, chunksize=self.chunk_size)
        for df_chunk in df:
            chunk_steps = math.ceil(len(df_chunk) / self.batch_size)
            steps += chunk_steps
        return steps
    

    此函数准确计算您的生成器将返回多少批次。

  4. 干杯:)