Необходимые очки знаний для сегментации изображения | Unet подробная теория + код

искусственный интеллект

Статья перенесена из публичного аккаунта WeChat [Machine Learning Alchemy]. Перепечатка статьи или сообщение для связи с автором WeChat: cyx645016617

Unet на самом деле довольно прост, поэтому сегодняшняя статья не будет очень длинной.

0 Обзор

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

На приведенном выше рисунке показаны результаты сегментации задачи мобильной сегментации в автономном вождении, которая может эффективно идентифицировать автомобили (темно-синий), пешеходов (красный), светофоры (желтый), дороги (светло-фиолетовый) и т. д.

Можно сказать, что Унетсамый обычный, самый простой— это простая, эффективная, понятная, простая в построении модель сегментации, которую можно обучить на небольших наборах данных.

Unet — это уже очень старая модель сегментации, модель, предложенная в «U-Net: сверточные сети для сегментации биомедицинских изображений» в 2015 году.

Ссылка на бумагу:АР Вест V.org/ABS/1505.04…

До Unet это была старая сеть FCN, FCN была обрывком Fully Convolutional Netowkrs, но этоВ основном это фреймворк и текущая сеть сегментации, кто посмеет сказать, что сверточный слой не используется.Однако точность сети FCN ниже, и ее не так просто использовать, как Unet. Сейчас есть Segnet, Mask RCNN, DeepLabv3+ и другие сети, но сегодня я сначала представлю Unet, ведь от одного укуса не потолстеешь.

1 Unet

Unet на самом деле довольно прост, поэтому сегодняшняя статья не будет очень длинной.

1.1 Выдвинуть первоначальное намерение (не важно)

  1. Первоначальной целью Unet было решить проблему сегментации медицинских изображений;
  2. U-образная сетевая структура для получения контекстной информации и информации о местоположении;
  3. В 2015 году неоднократно выигрывал первые места в соревнованиях по отслеживанию ячеек ISBI.Изначально это должно было решить задачу сегментации на клеточном уровне.

1.2 Структура сети

Эта структура состоит в том, чтобы сначала свернуть и объединить изображение.В документе Unet оно объединяется 4 раза.Например, изображение в начале имеет размер 224x224, затем оно станет 112x112, 56x56, 28x28, 14x14 с четырьмя различными размерами.Затем мы увеличиваем или деконволюцируем карту признаков 14 x 14, чтобы получить карту признаков 28 x 28. Эта карта признаков 28 x 28 и предыдущая карта признаков 28 x 28 объединяются с повреждением канала, а затем скручивается карта объединенных признаков. Продукт и повышающая дискретизация для получения 56 x 56 карта признаков, которая затем объединяется с предыдущей функцией 56x56, свертывается, а затем подвергается повышающей дискретизации.После четырех апсемплингов можно получить результат прогнозирования 224x224 с тем же размером, что и входное изображение.

По сути, в целом это тоже структура Encoder-Decoder:Сеть Unet очень проста: первая половина — это извлечение признаков, а вторая половина — повышение частоты дискретизации. В некоторых источниках эта структура называетсяАрхитектура кодировщик-декодер, потому что общая структура сети представляет собой большую английскую букву U, поэтому она называется U-net.

  • Кодер: левая половина состоит из двух сверточных слоев 3x3 (RELU) плюс слой максимального пула 2x2 для формирования модуля понижающей дискретизации (как можно увидеть в коде позже);
  • Декодер: есть половинные части, которые состоят из слоя свертки с повышающей дискретизацией (слоя деконволюции) + сшивки признаков concat + двух слоев свертки 3x3 (ReLU) многократно (как видно в коде);

В то время, по сравнению с ранее предложенной сетью FCN, Unet использовалсоединениекак метод слияния карт признаков.

  • FCN объединяет функции, добавляя соответствующие значения пикселей карты функций;
  • U-net может формировать более толстые элементы, объединяя количество каналов, конечно, это будет потреблять больше памяти;

Преимущества Unet, на мой взгляд, таковы: карта объектов, полученная за счет более глубокого сетевого слоя, имеет большее поле зрения, неглубокая свертка фокусируется на текстурных функциях, а глубокая сеть фокусируется на основных функциях, поэтому глубокие и мелкие функции все с сеткой Значимое; другой момент заключается в том, что край карты признаков большего размера, полученной с помощью деконволюции, является недостатком информации.В конце концов, каждый признак субдискретизации и уточнения неизбежно потеряет некоторые краевые признаки, и потерянные признаки не будут восстановлены. от повышающей дискретизации, поэтому поиск краевых функций достигается за счет объединения функций.

2 Почему Unet хорошо справляется с сегментацией медицинских изображений

Это открытый вопрос, если у вас есть какие-либо мнения, пожалуйста, ответьте на обсуждение.

Большинство задач семантической сегментации медицинских изображений сначала используют Unet в качестве основы. Конечно, преимущества Unet, описанные в предыдущей главе, определенно могут быть использованы в качестве ответа на этот вопрос. Давайте поговорим об этом здесь.Особенности медицинской визуализации

