TensorFlow 2-tf.keras:如何使用tf.data API和;TF记录

TensorFlow 2-tf.keras:如何使用tf.data API和;TF记录,keras,multitasking,tfrecord,tensorflow2.x,Keras,Multitasking,Tfrecord,Tensorflow2.x,最近我尝试使用TFRecords来训练tf.keras模型。因为对于TensorFlow 2,最有效的方法是使用tf.data API,所以我尝试使用它来训练我的MTCNN Keras模型。但让我困惑的是: 根据原始文件,不同的样本(pos、neg、零件面、landmark)参与培训的不同部分。每种样品在每个小批量中都有一个特定的比率,即对于一个小批量,pos、neg、零件面和landmark样品的比率应为1:3:1:2 因此,例如,在我制作了四个样本的TFR记录后,我需要从pos TFR记录中

最近我尝试使用TFRecords来训练tf.keras模型。因为对于TensorFlow 2,最有效的方法是使用tf.data API,所以我尝试使用它来训练我的MTCNN Keras模型。但让我困惑的是:

根据原始文件,不同的样本(pos、neg、零件面、landmark)参与培训的不同部分。每种样品在每个小批量中都有一个特定的比率,即对于一个小批量,pos、neg、零件面和landmark样品的比率应为1:3:1:2

因此,例如,在我制作了四个样本的TFR记录后,我需要从pos TFR记录中提取128个样本,从neg中提取384个样本,从零件表面提取128个样本,从landmark TFR记录中提取256个样本,并将它们混合到一个小批次中。然后我需要在训练前洗牌

在使用TFRecords和tf.data API时,我真的不知道如何进行此操作。现在我只能通过一批一批地阅读图像和标签来实现所有这些步骤,但这对于培训来说太慢了。因此,我想知道是否有任何有效的方法来做到这一点

任何建议都将不胜感激

更新日期2020.04.04 15:38
多亏了@AAudibert,我认为他/她的答案非常有效,我也找到了一种实现方法。以下是代码供参考:

raw_pos_dataset = tf.data.TFRecordDataset(POS_TFRECORDS_PATH_LIST)
raw_neg_dataset = tf.data.TFRecordDataset(NEG_TFRECORDS_PATH_LIST)
raw_part_dataset = tf.data.TFRecordDataset(PART_TFRECORDS_PATH_LIST)
raw_landmark_dataset = tf.data.TFRecordDataset(LANDMARK_TFRECORDS_PATH_LIST)

image_feature_description = {
    'height': tf.io.FixedLenFeature([], tf.int64),
    'width': tf.io.FixedLenFeature([], tf.int64),
    'depth': tf.io.FixedLenFeature([], tf.int64),
    'info': tf.io.FixedLenFeature([17], tf.float32),
    'image_raw': tf.io.FixedLenFeature([], tf.string),
    }

def _read_tfrecord(serialized_example):

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

    img = tf.image.decode_jpeg(example['image_raw'], channels = 3) # RGB rather than BGR!!! 
    img = (tf.cast(img, tf.float32) - 127.5) / 128.
    img_shape = [example['height'], example['width'], example['depth']]
    img = tf.reshape(img, img_shape)

    info = example['info']

    return img, info

parsed_pos_dataset = raw_pos_dataset.map(_read_tfrecord)
parsed_neg_dataset = raw_neg_dataset.map(_read_tfrecord)
parsed_part_dataset = raw_part_dataset.map(_read_tfrecord)
parsed_landmark_dataset = raw_landmark_dataset.map(_read_tfrecord)

parsed_image_dataset = tf.data.Dataset.zip((parsed_pos_dataset.repeat().shuffle(16384).batch(int(BATCH_SIZE * DATA_COMPOSE_RATIO[0])), 
                                            parsed_neg_dataset.repeat().shuffle(16384).batch(int(BATCH_SIZE * DATA_COMPOSE_RATIO[1])), 
                                            parsed_part_dataset.repeat().shuffle(16384).batch(int(BATCH_SIZE * DATA_COMPOSE_RATIO[2])), 
                                            parsed_landmark_dataset.repeat().shuffle(16384).batch(int(BATCH_SIZE * DATA_COMPOSE_RATIO[3]))))

def concatenate(pos_info, neg_info, part_info, landmark_info):

    img_tensor = tf.zeros((0, IMG_SIZE, IMG_SIZE, 3), dtype = tf.float32)
    label_tensor = tf.zeros((0, 17), dtype = tf.float32)
    pos_img = pos_info[0]
    neg_img = neg_info[0]
    part_img = part_info[0]
    landmark_img = landmark_info[0]
    pos_info = pos_info[1]
    neg_info = neg_info[1]
    part_info = part_info[1]
    landmark_info = landmark_info[1]
    img_tensor = tf.concat([img_tensor, pos_img, neg_img, part_img, landmark_img], axis = 0)
    info_tensor = tf.concat([label_tensor, pos_info, neg_info, part_info, landmark_info], axis = 0)

    return img_tensor, info_tensor

