首页 > 解决方案 > 如何将字符串映射到 int(类号)作为 tf.data.Dataset .map() 的一部分以在 Tensorflow 中进行预处理?

问题描述

我正在尝试创建一个从 TFRecord 读取(图像、标签)对的解析器函数。当标签是 int64 时,一切正常,但是当我尝试将标签保存为字符串并在解析器函数中将其转换为 int 时,事情就中断了。我还是这个框架的新手,所以我下面的实现使用了急切的 .numpy(),当我将 .map 应用于 tf.data.Dataset 时它不起作用。

一些背景:我的数据集中有层次结构,就像在这个例子中我使用“狗”和“拉布拉多”来表示它一样。我想允许训练可以对分类图像(猫、狗)进行分类的数据,并训练可以从相同的标记数据中对更具体的类型(斗牛犬、拉布拉多犬)进行分类的模型,这些数据通常具有最特定类型的标签在图像上。

这就是我试图做的:

#!/usr/bin/env python3
import tensorflow as tf
import functools

# example: this model classifies dogs and cats. this map translates a specific dog type to the "dog" label, 
# and the same for cats. all other labels would go to the negative class "neg".
example_label_map = {
    "bulldog": "dog",
    "labrador": "dog",
    "persian cat": "cat",
    "cow": "neg",
}

# map the N classes to an int of 0..N-1
labels_to_class_int = {
    "neg": 0,   # negative class
    "dog": 1,
    "cat": 2,
}

def parse_tfrec_function(example, labels_map):
    """
    labels is a map of labels to class numbers. e.g. "bulldog" -> 1, "labrador" -> 1, "persian cat" -> 2, ...
    """
    image_feature_description = {
        "image": tf.io.FixedLenFeature([], tf.string),
        "label": tf.io.FixedLenFeature([], tf.string)
    }

    features = tf.io.parse_single_example(example, image_feature_description)

    image = tf.io.parse_tensor(features["image"], tf.uint8)
    
    # *** the following fails. how can this be done efficiently (lazy)?
    label = features["label"].numpy().decode('utf-8')
    class_num = labels_map[label]

    return image, class_num


tfrec_file = ['/path/to/dataset.tfrec']
dataset = tf.data.TFRecordDataset(tfrec_file)

labels_map = {}
for k, v in example_label_map.items():
    labels_map[k] = labels_to_class_int[v]

print(labels_map)

parser_fn = functools.partial(parse_tfrec_function, labels_map=labels_map)
parset_dataset = dataset.map(parser_fn)

失败原因,因为它试图急切地运行:

AttributeError: 'Tensor' object has no attribute 'numpy'

正确的方法是什么?如果我想训练一个更具体的网络以区分特定的类子集,则将类编号存储在 TFRecord 中需要使用几乎相同的数据制作不同的 TFRecord。

给定作为预处理步骤运行的映射(.map for tf.data.Dataset),如何将标签字符串有效地转换为类号?

谢谢!

标签: pythontensorflowdata-preprocessing

解决方案


IIUC 的问题实际上是在图形模式下将字符串重新映射为 int。我认为应该可以使用tf.case执行这个 string->int 重新映射。

一个例子:

import tensorflow.compat.v1 as tf                                               
tf.disable_eager_execution()                                                    
                                                                             
                                                                                
def remap_string_to_int(tensor: tf.Tensor) -> tf.Tensor:                        
    pred_fn_pairs = [                                                           
        (tf.equal(tensor, 'neg'), lambda: 0),                                   
        (tf.equal(tensor, 'dog'), lambda: 1),                                   
        (tf.equal(tensor, 'cat'), lambda: 2),                                   
    ]                                                                           
    return tf.case(pred_fn_pairs)                           
                                                                                                                       
with tf.Session() as sess:                                                      
    label_tensor = tf.placeholder(tf.string, [])                                
    label_int_tensor = remap_string_to_int(label_tensor)                        
    print("int-value is: ",                                                     
          sess.run(label_int_tensor, feed_dict={label_tensor: 'dog'}))

印刷:

>>> int-value is:  1

推荐阅读