Генерация кода для обнаружения объектов лидара Используя глубокое обучение PointPillars

В этом примере показано, как сгенерировать CUDA® MEX для детектора объектов PointPillars с пользовательскими слоями. Для получения дополнительной информации смотрите Лидар 3-D Обнаружение объектов Используя пример Глубокого обучения PointPillars от Lidar Toolbox™.

Сторонние необходимые условия

Необходимый

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

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

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

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

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

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

Предварительно обученная сеть PointPillars

Загрузите предварительно обученный детектор PointPillars, обученный в Лидаре 3-D Обнаружение объектов Используя пример Глубокого обучения PointPillars. Чтобы обучить сеть самостоятельно, смотрите Лидар 3-D Обнаружение объектов Используя Глубокое обучение PointPillars.

pretrainedDetector = load('pretrainedPointPillarsDetector.mat','detector');
detector = pretrainedDetector.detector;

Извлеките предварительно обученную сеть.

net = detector.Network;

Поля точек функциональность слоя реализована с помощью functionLayer. Но, functionLayer не поддерживает генерацию кода. Используйте helperReplaceFunctionLayer функция помощника, чтобы заменить functionLayer в сети с helperScatterLayer пользовательский слой, который сделал, чтобы генерация кода поддержала и сохранила сеть как pointPillarsCodegenNet.mat файл.

[net, matFile] = helperReplaceFunctionLayer(net);

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

pointpillarsDetect функция точки входа берет функции столба и индексы столба, как введено и передает их обучившему сеть для предсказания через pointpillarPredict функция. pointpillarsDetect функционируйте загружает сетевой объект из файла MAT в персистентную переменную и снова использует постоянный объект для последующих вызовов предсказания. А именно, функция использует dlnetwork представление сети, обученной в Лидаре 3-D Обнаружение объектов Используя Глубокое обучение PointPillars.

type('pointpillarsDetect.m')
function [bboxes,scores,labels] = pointpillarsDetect(matFile, pillarFeatures, pillarIndices, gridParams, numOutputs, confidenceThreshold, overlapThreshold, classNames)
% The pointpillarsDetect function detects the bounding boxes, scores, and
% labels in the point cloud.

coder.extrinsic('helpergeneratePointPillarDetections');

% Define Anchor Boxes
anchorBoxes = {{1.92, 4.5, 1.69, -1.78, 0}, {1.92, 4.5, 1.69, -1.78, pi/2}, {2.1575, 6.0081, 2.3811, -1.78, 0}, {2.1575, 6.0081, 2.3811, -1.78, pi/2}};

% Predict the output
predictions = pointpillarPredict(matFile,pillarFeatures,pillarIndices,numOutputs);

% Generate Detections
[bboxes,scores,labels] = helpergeneratePointPillarDetections(predictions,gridParams,pillarIndices,...
                         anchorBoxes,confidenceThreshold,overlapThreshold,classNames);

end

function YPredCell = pointpillarPredict(matFile,pillarFeatures,pillarIndices,numOutputs)
% Predict the output of network and extract the following confidence,
% x, y, z, l, w, h, yaw and class.

% load the deep learning network for prediction
persistent net;

if isempty(net)
    net = coder.loadDeepLearningNetwork(matFile);
end

YPredCell = cell(1,numOutputs);
[YPredCell{:}] = predict(net,pillarIndices,pillarFeatures);
end

Выполните функцию точки входа для обнаружения объектов

Выполните функцию точки входа на облаке точек.

  • Задайте параметры сетки и параметры экстракции столба.

  • Считайте облако точек и генерируйте признаки столба и индексы с помощью createPillars функция помощника, присоединенная к этому примеру как вспомогательный файл.

  • Задайте порог доверия как 0,7, чтобы сохранить только обнаружения с оценками достоверности больше, чем это значение.

  • Задайте порог перекрытия как 0,1, чтобы удалить перекрывающиеся обнаружения.

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

  • Отобразите облако точек с ограничительными рамками.

Задайте параметры сетки.

xMin = detector.PointCloudRange(1,1);   % Minimum value along X-axis.
xMax = detector.PointCloudRange(1,2);   % Maximum value along X-axis.
yMin = detector.PointCloudRange(1,3);   % Minimum value along Y-axis.
yMax = detector.PointCloudRange(1,4);   % Maximum value along Y-axis.
zMin = detector.PointCloudRange(1,5);   % Minimum value along Z-axis.
zMax = detector.PointCloudRange(1,6);   % Maximum value along Z-axis.
xStep = detector.VoxelSize(1,1);   % Resolution along X-axis.
yStep = detector.VoxelSize(1,2);   % Resolution along Y-axis.
dsFactor = 2.0; % DownSampling factor.

Вычислите размерности для псевдоизображения.

Xn = round(((xMax - xMin) / xStep));
Yn = round(((yMax - yMin) / yStep));
gridParams = {{xMin,yMin,zMin},{xMax,yMax,zMax},{xStep,yStep,dsFactor},{Xn,Yn}};

Задайте параметры экстракции столба.

