Тензор потока, вывод большого изображения - недостаточно памяти

1

Я подготовил модель с высоким разрешением. Вывод:

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? Есть ли другие способы обхода?

  • 0
    Почему бы не установить TF с поддержкой GPU? Я думаю, в Ubuntu также есть вариант с поддержкой GPU.
  • 0
    Мой графический процессор имеет 12 ГБ графической памяти, но моя материнская плата имеет 16 ГБ. Вот почему
Показать ещё 4 комментария
Теги:
tensorflow
ram

2 ответа

1
Лучший ответ

Решила его, разбивая изображение на части, обрабатывая их один за другим и объединяя их. Чтобы избежать видимых "разделенных линий" на выходном изображении, я повторяю описанный выше процесс с разными размерами штук и вычисляет среднее значение.

Я закончил с этим:

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
0

В этом документе рассматривается ваша проблема и объясняется, почему она существует:

https://dl.acm.org/citation.cfm?id=3132847.3132872

Если вы не можете получить к нему доступ, вот несколько цитат/резюме:

Есть 2 проблемы: заполнение и нормализация.

Обивка:

При выполнении свертки сеть должна заполнять отсутствующие значения пикселей на границе изображения. Это связано с тем, что ядро первой пары пограничных пикселей лежит за пределами предоставленного изображения.

Нормализация:

В сети свертки применяется метод нормализации партии, чтобы ускорить сближение и уменьшить внутренний сдвиг ковариации.

Теперь предположим, что мы разделили изображение на два суб-изображения. Мы получаем две небольшие партии. Если они пройдут через CNN самостоятельно, мы получим два результата нормализации, которые применяют только суб-изображения локальных средств и дисперсии в вычислениях. Поэтому, даже если мы объединим эти части с одним изображением, мы получим результат, который визуально отличается от результата, созданного для всего изображения.


Они предлагают следующие решения:

Обивка:

Для внутренней границы мы используем новую технику заполнения, добавление словаря.

Это означает, что они используют соответствующие значения пикселей соседнего суб-изображения.

Для внешней границы мы используем круговые прокладки...

Это означает, что вы накладываете правую часть с помощью пикселей слева от изображения, как если бы вы сориентировали изображение справа (и наоборот). (То же самое с верхним дном)

Нормализация:

Это немного сложнее. В конце концов, они нормализуют под-изображения, совместно используют значения нормализации (среднее значение и дисперсию) между изображениями и объединяют их вместе.


Прокладка может быть легко реализована, но я не знаю, как сделать часть нормализации с помощью тензорного потока. Если кто-то выяснит это и отправит код, я был бы очень благодарен.

  • 0
    Эта статья выглядит очень многообещающе, но без кода это расстраивает.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню