Генерация кода для сети сегментации облака точек лидар

В этом примере показано, как сгенерировать код CUDA ® MEX для нейронной сети для глубокого обучения для семантической сегментации лидара. Этот пример использует предварительно обученную сеть SqueezeSegV2 [1], которая может сегментировать организованные облака точек лидара, принадлежащие трем классам (фон, автомобиль и грузовик). Для получения информации о процедуре обучения для сети смотрите Lidar Point Cloud Semantic Segmentation Using SqueezeSegV2 Deep Learning Network. Сгенерированный код MEX принимает облако точек как вход и выполняет предсказание для облака точек при помощи DAGNetwork объект для SqueezeSegV2 сети.

Необходимые условия для третьих лиц

Необходимый

Этот пример генерирует CUDA MEX и имеет следующие требования к третьим лицам.

  • CUDA включает графический процессор NVIDIA ® и совместимый драйвер.

Дополнительный

Для сборок, не являющихся MEX, таких как статические, динамические библиотеки или исполняемые файлы, этот пример имеет следующие дополнительные требования.

Проверьте окружение GPU

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

envCfg = coder.gpuEnvConfig('host');
envCfg.DeepLibTarget = 'cudnn';
envCfg.DeepCodegen = 1;
envCfg.Quiet = 1;
coder.checkGpuInstall(envCfg);

Сеть сегментации

SqueezeSegV2 - сверточная нейронная сеть (CNN), предназначенная для семантической сегментации организованных лидаров облаков точек. Это глубокая сеть сегментации энкодера-декодера, обученная на лидаре данных и импортированная в MATLAB ® для вывода. В SqueezeSegV2 подсеть энкодера состоит из слоев свертки, которые перемежаются слоями max-pooling. Эта схема последовательно уменьшает разрешение входного изображения. Подсеть декодера состоит из ряда транспонированных слоев свертки, которые последовательно увеличивают разрешение входного изображения. В сложение SqueezeSegV2 сеть снижает влияние недостающих данных, включая модули агрегирования контекста (CAM). КУЛАК - сверточная подсеть с filterSize значения [7, 7], что совокупности контекстная информация от более крупной восприимчивой области, которая улучшает робастность сети к недостающим данным. Сеть SqueezeSegV2 в этом примере обучена сегментным точкам, относящимся к трем классам (фон, автомобиль и грузовик).

Для получения дополнительной информации о обучении сети семантической сегментации в MATLAB ® с помощью набора данных Mathworks lidar, смотрите Lidar Point Cloud Semantic Segmentation Using PointSeg Deep Learning Network.

Загрузите предварительно обученную сеть SqueezeSegV2.

net = getSqueezeSegV2Net();
Downloading pretrained SqueezeSegV2 (2 MB)...

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

analyzeNetwork(net);

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

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

type('squeezesegv2_predict.m');
function out = squeezesegv2_predict(in)
%#codegen

% A persistent object mynet is used to load the DAG network object. At
% the first call to this function, the persistent object is constructed and
% setup. When the function is called subsequent times, the same object is
% reused to call predict on inputs, thus avoiding reconstructing and
% reloading the network object.

% Copyright 2020 The MathWorks, Inc.

persistent mynet;

if isempty(mynet)
    mynet = coder.loadDeepLearningNetwork('SqueezeSegV2Net.mat');
end

% pass in input
out = predict(mynet,in);

Сгенерируйте код MEX CUDA

Чтобы сгенерировать код MEX CUDA для squeezesegv2_predict.m функция точки входа, создайте объект строения кода GPU для цели MEX и установите целевой язык на C++. Используйте coder.DeepLearningConfig (GPU Coder) функция для создания CuDNN объект строения глубокого обучения и присвоение его DeepLearningConfig свойство объекта строения кода GPU. Запуск codegen команда, задающая вход [64, 1024, 5]. Это значение соответствует размеру входного слоя SqueezeSegV2 сети.

cfg = coder.gpuConfig('mex');
cfg.TargetLang = 'C++';
cfg.DeepLearningConfig = coder.DeepLearningConfig('cudnn');
codegen -config cfg squeezesegv2_predict -args {ones(64,1024,5,'uint8')} -report
Code generation successful: View report

Чтобы сгенерировать код CUDA C++, который использует преимущества библиотек NVIDIA TensorRT, в коде, задайте coder.DeepLearningConfig('tensorrt') вместо coder.DeepLearningConfig('cudnn').

Для получения информации о генерации кода MEX для сетей глубокого обучения на процессорах Intel ® смотрите Code Generation for Нейронные Сети для Глубокого Обучения with MKL-DNN (MATLAB Coder).

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

Загрузите организованное облако тестовых точек в MATLAB ®. Преобразуйте облако точек в пятиканальное изображение для предсказания .

ptCloud = pcread('ousterLidarDrivingData.pcd');
I = pointCloudToImage(ptCloud);

% Examine converted data
whos I
  Name       Size                 Bytes  Class    Attributes

  I         64x1024x5            327680  uint8              

Изображение имеет пять каналов. Координаты точки (x, y, z) состоят из первых трех каналов. Четвертый канал содержит измерение интенсивности лидара. Пятый канал содержит информацию о области значений, которая вычисляется какr=x2+y2+z2.