P = detector.NumPillars;   % Define number of prominent pillars.
N = detector.NumPointsPerPillar;   % Define number of points per pillar.

Вычислите количество сетевых выходных параметров.

networkOutputs = numel(net.OutputNames);

Считайте облако точек из набора данных Pandaset [2] и преобразуйте его в формат M-4.

pc = pcread('pandasetDrivingData.pcd');
ptCloud = cat(2,pc.Location,pc.Intensity);

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

processedPtCloud = createPillars({ptCloud,'',''}, gridParams,P,N);

Извлеките функции столба и индексы столба.

pillarFeatures = dlarray(single(processedPtCloud{1,1}),'SSCB');
pillarIndices = dlarray(single(processedPtCloud{1,2}),'SSCB');

Задайте имена классов.

classNames = cellstr(detector.ClassNames);

Задайте желаемые пороги.

confidenceThreshold = 0.7;
overlapThreshold = 0.1;

Используйте обнаружить метод в сети PointPillars и отобразите результаты.

[bboxes,~,labels] = pointpillarsDetect(matFile, pillarFeatures, pillarIndices,...
    gridParams, networkOutputs, confidenceThreshold, overlapThreshold, classNames);
bboxesCar = bboxes(labels == 'Car',:);
bboxesTruck = bboxes(labels == 'Truck',:);

Отобразите обнаружения на облаке точек.

helperDisplay3DBoxesOverlaidPointCloud(pc.Location, bboxesCar, 'green',...
    bboxesTruck, 'magenta', 'Predicted bounding boxes');

Сгенерируйте CUDA MEXscatter

Сгенерировать код CUDA® для pointpillarsDetect функция точки входа, создайте объект настройки графического процессора кода для цели MEX и установите выходной язык на C++. Используйте coder.DeepLearningConfig (GPU Coder) функция, чтобы создать cuDNN настройку глубокого обучения возражает и присвоить ее DeepLearningConfig свойство объекта настройки графического процессора кода.

cfg = coder.gpuConfig('mex');
cfg.TargetLang = 'C++';
cfg.DeepLearningConfig = coder.DeepLearningConfig(TargetLibrary='cudnn');

args = {coder.Constant(matFile), pillarFeatures, pillarIndices, gridParams,...
    coder.Constant(networkOutputs), confidenceThreshold, overlapThreshold, classNames};

codegen -config cfg pointpillarsDetect -args args -report
Code generation successful: View report

Запустите сгенерированный MEX

Вызовите сгенерированный MEX CUDA с теми же функциями столба и индексами как прежде. Отобразите результаты.

[bboxes, ~, labels] = pointpillarsDetect_mex(matFile, pillarFeatures, ...
    pillarIndices, gridParams, networkOutputs, confidenceThreshold,...
    overlapThreshold, classNames);
bboxesCar = bboxes(labels == 'Car',:);
bboxesTruck = bboxes(labels == 'Truck',:);

helperDisplay3DBoxesOverlaidPointCloud(pc.Location, bboxesCar, 'green',...
    bboxesTruck, 'magenta', 'Predicted bounding boxes');

Функции помощника

function helperDisplay3DBoxesOverlaidPointCloud(ptCld, labelsCar, carColor,...
    labelsTruck, truckColor, titleForFigure)
% Display the point cloud with different colored bounding boxes for different
% classes
    figure;
    ax = pcshow(ptCld);
    showShape('cuboid', labelsCar, 'Parent', ax, 'Opacity', 0.1, 'Color',...
        carColor, 'LineWidth', 0.5);
    hold on;
    showShape('cuboid', labelsTruck, 'Parent', ax, 'Opacity', 0.1, 'Color',...
        truckColor, 'LineWidth', 0.5);
    title(titleForFigure);
    zoom(ax,1.5);
end

function [net, matFile] = helperReplaceFunctionLayer(net)
% Replace the scatter functionLayer present in the pretrained Pointpillars
% network with custom layer having code generation support.

    matFile = './pointPillarsCodegenNet.mat';
    lgraph = net.layerGraph;

    id = find(...
        arrayfun( @(x)isa(x,'nnet.cnn.layer.FunctionLayer'), ...
        net.Layers));
    fcnLayer = net.Layers(id);

    customLayer = helperScatterLayer(2,"pillars|scatter_nd",[432 496]);
    lgraph = replaceLayer(lgraph,fcnLayer.Name,customLayer);

    net = dlnetwork(lgraph);
    save(matFile,'net');
end

Ссылки

[1] Ленг, Алекс Х., Sourabh Vora, Хольгер Цезарь, Лубин Чжоу, Цзюн Ян и Оскар Бейджбом. "PointPillars: Быстрые Энкодеры для Обнаружения объектов От Облаков точек". На 2019 Конференциях IEEE/CVF по Компьютерному зрению и Распознаванию образов (CVPR), 12689-12697. Лонг-Бич, CA, США: IEEE, 2019. https://doi.org/10.1109/CVPR.2019.01298.

[2] Hesai и Scale. PandaSet. https://scale.com/open-datasets/pandaset.