Tensorflow,大图像推理 - 内存不足
Tensorflow, large image inference - not enough memory
我训练了一个超分辨率模型。推理有效:
def inference(self, filename):
img_in = misc.imread(filename) / 255.0
res = self.sess.run(self.out, feed_dict={ self.x: [img_in], self.is_training: False, self.lr_input: 0.0 })[0] * 255.0
image = misc.toimage(res, cmin=0, cmax=255)
fn_res = filename.replace(".png", "_result.png").replace(".jpg", "_result.jpg")
misc.imsave(fn_res, image)
但是当图片大于600x600px时,会显示:
terminate called after throwing an instance of 'std::bad_alloc'
what(): std::bad_alloc
Aborted (core dumped)
我正在使用 16GB RAM 和 16GB 交换文件,使用 CPU 进行推理。但是在 Ubuntu 16.04 中设置的交换文件尽管足够了,但无济于事。
我知道我可以通过将图像拆分成多个部分并按顺序处理它们来解决这个问题。但是在输出中有明显的分裂痕迹。
为什么不起作用?有什么方法可以使用 Python 或 Tensorflow 实现内存交换文件吗?还有其他解决方法吗?
通过将图像分成几块,一张一张地处理并组合它们来解决它。为了避免在输出图像中可见 "split lines",我用不同的块尺寸重复上述过程并计算平均值。
我最终得到了这个:
def inference(self, filename, self_ensemble=False):
img_q = Image.open(filename)
scale = 4
if img_q.width > 400:
total = np.zeros((img_q.height * scale, img_q.width * scale, 3))
#repeat 7 times with different piece size
for x in range(7):
total += self.inference_inter(filename, scale, 32 * (x + 8), ensemble=self_ensemble)
total = total / 7.0
image = misc.toimage(total, cmin=0, cmax=255)
fn_res = filename.replace(".png", "_result.png").replace(".jpg", "_result.jpg")
misc.imsave(fn_res, image)
else:
img_in = misc.imread(filename) / 255.0
res = self.sess.run(self.out, feed_dict={ self.x: [img_in], self.is_training: False, self.lr_input: 0.0 })[0] * 255.0
image = misc.toimage(res, cmin=0, cmax=255)
fn_res = filename.replace(".png", "_result.png").replace(".jpg", "_result.jpg")
misc.imsave(fn_res, image)
def inference_inter(self, filename, scale, pat_size, ensemble=True):
img_in = misc.imread(filename) / 255.0
img_q = Image.open(filename)
res = np.zeros((img_q.height * scale, img_q.width * scale, 3))
for qx in range(0, img_q.width, pat_size):
for qy in range(0, img_q.height, pat_size):
res[(qy * scale):((qy + pat_size) * scale)][(qx * scale):((qx + pat_size) * scale)] = self.sess.run(self.out, feed_dict={ self.x: [img_in[qy:(qy + pat_size)][qx:(qx + pat_size)]], self.is_training: False, self.lr_input: 0.0 })[0] * 255.0
return res
本文解决了您的问题并解释了它存在的原因:
https://dl.acm.org/citation.cfm?id=3132847.3132872
如果您无法访问它,这里有一些引用/摘要:
有两个问题:填充和归一化。
填充:
进行卷积时,网络需要填充图像边界缺失的像素值。那是因为前几个边界像素的内核位于提供的图像之外。
归一化:
In convolution network, batch normalization technique is applied to speed up the convergence and reduce the internal covariate shift.
Now, suppose we split the image into two sub-images. We get two small batches. If they go through the CNN independently, we will obtain two normalization results which only apply sub-images’ local means and variances in the computations. Therefore, even if we merge those pieces back to one image, we will end up with a result that is visually different from the one generated for the whole image.
他们提出以下解决方案:
填充:
For internal border, we use a novel padding technique, dictionary padding.
这意味着他们使用相邻子图像的相应像素值。
For external border, we use circular paddings...
这意味着您用图像左侧的像素在右侧填充,就好像您在右侧连接了图像(反之亦然)。 (与上下相同)
归一化:
这有点复杂。最后,他们对子图像进行归一化,共享图像之间的归一化值(均值和方差)并将它们组合在一起。
填充可能很容易实现,但我不知道如何用tensorflow做归一化部分。如果有人弄清楚并发送一些代码,我将不胜感激。
我训练了一个超分辨率模型。推理有效:
def inference(self, filename):
img_in = misc.imread(filename) / 255.0
res = self.sess.run(self.out, feed_dict={ self.x: [img_in], self.is_training: False, self.lr_input: 0.0 })[0] * 255.0
image = misc.toimage(res, cmin=0, cmax=255)
fn_res = filename.replace(".png", "_result.png").replace(".jpg", "_result.jpg")
misc.imsave(fn_res, image)
但是当图片大于600x600px时,会显示:
terminate called after throwing an instance of 'std::bad_alloc'
what(): std::bad_alloc
Aborted (core dumped)
我正在使用 16GB RAM 和 16GB 交换文件,使用 CPU 进行推理。但是在 Ubuntu 16.04 中设置的交换文件尽管足够了,但无济于事。
我知道我可以通过将图像拆分成多个部分并按顺序处理它们来解决这个问题。但是在输出中有明显的分裂痕迹。
为什么不起作用?有什么方法可以使用 Python 或 Tensorflow 实现内存交换文件吗?还有其他解决方法吗?
通过将图像分成几块,一张一张地处理并组合它们来解决它。为了避免在输出图像中可见 "split lines",我用不同的块尺寸重复上述过程并计算平均值。
我最终得到了这个:
def inference(self, filename, self_ensemble=False):
img_q = Image.open(filename)
scale = 4
if img_q.width > 400:
total = np.zeros((img_q.height * scale, img_q.width * scale, 3))
#repeat 7 times with different piece size
for x in range(7):
total += self.inference_inter(filename, scale, 32 * (x + 8), ensemble=self_ensemble)
total = total / 7.0
image = misc.toimage(total, cmin=0, cmax=255)
fn_res = filename.replace(".png", "_result.png").replace(".jpg", "_result.jpg")
misc.imsave(fn_res, image)
else:
img_in = misc.imread(filename) / 255.0
res = self.sess.run(self.out, feed_dict={ self.x: [img_in], self.is_training: False, self.lr_input: 0.0 })[0] * 255.0
image = misc.toimage(res, cmin=0, cmax=255)
fn_res = filename.replace(".png", "_result.png").replace(".jpg", "_result.jpg")
misc.imsave(fn_res, image)
def inference_inter(self, filename, scale, pat_size, ensemble=True):
img_in = misc.imread(filename) / 255.0
img_q = Image.open(filename)
res = np.zeros((img_q.height * scale, img_q.width * scale, 3))
for qx in range(0, img_q.width, pat_size):
for qy in range(0, img_q.height, pat_size):
res[(qy * scale):((qy + pat_size) * scale)][(qx * scale):((qx + pat_size) * scale)] = self.sess.run(self.out, feed_dict={ self.x: [img_in[qy:(qy + pat_size)][qx:(qx + pat_size)]], self.is_training: False, self.lr_input: 0.0 })[0] * 255.0
return res
本文解决了您的问题并解释了它存在的原因:
https://dl.acm.org/citation.cfm?id=3132847.3132872
如果您无法访问它,这里有一些引用/摘要:
有两个问题:填充和归一化。
填充:
进行卷积时,网络需要填充图像边界缺失的像素值。那是因为前几个边界像素的内核位于提供的图像之外。
归一化:
In convolution network, batch normalization technique is applied to speed up the convergence and reduce the internal covariate shift.
Now, suppose we split the image into two sub-images. We get two small batches. If they go through the CNN independently, we will obtain two normalization results which only apply sub-images’ local means and variances in the computations. Therefore, even if we merge those pieces back to one image, we will end up with a result that is visually different from the one generated for the whole image.
他们提出以下解决方案:
填充:
For internal border, we use a novel padding technique, dictionary padding.
这意味着他们使用相邻子图像的相应像素值。
For external border, we use circular paddings...
这意味着您用图像左侧的像素在右侧填充,就好像您在右侧连接了图像(反之亦然)。 (与上下相同)
归一化:
这有点复杂。最后,他们对子图像进行归一化,共享图像之间的归一化值(均值和方差)并将它们组合在一起。
填充可能很容易实现,但我不知道如何用tensorflow做归一化部分。如果有人弄清楚并发送一些代码,我将不胜感激。