Генерация кода для семантического приложения сегментации на целевых устройствах ARM ® Neon, которые используют U-Net

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

Для аналогичного примера, который использует U-Net для сегментации изображений, но не использует codegen команда, см. Семантическая сегментация мультиспектральных изображений с использованием глубокого обучения (Image Processing Toolbox).

Необходимые условия

  • Процессор ARM, поддерживающий расширение NEON и имеющий ОЗУ не менее 3GB

  • ARM Compute Library (на целевом оборудовании ARM)

  • Переменные окружения для компиляторов и библиотек

  • MATLAB ® Coder™

  • Пакет поддержки MATLAB Coder Interface for Глубокое Обучение Libraries

  • Deep Learning Toolbox™

Версия библиотеки ARM Compute, которую использует этот пример, может быть не последней версией, которая поддержки генерацию кода. Для получения информации о поддерживаемых версиях библиотек и о переменных окружения, смотрите Необходимые условия для глубокого обучения с MATLAB Coder.

Этот пример не поддерживается в MATLAB Online.

Обзор U-Net

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

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

Этот пример использует Hamlin Beach State Park Data [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

The segmentationUnetARM Функция точки входа

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

type('segmentationUnetARM.m')
%  OUT = segmentationUnetARM(IM) returns a semantically segmented
%  image, which is segmented using the network multispectralUnet. This segmentation
%  is performed on the input image patchwise on patches of size 256,256.
%
% Copyright 2019-2020 The MathWorks, Inc.
function out = segmentationUnetARM(im)

%#codegen

persistent mynet;

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

% The input data has to be padded to the size compatible
% with the network Input Size. This input_data is padded inorder to
% perform semantic segmentation on each patch of size (Network Input Size)
[height, width, nChannel] = size(im);
patch = coder.nullcopy(zeros([256, 256, nChannel-1]));
% 
padSize = zeros(1,2);
padSize(1) = 256 - mod(height, 256);
padSize(2) = 256 - mod(width, 256);
% 
% Pad image must have have dimensions as multiples of network input dimensions
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:256:height_pad    
    for j =1:256:width_pad        
        for p = 1:nChannel -1             
            patch(:,:,p) = squeeze( im( i:i+255,...
                                            j:j+255,...
                                            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+255, j:j+255) = patch_seg;
       
    end
end

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

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

Загрузите multispectralUnet.mat файл и загрузка сетевого объекта U-Net DAG.

if ~exist('trainedUnet/multispectralUnet.mat','file')
    trainedUnet_url = 'https://www.mathworks.com/supportfiles/vision/data/multispectralUnet.mat';
    downloadUNet(trainedUnet_url,pwd);
end
ld = load("trainedUnet/multispectralUnet.mat");
net = ld.net;

Сеть DAG содержит 58 слоев, которые включают свертку, максимальное объединение, конкатенацию глубин и выходные слои классификации пикселей. Чтобы отобразить интерактивную визуализацию архитектуры нейронной сети для глубокого обучения, используйте analyzeNetwork (Deep Learning Toolbox) функция.

analyzeNetwork(net);

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

Загрузите данные о государственном парке Хамлин-Бич.

if ~exist(fullfile(pwd,'data'),'dir')
    url = 'http://www.cis.rit.edu/~rmk6217/rit18_data.mat';
    downloadHamlinBeachMSIData(url,pwd+"/data/");
end

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

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

Исследуйте данные

whos test_data

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

Мультиспектральные данные изображения расположены как массивы numChannels-by-width-by-height. В MATLAB многоканальные изображения расположены как массивы width-by-height-by-numChannels. Чтобы изменить форму данных так, чтобы каналы находились в третьей размерности, используйте функцию helper, switchChannelsToThirdPlane.

test_data = switchChannelsToThirdPlane(test_data);

Подтвердите, что данные имеют правильную структуру (последние каналы).

whos test_data

Этот пример использует обрезанную версию полного набора данных Hamlin Beach State Park, который test_data переменная содержит. Обрезка высоты и ширины test_data чтобы создать переменную input_data который использует этот пример.

test_datacropRGB = imcrop(test_data(:,:,1:3),[2600, 3000, 2000, 2000]);
test_datacropInfrared = imcrop(test_data(:,:,4:6),[2600, 3000, 2000, 2000]);
test_datacropMask = imcrop(test_data(:,:,7),[2600, 3000, 2000, 2000]);
input_data(:,:,1:3) = test_datacropRGB;
input_data(:,:,4:6) = test_datacropInfrared;
input_data(:,:,7) = test_datacropMask;

Исследуйте input_data переменная.

whos('input_data');

Запишите входные данные в текстовый файл, который передается как вход в сгенерированный исполняемый файл.

WriteInputDatatoTxt(input_data);
[height, width, channels] = size(input_data);

Настройка объекта строения генерации кода для статической библиотеки

Чтобы сгенерировать код, который нацелен на устройство на основе ARM, создайте объект строения для библиотеки. Не создавайте объект строения для исполняемой программы. Настройте объект строения только для генерации исходного кода C++.

cfg = coder.config('lib');
cfg.TargetLang = 'C++';
cfg.GenCodeOnly = true;

Настройте объект строения для генерации кода глубокого обучения

Создайте coder.ARMNEONConfig объект. Укажите версию библиотеки и архитектуру целевого процессора ARM. Например, предположим, что целевой платой является плата HiKey/Rock960 с ARMv8 архитектурой и ARM Compute Library версии 19.05.

dlcfg = coder.DeepLearningConfig('arm-compute');
dlcfg.ArmComputeVersion = '19.05';
dlcfg.ArmArchitecture = 'armv8';

Назначьте DeepLearningConfig свойство объекта строения генерации кода cfg к объекту строения глубокого обучения dlcfg.

cfg.DeepLearningConfig = dlcfg;

Сгенерируйте исходный код C++ при помощи codegen

codegen -config cfg segmentationUnetARM -args {ones(size(input_data),'uint16')} -d unet_predict -report

Код генерируется в unet_predict папка, расположенная в текущую рабочую директорию на хост-компьютер.

Сгенерируйте ZIP- Файла при помощи packNGo

The packNGo функция упакует все соответствующие файлы в сжатый zip-файл.

zipFileName = 'unet_predict.zip'; 
bInfo = load(fullfile('unet_predict','buildInfo.mat'));
packNGo(bInfo.buildInfo, {'fileName', zipFileName,'minimalHeaders', false, 'ignoreFileMissing',true});

Имя сгенерированного zip- файла unet_predict.zip.

Скопируйте сгенерированные ZIP- файла в Целевой компьютер

Скопируйте zip- файла в целевой компьютер плату. Извлеките содержимое zip- файла в папку и удалите zip- файла из оборудования.

В следующих командах замените:

  • password с вашим паролем

  • username с вашим именем пользователя

  • targetname с именем вашего устройства

  • targetDir с целевой папкой для файлов

На платформе Linux ® для передачи и извлечения zip-файла на целевом компьютере выполните следующие команды:

if isunix, system(['sshpass -p password scp -r '  fullfile(pwd,zipFileName) ' username@targetname:targetDir/']), end
if isunix, system('sshpass -p password ssh username@targetname "if [ -d targetDir/unet_predict ]; then rm -rf targetDir/unet_predict; fi"'), end
if isunix, system(['sshpass -p password ssh username@targetname "unzip targetDir/' zipFileName ' -d targetDir/unet_predict"']), end
if isunix, system(['sshpass -p password ssh username@targetname "rm -rf  targetDir/' zipFileName '"']), end

На платформе Windows ® для передачи и извлечения zip-файла на целевом компьютере выполните следующие команды:

if ispc, system(['pscp.exe -pw password -r '  fullfile(pwd,zipFileName) ' username@targetname:targetDir/']), end
if ispc, system('plink.exe -l username -pw password targetname "if [ -d targetDir/unet_predict ]; then rm -rf targetDir/unet_predict; fi"'), end
if ispc, system(['plink.exe -l username -pw password targetname "unzip targetDir/' zipFileName ' -d targetDir/unet_predict"']), end
if ispc, system(['plink.exe -l username -pw password targetname "rm -rf  targetDir/' zipFileName '"']), end

Копирование вспомогательных файлов на целевой компьютер

Скопируйте эти файлы из хоста-компьютера в целевой компьютер:

  • Входные данные, input_data.txt

  • Make-файл для создания библиотеки, unet_predict_rtw.mk

  • Make-файл для создания исполняемой программы, makefile_unet_arm_generic.mk

В следующих командах замените:

  • password с вашим паролем

  • username с вашим именем пользователя

  • targetname с именем вашего устройства

  • targetDir с целевой папкой для файлов

На платформе Linux ® для передачи поддерживающих файлов на целевой компьютер выполните следующие команды:

if isunix, system('sshpass -p password scp unet_predict_rtw.mk username@targetname:targetDir/unet_predict/'), end
if isunix, system('sshpass -p password scp input_data.txt username@targetname:targetDir/unet_predict/'), end
if isunix, system('sshpass -p password scp makefile_unet_arm_generic.mk username@targetname:targetDir/unet_predict/'), end

На платформе Windows ® для передачи поддерживающих файлов на целевой компьютер выполните следующие команды:

if ispc, system('pscp.exe -pw password unet_predict_rtw.mk username@targetname:targetDir/unet_predict/'), end
if ispc, system('pscp.exe -pw password input_data.txt username@targetname:targetDir/unet_predict/'), end
if ispc, system('pscp.exe -pw password makefile_unet_arm_generic.mk username@targetname:targetDir/unet_predict/'), end

Создайте библиотеку на целевом компьютере

Чтобы создать библиотеку на целевом компьютере, выполните сгенерированный make-файл на оборудовании ARM.

Убедитесь, что вы задаете переменные окружения ARM_COMPUTELIB и LD_LIBRARY_PATH на целевом компьютере. Смотрите Необходимые условия для глубокого обучения с MATLAB Coder. The ARM_ARCH переменная используется в Make-файле для передачи флагов компилятора на основе архитектуры ARM. The ARM_VER переменная используется в Make-файле для компиляции кода на основе версии библиотеки ARM Compute.

На серверной платформе Linux запустите эту команду, чтобы создать библиотеку:

if isunix, system(['sshpass -p password ssh username@targetname "make -C targetDir/unet_predict/ -f unet_predict_rtw.mk ARM_ARCH=' dlcfg.ArmArchitecture ' ARM_VER=' dlcfg.ArmComputeVersion ' "']), end

На хост-платформе Windows выполните эту команду, чтобы создать библиотеку:

if ispc, system(['plink.exe -l username -pw password targetname "make -C targetDir/unet_predict/ -f unet_predict_rtw.mk ARM_ARCH=' dlcfg.ArmArchitecture ' ARM_VER=' dlcfg.ArmComputeVersion ' "']), end

Создание исполняемого файла на целевом компьютере

В этих командах замените targetDir с конечной папкой, в которой создается библиотека. Переменные height, width, и channels представляют размерности входных данных.

main_unet_arm_generic.cpp - основной файл оболочки C++, который вызывает функцию segmentationUnetARM и передает ему вход изображение. Создайте библиотеку с файлом оболочки, чтобы создать исполняемый файл.

На серверной платформе Linux, чтобы создать исполняемый файл, запустите следующие команды:

if isunix, system('sshpass -p password scp main_unet_arm_generic.cpp username@targetname:targetDir/unet_predict/'), end
if isunix, system(['sshpass -p password ssh username@targetname "make -C targetDir/unet_predict/ IM_H=' num2str(height) ' IM_W=' num2str(width) ' IM_C=' num2str(channels) ' -f makefile_unet_arm_generic.mk"']), end

На серверной платформе Windows, чтобы создать исполняемый файл, запустите следующие команды:

if ispc, system('pscp.exe -pw password main_unet_arm_generic.cpp username@targetname:targetDir/unet_predict/'), end
if ispc, system(['plink.exe -l username -pw password targetname "make -C targetDir/unet_predict/ IM_H=' num2str(height) ' IM_W=' num2str(width) ' IM_C=' num2str(channels) ' -f makefile_unet_arm_generic.mk"']), end

Запуск исполняемого файла на целевом компьютере

Запустите исполняемый файл на целевом компьютере с входным файлом изображения input_data.txt.

На серверной платформе Linux выполните следующую команду:

if isunix, system('sshpass -p password ssh username@targetname "cd targetDir/unet_predict/; ./unet input_data.txt output_data.txt"'), end

На хост-платформе Windows выполните следующую команду:

if ispc, system('plink.exe -l username -pw password targetname "cd targetDir/unet_predict/; ./unet input_data.txt output_data.txt"'), end

The unet executable принимает входные данные. Из-за большого размера input_data (2001x2001x7), легче обработать входное изображение в закрашенных фигурах. Исполняемый файл разделяет вход изображение на несколько закрашенные фигуры, каждый из которых соответствует размеру входа сети. Исполняемый файл выполняет предсказание пикселей в одной конкретной закрашенной фигуре за раз, а затем объединяет все закрашенные фигуры вместе.

Перенесите выход из целевого компьютера в MATLAB

Скопируйте сгенерированный выходной файл output_data.txt вернемся к текущему сеансу работы с MATLAB. На платформе Linux запустите:

if isunix, system('sshpass -p password scp username@targetname:targetDir/unet_predict/output_data.txt ./'), end

Чтобы выполнить то же действие на платформе Windows, запустите:

if ispc, system('pscp.exe -pw password username@targetname:targetDir/unet_predict/output_data.txt ./'), end

Сохраните выходные данные в переменной segmentedImage:

segmentedImage = uint8(importdata('output_data.txt'));
segmentedImage = reshape(segmentedImage,[height,width]);

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

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

Удалите шум и бродячие пиксели с помощью medfilt2 функция.

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

Отображение сегментированных данных U-Net

Эта строка кода создает вектор имен классов. classNames = net. Слои (конец) .Classes; disp (classNames);

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

Отобразите входные данные

figure(1);
imshow(histeq(input_data(:,:,1:3)));
title('Input Image');

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

Отображение сегментированных данных

title('Segmented Image using Codegen on ARM');
N = numel(classNames);
ticks = 1/(N*2):1/N:1;
colorbar('TickLabels',cellstr(classNames),'Ticks',ticks,'TickLength',0,'TickLabelInterpreter','none');
colormap(cmap)

Отображение сегментированного изображения наложения

segmentedImageOverlay = labeloverlay(imadjust(input_data(:,:,4:6),[0 0.6],[0.1 0.9],0.55),segmentedImage,'Transparency',0.7,'Colormap',cmap);
figure(3);
imshow(segmentedImageOverlay);
title('Segmented Overlayed Image');

Ссылки

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

[2] Kemker, R., C. Salvaggio, and C. Kanan. «Мультиспектральный набор данных высокого разрешения для семантической сегментации». CoRR, abs/1703.01918, 2017.

[3] Используемые справочные входные данные являются частью данных парка штата Хэмлин-Бич. Следующие шаги могут использоваться для загрузки данных для дальнейшей оценки.

if ~exist(fullfile(pwd,'data'))
    url = 'http://www.cis.rit.edu/~rmk6217/rit18_data.mat';
    downloadHamlinBeachMSIData(url,pwd+"/data/");
end

См. также

| | |

Похожие темы