Согласно обсуждению пользователей сети, полученные результаты:

  1. Семантика медицинских изображений относительно проста, а структура фиксирована. Следовательно, семантическая информация относительно проста по сравнению с автоматическим вождением, поэтому нет необходимости отфильтровывать бесполезную информацию.Все признаки медицинских изображений важны, поэтому важны низкоуровневые признаки и высокоуровневые семантические признаки, поэтому лучше использовать структуру соединения с пропуском (сращивание признаков) U-образной структуры.

  2. Медицинские изображения содержат меньше данных и их трудно получить.Объем данных может составлять всего несколько сотен или даже меньше 100. Поэтому, если используется большая сеть, такая как DeepLabv3+, ее легко переобучить. Преимущество больших сетей заключается в более сильных возможностях представления изображений, в то время как более простые и менее многочисленные медицинские изображения не содержат так много контента для выражения, поэтому некоторые люди обнаружили, чтоВ малом порядке раздельная модель SOTA и облегченный Unet не имеют преимущества перед богами и демонами.

  3. Медицинская визуализация имеет тенденцию быть мультимодальной. Например, в соревновании ISLES по инфаркту мозга чиновник предоставил данные CBF, MTT, CBV и других мультимодальных модальностей (можно этого не понимать). следовательноВ задачах медицинской визуализации часто необходимо разработать сеть для извлечения различных модальных функций, поэтому легкий и простой Unet может иметь большее рабочее пространство.

3 Код модели Pytorch

Это код, который я написал сам, поэтому он не очень краток, но его следует хорошо понять, и он точно такой же, как я объяснял ранее (вы можете связаться со мной, если у вас есть какие-либо вопросы: cyx645016617):

import torch
import torch.nn as nn
import torch.nn.functional as F

class double_conv2d_bn(nn.Module):
    def __init__(self,in_channels,out_channels,kernel_size=3,strides=1,padding=1):
        super(double_conv2d_bn,self).__init__()
        self.conv1 = nn.Conv2d(in_channels,out_channels,
                               kernel_size=kernel_size,
                              stride = strides,padding=padding,bias=True)
        self.conv2 = nn.Conv2d(out_channels,out_channels,
                              kernel_size = kernel_size,
                              stride = strides,padding=padding,bias=True)
        self.bn1 = nn.BatchNorm2d(out_channels)
        self.bn2 = nn.BatchNorm2d(out_channels)
    
    def forward(self,x):
        out = F.relu(self.bn1(self.conv1(x)))
        out = F.relu(self.bn2(self.conv2(out)))
        return out
    
class deconv2d_bn(nn.Module):
    def __init__(self,in_channels,out_channels,kernel_size=2,strides=2):
        super(deconv2d_bn,self).__init__()
        self.conv1 = nn.ConvTranspose2d(in_channels,out_channels,
                                        kernel_size = kernel_size,
                                       stride = strides,bias=True)
        self.bn1 = nn.BatchNorm2d(out_channels)
        
    def forward(self,x):
        out = F.relu(self.bn1(self.conv1(x)))
        return out
    
class Unet(nn.Module):
    def __init__(self):
        super(Unet,self).__init__()
        self.layer1_conv = double_conv2d_bn(1,8)
        self.layer2_conv = double_conv2d_bn(8,16)
        self.layer3_conv = double_conv2d_bn(16,32)
        self.layer4_conv = double_conv2d_bn(32,64)
        self.layer5_conv = double_conv2d_bn(64,128)
        self.layer6_conv = double_conv2d_bn(128,64)
        self.layer7_conv = double_conv2d_bn(64,32)
        self.layer8_conv = double_conv2d_bn(32,16)
        self.layer9_conv = double_conv2d_bn(16,8)
        self.layer10_conv = nn.Conv2d(8,1,kernel_size=3,
                                     stride=1,padding=1,bias=True)
        
        self.deconv1 = deconv2d_bn(128,64)
        self.deconv2 = deconv2d_bn(64,32)
        self.deconv3 = deconv2d_bn(32,16)
        self.deconv4 = deconv2d_bn(16,8)
        
        self.sigmoid = nn.Sigmoid()
        
    def forward(self,x):
        conv1 = self.layer1_conv(x)
        pool1 = F.max_pool2d(conv1,2)
        
        conv2 = self.layer2_conv(pool1)
        pool2 = F.max_pool2d(conv2,2)
        
        conv3 = self.layer3_conv(pool2)
        pool3 = F.max_pool2d(conv3,2)
        
        conv4 = self.layer4_conv(pool3)
        pool4 = F.max_pool2d(conv4,2)
        
        conv5 = self.layer5_conv(pool4)
        
        convt1 = self.deconv1(conv5)
        concat1 = torch.cat([convt1,conv4],dim=1)
        conv6 = self.layer6_conv(concat1)
        
        convt2 = self.deconv2(conv6)
        concat2 = torch.cat([convt2,conv3],dim=1)
        conv7 = self.layer7_conv(concat2)
        
        convt3 = self.deconv3(conv7)
        concat3 = torch.cat([convt3,conv2],dim=1)
        conv8 = self.layer8_conv(concat3)
        
        convt4 = self.deconv4(conv8)
        concat4 = torch.cat([convt4,conv1],dim=1)
        conv9 = self.layer9_conv(concat4)
        outp = self.layer10_conv(conv9)
        outp = self.sigmoid(outp)
        return outp
    

model = Unet()
inp = torch.rand(10,1,224,224)
outp = model(inp)
print(outp.shape)
==> torch.Size([10, 1, 224, 224])

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

Справочный блог:

  1. blog.CSDN.net/Ван Дунвэй…
  2. Ууху. Call.com/question/26…
  3. zhuanlan.zhihu.com/p/90418337