ds = parsed_image_dataset.map(concatenate)

您可以使用

有关示例,请参见。我还复制了下面的代码

import tensorflow as tf

batch_size = 8

pos = tf.data.Dataset.range(0, 100)
neg = tf.data.Dataset.range(100, 200)
part_face = tf.data.Dataset.range(200, 300)
landmark = tf.data.Dataset.range(300, 400)

dataset = tf.data.experimental.sample_from_datasets(
    [pos, neg, part_face, landmark], [1/7, 3/7, 1/7, 2/7])
dataset = dataset.batch(batch_size)

# Optionally shuffle data further. Samples will already be interspersed between datasets.
# dataset = dataset.map(lambda batch: tf.random.shuffle(batch))

for elem in dataset:
  print(elem.numpy())

# Prints
[200 300 100 201 301 302 101 303]
[  0 304 202 102 203 103 305 104]
[306 307 105 204 308 205 206   1]
[207 309 106 107 310 108 311 312]
[208 209 210   2 109 211 110 212]
...

您可以使用

有关示例,请参见。我还复制了下面的代码

import tensorflow as tf

batch_size = 8

pos = tf.data.Dataset.range(0, 100)
neg = tf.data.Dataset.range(100, 200)
part_face = tf.data.Dataset.range(200, 300)
landmark = tf.data.Dataset.range(300, 400)

dataset = tf.data.experimental.sample_from_datasets(
    [pos, neg, part_face, landmark], [1/7, 3/7, 1/7, 2/7])
dataset = dataset.batch(batch_size)

# Optionally shuffle data further. Samples will already be interspersed between datasets.
# dataset = dataset.map(lambda batch: tf.random.shuffle(batch))

for elem in dataset:
  print(elem.numpy())

# Prints
[200 300 100 201 301 302 101 303]
[  0 304 202 102 203 103 305 104]
[306 307 105 204 308 205 206   1]
[207 309 106 107 310 108 311 312]
[208 209 210   2 109 211 110 212]
...

嗨@AAudibert,非常感谢你的解决方案,我认为它对我很有效。我还通过使用类似于tf.concat的函数实现了一个:img_tensor=tf.concat([img_tensor,pos_img,neg_img,part_img,landmark_img],axis=0)`但这两种方法似乎都存在一个问题,即当来自每个数据集(pos,neg,part和landmark)的样本数没有达到我们需要的比率时(假设我有32个pos、96个neg、32个part和1024个landmark样本),即使我使用.repeat()合并的数据集也会出错在对每个数据集进行采样之前,对每个数据集进行采样。从数据集中采样。这是我在回购协议中为MTCNN编写的自定义损失。当培训进一步进行时,损失突然变为“nan”以及验证损失,它们再也不会回来了。我想知道您以前是否遇到过类似的情况。有什么建议可以帮助您吗。谢谢。嗨@AAudibert,不知怎的,我现在,Windows CPU tf 2.0.0 PC上的代码运行良好,没有出现“nan”丢失。我可能需要在下班后验证此结果。@tmaysgs如果您重复()输入数据集,该比率预计将保持不变(尽管可能由于随机采样而略有下降)。如果您共享代码来重现问题,我将尝试找出问题所在。您好@AAudibert,谢谢您的回复。请查看页面或我提出的页面。我一步一步检查了培训过程,发现是back prop将权重更新为“nan”,与tf.data.Dataset API无关。如果您可以查看页面,请继续如果可以,我将不胜感激。您好@AAudibert,非常感谢您的解决方案,我认为它对我有效。我还使用tf.concat实现了一个,比如:`img\u tensor=tf.concat([img\u tensor,pos\u img,neg\u img,part\u img,landmark\u img],axis=0)“但这两种方法似乎都有一个问题,即当来自每个数据集(pos、neg、part和landmark)的样本数不符合我们需要的比例时(假设我有32个pos、96个neg、32个part和1024个landmark样本),即使我使用了,合并的数据集也会出错。repeat()在对每个数据集进行采样之前,对每个数据集进行采样。从数据集中采样。这是我在回购协议中为MTCNN编写的自定义损失。当培训进一步进行时,损失突然变为“nan”以及验证损失,它们再也不会回来了。我想知道您以前是否遇到过类似的情况。有什么建议可以帮助您吗。谢谢。嗨@AAudibert,不知怎的,我现在,Windows CPU tf 2.0.0 PC上的代码运行良好,没有出现“nan”丢失。我可能需要在下班后验证此结果。@tmaysgs如果您重复()输入数据集,该比率预计将保持不变(尽管可能由于随机采样而略有下降)。如果您共享代码来重现问题,我将尝试找出问题所在。您好@AAudibert,谢谢您的回复。请查看页面或我提出的页面。我一步一步检查了培训过程,发现是back prop将权重更新为“nan”,与tf.data.Dataset API无关。如果您可以查看页面,请继续如果有空,我将不胜感激。