【问题标题】:How to efficiently feed data into TensorFlow 2.x,如何有效地将数据输入 TensorFlow 2.x,
【发布时间】:2021-06-11 05:18:24
【问题描述】:

我正在查看对大量文本数据的数据预处理任务,并希望将预处理后的数据加载到 TensorFlow 2.x 中。预处理数据包含整数值数组,因为预处理步骤生成:

  • 一个热编码数组作为标签列
  • 每个数据行的标记化标记列表
  • 用于转换器的激活掩码

所以,我一直在想我会使用 pyspark 来预处理数据并将结果转储到 JSON 文件中(因为 CSV 无法存储结构化数据)。到目前为止,一切正常。但是我在处理tf.data.Dataset 中的JSON 文件时遇到了问题(或者任何其他可以高效扩展并可以与TensorFlow 2.x 接口的文件)。

我不想使用/安装除 Tensorflow 和 PySpark 之外的其他库(例如 TensorFlowOnSpark),所以我想知道是否可以使用 JSON 文件以有效的方式链接这两者,因为似乎没有其他方法可以保存/loading 包含数据列表的记录(?)。 JSON 测试文件如下所示:

readDF = spark.read.format('json').option('header',True).option('sep','|').load('/output.csv')
readDF.select('label4').show(15, False)

+---------------------------------------------------------+
|label4                                                   |
+---------------------------------------------------------+
|[0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]|
|[0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]|
|[0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]|
|[0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]|
|[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0]|
|[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0]|
|[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0]|
|[0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]|
|[0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]|
|[0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]|
|[0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]|
|[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]|
|[0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]|
|[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0]|
|[0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]|
+---------------------------------------------------------+

因此,label4 列已经过一次热编码,并且一旦应用标记器,标记化的文本列将看起来相似。所以,我的问题是:JSON 文件可以有效地加载(可能通过生成器函数)tf.data.Dataset,还是我应该为此走一条不同的道路(使用额外的库)?

【问题讨论】:

    标签: python tensorflow pyspark tf.data.dataset


    【解决方案1】:

    tf.data 提供了多种方法来有效地使用来自不同来源的数据。虽然我会说一个“更清洁”的解决方案可能是使用 TensorFlow 本身来处理预处理,但让我为您的用例提出一些想法:

    1) one-hot 编码

    我可以看到您对数据进行了预处理并存储了整个 one-hot 编码向量,这将惩罚您的数据传输,因为您将读取的大部分内容都是零,而不是实际感兴趣的标签。我建议将其编码为整数,并在摄取时使用 python 生成器将其转换为单热编码。或者,如果您使用分类交叉熵损失函数,则可以使用标签编码(将每个类编码为整数),并改用 sparse categorical cross entropy

    如果你已经有 one-hot-encoded 列表,你可以简单地使用my_list.index(1) 来获取标签编码(毕竟它与向量中唯一1的索引相同。)

    2) 使用生成器

    这完全可以使用tf.data。事实上,它们提供了from_generator 函数来包装python 基因,用于将数据摄取到模型中。如文档中所述,这是您将如何使用它:

    def gen():
      ragged_tensor = tf.ragged.constant([[1, 2], [3]])
      yield 42, ragged_tensor
    
    dataset = tf.data.Dataset.from_generator(
         gen,
         output_signature=(
             tf.TensorSpec(shape=(), dtype=tf.int32),
             tf.RaggedTensorSpec(shape=(2, None), dtype=tf.int32)))
    
    list(dataset.take(1))
    

    3) 考虑回到 CSV

    如果您正在处理大量数据,您可能可以解决 JSON 编码问题并在类似 CSV 的格式(例如 TSV)中编码一些结构,如果您需要类似列表的列,您可以使用其他分隔符(例如,您可以使用\t 分隔列,然后您可以使用,| 或任何可以减少与现有数据冲突的字符来分隔每列中的元素。

    例如,假设您的 CSV 文件具有以下结构:

    comlumn name 1, column name 2, column name 3, column name 4
    0.1,0.2,0.3,0:0:0:1
    0.1,0.2,0.3,0:0:1:0
    0.1,0.2,0.3,0:1:0:0
    ...
    

    也就是说,您有 4 列,由 , 分隔,而第 4 列本身就是由 : 分隔的值列表,这也是 4 个类的一个热门表示,您可以使用的生成器上面的代码是:

    def my_generator(filename):
        first_line = True
        with open(filename) as f:
            for line in f:
                if first_line:
                    # do something to handle the header
                    first_line = False
                    continue
                fields = line.split(',')
                # here you extract the index of the one-hot encoded class
                label = fields[3].split(':').index(1)
                fields[3] = label
                yield fields # return a list of features and the class
    

    【讨论】:

    • 您能否提供示例 python 代码(或指向每个选项的链接)?我喜欢选项 2),但不知道如何包装一个生成器(例如从 python 读取)以供 tf.data 使用:-(选项 3)也很有趣,但你能提供一个关于如何热编码列表的 python 示例(我也在看多热编码)可以为tf.data解码,当它被编码为'0,1,0,0,0,0'时?
    • 我添加了一些代码sn-ps和相关文档的链接,只需点击tf.datafrom_generator,它们的格式类似于代码,但它们是链接:)
    • 生成器函数不会读取 JSON 或 CSV 文件或任何在其列中包含列表的文件。我也可以查找文档,但我需要解决使用 tf.data 读取结构化列表的特定问题。我如何在生成器函数或其他 3 种方法中实际执行此操作?
    • from_generator 函数将创建 tf.data.Dataset 对象并摄取生成器提供的数据,如何解析 JSON 或 csv 取决于生成器本身。这就是为什么我建议改用 CSV 的原因,您可以编写一个自定义 CSV 解析器作为 python 生成器,也就是说,第 4 列应该被解释为一个列表。
    • 但是,将第 4 列理解为列表并以这种方式填充它的生成器是什么样的?这是最初的问题,只是跳过它不是一个有用的答案,因为我仍然无法在这里实施更有效的策略:-(
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-29
    • 2020-08-24
    • 2019-04-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多