【问题标题】:Large data quantities in keras model.predictkeras model.predict 中的大数据量
【发布时间】:2020-08-19 16:39:07
【问题描述】:

我有一个这样定义的 CNN:

inputs = keras.Input(shape=(1024,1))
x=inputs

# 1st convolutional block
x = keras.layers.Conv1D(16, kernel_size=(3), name='Conv_1')(x)
x = keras.layers.LeakyReLU(0.1)(x)      
x = keras.layers.MaxPool1D((2), name='MaxPool_1')(x)

x = keras.layers.Flatten(name='Flatten')(x)

# Classifier
x = keras.layers.Dense(64, name='Dense_1')(x)
x = keras.layers.ReLU(name='ReLU_dense_1')(x)
x = keras.layers.Dropout(0.2)(x)
x = keras.layers.Dense(64, name='Dense_2')(x)
x = keras.layers.ReLU(name='ReLU_dense_2')(x)

我在一次 google colab 会话中对其进行训练,然后打开训练好的模型并使用 keras 的model.predict(dataarr) 来预测结果。

问题是我希望能够使用大量数据进行预测,但数据保存在 .txt 文件中,这些文件变得非常大 (>8GB),因此 google colab 没有足够的 RAM 来打开文件并将所有数据读入单个数组。

处理此问题的最佳方法是什么?我正在用 C++ 生成数据,而且我不是专家,但是当我写出数据时必须可以将数据转换为二进制,并在读取时将其转换回来。这是一个明智的选择吗?或者有没有办法让 keras 批量预测,因为 .txt 文件中的每组 1024 行都独立于下一组?

【问题讨论】:

  • 当您的输入大小设置为(1024,1) 时,您的输入怎么可能大于8GB?你想预测什么?您是否尝试过批量处理?
  • @Ruli 据我了解, Input(shape) 意味着模型的输入正好有 1024 个神经元,因为我传递给模型的每个数据点都用 1024 行表示.txt 文件。该模型所做的是获取每个由 1024 个数字组成的波形,并预测有多少粒子撞击探测器以创建该波形。没试过批量预测,因为不知道在keras怎么做,也不知道是不是最智能的方案

标签: python keras


【解决方案1】:

那么什么是输入形状?

来自keras documentation

shape:一个形状元组(整数),不包括批量大小。例如,shape=(32,) 表示预期输入将是一批 32 维向量。这个元组的元素可以是 None; “无”元素表示形状未知的维度。

这是什么意思?您的输入层keras.Input(shape=(1024,1)) 说,您将输入 1024 个一维向量的向量,因此是 1024 个值。如您正确理解的那样,输入层中有 1024 个神经元。然而,单个神经元不适用于输入序列(即行),但可以组合来自前一层神经元的输入及其权重或输入上的单个值。提供的每个下一个值(从序列中)只是另一个独立的评估。阅读有关neurons here. 的更多信息。但是,卷积层是 NN 的特定类型,它使用过滤器并试图在提供的数据中找到模式,期望始终具有相同形状的数据,例如相同大小的图像或信号部分。

如果您想提供形状不一致的数据,您有两种选择:

  1. 将数据拆分成批次以适应输入形状并选择合理的批次大小以适应您的 RAM,但这可能会导致信息丢失,因为您的数据可能具有连续性,拆分时会丢失
  2. 使用另一种适用于顺序数据的神经网络 - 循环神经网络,例如 LSTM。这些网络将编码的字符/单词/值作为单个输入,并通过网络处理它,并部分记忆数据。 LSTM 网络广泛用于文本分类,不需要像大多数 NN 那样输入静态大小。如果您使用带有一组键的数据,例如自然文本、源代码等,您还应该考虑通过哈希映射对数据进行编码(如果尚未这样做)。您可以节省空间,并且 NN 的工作方式更直观带有数字数据。

