gpt4 book ai didi

python - 如何在 map 方法中预处理和标记 TensorFlow CsvDataset?

转载 作者:行者123 更新时间:2023-12-02 16:42:04 27 4
gpt4 key购买 nike

我制作了一个 TensorFlow CsvDataset,我正在尝试将数据标记为这样:

import os
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3'
from tensorflow import keras
import tensorflow as tf
from tensorflow.keras.preprocessing.text import Tokenizer
import os
os.chdir('/home/nicolas/Documents/Datasets')

fname = 'rotten_tomatoes_reviews.csv'


def preprocess(target, inputs):
tok = Tokenizer(num_words=5_000, lower=True)
tok.fit_on_texts(inputs)
vectors = tok.texts_to_sequences(inputs)
return vectors, target


dataset = tf.data.experimental.CsvDataset(filenames=fname,
record_defaults=[tf.int32, tf.string],
header=True).map(preprocess)

运行它,出现以下错误:

ValueError: len requires a non-scalar tensor, got one of shape Tensor("Shape:0", shape=(0,), dtype=int32)

我尝试过的:几乎所有可能的领域。请注意,如果我删除预处理步骤,一切都会运行。

数据是什么样的:

(<tf.Tensor: shape=(), dtype=int32, numpy=1>,
<tf.Tensor: shape=(), dtype=string, numpy=b" Some movie critic review...">)

最佳答案

首先,让我们找出代码中的问题:

  • 第一个问题,也是给定错误背后的原因,是 fit_on_texts 方法接受文本列表,而不是单个文本字符串。因此,它应该是:tok.fit_on_texts([inputs])

  • 修复该问题并再次运行代码后,您会收到另一个错误:AttributeError: 'Tensor' object has no attribute 'lower'。这是因为dataset中的元素都是Tensor对象,map函数应该可以处理;然而,Tokenizer 类并不是为处理 Tensor 对象而设计的(这个问题有一个解决方案,但由于下一个问题,我现在不会解决它)。

  • 最大的问题是每次调用 map 函数,即 preprocess 时,都会创建一个 Tokenizer 类的新实例,它会适合在单个文本文档上。 更新:作为@Princy在评论部分正确指出,fit_on_texts 方法实际上执行部分拟合(即更新或扩充内部词汇表统计数据,而不是从头开始)。因此,如果我们在 preprocess 函数之外创建 Tokenizer 类,并且假设词汇集事先已知(否则,您无法过滤最部分拟合方案中的常用词,除非您首先拥有或构建词汇集),那么在应用上述修复后也可以使用这种方法(即基于 Tokenizer 类)。但是,就我个人而言,我更喜欢下面的解决方案。


那么,我们该怎么办呢?如上所述,在几乎所有处理文本数据的模型中,我们首先需要将文本转换为数字特征,即对其进行编码。为了执行编码,首先我们需要一个词汇集或标记字典。因此,我们应该采取的步骤如下:

  1. 如果有可用的预建词汇表,则跳至下一步。否则,首先标记化所有文本数据并构建词汇表。

  2. 使用词汇集对文本数据进行编码。

为了执行第一步,我们使用 tfds.features.text.Tokenizer通过迭代数据集来标记文本数据并构建词汇表。

对于第二步,我们使用 tfds.features.text.TokenTextEncoder使用上一步中构建的词汇集对文本数据进行编码。请注意,对于此步骤,我们使用 map 方法;然而,由于 map 仅在图形模式下起作用,我们将 encode 函数包装在 tf.py_function 中,以便它可以与 map

这是代码(请阅读代码中的注释以获取更多要点;我没有将它们包含在答案中,因为它们没有直接关系,但它们很有用且实用):

import tensorflow as tf
import tensorflow_datasets as tfds
from collections import Counter

fname = "rotten_tomatoes_reviews.csv"
dataset = tf.data.experimental.CsvDataset(filenames=fname,
record_defaults=[tf.int32, tf.string],
header=True)

# Create a tokenizer instance to tokenize text data.
tokenizer = tfds.features.text.Tokenizer()

# Find unique tokens in the dataset.
lowercase = True # set this to `False` if case-sensitivity is important.
vocabulary = Counter()
for _, text in dataset:
if lowercase:
text = tf.strings.lower(text)
tokens = tokenizer.tokenize(text.numpy())
vocabulary.update(tokens)

# Select the most common tokens as final vocabulary set.
# Note: if you want all the tokens to be included,
# set `vocab_size = len(vocabulary)` instead.
vocab_size = 5000
vocabulary, _ = zip(*vocabulary.most_common(vocab_size))

# Create an encoder instance given our vocabulary set.
encoder = tfds.features.text.TokenTextEncoder(vocabulary,
lowercase=lowercase,
tokenizer=tokenizer)

# Set this to a non-zero integer if you want the texts
# to be truncated when they have more than `max_len` tokens.
max_len = None

def encode(target, text):
text_encoded = encoder.encode(text.numpy())
if max_len:
text_encoded = text_encoded[:max_len]
return text_encoded, target

# Wrap `encode` function inside `tf.py_function` so that
# it could be used with `map` method.
def encode_pyfn(target, text):
text_encoded, target = tf.py_function(encode,
inp=[target, text],
Tout=(tf.int32, tf.int32))

# (optional) Set the shapes for efficiency.
text_encoded.set_shape([None])
target.set_shape([])

return text_encoded, target

# Apply encoding and then padding.
# Note: if you want the sequences in all the batches
# to have the same length, set `padded_shapes` argument accordingly.
dataset = dataset.map(encode_pyfn).padded_batch(batch_size=3,
padded_shapes=([None,], []))

# Important Note: probably this dataset would be used as input to a model
# which uses an Embedding layer. Therefore, don't forget that you
# should set the vocabulary size for this layer properly, i.e. the
# current value of `vocab_size` does not include the padding (added
# by `padded_batch` method) and also the OOV token (added by encoder).

给 future 读者的旁注:请注意参数的顺序,即 target, text 和数据类型基于 OP 的数据集。根据您自己的数据集/任务根据需要进行调整(尽管在最后,即 return text_encoded, target,我们对此进行了调整以使其与 fit 方法的预期格式兼容).

关于python - 如何在 map 方法中预处理和标记 TensorFlow CsvDataset?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61445913/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com