从图像 Tensorflow OOM 中提取特征向量
Extracting feature vector from Images Tensorflow OOM
我使用从 Caffe zoo 下载的预训练网络权重在 tensorflow 中构建了一个特征提取器 (VGG-16)。
因此,我重新定义了 TF 中的网络架构,将导入的权重作为常量,并添加了一个额外的 tf.Variables 完全连接层,以通过 SGD 在 Hinge 损失成本上训练线性 SVM。
我的初始训练集由 100000 张 32x32x3 的图像组成,采用 numpy 数组的形式。
因此,我不得不将它们的大小调整为 224x224x3,这是 VGG 的输入大小,但不适合内存。
所以我删除了不必要的示例并将其缩小到 10000x224x224x3 图像,这很糟糕但仍然可以接受,因为只有支持向量很重要,但即便如此我在训练时仍然会遇到 TF 的 OOM。
不应该是这种情况,因为唯一重要的表示是来自倒数第二层的大小为 4096 的表示,它易于管理,并且反向传播的权重仅为大小(4096+1bias)。
所以我能做的是首先将我所有的图像转换为只有常数的 TF 网络的特征,以形成 10000x4096 数据集,然后训练第二个张量流模型。
或者在每个批次重新计算该批次的所有特征。在 next_batch 方法中。或者使用 TF 提供的 buffers/queue runners 的全套但它有点可怕,因为我不太熟悉那些。
我不喜欢那些方法我认为应该有更优雅的方法(如果可能的话不要太多队列)。
处理这个问题的最 Tensorflow 方法是什么?
如果我对你的问题理解正确,100K 图像根本不适合内存,而 10K 图像适合内存,但随后网络本身 OOM。这听起来很合理,因为仅 10K 个图像,假设它们使用每个通道每个像素 4 个字节表示,占用 space 的 5.6GiB(如果您以某种方式每个通道每个像素只花费 1 个字节,则占用 1.4GiB),所以即使如果数据集恰好适合内存,当您添加模型时,它将占用更多的 GiB,您将 OOM。
现在,您可以通过多种方式解决它:
您应该使用小批量进行训练(如果您还没有这样做的话)。使用大小为 512 的小批量,您将向 GPU 加载的数据明显减少。使用小批量,您也不需要在开始时将整个数据集加载到一个 numpy 数组中。以一次加载 512 张图像、运行 向前和向后传递 (sess.run(train...)
)、加载接下来的 512 张图像等的方式构建迭代器。这种方式在任何时候都不需要 10K 或内存中同时存储 10 万张图像。
当您的原始图像小得多时,放大图像也显得非常浪费。您可能会考虑从 VGG 网络中获取卷积层(卷积层的维度不依赖于原始图像的维度),并从头开始在它们之上训练完全连接的层。要做到这一点,只需 trim 扁平化层之后的 VGG 网络,运行 它用于您拥有的所有图像并为每个图像生成扁平化层的输出,然后训练一个三层完全连接的网络这些特征(与训练整个 conv 网络相比,这将相对较快),并将生成的网络插入原始 VGG 网络的展平层之后。这也可能会产生更好的结果,因为训练卷积层是为了在原始尺寸图像中寻找特征,而不是在模糊的放大图像中寻找特征。
我想一种使用一些队列和线程但不是太多的方法是使用 tf.python_io.TFRecordWriter
将训练集保存为 tensorflow protobuf 格式(或几种)。
然后创建一个方法来从 protobuf 中读取和解码单个示例,最后使用 tf.train.shuffle_batch
将 BATCH_SIZE 个示例提供给使用前一种方法的优化器。
这样内存中同时只有最大容量(定义在shuffle_batch)个张量。
这个awesome tutorial from Indico解释了一切。
我使用从 Caffe zoo 下载的预训练网络权重在 tensorflow 中构建了一个特征提取器 (VGG-16)。
因此,我重新定义了 TF 中的网络架构,将导入的权重作为常量,并添加了一个额外的 tf.Variables 完全连接层,以通过 SGD 在 Hinge 损失成本上训练线性 SVM。
我的初始训练集由 100000 张 32x32x3 的图像组成,采用 numpy 数组的形式。 因此,我不得不将它们的大小调整为 224x224x3,这是 VGG 的输入大小,但不适合内存。
所以我删除了不必要的示例并将其缩小到 10000x224x224x3 图像,这很糟糕但仍然可以接受,因为只有支持向量很重要,但即便如此我在训练时仍然会遇到 TF 的 OOM。
不应该是这种情况,因为唯一重要的表示是来自倒数第二层的大小为 4096 的表示,它易于管理,并且反向传播的权重仅为大小(4096+1bias)。
所以我能做的是首先将我所有的图像转换为只有常数的 TF 网络的特征,以形成 10000x4096 数据集,然后训练第二个张量流模型。 或者在每个批次重新计算该批次的所有特征。在 next_batch 方法中。或者使用 TF 提供的 buffers/queue runners 的全套但它有点可怕,因为我不太熟悉那些。
我不喜欢那些方法我认为应该有更优雅的方法(如果可能的话不要太多队列)。
处理这个问题的最 Tensorflow 方法是什么?
如果我对你的问题理解正确,100K 图像根本不适合内存,而 10K 图像适合内存,但随后网络本身 OOM。这听起来很合理,因为仅 10K 个图像,假设它们使用每个通道每个像素 4 个字节表示,占用 space 的 5.6GiB(如果您以某种方式每个通道每个像素只花费 1 个字节,则占用 1.4GiB),所以即使如果数据集恰好适合内存,当您添加模型时,它将占用更多的 GiB,您将 OOM。
现在,您可以通过多种方式解决它:
您应该使用小批量进行训练(如果您还没有这样做的话)。使用大小为 512 的小批量,您将向 GPU 加载的数据明显减少。使用小批量,您也不需要在开始时将整个数据集加载到一个 numpy 数组中。以一次加载 512 张图像、运行 向前和向后传递 (
sess.run(train...)
)、加载接下来的 512 张图像等的方式构建迭代器。这种方式在任何时候都不需要 10K 或内存中同时存储 10 万张图像。当您的原始图像小得多时,放大图像也显得非常浪费。您可能会考虑从 VGG 网络中获取卷积层(卷积层的维度不依赖于原始图像的维度),并从头开始在它们之上训练完全连接的层。要做到这一点,只需 trim 扁平化层之后的 VGG 网络,运行 它用于您拥有的所有图像并为每个图像生成扁平化层的输出,然后训练一个三层完全连接的网络这些特征(与训练整个 conv 网络相比,这将相对较快),并将生成的网络插入原始 VGG 网络的展平层之后。这也可能会产生更好的结果,因为训练卷积层是为了在原始尺寸图像中寻找特征,而不是在模糊的放大图像中寻找特征。
我想一种使用一些队列和线程但不是太多的方法是使用 tf.python_io.TFRecordWriter
将训练集保存为 tensorflow protobuf 格式(或几种)。
然后创建一个方法来从 protobuf 中读取和解码单个示例,最后使用 tf.train.shuffle_batch
将 BATCH_SIZE 个示例提供给使用前一种方法的优化器。
这样内存中同时只有最大容量(定义在shuffle_batch)个张量。
这个awesome tutorial from Indico解释了一切。