Генерация кода для Семантической Сети Сегментации, использующей U-net

Этот пример демонстрирует генерацию кода для приложения сегментации изображений, которое использует глубокое обучение. Это использует команду codegen, чтобы сгенерировать MEX-функцию, которая запускает прогноз на Сетевом объекте DAG для U-Net, популярной нейронной сети для глубокого обучения для сегментации изображений.

Для подобного примера, покрывающего сегментацию изображений с помощью U-Net без codegen, смотрите Семантическую Сегментацию Многоспектральных Изображений Используя Глубокое обучение.

Предпосылки

  • CUDA® включил NVIDIA®, графический процессор с вычисляет возможность 3.2 или выше.

  • NVIDIA инструментарий CUDA и драйвер.

  • Библиотека NVIDIA cuDNN (v7 и выше).

  • Deep Learning Toolbox™, чтобы использовать Сетевой объект DAG.

  • Image Processing Toolbox™ для чтения и отображения изображений.

  • Система Компьютерного зрения Toolbox™ для функции labeloverlay используется в этом примере.

  • Переменные окружения для компиляторов и библиотек. Для получения информации о поддерживаемых версиях компиляторов и библиотек, смотрите Сторонние продукты (GPU Coder). Для подготовки переменных окружения смотрите Подготовку Необходимых как условие продуктов (GPU Coder).

  • Интерфейс GPU Coder для Библиотек Глубокого обучения поддерживает пакет. Чтобы установить этот пакет поддержки, используйте Add-On Explorer.

Проверьте среду графического процессора

Используйте coder.checkGpuInstall, функционируют и проверяют, что компиляторы и библиотеки, необходимые для выполнения этого примера, настраиваются правильно.

coder.checkGpuInstall('gpu','codegen','cudnn','quiet');

О сети сегментации

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

Основанная на глубоком обучении семантическая сегментация может привести к точному измерению растительного покрова из воздушных фотографий с высоким разрешением. Одна проблема дифференцирует классы с подобными визуальными характеристиками, такими как попытка классифицировать зеленый пиксель как траву, кустарник или дерево. Чтобы увеличить точность классификации, некоторые наборы данных содержат многоспектральные изображения, которые предоставляют дополнительную информацию о каждом пикселе. Например, набор данных национального парка Hamlin Beach добавляет цветные изображения с почти инфракрасными каналами, которые обеспечивают более ясное разделение классов.

Эта демонстрация будет использовать Данные о национальном парке Hamlin Beach [2] наряду с предварительно обученной сетью U-Net по порядку, чтобы правильно классифицировать каждый пиксель.

Используемый U-Net обучен сегментировать пиксели, принадлежащие 18 классам, который включает:

0. Other Class/Image Border      7. Picnic Table         14. Grass
1. Road Markings                 8. Black Wood Panel     15. Sand
2. Tree                          9. White Wood Panel     16. Water (Lake)
3. Building                     10. Orange Landing Pad   17. Water (Pond)
4. Vehicle (Car, Truck, or Bus) 11. Water Buoy           18. Asphalt (Parking Lot/Walkway)
5. Person                       12. Rocks
6. Lifeguard Chair              13. Other Vegetation

О функции 'segmentImageUnet'

segmentImageUnet.m выполняет patchwise семантическую сегментацию на входном изображении с помощью multispectralUnet сети, найденной в файле multispectralUnet.mat. Функция загружает сетевой объект от multispectralUnet.mat в персистентную переменную mynet. На последующих вызовах функции постоянный объект снова используется для прогноза.

type('segmentImageUnet.m')
%  OUT = segmentImageUnet(IM, PATCHSIZE) returns a semantically segmented
%  image, segmented using the network multispectralUnet. The segmentation
%  is performed patches-wise on patches of size PATCHSIZE.
%
% Copyright 2018 The MathWorks, Inc.
function out = segmentImageUnet(im, patchSize)

%#codegen

coder.gpu.kernelfun;

persistent mynet;

if isempty(mynet)
    mynet = coder.loadDeepLearningNetwork('trainedUnet/multispectralUnet.mat');
end

[height, width, nChannel] = size(im);
patch = coder.nullcopy(zeros([patchSize, nChannel-1]));

% pad image to have dimensions as multiples of patchSize
padSize = zeros(1,2);
padSize(1) = patchSize(1) - mod(height, patchSize(1));
padSize(2) = patchSize(2) - mod(width, patchSize(2));

im_pad = padarray (im, padSize, 0, 'post');
[height_pad, width_pad, ~] = size(im_pad);

out = zeros([size(im_pad,1), size(im_pad,2)], 'uint8');

for i = 1:patchSize(1):height_pad    
    for j =1:patchSize(2):width_pad        
        for p = 1:nChannel-1              
            patch(:,:,p) = squeeze( im_pad( i:i+patchSize(1)-1,...
                                            j:j+patchSize(2)-1,...
                                            p));            
        end
         
        % pass in input
        segmentedLabels = activations(mynet, patch, 'Segmentation-Layer');
        
        % Takes the max of each channel (6 total at this point)
        [~,L] = max(segmentedLabels,[],3);
        patch_seg = uint8(L);
        
        % populate section of output
        out(i:i+patchSize(1)-1, j:j+patchSize(2)-1) = patch_seg;
       
    end
end

% Remove the padding
out = out(1:height, 1:width);

Получите предварительно обученный сетевой объект U-Net DAG

trainedUnet_url = 'https://www.mathworks.com/supportfiles/vision/data/multispectralUnet.mat';
downloadTrainedUnet(trainedUnet_url,pwd);
Downloading Pre-trained U-net for Hamlin Beach dataset...
This will take several minutes to download...
done.

