0 Обзор
- Название статьи: «Более широкие сверточные функции для обнаружения краев»
- Ссылка на бумагу:открытый доступ. Город Тяньхэ VF.com/content_CV с…
- Аббревиатура: РКФ
Мне кажется, что это сочинениеЭто улучшение сети HED CVPR 2015 (обнаружение целостных вложенных краев), и документ RCF в основном сравнивается с сетью HED во всем мире..
В прошлой статье мы смутно помним, что модель HED имеет такой график:
Среди них карты характеристик пяти побочных выходов HED.Следующий рисунок - это рисунок в документе RCF:
Мы можем понять улучшение RCF по сравнению с HED по разнице между этими двумя цифрами.Вы можете взглянуть на рисунок.
Раскройте ответ:
- HED — изображение леопарда, а RCF — изображение двух птиц (ручные собачьи головы)
- В HED это карта характеристик вывода побочного вывода, а в RCF это conv3_1, conv3_2, что означаетRCF, похоже, использует карту выходных признаков каждой свертки в качестве побочного вывода..
Правильно, HED выбирает 5 побочных выходных данных, каждый боковой выход представляет собой карту объектов, выводимую слоем свертки перед слоем пула; а RCF использует выходную карту объектов каждой свертки в качестве дополнительного вывода, другими словамиВ финальном стороннем выводе может быть более одного вывода одинакового размера..
Если вы еще этого не понимаете, см. следующую главу «Структура модели».
1 Структура модели
Основой RCF является модель VGG:
Как видно из рисунка:
- Магистральная сеть разделена на состояния от 1 до 5, этап 1 имеет два сверточных слоя, этап 2 имеет два сверточных слоя, всего 13 сверточных слоев, изображение, выводимое каждой сверткой, дополнительно подключено к свертке 1x1. Чтобы уменьшить количество каналов, вы можете видеть, что на рисунке присутствует большое количество 21-канальных сверточных слоев.
- 21-канальная карта признаков того же этапа склеивается в 42-канальную или 63-канальную карту признаков, затем проходит сверточный слой 1x1, чтобы уменьшить количество каналов до 1, а затем проходит через сигмовидный слой. для вывода Результат является побочным выводом в модели RCF
2 Функция потерь
Функция потерь здесь фактически аналогична HED:
Во-первых, функция потерь по-прежнему использует бинарную кросс-энтропию.
впредставляет отрицательное значение пикселя,Представляет положительное значение пикселя.Вообще говоря, в задаче обнаружения контуров положительных образцов должно быть меньше, поэтомуЗначение мало, поэтому в первой строке функции потерь y=0, то есть при расчете потерь неконтурной части будет добавлен меньший вес, чтобы избежать проблемы дисбаланса классов.
В функции потерь есть две константы, одна, это постоянная веса, по умолчанию 1,1, другая. Описание в статье такое:
Наборы данных краев в этом сообществе обычно помечаются несколькими аннотаторами, использующими свои знания о наличии объектов и частей объектов. Хотя люди различаются по познанию, эти помеченные человеком края для одного и того же изображения имеют высокую согласованность. Для каждого изображения мы усредняем все наземная правда для создания карты вероятности края, которая находится в диапазоне от 0 до 1. Здесь 0 означает, что ни один аннотатор не помечен в этом пикселе, а 1 означает, что все аннотаторы пометили в этом пикселе.Мы рассматриваем пиксели с вероятностью края выше η как положительные выборки и пиксели с вероятностью края, равной 0, как отрицательные выборки. В противном случае, если пиксель отмечен менее чем η аннотаторов, этот пиксель может быть семантически спорным, чтобы быть точкой края. Таким образом, рассматривать ли его как положительный или отрицательный выборки могут сбить сеть с толку, поэтому мы игнорируем пиксели в этой категории.
Общая идея такова: как правило, маркировка набора данных выполняется несколькими людьми. Хотя у разных людей разное сознание, их контурные аннотации к одному и тому же изображению часто совпадают. Окончательный вывод сети RCF генерируется путем слияния 5 побочных выходов, поэтому вывод вашей RCF также должен быть больше, чемсчитается положительным, то меньшесчитается отрицательным.На самом деле я этого не учел, когда сам воспроизводил.Не учел этого в гитхабе и официальном коде в интернете.Они все прям кросс-энтропия. . . Я также объясню это в статье без дальнейших церемоний.значение
3 pytorch часть кода
Для этой статьи RCF ключом является построение модели, а другой - построение функции потерь.Вот две части кода, которые помогут вам лучше понять вышеизложенное.
3.1 Модельная часть
Следующий код в части апсэмплинга написан по старинке, потому что найденная в интернете версия pytorch оценивается как старая.На тот момент не было пакета функций типа Conv2DTrans, но это не помешало вам изучить RCF через код.
class RCF(nn.Module):
def __init__(self):
super(RCF, self).__init__()
#lr 1 2 decay 1 0
self.conv1_1 = nn.Conv2d(3, 64, 3, padding=1)
self.conv1_2 = nn.Conv2d(64, 64, 3, padding=1)
self.conv2_1 = nn.Conv2d(64, 128, 3, padding=1)
self.conv2_2 = nn.Conv2d(128, 128, 3, padding=1)
self.conv3_1 = nn.Conv2d(128, 256, 3, padding=1)
self.conv3_2 = nn.Conv2d(256, 256, 3, padding=1)
self.conv3_3 = nn.Conv2d(256, 256, 3, padding=1)
self.conv4_1 = nn.Conv2d(256, 512, 3, padding=1)
self.conv4_2 = nn.Conv2d(512, 512, 3, padding=1)
self.conv4_3 = nn.Conv2d(512, 512, 3, padding=1)
self.conv5_1 = nn.Conv2d(512, 512, kernel_size=3,
stride=1, padding=2, dilation=2)
self.conv5_2 = nn.Conv2d(512, 512, kernel_size=3,
stride=1, padding=2, dilation=2)
self.conv5_3 = nn.Conv2d(512, 512, kernel_size=3,
stride=1, padding=2, dilation=2)
self.relu = nn.ReLU()
self.maxpool = nn.MaxPool2d(2, stride=2, ceil_mode=True)
self.maxpool4 = nn.MaxPool2d(2, stride=1, ceil_mode=True)
#lr 0.1 0.2 decay 1 0
self.conv1_1_down = nn.Conv2d(64, 21, 1, padding=0)
self.conv1_2_down = nn.Conv2d(64, 21, 1, padding=0)
self.conv2_1_down = nn.Conv2d(128, 21, 1, padding=0)
self.conv2_2_down = nn.Conv2d(128, 21, 1, padding=0)
self.conv3_1_down = nn.Conv2d(256, 21, 1, padding=0)
self.conv3_2_down = nn.Conv2d(256, 21, 1, padding=0)
self.conv3_3_down = nn.Conv2d(256, 21, 1, padding=0)
self.conv4_1_down = nn.Conv2d(512, 21, 1, padding=0)
self.conv4_2_down = nn.Conv2d(512, 21, 1, padding=0)
self.conv4_3_down = nn.Conv2d(512, 21, 1, padding=0)
self.conv5_1_down = nn.Conv2d(512, 21, 1, padding=0)
self.conv5_2_down = nn.Conv2d(512, 21, 1, padding=0)
self.conv5_3_down = nn.Conv2d(512, 21, 1, padding=0)
#lr 0.01 0.02 decay 1 0
self.score_dsn1 = nn.Conv2d(21, 1, 1)
self.score_dsn2 = nn.Conv2d(21, 1, 1)
self.score_dsn3 = nn.Conv2d(21, 1, 1)
self.score_dsn4 = nn.Conv2d(21, 1, 1)
self.score_dsn5 = nn.Conv2d(21, 1, 1)
#lr 0.001 0.002 decay 1 0
self.score_final = nn.Conv2d(5, 1, 1)
def forward(self, x):
# VGG
img_H, img_W = x.shape[2], x.shape[3]
conv1_1 = self.relu(self.conv1_1(x))
conv1_2 = self.relu(self.conv1_2(conv1_1))
pool1 = self.maxpool(conv1_2)
conv2_1 = self.relu(self.conv2_1(pool1))
conv2_2 = self.relu(self.conv2_2(conv2_1))
pool2 = self.maxpool(conv2_2)
conv3_1 = self.relu(self.conv3_1(pool2))
conv3_2 = self.relu(self.conv3_2(conv3_1))
conv3_3 = self.relu(self.conv3_3(conv3_2))
pool3 = self.maxpool(conv3_3)
conv4_1 = self.relu(self.conv4_1(pool3))
conv4_2 = self.relu(self.conv4_2(conv4_1))
conv4_3 = self.relu(self.conv4_3(conv4_2))
pool4 = self.maxpool4(conv4_3)
conv5_1 = self.relu(self.conv5_1(pool4))
conv5_2 = self.relu(self.conv5_2(conv5_1))
conv5_3 = self.relu(self.conv5_3(conv5_2))
conv1_1_down = self.conv1_1_down(conv1_1)
conv1_2_down = self.conv1_2_down(conv1_2)
conv2_1_down = self.conv2_1_down(conv2_1)
conv2_2_down = self.conv2_2_down(conv2_2)
conv3_1_down = self.conv3_1_down(conv3_1)
conv3_2_down = self.conv3_2_down(conv3_2)
conv3_3_down = self.conv3_3_down(conv3_3)
conv4_1_down = self.conv4_1_down(conv4_1)
conv4_2_down = self.conv4_2_down(conv4_2)
conv4_3_down = self.conv4_3_down(conv4_3)
conv5_1_down = self.conv5_1_down(conv5_1)
conv5_2_down = self.conv5_2_down(conv5_2)
conv5_3_down = self.conv5_3_down(conv5_3)
so1_out = self.score_dsn1(conv1_1_down + conv1_2_down)
so2_out = self.score_dsn2(conv2_1_down + conv2_2_down)
so3_out = self.score_dsn3(conv3_1_down + conv3_2_down + conv3_3_down)
so4_out = self.score_dsn4(conv4_1_down + conv4_2_down + conv4_3_down)
so5_out = self.score_dsn5(conv5_1_down + conv5_2_down + conv5_3_down)
## transpose and crop way
weight_deconv2 = make_bilinear_weights(4, 1).cuda()
weight_deconv3 = make_bilinear_weights(8, 1).cuda()
weight_deconv4 = make_bilinear_weights(16, 1).cuda()
weight_deconv5 = make_bilinear_weights(32, 1).cuda()
upsample2 = torch.nn.functional.conv_transpose2d(so2_out, weight_deconv2, stride=2)
upsample3 = torch.nn.functional.conv_transpose2d(so3_out, weight_deconv3, stride=4)
upsample4 = torch.nn.functional.conv_transpose2d(so4_out, weight_deconv4, stride=8)
upsample5 = torch.nn.functional.conv_transpose2d(so5_out, weight_deconv5, stride=8)
### center crop
so1 = crop(so1_out, img_H, img_W)
so2 = crop(upsample2, img_H, img_W)
so3 = crop(upsample3, img_H, img_W)
so4 = crop(upsample4, img_H, img_W)
so5 = crop(upsample5, img_H, img_W)
fusecat = torch.cat((so1, so2, so3, so4, so5), dim=1)
fuse = self.score_final(fusecat)
results = [so1, so2, so3, so4, so5, fuse]
results = [torch.sigmoid(r) for r in results]
return results
3.2 Часть функции потерь
def cross_entropy_loss_RCF(prediction, label):
label = label.long()
mask = label.float()
num_positive = torch.sum((mask==1).float()).float()
num_negative = torch.sum((mask==0).float()).float()
mask[mask == 1] = 1.0 * num_negative / (num_positive + num_negative)
mask[mask == 0] = 1.1 * num_positive / (num_positive + num_negative)
mask[mask == 2] = 0
cost = torch.nn.functional.binary_cross_entropy(
prediction.float(),label.float(), weight=mask, reduce=False)
return torch.sum(cost)
Справочная статья: