Я подготовил модель с высоким разрешением. Вывод:
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)
Я использую 16-гигабайтную оперативную память и 16-гигабайтный swap файл, выводя используя CPU. Но файл подкачки, установленный в Ubuntu 16.04, не помогает, несмотря на то, что этого достаточно.
Я знаю, что могу обойти это, разбивая изображение на части и обрабатывая их по порядку. Но на выходе есть видимые следы расщепления.
Почему это не работает? Есть ли способ реализовать swap файл памяти с помощью Python или Tensorflow? Есть ли другие способы обхода?
Решила его, разбивая изображение на части, обрабатывая их один за другим и объединяя их. Чтобы избежать видимых "разделенных линий" на выходном изображении, я повторяю описанный выше процесс с разными размерами штук и вычисляет среднее значение.
Я закончил с этим:
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
Если вы не можете получить к нему доступ, вот несколько цитат/резюме:
При выполнении свертки сеть должна заполнять отсутствующие значения пикселей на границе изображения. Это связано с тем, что ядро первой пары пограничных пикселей лежит за пределами предоставленного изображения.
В сети свертки применяется метод нормализации партии, чтобы ускорить сближение и уменьшить внутренний сдвиг ковариации.
Теперь предположим, что мы разделили изображение на два суб-изображения. Мы получаем две небольшие партии. Если они пройдут через CNN самостоятельно, мы получим два результата нормализации, которые применяют только суб-изображения локальных средств и дисперсии в вычислениях. Поэтому, даже если мы объединим эти части с одним изображением, мы получим результат, который визуально отличается от результата, созданного для всего изображения.
Для внутренней границы мы используем новую технику заполнения, добавление словаря.
Это означает, что они используют соответствующие значения пикселей соседнего суб-изображения.
Для внешней границы мы используем круговые прокладки...
Это означает, что вы накладываете правую часть с помощью пикселей слева от изображения, как если бы вы сориентировали изображение справа (и наоборот). (То же самое с верхним дном)
Это немного сложнее. В конце концов, они нормализуют под-изображения, совместно используют значения нормализации (среднее значение и дисперсию) между изображениями и объединяют их вместе.
Прокладка может быть легко реализована, но я не знаю, как сделать часть нормализации с помощью тензорного потока. Если кто-то выяснит это и отправит код, я был бы очень благодарен.