TensorFlow中tf.data.Dataset.map标签传参及自定义标签问题
创建音频数据集的常规方法
# 从文件中收集数据 ''' .....部分代码省略........ ''' # 创建映射函数 def get_label(file_path): parts = tf.strings.split( input=file_path, sep=os.path.sep) # 注意:此处使用索引而非元组解包,以支持TensorFlow图模式运行 return parts[-2] # 映射函数 def get_waveform_and_label(file_path): label = get_label(file_path) audio_binary = tf.io.read_file(file_path) waveform = decode_audio(audio_binary) return waveform, label AUTOTUNE = tf.data.AUTOTUNE # 创建数据集 files_ds = tf.data.Dataset.from_tensor_slices(train_files) # 为数据集中每个数据添加标签最常用的方法是使用tf.data.Dataset.map(): waveform_ds = files_ds.map( map_func=get_waveform_and_label, num_parallel_calls=AUTOTUNE) for element in waveform_ds: print(element)
执行print后,输出的数据集元素示例(随机选取两条):
(<tf.Tensor: shape=(16000,), dtype=float32, numpy= array([ 9.1552734e-05, 1.5258789e-04, 2.4414062e-04, ..., -3.3569336e-04, -3.6621094e-04, -2.4414062e-04], dtype=float32)>, <tf.Tensor: shape=(), dtype=string, numpy=b'right'>) (<tf.Tensor: shape=(16000,), dtype=float32, numpy= array([ 0.0010376 , 0.00097656, 0.00094604, ..., -0.00183105, -0.00158691, -0.00152588], dtype=float32)>, <tf.Tensor: shape=(), dtype=string, numpy=b'no'>)
技术问题
- 在调用
tf.data.Dataset.map时未向get_waveform_and_label传递参数,该函数是如何确定要处理的标签类型的? - 若想使用自定义的列表、元组或字典形式的标签(而非从文件路径文件夹中获取),例如:
my_labels = ['relaxation', 'grip', 'ungrip']
除了将my_labels作为常量写入映射函数get_waveform_and_label外,还有其他实现方式吗?
尝试代码(非核心)
RaggedTensor类型的timeframes存储的普通张量示例:
tf.Tensor( [[0.5369535 0.2724565 0.073154 ... 0.0074817 0.2035824 0.0882927] [0.5376732 0.2733304 0.0730333 ... 0.0017834 0.1970369 0.0859187] [0.5307747 0.2692053 0.0720603 ... 0.0029357 0.1989727 0.0866213] ... [0.5395046 0.2826822 0.0747677 ... 0.0085316 0.1982029 0.0849934] [0.5299433 0.2774992 0.073246 ... 0.0083179 0.1994617 0.085429 ] [0.5329857 0.278462 0.0736021 ... 0.0070133 0.2008929 0.0860079]], shape=(117, 128), dtype=float64) tf.Tensor( [[0.5278226 0.27012 0.0709168 ... 0.0110207 0.1954106 0.0877619] [0.5296971 0.2716435 0.0712691 ... 0.005279 0.1967631 0.0881876] [0.5316442 0.2725459 0.0716114 ... 0.0044511 0.1991368 0.089243 ] ... [0.5419291 0.2776711 0.0726136 ... 0.0114332 0.1941741 0.0884957] [0.5319294 0.2723156 0.071426 ... 0.010159 0.1962118 0.0891404] [0.5338816 0.2737131 0.0718814 ... 0.0103788 0.1974683 0.0897296]], shape=(118, 128), dtype=float64)
尝试的映射代码:
def maplabel(dataset, tensored_label): return dataset, tensored_label def get_timeFrames_with_label(timeframes:tf.RaggedTensor, \ label:str): samplesCount = timeframes.shape[0] dataset_lines = [None] * samplesCount str_tensors = [None] * samplesCount for i in range(samplesCount): dataset_lines[i] = tf.data.Dataset.from_tensors(timeframes[i]) str_tensors[i] = tf.constant(label, dtype=tf.string) com1tframes_ds = tf.data.Dataset.choose_from_datasets(dataset_lines, tf.data.Dataset.range(samplesCount)) # command_ds = tf.data.Dataset.from_tensor_slices(str_tensors) # ...Dataset.zip(com1tframes_ds, command_ds) 报错:"command_ds has no function # string.isidentifier" com1tframes_ds.map(map_func=maplabel(com1tframes_ds, label), \ num_parallel_calls=tf.data.AUTOTUNE)
问题解答
问题1:map方法的参数传递逻辑
tf.data.Dataset.map会自动将数据集的每个元素作为参数传入映射函数。在你的代码中,files_ds的每个元素是单个文件路径字符串,所以调用map(get_waveform_and_label)时,每个文件路径会被自动传给get_waveform_and_label的file_path参数。
标签类型由get_label函数决定:它从文件路径中解析出文件夹名(parts[-2]),TensorFlow会自动将其转为string类型的张量,这就是输出中标签为b'right'这类字符串张量的原因。
问题2:自定义标签的灵活实现方式
除了硬编码到映射函数,还有两种更合理的方式:
方式1:用tf.data.Dataset.zip配对数据和标签
如果数据和标签一一对应,可分别创建数据集后用zip合并:
# 假设timeframes是数据张量(或RaggedTensor),my_labels是对应标签列表 data_ds = tf.data.Dataset.from_tensor_slices(timeframes) labels_ds = tf.data.Dataset.from_tensor_slices(my_labels) # 配对成(数据,标签)格式的数据集 dataset = tf.data.Dataset.zip((data_ds, labels_ds))
若timeframes是RaggedTensor,from_tensor_slices会自动按第一维度拆分样本,与标签一一匹配。
方式2:用lambda或偏函数传递额外参数
若需给所有样本统一添加某个标签,可通过lambda包装映射函数:
def add_label(data, label): return data, label target_label = 'relaxation' data_ds = tf.data.Dataset.from_tensor_slices(timeframes) dataset = data_ds.map(lambda x: add_label(x, target_label), num_parallel_calls=AUTOTUNE)
修复尝试代码的错误
你的代码中map调用有误:map_func需要传入函数对象,而非函数执行结果。同时choose_from_datasets在此场景下冗余,直接用from_tensor_slices更简洁:
def get_timeFrames_with_label(timeframes: tf.RaggedTensor, label: str): # 从RaggedTensor创建数据数据集 data_ds = tf.data.Dataset.from_tensor_slices(timeframes) # 创建对应标签的数据集,每个样本对应同一标签 label_ds = tf.data.Dataset.from_tensors(label).repeat(timeframes.shape[0]) # 配对数据与标签 return tf.data.Dataset.zip((data_ds, label_ds))
或用lambda映射实现:
def get_timeFrames_with_label(timeframes: tf.RaggedTensor, label: str): data_ds = tf.data.Dataset.from_tensor_slices(timeframes) return data_ds.map(lambda x: (x, tf.constant(label, dtype=tf.string)), num_parallel_calls=tf.data.AUTOTUNE)
内容的提问来源于stack exchange,提问作者Hell576
相关产品推荐
相关产品推荐