ld = load("trainedUnet/multispectralUnet.mat");
net = ld.net;

Сеть DAG содержит 58 слоев включая свертку, макс. объединение, конкатенацию глубины и классификацию пикселей выходные слои. Используйте команду net.Layers, чтобы видеть слои сети.

Подготовка данных

Загрузите данные о национальном парке Hamlin Beach.

if ~exist(fullfile(pwd,'data'))
    url = 'http://www.cis.rit.edu/~rmk6217/rit18_data.mat';
    downloadHamlinBeachMSIData(url,pwd+"/data/");
end
Downloading Hamlin Beach dataset...
This will take several minutes to download...
done.

Загрузите и исследуйте данные в MATLAB.

load(fullfile(pwd,'data','rit18_data','rit18_data.mat'));

% Examine data
whos test_data
  Name           Size                         Bytes  Class     Attributes

  test_data      7x12446x7654            1333663576  uint16              

Обратите внимание на то, что изображение имеет 7 каналов. Цветовые каналы RGB являются 4-ми, 5-ми, и 6-ми каналами изображений. Первые три канала соответствуют почти инфракрасным полосам и подсвечивают различные компоненты изображения на основе их подписей тепла. Канал 7 является маской, которая указывает на допустимую область сегментации.

Многоспектральные данные изображения располагаются как numChannels шириной массивами высоты. Однако в MATLAB, многоканальные изображения располагаются как ширина высотой numChannels массивами. Чтобы изменить данные так, чтобы каналы были в третьей размерности, используйте функцию помощника, switchChannelsToThirdPlane.

test_data  = switchChannelsToThirdPlane(test_data);

% Confirm data has the correct structure (channels last).
whos test_data
  Name               Size                     Bytes  Class     Attributes

  test_data      12446x7654x7            1333663576  uint16              

Запустите генерацию кода MEX для функции 'segmentImageUnet'

Чтобы сгенерировать код CUDA от segmentImageUnet.m, создайте объект GPU Configuration для цели MEX, устанавливающей выходной язык на C++. Используйте функцию coder.DeepLearningConfig, чтобы создать объект настройки глубокого обучения cuDNN и присвоить ее свойству DeepLearningConfig объекта настройки графического процессора кода. Запустите команду codegen, задающую вход размера (test_data) = [12446,7654,7] и размера закрашенной фигуры [1024 1024]. Эти значения соответствуют целому test_data размеру, и меньшие размеры закрашенной фигуры будут использоваться, чтобы ускорить вывод. Смотрите файл segmentImageUnet.m, чтобы видеть, как закрашенные фигуры вычисляются.

cfg = coder.gpuConfig('mex');
cfg.TargetLang = 'C++';
cfg.DeepLearningConfig = coder.DeepLearningConfig('cudnn');
codegen -config cfg segmentImageUnet -args {ones(size(test_data),'uint16'),coder.Constant([1024 1024])} -report
Code generation successful: To view the report, open('codegen/mex/segmentImageUnet/html/report.mldatx').

Запустите Сгенерированный MEX, чтобы Предсказать Результаты для test_data

Эта функция segmentImageUnet берет в данных, которые мы хотим протестировать (test_data) и вектор, содержащий размерности размера закрашенной фигуры, который мы собираемся использовать. Идея здесь состоит в том, чтобы взять закрашенные фигуры изображения, предсказать пиксели в конкретной закрашенной фигуре, затем объединить все закрашенные фигуры вместе в конце. Это сделано из-за размера test_data (12446x7654x7). Легче обработать такое большое изображение в закрашенных фигурах.

segmentedImage = segmentImageUnet_mex(test_data,[1024 1024]);

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

segmentedImage = uint8(test_data(:,:,7)~=0) .* segmentedImage;

Поскольку вывод семантической сегментации является шумным, удалите шум и случайные пиксели при помощи функции medfilt2.

segmentedImage = medfilt2(segmentedImage,[5,5]);

Отображение U-Net Сегментированный test_data

Следующая строка кода создает вектор имен классов.

classNames = [ "RoadMarkings","Tree","Building","Vehicle","Person", ...
               "LifeguardChair","PicnicTable","BlackWoodPanel",...
               "WhiteWoodPanel","OrangeLandingPad","Buoy","Rocks",...
               "LowLevelVegetation","Grass_Lawn","Sand_Beach",...
               "Water_Lake","Water_Pond","Asphalt"];

Наложите метки на сегментированном тесте RGB, отображают и добавляют цветную полосу в изображение сегментации.

cmap = jet(numel(classNames));
B = labeloverlay(imadjust(test_data(:,:,4:6),[0 0.6],[0.1 0.9],0.55),segmentedImage,'Transparency',0.8,'Colormap',cmap);
figure
imshow(B)

N = numel(classNames);
ticks = 1/(N*2):1/N:1;
colorbar('TickLabels',cellstr(classNames),'Ticks',ticks,'TickLength',0,'TickLabelInterpreter','none');
colormap(cmap)
title('Segmented Image');
Warning: Image is too big to fit on screen; displaying at 6% 

Ссылки

[1] Ronneberger, Олаф, Филипп Фишер и Томас Брокс. "U-Net: Сверточные Сети для Биомедицинской Сегментации Изображений". arXiv предварительно распечатывают arXiv:1505.04597, 2015.

[2] Kemker, R., К. Сальвагхио и К. Кэнэн. "Многоспектральный Набор данных с высоким разрешением для Семантической Сегментации". CoRR, abs/1703.01918. 2017.