Визуализация канала интенсивности изображения.

intensityChannel = I(:,:,4);    

figure;
imshow(intensityChannel);
title('Intensity Image');

Запуск сгенерированного MEX на данных

Функции squeezesegv2_predict_mex на пятиканальном изображении.

predict_scores = squeezesegv2_predict_mex(I);

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

[~,argmax] = max(predict_scores,[],3);

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

classes = [
    "background"
    "car"
    "truck"
    ];

cmap = lidarColorMap();
SegmentedImage = labeloverlay(intensityChannel,argmax,'ColorMap',cmap);
SegmentedImage = imresize(SegmentedImage, 'Scale', [2 1], 'method', 'nearest');
figure;
imshow(SegmentedImage);

N = numel(classes);
ticks = 1/(N*2):1/N:1;
colorbar('TickLabels',cellstr(classes),'Ticks',ticks,'TickLength',0,'TickLabelInterpreter','none');
colormap(cmap)
title('Semantic Segmentation Result');

Запуск сгенерированного кода MEX в последовательности облаков точек

Считайте последовательность облака входных точек. Последовательность содержит 10 организованных pointCloud системы координат, собранные с помощью датчика Ouster OS1 lidar. Входные данные имеют высоту 64 и ширину 1024, поэтому каждый объект pointCloud имеет размер 64 на 1024.

dataFile = 'highwaySceneData.mat';

% Load data in workspace.
load(dataFile);

Настройте различные цвета, чтобы визуализировать точечные метки для разных интересующих классов.

% Apply the color red to cars.
carClassCar = zeros(64, 1024, 3, 'uint8');
carClassCar(:,:,1) = 255*ones(64, 1024, 'uint8');

% Apply the color blue to trucks.
truckClassColor = zeros(64, 1024, 3, 'uint8');
truckClassColor(:,:,3) = 255*ones(64, 1024, 'uint8');

% Apply the color gray to background.
backgroundClassColor = 153*ones(64, 1024, 3, 'uint8');

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

xlimits = [0 120.0];
ylimits = [-80.7 80.7];
zlimits = [-8.4 27];

player = pcplayer(xlimits, ylimits, zlimits);
set(get(player.Axes,'parent'), 'units','normalized','outerposition',[0 0 1 1]);
zoom(get(player.Axes,'parent'),2);
set(player.Axes,'XColor','none','YColor','none','ZColor','none');

for i = 1 : numel(inputData)
    ptCloud = inputData{i};
    
    % Convert point cloud to five-channel image for prediction.
    I = pointCloudToImage(ptCloud);
    
    % Call squeezesegv2_predict_mex on the 5-channel image.
    predict_scores = squeezesegv2_predict_mex(I);
    
    % Convert the numeric output values to categorical labels.
    [~,predictedOutput] = max(predict_scores,[],3);
    predictedOutput = categorical(predictedOutput, 1:3, classes);
    
    % Extract the indices from labels.
    carIndices = predictedOutput == 'car';
    truckIndices = predictedOutput == 'truck';
    backgroundIndices = predictedOutput == 'background';
    
    % Extract a point cloud for each class.
    carPointCloud = select(ptCloud, carIndices, 'OutputSize','full');
    truckPointCloud = select(ptCloud, truckIndices, 'OutputSize','full');
    backgroundPointCloud = select(ptCloud, backgroundIndices, 'OutputSize','full');
    
    % Fill the colors to different classes.
    carPointCloud.Color = carClassCar;
    truckPointCloud.Color = truckClassColor;
    backgroundPointCloud.Color = backgroundClassColor;
    
    % Merge and add all the processed point clouds with class information.
    coloredCloud = pcmerge(carPointCloud, truckPointCloud, 0.01);
    coloredCloud = pcmerge(coloredCloud, backgroundPointCloud, 0.01);
    
    % View the output.
    view(player, coloredCloud);
    drawnow;
end

Вспомогательные функции

Ниже приведены вспомогательные функции, используемые в этом примере.

type pointCloudToImage.m
function image = pointCloudToImage(ptcloud)
%pointCloudToImage Converts organized 3-D point cloud to 5-channel 
%   2-D image.

image = ptcloud.Location;
image(:,:,4) = ptcloud.Intensity;
rangeData = iComputeRangeData(image(:,:,1),image(:,:,2),image(:,:,3));
image(:,:,5) = rangeData;

% Cast to uint8.
image = uint8(image);
end

%--------------------------------------------------------------------------
function rangeData = iComputeRangeData(xChannel,yChannel,zChannel)
rangeData = sqrt(xChannel.*xChannel+yChannel.*yChannel+zChannel.*zChannel);
end
type lidarColorMap.m
function cmap = lidarColorMap()

cmap = [
   0.00  0.00   0.00  % background
   0.98  0.00   0.00  % car
   0.00  0.00   0.98  % truck
   ];
end

Ссылки

[1] У, Бичэнь, Сюаньюй Чжоу, Сычэн Чжао, Сянъюй Юэ и Курт Кейцер. «SqueezeSegV2: улучшенная структура модели и неконтролируемая адаптация области для сегментации дорог и объектов из облака точек лИДАР». Препринт, представленный 22 сентября 2018 года. http://arxiv.org/abs/1809.08495.