附带说明,如果您没有非常强大的机器,您根本不想用如此庞大的数据训练/测试/执行 NN(期望您有多个具有如此大小的文件),时间复杂度为使用这种规模的数据进行训练太高了,您可能永远无法获得训练有素的模型。

编辑 经过OP的进一步解释:

上述内容仍然适用,但在这种情况下不适用,将其留在那里,因为它可能对其他人有帮助。

关于 OPs 问题,仍然应该应用批量加载。 RAM 不会变得更大,因此需要将数据集分成块。一次加载(即 100 或 1000 行)不应加载太多 RAM - 您应该尝试找出机器的限制在哪里。您可以使用以下代码加载行:

with open("log.txt") as infile:
    for line in infile:
        do_something_with(line)

文件将在处理后关闭,垃圾收集器将从内存中释放行。您可以在ndarray 中堆叠行以将它们处理到predict() 方法。如果不预测单个样本,您还需要提供batch_size

编辑 2:

你真正需要做的是一次加载n行,完成它的线程是here。您打开文件并加载 n x n 块,例如我提供的示例数据我选择了 2 块,您可以使用您需要的任何数字,例如1000.

from itertools import zip_longest
import numpy as np

n = 2  # Or whatever chunk size you want
with open("file.txt", 'rb') as f:
    for n_lines in zip_longest(*[f]*n, fillvalue=b''):
      arr = np.char.decode(np.array(n_lines),encoding='utf_8')
      print(arr)

我在示例文件中使用的数据如下:

1dsds
2sdas
3asdsa
4asdsaad
5asdsaad
6dww
7vcvc
8uku
9kkk1

我选择了奇数和2作为块大小,所以你可以看到它附加了空数据,函数的输出如下:

['1dsds\n' '2sdas\n']
['3asdsa\n' '4asdsaad\n']
['5asdsaad\n' '6dww\n']
['7vcvc\n' '8uku\n']
['9kkk1' '']

此代码一次加载 2 行,然后您可以在 [s.replace('\n' , '') for s in arr] 需要时删除换行符

要成功使用返回的数据,请使用 yield 并迭代此函数:

from itertools import zip_longest
import numpy as np

def batcher(filename: str):
    n = 2  # Or whatever chunk size you want
    with open(filename, 'rb') as f:
        for n_lines in zip_longest(*[f]*n, fillvalue=b''):
          #decode the loaded byte arrays to strings 
          arr = np.char.decode(np.array(n_lines),encoding='utf_8')
          yield arr.astype(np.float)
for batch_i, arr in enumerate(batcher("file.txt")):
    out = model.predict(arr.reshape( your_shape_comes_here ))
    #do what you need with the predictions

【讨论】:

  • 也许我还没有说清楚。我要评估的每个“事件”都由 1024 个数据点组成。因此,我的网络的 1024 个输入神经元是正确的数字。数据不是连续的,一个事件完全独立于下一个事件,因此我不需要 LSTM。我的 CNN 已经训练过了,我只想知道使用它来评估一个非常大的数据样本的最有效方法
  • @BethLong 我已经编辑了答案,我对误解你做什么/需要什么不好,你应该按批次预测,这是处理大型数据集的标准方法
  • 我仍然不明白 model.predict() 行将如何处理我的批量数据。我是否必须为 infile 逐行执行 model.predict(one_event) ,其中 one_event 将是一个 [1,1024] 数组,表示要预测的一个事件?这会比使用不同的文件类型而不是 txt 更容易或更有效吗?
  • @BethLong 将很快尝试提供您需要的代码
  • @BethLong 我已经尽力了,可能无法再帮助您了,如果您感谢我的帮助,请考虑接受和/或支持答案。如果您认为可能有更有效的方法来实现这一点,您可能会考虑提出一个新问题,以提高当前代码的效率。你可能比这个 2 个月大的问题更幸运。
猜你喜欢
  • 2018-02-05
  • 1970-01-01
  • 2018-02-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-09
相关资源
最近更新 更多