use*_*771 5 python tensorflow tensorflow-datasets
我在 ubuntu 16.04 上运行我的神经网络,有 1 个 GPU (GTX 1070) 和 4 个 CPU。
我的数据集包含大约 35,000 张图像,但数据集并不平衡:0 类占 90%,1、2、3、4 类共享其他 10%。因此,我通过使用dataset.repeat(class_weight)[我也使用一个函数来应用随机增强] 对1-4 类进行过采样,然后使用concatenate它们。
重采样策略为:
1) 一开始,class_weight[n]将设置为一个较大的数字,以便每个类将具有与类 0 相同的图像数量。
2) 随着训练的进行,epoch 数增加,权重会根据 epoch 数下降,从而使分布变得更接近实际分布。
因为我class_weight会随着时代的变化而变化,所以我不能在一开始就打乱整个数据集。相反,我必须逐个类接收数据,并在连接每个类的过采样数据后对整个数据集进行混洗。而且,为了实现平衡的批次,我必须按元素对整个数据集进行洗牌。
以下是我的代码的一部分。
def my_estimator_func():
d0 = tf.data.TextLineDataset(train_csv_0).map(_parse_csv_train)
d1 = tf.data.TextLineDataset(train_csv_1).map(_parse_csv_train)
d2 = tf.data.TextLineDataset(train_csv_2).map(_parse_csv_train)
d3 = tf.data.TextLineDataset(train_csv_3).map(_parse_csv_train)
d4 = tf.data.TextLineDataset(train_csv_4).map(_parse_csv_train)
d1 = d1.repeat(class_weight[1])
d2 = d2.repeat(class_weight[2])
d3 = d3.repeat(class_weight[3])
d4 = d4.repeat(class_weight[4])
dataset = d0.concatenate(d1).concatenate(d2).concatenate(d3).concatenate(d4)
dataset = dataset.shuffle(180000) # <- This is where the issue comes from
dataset = dataset.batch(100)
iterator = dataset.make_one_shot_iterator()
feature, label = iterator.get_next()
return feature, label
def _parse_csv_train(line):
parsed_line= tf.decode_csv(line, [[""], []])
filename = parsed_line[0]
label = parsed_line[1]
image_string = tf.read_file(filename)
image_decoded = tf.image.decode_jpeg(image_string, channels=3)
# my_random_augmentation_func will apply random augmentation on the image.
image_aug = my_random_augmentation_func(image_decoded)
image_resized = tf.image.resize_images(image_aug, image_resize)
return image_resized, label
Run Code Online (Sandbox Code Playgroud)
为了清楚起见,让我逐步描述为什么我面临这个问题:
因为我的数据集中的类不平衡,所以我想对这些少数类进行过度采样。
由于 1.,我想对这些类应用随机增强并将多数类(类 0)与它们连接起来。
经过一番研究,我发现repeat()如果有随机函数会产生不同的结果,所以我使用repeat()和my_random_augmentation_func来实现2。
现在,实现了 2.,我想合并所有数据集,所以我使用 concatenate()
4.我现在面临一个问题:总共有大约40,000 - 180,000张图像(因为class_weight逐个epoch变化,一开始总共会有180,000张图像,最后大约有40,000张),并将它们连接起来逐个类,数据集看起来像 [0000-1111-2222-3333-4444],因此批大小为 100,没有任何改组,几乎总是每批中只有一个类,这意味着每批中的分布会失衡。
为了解决 5. 中的“批次不平衡”问题,我想出了应该对整个数据集进行洗牌的想法,因此我使用shuffle(180000).
最后,砰,当涉及到数据集中的 180000 个项目时,我的计算机死机了。
那么,有没有更好的方法可以让我获得平衡的批次,但仍然保持我想要的特征(例如,逐个改变分布纪元)?
--- 编辑:问题已解决---
原来我一开始就不应该应用map函数。我应该只接收文件名而不是真实文件,然后将文件名打乱,然后将它们映射到真实文件。
更详细的说,把map(_parse_csv_train)后面d0 = tf.data.TextLineDataset(train_csv_0)和其他4行的部分删掉,shuffle(180000)dataset = dataset.map(_parse_csv_train) 后面加一行。
我还想对@P-Gn 说声谢谢,他“洗牌”部分中的博客链接真的很有帮助。它回答了我脑海中的一个问题,但我没有问:“我可以通过使用许多小洗牌与一次大洗牌来获得类似的随机性吗?” (我不会在这里给出答案,请查看该博客!)该博客中的方法也可能是解决此问题的潜在方法,但我还没有尝试过。
我建议依赖tf.contrib.data.choose_from_datasets,并使用发行版选择的标签tf.multinomial。与其他基于样本拒绝的函数相比,这样做的优点是您不会因为读取未使用的样本而丢失 I/O 带宽。
这是与您的情况类似的情况的工作示例,具有虚拟数据集:
\n\nimport tensorflow as tf\n\n# create dummy datasets\nclass_num_samples = [900, 25, 25, 25, 25]\nclass_start = [0, 1000, 2000, 3000, 4000]\nds = [\n tf.data.Dataset.range(class_start[0], class_start[0] + class_num_samples[0]),\n tf.data.Dataset.range(class_start[1], class_start[1] + class_num_samples[1]),\n tf.data.Dataset.range(class_start[2], class_start[2] + class_num_samples[2]),\n tf.data.Dataset.range(class_start[3], class_start[3] + class_num_samples[3]),\n tf.data.Dataset.range(class_start[4], class_start[4] + class_num_samples[4])\n]\n\n# pick from dataset according to a parameterizable distribution\nclass_relprob_ph = tf.placeholder(tf.float32, shape=len(class_num_samples))\npick = tf.data.Dataset.from_tensor_slices(\n tf.multinomial(tf.log(class_relprob_ph)[None], max(class_num_samples))[0])\nds = tf.contrib.data.choose_from_datasets(ds, pick).repeat().batch(20)\n\niterator = ds.make_initializable_iterator()\nbatch = iterator.get_next()\n\nwith tf.Session() as sess:\n # choose uniform distribution\n sess.run(iterator.initializer, feed_dict={class_relprob_ph: [1, 1, 1, 1, 1]})\n print(batch.eval())\n# [ 0 1000 1001 1 3000 4000 3001 4001 2 3 1002 1003 2000 4 5 2001 3002 1004 6 2002]\n\n # now follow input distribution\n sess.run(iterator.initializer, feed_dict={class_relprob_ph: class_num_samples})\n print(batch.eval())\n# [ 0 1 4000 2 3 4 5 3000 6 7 8 9 2000 10 11 12 13 4001 14 15]\nRun Code Online (Sandbox Code Playgroud)\n\n请注意,“纪元”的长度现在由多项式采样的长度定义。我在这里稍微任意地设置了max(class_num_samples)\xe2\x80\x94 当你开始混合不同长度的数据集时,对于纪元的定义确实没有好的选择。
然而,有一个具体的原因让它至少与最大的数据集一样大:正如您所注意到的,从头开始调用iterator.initializerrestart 。Dataset因此,现在您的洗牌缓冲区比您的数据小得多(通常是这种情况),重要的是不要过早重新启动以确保训练看到所有数据。
这个答案解决了使用自定义权重交错数据集的问题,而不是数据集改组的问题,这是一个不相关的问题。洗牌大型数据集需要做出妥协\xe2\x80\x94,如果不以某种方式牺牲内存和性能,你就无法进行有效的动态洗牌。例如,这篇优秀的博客文章以图形方式说明了缓冲区大小对洗牌质量的影响。
\n| 归档时间: |
|
| 查看次数: |
1456 次 |
| 最近记录: |