- Оригинальный адрес:Семантическая сегментация — U-Net (Часть 1)
- Оригинальный автор:Kerem Turgutlu
- Перевод с:Программа перевода самородков
- Постоянная ссылка на эту статью:GitHub.com/rare earth/gold-no…
- Переводчик:JohnJiangLA
- Корректор:haiyang-tju leviding
Мне 6 месяцев назад
В основном я сосредоточусь на задаче классификации на уровне пикселей, такой как семантическая сегментация и конкретная реализация алгоритма. Также я приведу несколько кейс-упражнений, над которыми недавно работал.
Семантическая сегментация, по определению, представляет собой процесс сегментации изображения на последовательные части. Например, классифицируйте каждый пиксель, принадлежащий человеку, машине, дереву или любому другому объекту в наборе данных.
Семантическая сегментация против сегментации экземпляра
Семантическая сегментация намного проще, чем сегментация экземпляра старшего брата.
При сегментации экземпляров наша цель состоит не только в том, чтобы делать прогнозы на уровне пикселей для каждого человека и каждой машины, но и в том, чтобы различать сущности на человека 1, человека 2, дерево 1, дерево 2, машину 1, машину 2 и так далее. В настоящее время лучшим алгоритмом сегментации является Mask-RCNN: двухэтапное сотрудничество между несколькими подсетями с использованием методов RPN (сеть региональных предложений), FPN (сеть функциональных пирамид) и FCN (полностью сверточная сеть) [5, 6, 7, 8].
Рисунок 4. Семантическая сегментация
Рисунок 5. Сегментация экземпляра
Практический пример: чаша науки о данных, 2018 г.
Data Science Bowl 2018 только что закончился, и я многому научился на конкурсе. Возможно, самым важным из них является то, что даже при глубоком обучении, которое более автоматизировано, чем традиционное машинное обучение, предварительная и постобработка могут быть ключом к достижению хороших результатов. Это важные навыки, которыми должны овладеть практики, и они определяют, как проблема структурируется и моделируется.
Так какKaggleБыло много обсуждений и объяснений этой задачи и методологии, используемой в конкурсе, поэтому я не буду вдаваться в подробности этого конкурса. Но поскольку схема чемпионата связана с основой этого сообщения в блоге, она будет кратко объяснена.
Data Science Bowl 2018, как и предыдущие соревнования, организован фондом Booz Allen Foundation. Задача этого года — идентифицировать ядра на данном микроскопическом изображении и нарисовать для них индивидуальные маски сегментации.
Теперь потратьте минуту или две, чтобы угадать, какой тип сегментации требуется для этой задачи: семантическая или сущностная?
Вот образец изображения маски и необработанное изображение микроскопа.
Рисунок 6. Маска ядра (слева) и исходное изображение (справа)
Хотя эта задача на первый взгляд звучит как задача семантической сегментации, на самом деле она требует сегментации экземпляров. Нам нужно обработать каждое ядро на изображении независимо и идентифицировать их как ядра 1, ядра 2, ядра 3 и т. д., аналогично Car 1, Car 2, Person 1 и т. д. в предыдущем примере. Возможно, мотивация для этой задачи заключалась в том, чтобы отслеживать размер, количество и характеристики ядер в образце клеток. Такой автоматизированный процесс отслеживания и записи очень важен и поможет еще больше ускорить исследовательский процесс различных экспериментов по лечению заболеваний.
Вам может быть интересно, если этот пост посвящен семантической сегментации, но если Data Science Bowl 2018 является примером задачи сегментации экземпляров, то почему я всегда обсуждаю это конкретное соревнование. Если вы думаете об этом, вы абсолютно правы, конечная цель этого конкурса не в том, чтобы служить примером для семантической сегментации. Однако как перевести эту проблему сегментации экземпляров в задачу семантической сегментации нескольких классов. Это метод, который я пробовал, и хотя на практике он не удался, он также помог добиться окончательного успеха.
Во время трехмесячного конкурса только две модели (или их варианты) были распространены или, по крайней мере, открыто обсуждались на форуме: Mask-RCNN и U-Net. Как упоминалось ранее, Mask-RCNN — это современный алгоритм обнаружения объектов, который обнаруживает отдельные объекты и предсказывает их маски, как при сегментации экземпляров. Однако, поскольку Mask-RCNN использует двухэтапный метод, ему необходимо оптимизировать RPN (сеть региональных предложений), а затем одновременно прогнозировать ограничивающую рамку, категорию и маску, поэтому развертывание и обучение будут очень сложными.
С другой стороны, U-Net — очень популярная сквозная сеть кодера-декодера для семантической сегментации [9]. Первоначально он также был создан и применен в области сегментации биомедицинских изображений, что очень похоже на задачу Data Science Bowl. В такого рода соревнованиях нет серебряной пули, ни одна из этих двух архитектур не может дать хороших прогнозов без постобработки или предварительной обработки или незначительных структурных изменений. У меня не было возможности попробовать Mask-RCNN в этом конкурсе, поэтому я поэкспериментировал с U-Net и многому научился.
Кроме того, поскольку наша тема — семантическая сегментация, Mask-RCNN остается объяснить другим блогерам. Но если вы хотите попробовать их в своем собственном приложении CV, вот два популярных репозитория github, в которых реализована функциональность:TensorflowиPyTorch. [10, 11]
Теперь давайте перейдем к U-Net и углубимся в его детали...
Начнем с его архитектуры:
Рисунок 7. Собственная U-Net
Для друзей, знакомых с традиционными сверточными нейронными сетями, структура первой части (обозначаемой как спуск) очень знакома. Первую часть можно назвать спуском, или вы можете думать о ней как о части кодировщика, где вы делаете это с помощью блока свертки, а затем выполняете субдискретизацию с максимальным объединением для кодирования входного изображения в разные уровни представления признаков.
Вторая часть сети состоит из повышающей дискретизации и конкатенации, за которыми следуют обычные операции свертки. Использование повышающей дискретизации в CNN может быть новой концепцией для некоторых читателей, но идея проста: расширить размер объекта, чтобы достичь того же размера, что и соответствующий объединенный блок слева. Серые и зеленые стрелки здесь представляют собой сопоставление двух объектов вместе. По сравнению с другими сетями сегментации FCN, основной вклад U-Net в этом отношении заключается в том, что во время повышающей дискретизации и глубокого сетевого процесса мы объединяем функции высокого разрешения при понижающей дискретизации с функциями повышающей дискретизации для последующих сверток. представления в процессе. Поскольку повышающая дискретизация — это разреженная операция, нам нужно получить хорошие априорные значения на ранней стадии обработки, чтобы лучше представить информацию о местоположении. В FPN (Feature Pyramidal Networks) есть аналогичная идея классификации соответствия соединений.
Рис. 7. Нативная тензорная диаграмма U-Net
Мы можем определить рабочий модуль в нисходящей части как «свертка → субдискретизация».
# 一个采样下降模块
def make_conv_bn_relu(in_channels, out_channels, kernel_size=3, stride=1, padding=1):
return [
nn.Conv2d(in_channels, out_channels, kernel_size=kernel_size, stride=stride, padding=padding, bias=False),
nn.BatchNorm2d(out_channels),
nn.ReLU(inplace=True)
]
self.down1 = nn.Sequential(
*make_conv_bn_relu(in_channels, 64, kernel_size=3, stride=1, padding=1 ),
*make_conv_bn_relu(64, 64, kernel_size=3, stride=1, padding=1 ),
)
# 卷积然后最大池化
down1 = self.down1(x)
out1 = F.max_pool2d(down1, kernel_size=2, stride=2)
Модуль понижающей дискретизации U-Net
Точно так же мы можем определить модуль операции в восходящей части: «Апсемплинг → Конкатенация → Свертка».
# 一个采样上升模块
def make_conv_bn_relu(in_channels, out_channels, kernel_size=3, stride=1, padding=1):
return [
nn.Conv2d(in_channels, out_channels, kernel_size=kernel_size, stride=stride, padding=padding, bias=False),
nn.BatchNorm2d(out_channels),
nn.ReLU(inplace=True)
]
self.up4 = nn.Sequential(
*make_conv_bn_relu(128,64, kernel_size=3, stride=1, padding=1 ),
*make_conv_bn_relu(64,64, kernel_size=3, stride=1, padding=1 )
)
self.final_conv = nn.Conv2d(32, num_classes, kernel_size=1, stride=1, padding=0 )
# 对 out_last 上采样,并与 down1 级联,然后卷积
out = F.upsample(out_last, scale_factor=2, mode='bilinear')
out = torch.cat([down1, out], 1)
out = self.up4(out)
# 用于最后预测的 1 * 1 卷积
final_out = self.final_conv(out)
Модуль повышения частоты дискретизации U-Net
Присмотревшись к структурной схеме, вы обнаружите, что размер вывода (388 * 388) не соответствует исходному входу (572 * 572). Если вы хотите, чтобы выходные данные оставались согласованными по размеру, вы можете использовать дополненные свертки, чтобы поддерживать согласованные размеры по всему каскаду, как мы сделали в приведенном выше примере кода.
Говоря об этом виде повышения дискретизации, вы можете встретить один из следующих терминов: транспонированная свертка, повышающая свертка, деконволюция или повышающая дискретизация. Многим людям, в том числе мне и технической документации PyTorch, не нравится термин «деконволюция», потому что на этапе повышающей дискретизации мы фактически выполняем обычные операции свертки, и нет буквального «обратного». Прежде чем идти дальше, если вы не знакомы с основными операциями свертки и их арифметикой, я настоятельно рекомендую посетитьhere.. [12]
Я объясню методы повышения частоты дискретизации от простого к сложному. Вот три способа повышения дискретизации 2D-тензоров в PyTorch:
интерполяция ближайшего соседа
Это самый простой способ найти недостающие значения пикселей при изменении размера (преобразовании) тензора в больший тензор, такой как 2x2 в 4x4, 5x5 или 6x6.
Мы используем Numpy для пошаговой реализации этого базового алгоритма компьютерного зрения:
def nn_interpolate(A, new_size):
"""
逐步实现最近邻插值
"""
# 获取大小
old_size = A.shape
# 计算扩充后的行与列
row_ratio, col_ratio = new_size[0]/old_size[0], new_size[1]/old_size[1]
# 定义新的行与列位置
new_row_positions = np.array(range(new_size[0]))+1
new_col_positions = np.array(range(new_size[1]))+1
# 按照比例标准化新行与列的位置
new_row_positions = new_row_positions / row_ratio
new_col_positions = new_col_positions / col_ratio
# 对新行与列位置应用 ceil (计算大于等于该值的最小整数)
new_row_positions = np.ceil(new_row_positions)
new_col_positions = np.ceil(new_col_positions)
# 计算各点需要重复的次数
row_repeats = np.array(list(Counter(new_row_positions).values()))
col_repeats = np.array(list(Counter(new_col_positions).values()))
# 在矩阵的各列执行列向插值
row_matrix = np.dstack([np.repeat(A[:, i], row_repeats)
for i in range(old_size[1])])[0]
# 在矩阵的各列执行列向插值
nrow, ncol = row_matrix.shape
final_matrix = np.stack([np.repeat(row_matrix[i, :], col_repeats)
for i in range(nrow)])
return final_matrix
def nn_interpolate(A, new_size):
""向量化最近邻插值"""
old_size = A.shape
row_ratio, col_ratio = np.array(new_size)/np.array(old_size)
# 行向插值
row_idx = (np.ceil(range(1, 1 + int(old_size[0]*row_ratio))/row_ratio) - 1).astype(int)
# 列向插值
col_idx = (np.ceil(range(1, 1 + int(old_size[1]*col_ratio))/col_ratio) - 1).astype(int)
final_matrix = A[:, row_idx][col_idx, :]
return final_matrix
[PyTorch]F.upsample(…, режим = «ближайший»)
>>> input = torch.arange(1, 5).view(1, 1, 2, 2)
>>> input
(0 ,0 ,.,.) =
1 2
3 4
[torch.FloatTensor of size (1,1,2,2)]
>>> m = nn.Upsample(scale_factor=2, mode='nearest')
>>> m(input)
(0 ,0 ,.,.) =
1 1 2 2
1 1 2 2
3 3 4 4
3 3 4 4
[torch.FloatTensor of size (1,1,4,4)]
билинейная интерполяция
Билинейная интерполяция, хотя и не такая эффективная с вычислительной точки зрения, как интерполяция ближайшего соседа, является более точным алгоритмом аппроксимации. Значение одного пикселя рассчитывается как средневзвешенное значение всех других значений пикселей на основе расстояния.
[PyTorch]F.upsample(…, режим = «билинейный»)
>>> input = torch.arange(1, 5).view(1, 1, 2, 2)
>>> input
(0 ,0 ,.,.) =
1 2
3 4
[torch.FloatTensor of size (1,1,2,2)]
>>> m = nn.Upsample(scale_factor=2, mode='bilinear')
>>> m(input)
(0 ,0 ,.,.) =
1.0000 1.2500 1.7500 2.0000
1.5000 1.7500 2.2500 2.5000
2.5000 2.7500 3.2500 3.5000
3.0000 3.2500 3.7500 4.0000
[torch.FloatTensor of size (1,1,4,4)]
транспонированная свертка
В транспонированной свертке мы можем узнать веса с помощью обратного распространения. В статье я испробовал все методы апсемплинга для разных ситуаций, на практике вы можете изменить архитектуру сети, вы можете попробовать все из них, чтобы найти лучший для проблемы. Я лично предпочитаю транспонированную свертку, потому что она более управляема, но вы можете напрямую использовать простую билинейную интерполяцию или интерполяцию ближайшего соседа.
[PyTorch]nn.ConvTranspose2D(…, шаг=…, отступ=…)
Рис. 8. Пример транспонированной свертки с разными параметрами изGitHub.com/VDU в лесу/От… [12]
В этом конкретном случае Data Science Bowl основным недостатком использования родной U-Net является перекрытие ядер. Как показано на предыдущем рисунке, создавая двоичную маску в качестве целевого вывода, U-Net может точно создавать аналогичные маски предсказания, так что перекрывающиеся или соседние ядра создают комбинированную маску.
Рис. 9. Перекрывающиеся маски ядер
Для проблемы перекрытия экземпляров авторы статьи U-Net используют взвешенную кросс-энтропию, чтобы сосредоточиться на изучении границ ячеек. Такой подход помогает разделить перекрывающиеся экземпляры. Основная идея состоит в том, чтобы выполнять более взвешенные операции на границах, чтобы сеть могла узнать расстояние между соседними экземплярами.
Рисунок 10. Взвешенная карта
Рис. 11. (a) Исходное изображение (b) Каждый экземпляр добавляет разные цвета фона (c) Генерирует маску сегментации (d) Взвешенное по пикселям сопоставление
Еще один способ решить проблему такого типа — преобразовать бинарную маску в цель составного типа — подход, используемый многими конкурентами, включая выигрышные схемы. Одним из преимуществ U-Net является то, что сеть может быть построена для достижения произвольного количества выходов за счет использования сверток 1*1 на последнем уровне для представления нескольких типов.
Цитата из предложения победителя Data Science Bowl:
Целью является сеть, использующая функцию активации sigmod для 2-канальной маски, т. е. (маска - граница, граница); целью является сеть, использующая функцию активации softmax для 3-канальной маски, то есть (маска - граница, 1 - маска - граница) 2-канальная полная маска, т.е. (маска, граница)
После этих операций прогнозирования традиционные алгоритмы обработки изображений, такие как водораздел, могут использоваться для постобработки для дальнейшего сегментирования отдельных ядер. [14]
Рисунок 12. Визуальная классификация: передний план (зеленый), контур (желтый), фон (черный)
Это первый раз, когда я набрался смелости, чтобы принять участие в официальном конкурсе CV на Kaggle, и это был Data Science Bowl. Несмотря на то, что я закончил соревнование только с лучшими 20% (что обычно является средним показателем соревнования), я имел удовольствие участвовать в этом кубке науки о данных и узнал то, что вы можете узнать, только играя и пытаясь. Активное обучение гораздо более продуктивно, чем просмотр и чтение ресурсов онлайн-курсов.
как новичокFast.aiDeep Learning Practitioner для изучения курса, это важный шаг в моем долгом обучении, и я могу получить от него ценный опыт. Поэтому я предлагаю вам сознательно попытаться столкнуться с некоторыми проблемами, которые вы никогда не видели и не решали, чтобы испытать великую радость познания неизвестного.
Еще один ценный урок, который я извлек из этого соревнования, заключается в том, что в соревнованиях по компьютерному зрению (а также для НЛП) важно проверять каждый прогноз лично, чтобы увидеть, что работает. Если ваш набор данных достаточно мал, то следует проверять каждый вывод. Это поможет вам найти лучшие идеи или отладить код, если что-то пойдет не так.
передача обучения и многое другое
До сих пор мы объясняли архитектурные модули собственной U-Net и то, как преобразовать цель для решения проблемы сегментации экземпляров. Давайте теперь обсудим гибкость этих типов сетей кодер-декодер. Под гибкостью я подразумеваю свободу и инновации, которые вы можете получить при проектировании своей сети.
Трансферное обучение — настолько мощная идея, что никто, использующий глубокое обучение, не может избежать ее. Проще говоря, трансферное обучение — это использование предварительно обученных сетей для выполнения аналогичных задач с большими объемами данных при отсутствии крупномасштабных наборов данных. Даже когда данных достаточно, трансферное обучение может в некоторой степени повысить производительность, и его можно использовать не только в компьютерном зрении, но и для НЛП.
Трансферное обучение также является мощным методом для таких систем, как U-Net. Ранее мы определили два важных компонента в U-Net: повышение частоты дискретизации и понижение частоты дискретизации. Здесь мы понимаем их как кодер и декодер. Кодер берет ввод и кодирует его в низкоразмерное пространство признаков, которое характеризует ввод в более низких измерениях. Затем представьте, если вы замените этот кодировщик своим идеальным ImageNet, таким как: VGG, ResNet, Inception, NasNet, что угодно. Все эти высокотехнологичные сети выполняют одну задачу: наилучшим образом кодируют естественные изображения, а их предварительно обученные весовые модели доступны онлайн на ImageNet.
Так почему бы не использовать одну из этих архитектур в качестве кодировщика и не создать декодер, который будет так же удобен в использовании, как и оригинальный U-Net, но лучше и агрессивнее.
TernausNet этоKaggleVagle CarvanaСетевая архитектура выигрышной схемы вызова использует ту же идею с VGG11 в качестве кодировщика. [15, 16]
TernausNet Владимира Игловикова и Алексея Швеца
Fast.ai: Динамический U-Net
Вдохновленный статьей TernausNet и многими другими превосходными источниками, я описываю идею как применение предварительно обученного или предустановленного кодировщика к архитектуре, подобной U-net. Итак, я придумал общую архитектуру:Динамический U-Net.
Dynamic U-Net является реализацией этой идеи, которая выполняет все вычисления и сопоставления для автоматического создания декодера для любого заданного кодировщика. Кодер может быть либо готовой предварительно обученной сетью, либо пользовательской сетевой архитектурой.
Он написан на PyTorch и в настоящее время находится вFast.aiв библиотеке. можно обратиться к этомуДокументацияувидеть практический пример или увидетьисходный код. Основная цель Dynamic U-Net — сэкономить время разработки и упростить эксперименты с различными кодировщиками с минимальным количеством кода.
Во второй части я объясню модели кодировщика-декодера для 3D-данных, таких как МРТ (магнитно-резонансная томография), и приведу примеры из реальной жизни, над которыми я работал.
использованная литература
[5] Faster R-CNN: Towards Real-Time Object Detection with Region Proposal Networks: АР Вест V.org/ABS/1506.01…
[6] Mask R-CNN: https://arxiv.org/abs/1703.06870
[7] Feature Pyramid Networks for Object Detection: https://arxiv.org/abs/1612.03144
[8] Fully Convolutional Networks for Semantic Segmentation: https://people.eecs.berkeley.edu/~jonlong/long_shelhamer_fcn.pdf
[9] U-net: Convolutional Networks for Biomedical Image Segmentation: https://arxiv.org/abs/1505.04597
[10] Tensorflow Mask-RCNN: https://github.com/matterport/Mask_RCNN
[11] Pytorch Mask-RCNN: https://github.com/multimodallearning/pytorch-mask-rcnn
[12] Convolution Arithmetic: https://github.com/vdumoulin/conv_arithmetic
[13] Data Science Bowl 2018 Winning Solution, ods-ai: https://www.kaggle.com/c/data-science-bowl-2018/discussion/54741
[14] Watershed Algorithm Ни один из 3/ из docs.OpenCV.org/3.3.1/…
[15] Carvana Image Masking Challenge: woohoo.carreform.com/from/фургон A-i…
[16] TernausNet: U-Net with VGG11 Encoder Pre-Trained on ImageNet for Image Segmentation: https://arxiv.org/abs/1801.05746
благодарныйPrince GroverиSerdar Ozsoy.
Если вы обнаружите ошибки в переводе или в других областях, требующих доработки, добро пожаловать наПрограмма перевода самородковВы также можете получить соответствующие бонусные баллы за доработку перевода и PR. начало статьиПостоянная ссылка на эту статьюЭто ссылка MarkDown этой статьи на GitHub.
Программа перевода самородковэто сообщество, которое переводит высококачественные технические статьи из Интернета сНаггетсДелитесь статьями на английском языке на . Охват контентаAndroid,iOS,внешний интерфейс,задняя часть,блокчейн,продукт,дизайн,искусственный интеллектЕсли вы хотите видеть более качественные переводы, пожалуйста, продолжайте обращать вниманиеПрограмма перевода самородков,официальный Вейбо,Знай колонку.