【问题标题】:Tensorflow access tensor.numpy() in .map function but using py_function slows down iterator generationTensorflow 在 .map 函数中访问 tensor.numpy() 但使用 py_function 会减慢迭代器的生成速度
【发布时间】:2021-12-25 11:05:28
【问题描述】:

我想用我自己的一个热编码器给一个热编码器一个张量。为了这, 我必须在.map 中调用tf.keras.backend.get_value(),这只有在使用tf.py_function 时才有可能:

def one_hot_encode(categories,input):
  encoded_input = []
  data = tf.keras.backend.get_value(input)
  for category in categories:
    encoded_input.append(data==category)
  return np.array(encoded_input)

问题是,在映射数据集并调用one_hot_encode时:

ds = ds.map(lambda input, target: (input, tf.py_function(one_hot_encode,inp=[[1,2,3,4,5,6,7,8,9,10],target], Tout=tf.float32)))
ds = ds.map(lambda input, target: (input, tf.reshape(target, (10,))))

tensorflow 将永远为这个数据集创建一个迭代器,例如尝试在 for 循环中访问数据时:

for (input, target) in dataset:
 ...

但如果我在一个热编码器中使用 tensorflows 构建,一切正常且 tensorflow 速度很快。

ds = ds.map(lambda input, target: (input, tf.one_hot(target,10)))
ds = ds.map(lambda input, target: (input, tf.reshape(target, (10,))))

在这两种方法中,数据集和所有张量都具有相同的形状。有谁知道另一种访问 .map 中张量值的方法,或者为什么 tensorflow 变得这么慢?

【问题讨论】:

  • 输入数据(输入、标签)的形状是什么?你的目标到底是什么?
  • 我正在使用来自 tensorflow 的基因组学_ood 数据集。我的目标是对基因组序列进行热编码。有 4 个字符,(A,C,G,T),每个序列有 250 个字符,所以一个热编码张量的形状为 (1000,),标签的形状为 (10,)。如果我在 one_hot 中使用 tensorflow,一切正常,但如果我将自己的 one_hot(所有值和形状在两种情况下都匹配)与 py_function 一起使用,则 tensorflow 会变得非常慢。而且因为我想/必须自己做一个热编码器,所以我不能使用内置功能。
  • 你能展示一下你是如何实现你的一个热门编码器的吗?
  • 我编辑了原帖。为简单起见,我没有对序列进行热编码,而是对可以是 1 到 10 的数字的标签进行热编码。但这不会改变输出行为
  • 对不起,我目前很忙,项目的时间有限。我可能会在 2 或几天或一段时间内恢复它。我会让你知道它是否有效:)。谢谢回答

标签: python tensorflow iterator tf.keras eager-execution


【解决方案1】:

我认为您可以用tf 操作替换您当前的实现,同时仍保留您的自定义逻辑。例如,这里有一个代码 sn-p 将分类标签从 0 到 4 转换为 one-hot 编码标签,而不使用 numpytf.py_function

import tensorflow as tf
import pathlib

dataset_url = "https://storage.googleapis.com/download.tensorflow.org/example_images/flower_photos.tgz"
data_dir = tf.keras.utils.get_file('flower_photos', origin=dataset_url, untar=True)
data_dir = pathlib.Path(data_dir)

batch_size = 32

train_ds = tf.keras.utils.image_dataset_from_directory(
  data_dir,
  validation_split=0.2,
  subset="training",
  seed=123,
  image_size=(28, 28),
  batch_size=batch_size)


def change_inputs(images, labels, categories):
  tf.print('Before one hot encoding --> \n',labels, summarize=-1)

  temp_labels = tf.repeat(labels, repeats=len(categories), axis = 0)
  temp_labels = tf.reshape(temp_labels, shape=(tf.shape(labels)[0], len(categories)))
  one_hot_encoded_labels = tf.identity(temp_labels)

  for cat in categories:
    indices = tf.where(tf.equal(tf.constant(cat), temp_labels))
    values = tf.zeros(len(categories))
    values = tf.cast(tf.tensor_scatter_nd_update(values, [[cat]], [1.0]), dtype=tf.int32)
    values = tf.tile(values, multiples=[int(tf.shape(indices)[0]/len(categories))])
    one_hot_encoded_labels = tf.tensor_scatter_nd_update(one_hot_encoded_labels, indices, values)

  return images, one_hot_encoded_labels

categories = [0, 1, 2, 3, 4]
train_ds = train_ds.map(lambda input, target: change_inputs(input, target, categories))

for x, y in train_ds.take(1):
  tf.print('After one hot encoding --> \n', y, summarize=-1)
Found 3670 files belonging to 5 classes.
Using 2936 files for training.
Before one hot encoding --> 
 [2 1 4 3 1 2 1 2 4 1 4 4 3 4 1 2 0 4 1 1 1 4 3 2 3 1 4 2 2 3 4 3]
After one hot encoding --> 
 [[0 0 1 0 0]
 [0 1 0 0 0]
 [0 0 0 0 1]
 [0 0 0 1 0]
 [0 1 0 0 0]
 [0 0 1 0 0]
 [0 1 0 0 0]
 [0 0 1 0 0]
 [0 0 0 0 1]
 [0 1 0 0 0]
 [0 0 0 0 1]
 [0 0 0 0 1]
 [0 0 0 1 0]
 [0 0 0 0 1]
 [0 1 0 0 0]
 [0 0 1 0 0]
 [1 0 0 0 0]
 [0 0 0 0 1]
 [0 1 0 0 0]
 [0 1 0 0 0]
 [0 1 0 0 0]
 [0 0 0 0 1]
 [0 0 0 1 0]
 [0 0 1 0 0]
 [0 0 0 1 0]
 [0 1 0 0 0]
 [0 0 0 0 1]
 [0 0 1 0 0]
 [0 0 1 0 0]
 [0 0 0 1 0]
 [0 0 0 0 1]
 [0 0 0 1 0]]

简而言之,在使用tf.data.Dataset.map 修改数据集时,您通常不必使用tensor.numpy()tf.py_function

【讨论】:

    猜你喜欢
    • 2014-09-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多