"Это 6-й день моего участия в ноябрьском испытании обновлений, ознакомьтесь с подробностями события:Вызов последнего обновления 2021 г."
Пространственная адаптивная нормализация (SPADE)
Пространственная адаптивная нормализация (Spatial Adaptive Normalization, SPADE
)ДаGauGAN
Основное новшество в , которое используется для послойной нормализации графов семантической сегментации, для лучшей интерпретацииSPADE
, надо сначала понятьGauGAN
Сетевой вход -语义分割图
.
Маски сегментации меток с использованием одноразового кодирования
Рассмотрите возможность обученияGauGAN
использовалFacades数据集
. Среди них карта сегментации находится вRGB
Изображения кодируются разными цветами, как показано на изображении ниже. Например, стена отображается синим цветом, а колонна — красным. Это представление визуально просто для понимания, но бесполезно для обучения нейронной сети, потому что дляGAN
С точки зрения цветов семантики нет.
Тот факт, что цвета ближе в цветовом пространстве, не означает, что они близки и семантически. Например, мы можем изобразить траву светло-зеленым цветом, а самолеты — темно-зеленым, хотя карты сегментации имеют похожий оттенок, их семантика не имеет значения.
Поэтому вместо того, чтобы использовать цвета для маркировки пикселей, мы должны использовать метки классов. Однако это все еще не решает проблему, потому что метки классов являются случайными числами и не имеют семантики. Таким образом, лучший подход — использовать маску сегментации с меткой 1, если в этом пикселе есть объект, и маску сегментации с меткой 0 в противном случае. Другими словами, мы сразу кодируем метки на карте сегментации в виде форм.(H, W, number of classes)
маска сегментации.
существуетJPEG
При кодировании некоторая визуальная информация, не очень важная для визуального эффекта, удаляется в процессе сжатия. Несмотря на то, что результирующие пиксели должны принадлежать к одному классу и иметь один и тот же цвет, они могут иметь разные значения. Поэтому мы не можемJPEG
Цвета на изображении сопоставлены с классами. Чтобы решить эту проблему, нам нужно использовать несжатый формат изображенияBMP
. При загрузке и предварительной обработке изображений мы будем загружать файлы и конвертировать их изBMP
Преобразуйте в маску сегментации с горячим кодированием.
иногда,TensorFlow
базовая предварительная обработка изображенийAPI
Некоторые сложные задачи не могут быть выполнены, поэтому нам нужно использовать другиеPython
библиотека,tf.py_function
позвольте намTensorFlow
Общий бег в тренировочном процессеPython
функция:
def load(image_file):
def load_data(image_file):
jpg_file = image_file.numpy().decode('utf-8')
bmp_file = jpg_file.replace('.jpg', '.bmp')
png_file = jpg_file.replace('.jpg', '.png')
image = np.array(Image.open(jpg_file))/127.5-1
map = np.array(Image.open(png_file))/127.5-1
labels = np.array(Image.open(bmp_file), dtype=np.uint8)
h,w,_ = image.shape
n_class = 12
mask = np.zeros((h,w,n_class),dtype=np.float32)
for i in range(n_class):
one_hot[labels==i,i] = 1
return map, image, mask
[mask, image, label] = tf.py_function(load_data, [image_file], [tf.float32, tf.float32, tf.float32])
Поняв формат маски семантической сегментации с горячим кодированием, мы будем использоватьTensorFlow2
выполнитьSPADE
.
Реализовать ЛОПАТУ
实例归一化
Он стал очень популярен при создании изображений, но имеет тенденцию ослаблять семантику масок сегментации: предположим, что входное изображение содержит только одну метку сегментации; например, если предположить, что все изображение представляет собой небо, поскольку входные данные имеют одинаковые значения, выходные Слои позже также будут иметь единые значения.
Нормализация экземпляра вычисляет среднее значение по измерениям (H, W) для каждого канала. Следовательно, среднее значение для этого канала будет одинаковым, а нормализованная активация после вычитания среднего станет равной нулю. Очевидно, что семантика была потеряна, что является довольно крайним примером, но логика похожа, мы видим, что маска сегментации теряет свое семантическое значение по мере увеличения ее площади.
Для решения этой проблемы,SPADE
Нормализует локальную область, ограниченную маской сегментации, а не всей маской. На рисунке ниже показаноSPADE
Архитектура:
При пакетной нормализации вычисления по измерениям(N, H, W)
Среднее значение и стандартное отклонение каналов, дляSPADE
то же самое. Разница в том, что каждый каналγ
иβ
больше не скалярное значение, а двумерный вектор формы(H, W)
. Другими словами, для каждой активации, полученной из карты семантической сегментации, существуетγ
иβ
ценность. Поэтому нормализация применяется по-разному к разным сегментированным областям. Эти два параметра изучаются с помощью двух сверточных слоев, как показано на следующем рисунке:
SPADE
Применяется не только к входному каскаду сети, но и к внутренним слоям. Теперь мы можем использоватьTensorFlow2
Реализация пользовательского слояSPADE
.
сначала будет__init__
Сверточный слой определяется в конструкторе следующим образом:
class SPADE(layers.Layer):
def __init__(self, filters, epsilon=1e-5):
super(SPADE, self).__init__()
self.epsilon = epsilon
self.conv = layers.Conv2D(128, 3, padding='same', activation='relu')
self.conv_gamma = layers.Conv2D(filters, 3, padding='same')
self.conv_beta = layers.Conv2D(filters, 3, padding='same')
Затем получите размеры карты активации, чтобы использовать их при изменении размера позже:
def build(self, input_shape):
self.resize_shape = input_shape[1:3]
Наконец, вcall()
Соедините слои и операции вместе следующим образом:
def call(self, input_tensor, raw_mask):
mask = tf.image.resize(raw_mask, self.resize_shape, method='nearest')
x = self.conv(mask)
gamma = self.conv_gamma(x)
beta = self.conv_beta(x)
mean, var = tf.nn.moments(input_tensor, axes=(0,1,2), keepdims=True)
std = tf.sqrt(var+self.epsilon)
normalized = (input_tensor - mean) / std
output = gamma * normalized + beta
return output
Далее мы рассмотрим, как использоватьSPADE
.
Применение SPADE в остаточных сетях
Наконец, мы будем изучать, какSPADE
Вставьте в остаточный блок:
SPADE
Основными строительными блоками остаточного блока являютсяSPADE-ReLU-Conv
Этаж. каждыйSPADE
Оба принимают два входа — активации предыдущего слоя и карту семантической сегментации.
Как и в случае со стандартным остаточным блоком, есть две свертки.ReLU
слои и путь перехода. Соединения пропуска обучения требуются всякий раз, когда изменяется количество каналов до и после остаточного блока. Когда это происходит, двое на прямом путиSPADE
Карты активации на входе будут иметь разную размерность. Однако мы ужеSPADE
В блок встроена возможность изменения размера. Следующие используются дляSPADE
Код остаточных блоков для построения необходимых слоев:
class Resblock(layers.Layer):
def __init__(self, filters):
super(Resblock, self).__init__()
self.filters = filters
def build(self, input_shape):
input_filter = input_shape[-1]
self.spade_1 = SPADE(input_filter)
self.spade_2 = SPADE(self.filters)
self.conv_1 = layers.Conv2D(self.filters, 3, padding='same')
self.conv_2 = layers.Conv2D(self.filters, 3, padding='same')
self.learned_skip = False
if self.filters != input_filter:
self.learned_skip = True
self.spade_3 = SPADE(input_filter)
self.conv_3 = layers.Conv2D(self.filters, 3, padding='same')
Наконец, вcall()
Соедините слои в:
def call(self, input_tensor, mask):
x = self.spade_1(input_tensor, mask)
x = self.conv_1(tf.nn.leaky_relu(x, 0.2))
x = self.spade_2(x, mask)
x = self.conv_2(tf.nn.leaky_relu(x, 0.2))
if self.learned_skip:
skip = self.spade_3(input_tensor, mask)
skip = self.conv_3(tf.nn.leaky_relu(skip, 0.2))
else:
skip = input_tensor
output = skip + x
return output