tensorflow dataset构建输入时进行padding

2024-01-04  本文已影响0人  井底蛙蛙呱呱呱

序列特征作为一个常见的特征类型,在输入模型时常常需要进行padding,而基于模型的不同,padding方式也有差别。

1、在数据输入模型之前进行padding

当我们输入的序列特征是进行embedding pooling操作时,则需要提前进行补齐(padding)以保证所有样本特征维度相同。
此时可采用两种方式进行补齐:

方法1操作简单,但是由于需要提前处理全部数据,可能会占用较大的内存。
方法2在构建数据流输入时进行batch padding,每次仅需要padding到当前batch的最大长度即可,不仅占用内存更小,而且可保存更大的序列长度。

基于TensorFlow Dataset模块batch padding demo如下:

import numpy as np
import tensorflow as tf

def parse_record(serialized):
    parse_features = tf.io.parse_single_example(serialized, features=Config.columns)
    labels = parse_features["label"]
    for col in Config.columns:
        if isinstance(Config.columns[col], tf.VarLenFeature):
            if Config.columns[col].dtype == tf.string:
                parse_features[col] = tf.sparse_tensor_to_dense(parse_features[col], default_value="")
            elif Config.columns[col].dtype==tf.float32:
                parse_features[col] = tf.sparse_tensor_to_dense(parse_features[col], default_value=0.0)
            else:
                parse_features[col] = tf.sparse_tensor_to_dense(parse_features[col], default_value=-1)

    return parse_features, labels

dataset = tf.data.Dataset.from_tensor_slices(["data/p.tfrecord.gz"])
dataset = dataset.apply(tf.contrib.data.parallel_interleave(
        lambda filename: tf.data.TFRecordDataset(filename, compression_type="GZIP",
                                                 num_parallel_reads=2,
                                                 buffer_size=40960),
        # 同时读取的文件数
        cycle_length=1,
        sloppy=True
    ))

# 定义各个字段padding shape
columns_padded_shapes = {
 'income': [],   # 单值类型,不需要进行padding
 'sex': [],
 'tvAge': [None], # 序列类型,None表示padding到batch最大长度,如需padding到指定长度,则需要预先处理全部数据并将所有数据最大长度裁剪到指定长度
 'tvSex': [None],
 'consumptionLevelOfBaidu': [None],
 'interestPreferenceOfBaidu': [None]
... 
}

# padding values可按需设置,默认字符类型补充空字符串,数字类型补0. 在配置的时候可与后面特征处理的时候缺失值的默认值保持一致。
# 此外,填充值可直接写数字如-1,也可写Tensor如 tf.constant(-1, dtype=tf.int64)
pad_vals = {
 'income':  tf.constant(-1, dtype=tf.int64),
 'sex': tf.constant(-1, dtype=tf.int64),
"tvAge": tf.constant(-1, dtype=tf.int64),
"tvSex": tf.constant(-1, dtype=tf.int64),
 'consumptionLevelOfBaidu': [None],
 'interestPreferenceOfBaidu': [None],
"consumptionLevelOfBaidu": tf.constant(-1, dtype=tf.int64),
"interestPreferenceOfBaidu": tf.constant("UNK", dtype=tf.string)
...
}

dataset = dataset.repeat(4)
dataset = dataset.map(parse_record, num_parallel_calls=tf.data.experimental.AUTOTUNE)
# 注意这里padded_shapes和padding_values都是元组,这是因为parse_record函数的返回值有两个
dataset = dataset.padded_batch(32, padded_shapes=(columns_padded_shapes, []),
                               padding_values=(pad_vals, 0.0))

2、模型中进行padding

这种情况一般是序列作为RNN类网络的输入。
在特征编码后作为输入时:

sequence_feature_layer = tf.keras.experimental.SequenceFeatures(params['seq_feature_columns'])
sequence_input, sequence_length = sequence_feature_layer({key: features[key] for key in params['seq_features']})
sequence_mask = tf.sequence_mask(sequence_length)
lstm_layer = tf.keras.layers.LSTM(params['lstm_output_size'])
lstm_output = lstm_layer(sequence_input, mask=sequence_mask)

参考:
https://stackoverflow.com/questions/49840100/tf-data-dataset-padded-batch-pad-differently-each-feature

上一篇 下一篇

猜你喜欢

热点阅读