tensorflow dataset構建輸入時進行padding

序列特征作為一個常見的特征類型,在輸入模型時常常需要進行padding,而基于模型的不同,padding方式也有差別。

1、在數(shù)據(jù)輸入模型之前進行padding

當我們輸入的序列特征是進行embedding pooling操作時,則需要提前進行補齊(padding)以保證所有樣本特征維度相同。
此時可采用兩種方式進行補齊:

  • 1)對全部數(shù)據(jù)進行操作,短的補齊,長的裁剪;
  • 2)在構建輸入時進行batch padding。

方法1操作簡單,但是由于需要提前處理全部數(shù)據(jù),可能會占用較大的內(nèi)存。
方法2在構建數(shù)據(jù)流輸入時進行batch padding,每次僅需要padding到當前batch的最大長度即可,不僅占用內(nèi)存更小,而且可保存更大的序列長度。

基于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),
        # 同時讀取的文件數(shù)
        cycle_length=1,
        sloppy=True
    ))

# 定義各個字段padding shape
columns_padded_shapes = {
 'income': [],   # 單值類型,不需要進行padding
 'sex': [],
 'tvAge': [None], # 序列類型,None表示padding到batch最大長度,如需padding到指定長度,則需要預先處理全部數(shù)據(jù)并將所有數(shù)據(jù)最大長度裁剪到指定長度
 'tvSex': [None],
 'consumptionLevelOfBaidu': [None],
 'interestPreferenceOfBaidu': [None]
... 
}

# padding values可按需設置,默認字符類型補充空字符串,數(shù)字類型補0. 在配置的時候可與后面特征處理的時候缺失值的默認值保持一致。
# 此外,填充值可直接寫數(shù)字如-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函數(shù)的返回值有兩個
dataset = dataset.padded_batch(32, padded_shapes=(columns_padded_shapes, []),
                               padding_values=(pad_vals, 0.0))

2、模型中進行padding

這種情況一般是序列作為RNN類網(wǎng)絡的輸入。
在特征編碼后作為輸入時:

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

?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容