exponenta event banner

Обнаружение объектов Lidar 3-D с помощью Deep Learning

В этом примере показано, как обучить сеть, предназначенную для обнаружения объектов в облаках точек.

Данные облака точек Lidar могут быть получены различными датчиками lidar, включая датчики Velodine ®, Pandar и Ouster. Эти датчики фиксируют 3-D информацию о положении объектов в сцене, что полезно для многих приложений в автономном вождении и дополненной реальности. Однако обучение надежных детекторов данным облака точек является сложной задачей из-за разреженности данных на объект, окклюзии объекта и шума датчика. Было показано, что методы глубокого обучения решают многие из этих проблем, изучая надежные представления функций непосредственно из данных облака точек. Одним из методов глубокого обучения для 3-D обнаружения объектов является, по крайней мере, StartStolps [1]. Используя архитектуру, сходную с той, которая используется при работе с StartNet, в сети, которая извлекает плотные, надежные элементы из разреженных точечных облаков, называемых столбами, затем используется 2-D сеть глубокого обучения с модифицированной сетью обнаружения объектов SSD для оценки совместных 3-D ограничивающих коробок, ориентаций и предсказаний классов.

В этом примере используется набор данных PandaSet [2] из Hesai и Scale. PandaSet содержит 8240 неорганизованных сканирований облака точек лидара различных городских сцен, захваченных с помощью датчика Pandar64. Набор данных содержит метки 3-D ограничивающие рамки для 18 различных классов объектов, включая легковые автомобили, грузовики и пешеходы.

Загрузить набор данных Lidar

В этом примере используется подмножество PandaSet, содержащее 2560 предварительно обработанных организованных облаков точек. Каждое облако точек охватывает 360o вида и определяется как матрица 64 на 1856. Облака точек хранятся в формате PCD, а соответствующие им данные истинности земли хранятся в PandaSetLidarGroundTruth.mat файл. Файл содержит информацию 3-D ограничивающей рамку для трех классов - легкового автомобиля, грузовика и пешехода. Размер набора данных составляет 5,2 ГБ.

Загрузите набор данных Pandaset с заданного URL-адреса с помощью helperDownloadPandasetData вспомогательная функция, определенная в конце этого примера.

outputFolder = fullfile(tempdir,'Pandaset');
lidarURL = ['https://ssd.mathworks.com/supportfiles/lidar/data/' ...
    'Pandaset_LidarData.tar.gz'];
helperDownloadPandasetData(outputFolder,lidarURL);

В зависимости от подключения к Интернету процесс загрузки может занять некоторое время. Код приостанавливает выполнение MATLAB ® до завершения процесса загрузки. Можно также загрузить набор данных на локальный диск с помощью веб-браузера и извлечь файл. В этом случае измените outputFolder переменная в коде к местоположению загруженного файла.

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

Загрузите предварительно обученную сеть с заданного URL-адреса с помощью helperDownloadPretrainedPointPillarsNet вспомогательная функция, определенная в конце этого примера. Предварительно обученная модель позволяет выполнять весь пример без необходимости ждать завершения обучения. Если вы хотите обучить сеть, установите doTraining переменная для true.

pretrainedNetURL = ['https://ssd.mathworks.com/supportfiles/lidar/data/' ...
    'trainedPointPillarsPandasetNet.zip'];

doTraining = false;
if ~doTraining
    helperDownloadPretrainedPointPillarsNet(outputFolder,pretrainedNetURL);
end

Загрузить данные

Создайте хранилище данных для загрузки PCD-файлов по указанному пути с помощью pcread функция.

path = fullfile(outputFolder,'Lidar');
lidarData = fileDatastore(path,'ReadFcn',@(x) pcread(x));

Загрузите метки ограничивающей рамки 3-D для объектов автомобиля и грузовика.

gtPath = fullfile(outputFolder,'Cuboids','PandaSetLidarGroundTruth.mat');
data = load(gtPath,'lidarGtLabels');
Labels = timetable2table(data.lidarGtLabels);
boxLabels = Labels(:,2:3);

Отображение облака точек полного вида.

figure
ptCld = read(lidarData);
ax = pcshow(ptCld.Location);
set(ax,'XLim',[-50 50],'YLim',[-40 40]);
zoom(ax,2.5);
axis off;

reset(lidarData);

Данные предварительной обработки

Данные PandaSet состоят из полновидовых облаков точек. В этом примере можно обрезать облака точек полного вида до облаков точек переднего вида с помощью стандартных параметров [1]. Эти параметры определяют размер входного сигнала, передаваемого в сеть. Выбор меньшего диапазона точечных облаков вдоль осей x, y и z помогает обнаруживать объекты, которые ближе к началу координат, а также уменьшает общее время обучения сети.

xMin = 0.0;     % Minimum value along X-axis.
yMin = -39.68;  % Minimum value along Y-axis.
zMin = -5.0;    % Minimum value along Z-axis.
xMax = 69.12;   % Maximum value along X-axis.
yMax = 39.68;   % Maximum value along Y-axis.
zMax = 5.0;     % Maximum value along Z-axis.
xStep = 0.16;   % Resolution along X-axis.
yStep = 0.16;   % Resolution along Y-axis.
dsFactor = 2.0; % Downsampling factor.

% Calculate the dimensions for the pseudo-image.
Xn = round(((xMax - xMin) / xStep));
Yn = round(((yMax - yMin) / yStep));

% Define the pillar extraction parameters.
gridParams = {{xMin,yMin,zMin},{xMax,yMax,zMax},{xStep,yStep,dsFactor},{Xn,Yn}};

Используйте cropFrontViewFromLidarData вспомогательная функция, присоединенная к этому примеру в качестве вспомогательного файла, для:

  • Обрезка вида спереди из входного облака точек полного вида.

  • Выберите метки полей, которые находятся внутри ROI, указанного gridParams.

[croppedPointCloudObj,processedLabels] = cropFrontViewFromLidarData(...
    lidarData,boxLabels,gridParams);
Processing data 100% complete

Отображение обрезанного облака точек и меток поля истинности грунта с помощью helperDisplay3DBoxesOverlaidPointCloud вспомогательная функция, определенная в конце примера.

pc = croppedPointCloudObj{1,1};
gtLabelsCar = processedLabels.Car{1};
gtLabelsTruck = processedLabels.Truck{1};

helperDisplay3DBoxesOverlaidPointCloud(pc.Location,gtLabelsCar,...
   'green',gtLabelsTruck,'magenta','Cropped Point Cloud');

reset(lidarData);

Создание объектов хранилища данных для обучения

Разбейте набор данных на учебные и тестовые наборы. Выберите 70% данных для обучения сети, а остальные - для оценки.

rng(1);
shuffledIndices = randperm(size(processedLabels,1));
idx = floor(0.7 * length(shuffledIndices));

trainData = croppedPointCloudObj(shuffledIndices(1:idx),:);
testData = croppedPointCloudObj(shuffledIndices(idx+1:end),:);

trainLabels = processedLabels(shuffledIndices(1:idx),:);
testLabels = processedLabels(shuffledIndices(idx+1:end),:);

Чтобы легко получить доступ к хранилищам данных, сохраните учебные данные в виде PCD-файлов с помощью saveptCldToPCD вспомогательная функция, присоединенная к этому примеру в качестве вспомогательного файла. Можно задать writeFiles комуfalse" если данные обучения сохранены в папке и поддерживаются pcread функция.

writeFiles = true;
dataLocation = fullfile(outputFolder,'InputData');
[trainData,trainLabels] = saveptCldToPCD(trainData,trainLabels,...
    dataLocation,writeFiles);
Processing data 100% complete

Создание хранилища данных файла с помощью fileDatastore для загрузки файлов PCD с помощью pcread функция.

lds = fileDatastore(dataLocation,'ReadFcn',@(x) pcread(x));

Создание хранилища данных меток коробки с помощью boxLabelDatastore для загрузки меток ограничивающей рамки 3-D.

bds = boxLabelDatastore(trainLabels);

Используйте combine для объединения облаков точек и меток ограничивающих 3-D в единое хранилище данных для обучения.

cds = combine(lds,bds);

Увеличение объема данных

В этом примере для добавления большего разнообразия к обучающим данным и соответствующим рамкам используется увеличение данных истинности земли и несколько других методов глобального увеличения данных. Дополнительные сведения о типичных методах увеличения объема данных, используемых в 3-D рабочих процессах обнаружения объектов с использованием данных lidar, см. в разделе Увеличение объема данных для обнаружения объектов Lidar с помощью глубокого обучения.

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

augData = read(cds);
augptCld = augData{1,1};
augLabels = augData{1,2};
augClass = augData{1,3};

labelsCar = augLabels(augClass=='Car',:);
labelsTruck = augLabels(augClass=='Truck',:);

helperDisplay3DBoxesOverlaidPointCloud(augptCld.Location,labelsCar,'green',...
    labelsTruck,'magenta','Before Data Augmentation');

reset(cds);

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

gtData = generateGTDataForAugmentation(trainData,trainLabels);

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

samplesToAdd = struct('Car',10,'Truck',10);
cdsAugmented = transform(cds,@(x) groundTruthDataAugmenation(x,gtData,samplesToAdd));

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

  • Случайное разворот вдоль оси X

  • Случайное масштабирование на 5 процентов

  • Случайное вращение вдоль оси Z от [-pi/4, pi/4]

  • Случайное перемещение на [0,2, 0,2, 0,1] метров вдоль осей x, y и z соответственно

cdsAugmented = transform(cdsAugmented,@(x) augmentData(x));

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

augData = read(cdsAugmented);
augptCld = augData{1,1};
augLabels = augData{1,2};
augClass = augData{1,3};

labelsCar = augLabels(augClass=='Car',:);
labelsTruck = augLabels(augClass=='Truck',:);

helperDisplay3DBoxesOverlaidPointCloud(augptCld(:,1:3),labelsCar,'green',...
    labelsTruck,'magenta','After Data Augmentation');

reset(cdsAugmented);

Извлечь информацию о столбах

Можно применить 2-D архитектуру свертки к облакам точек для более быстрой обработки. Для этого сначала преобразуйте облака 3-D точек в 2-D представление. Используйте transform функции с помощью createPillars вспомогательная функция, присоединенная к этому примеру в качестве файла поддержки, для создания элементов столбов и индексов столбов из облаков точек. Вспомогательная функция выполняет следующие операции:

  • Дискретизируйте облака 3-D точек в равномерно разнесенные сетки в плоскости x-y, чтобы создать набор вертикальных столбцов, называемых столбами.

  • Выберите видные столбы (P) на основе количества точек на столб (N).

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

  • Вычислите смещение от центра колонны.

  • Используйте значения положения x, y, z, интенсивности, расстояния и смещения для создания девятимерного (9-D) вектора для каждой точки столба.

% Define number of prominent pillars.
P = 12000; 

% Define number of points per pillar.
N = 100;   
cdsTransformed = transform(cdsAugmented,@(x) createPillars(x,gridParams,P,N));

Определение сети

В сети StartToples используется упрощенная версия сети, в которой в качестве входных данных используются функции столбов. Для каждого элемента колонны сеть применяет линейный уровень, за которым следует пакетная нормализация и уровни ReLU. Наконец, сеть применяет операцию максимального объединения по каналам для получения кодированных функций высокого уровня. Эти закодированные элементы разбросаны по исходному расположению столбов для создания псевдоизображения с использованием пользовательского слоя. helperscatterLayer, прилагается к этому примеру как вспомогательный файл. Затем сеть обрабатывает псевдоизображение с 2-D сверточной магистралью, за которой следуют различные головки обнаружения SSD, чтобы предсказать 3-D ограничивающие рамки вместе со своими классами.

Определите размеры якорей привязки на основе определяемых классов. Как правило, эти размеры являются средством всех значений ограничивающей рамки в обучающем наборе [1]. Кроме того, можно использовать calculateAnchorBoxes вспомогательная функция, прилагаемая к примеру, для получения соответствующих анкерных ящиков из любого обучающего набора. Поля привязки определяются в формате {длина, ширина, высота, z-центр, угол рыскания}.

anchorBoxes = calculateAnchorsPointPillars(trainLabels);
numAnchors = size(anchorBoxes,2);
classNames = trainLabels.Properties.VariableNames;
numClasses = numel(classNames);

Затем создайте сеть, используя pointpillarNetwork вспомогательная функция, присоединенная к этому примеру в качестве вспомогательного файла.

lgraph = pointpillarNetwork(numAnchors,gridParams,P,N,numClasses);

Укажите параметры обучения

Укажите следующие параметры обучения.

  • Установите число эпох равным 60.

  • Установите размер мини-партии равным 2. При наличии большего объема памяти можно задать для размера мини-пакета большее значение.

  • Установите скорость обучения 0,0002.

  • Набор learnRateDropPeriod до 15. Этот параметр обозначает количество периодов, после которых необходимо сбросить скорость обучения на основе формулы learningRate × (итерация% learnRateDropPeriod) × learnRateDropFactor.

  • Набор learnRateDropFactor до 0,8. Этот параметр обозначает скорость, на которую следует сбрасывать скорость обучения после каждого learnRateDropPeriod.

  • Установите коэффициент градиентного затухания равным 0,9.

  • Установите коэффициент спада градиента в квадрате равным 0,999.

  • Инициализируйте среднее значение градиентов для []. Используется оптимизатором Adam.

  • Инициализируйте среднее значение квадрата градиентов до []. Используется оптимизатором Adam.

numEpochs = 60;
miniBatchSize = 2;
learningRate = 0.0002;
learnRateDropPeriod = 15;
learnRateDropFactor = 0.8;
gradientDecayFactor = 0.9;
squaredGradientDecayFactor = 0.999;
trailingAvg = [];
trailingAvgSq = [];

Модель поезда

Обучение сети с помощью CPU или графического процессора. Для использования графического процессора требуются параллельные вычислительные Toolbox™ и графический процессор NVIDIA ® с поддержкой CUDA ®. Дополнительные сведения см. в разделе Поддержка графического процессора по выпуску (Панель инструментов параллельных вычислений). Чтобы автоматически определить, доступен ли графический процессор, установитеexecutionEnvironment кому "auto". Если у вас нет графического процессора или вы не хотите использовать его для обучения, установите executionEnvironment кому "cpu". Для обеспечения использования графического процессора для обучения, установить executionEnvironment кому "gpu".

Далее создайте minibatchqueue (Deep Learning Toolbox) для загрузки данных партиями miniBatchSize во время обучения.

executionEnvironment = "auto";
if canUseParallelPool
    dispatchInBackground = true;
else
    dispatchInBackground = false;
end

mbq = minibatchqueue(...
    cdsTransformed,3,...
    "MiniBatchSize",miniBatchSize,...
    "OutputEnvironment",executionEnvironment,...
    "MiniBatchFcn",@(features,indices,boxes,labels) ...
    helperCreateBatchData(features,indices,boxes,labels,classNames),...
    "MiniBatchFormat",["SSCB","SSCB",""],...
    "DispatchInBackground",true);

Чтобы обучить сеть с помощью пользовательского цикла обучения и включить автоматическое дифференцирование, преобразуйте график слоев в dlnetwork(Панель инструментов глубокого обучения). Затем создайте плоттер хода обучения с помощью helperConfigureTrainingProgressPlotter вспомогательная функция, определенная в конце этого примера.

Наконец, укажите индивидуальный цикл обучения. Для каждой итерации:

  • Прочитайте облака точек и поля истины земли из minibatchqueue (Deep Learning Toolbox) объект с использованием next (Deep Learning Toolbox).

  • Оценка градиентов модели с помощью dlfeval (инструментарий глубокого обучения) и modelGradients функция. modelGradients вспомогательная функция, определенная в конце примера, возвращает градиенты потерь относительно обучаемых параметров в netсоответствующая потеря мини-партии и состояние текущей партии.

  • Обновление параметров сети с помощью adamupdate (Deep Learning Toolbox).

  • Обновить параметры состояния net.

  • Обновите график хода обучения.

if doTraining
    % Convert layer graph to dlnetwork.
    net = dlnetwork(lgraph);
    
    % Initialize plot.
    fig = figure;
    lossPlotter = helperConfigureTrainingProgressPlotter(fig);    
    iteration = 0;
       
    % Custom training loop.
    for epoch = 1:numEpochs
        
        % Reset datastore.
        reset(mbq);
        while(hasdata(mbq))
            iteration = iteration + 1;
            
            % Read batch of data.
            [pillarFeatures,pillarIndices,boxLabels] = next(mbq);
                        
            % Evaluate the model gradients and loss using dlfeval 
            % and the modelGradients function.
            [gradients,loss,state] = dlfeval(@modelGradients,net,...
                pillarFeatures,pillarIndices,boxLabels,gridParams,...
                anchorBoxes,numClasses,executionEnvironment);
            
            % Do not update the network learnable parameters if NaN values
            % are present in gradients or loss values.
            if helperCheckForNaN(gradients,loss)
                continue;
            end
                    
            % Update the state parameters of dlnetwork.
            net.State = state;
            
            % Update the network learnable parameters using the Adam
            % optimizer.
            [net.Learnables,trailingAvg,trailingAvgSq] = ...
                adamupdate(net.Learnables,gradients,trailingAvg,...
                trailingAvgSq,iteration,learningRate,...
                gradientDecayFactor,squaredGradientDecayFactor);
            
            % Update training plot with new points.         
            addpoints(lossPlotter,iteration,double(gather(extractdata(loss))));
            title("Training Epoch " + epoch +" of " + numEpochs);
            drawnow;
        end
        
        % Update the learning rate after every learnRateDropPeriod.
        if mod(epoch,learnRateDropPeriod) == 0
            learningRate = learningRate * learnRateDropFactor;
        end
    end
else
    preTrainedMATFile = fullfile(outputFolder,'trainedPointPillarsPandasetNet.mat');
    pretrainedNetwork = load(preTrainedMATFile,'net');
    net = pretrainedNetwork.net;
end

Создание обнаружений

Используйте обученную сеть для обнаружения объектов в тестовых данных:

  • Считывание облака точек из тестовых данных.

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

  • Отображение облака точек с ограничивающими прямоугольниками с помощью helperDisplay3DBoxesOverlaidPointCloud вспомогательная функция, определенная в конце примера.

ptCloud = testData{45,1};
gtLabels = testLabels(45,:);

% The generatePointPillarDetections function detects the 
% bounding boxes, and scores for a given point cloud.
confidenceThreshold = 0.5;
overlapThreshold = 0.1;
[box,score,labels] = generatePointPillarDetections(net,ptCloud,anchorBoxes,...
    gridParams,classNames,confidenceThreshold,overlapThreshold,P,N,...
    executionEnvironment);

boxlabelsCar = box(labels'=='Car',:);
boxlabelsTruck = box(labels'=='Truck',:);

% Display the predictions on the point cloud.
helperDisplay3DBoxesOverlaidPointCloud(ptCloud.Location,boxlabelsCar,'green',...
    boxlabelsTruck,'magenta','Predicted Bounding Boxes');

Оценка модели

Computer Vision Toolbox™ предоставляет функции оценки детекторов объектов для измерения общих метрик, таких как средняя точность (evaluateDetectionAOS). В этом примере используется метрика средней точности. Средняя точность обеспечивает одно число, которое включает в себя способность детектора делать правильные классификации (точность) и способность детектора находить все соответствующие объекты (вспомним).

Оценка обученных dlnetwork(Панель инструментов глубокого обучения) net на тестовых данных путем выполнения следующих шагов.

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

  • Укажите порог перекрытия для удаления перекрывающихся обнаружений.

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

  • Звонить evaluateDetectionAOS с detectionResults и groundTruthData в качестве аргументов.

numInputs = numel(testData);

% Generate rotated rectangles from the cuboid labels.
bds = boxLabelDatastore(testLabels);
groundTruthData = transform(bds,@(x) createRotRect(x));

% Set the threshold values.
nmsPositiveIoUThreshold = 0.5;
confidenceThreshold = 0.25;
overlapThreshold = 0.1;

% Set numSamplesToTest to numInputs to evaluate the model on the entire
% test data set.
numSamplesToTest = 50;
detectionResults = table('Size',[numSamplesToTest 3],...
                        'VariableTypes',{'cell','cell','cell'},...
                        'VariableNames',{'Boxes','Scores','Labels'});

for num = 1:numSamplesToTest
    ptCloud = testData{num,1};
    
    [box,score,labels] = generatePointPillarDetections(net,ptCloud,anchorBoxes,...
        gridParams,classNames,confidenceThreshold,overlapThreshold,...
        P,N,executionEnvironment);
 
    % Convert the detected boxes to rotated rectangle format.
    if ~isempty(box)
        detectionResults.Boxes{num} = box(:,[1,2,4,5,7]);
    else
        detectionResults.Boxes{num} = box;
    end
    detectionResults.Scores{num} = score;
    detectionResults.Labels{num} = labels;
end

metrics = evaluateDetectionAOS(detectionResults,groundTruthData,...
    nmsPositiveIoUThreshold);
disp(metrics(:,1:2))
               AOS        AP   
             _______    _______

    Car      0.86746    0.86746
    Truck    0.61463    0.61463

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

Градиенты модели

Функция modelGradients принимает в качестве входного значения dlnetwork(Панель инструментов глубокого обучения) net и мини-пакет входных данных pillarFeatures и pillarIndices с соответствующими ящиками истинности земли, ящиками привязки и параметрами сетки. Функция возвращает градиенты потерь относительно обучаемых параметров в netсоответствующая потеря мини-партии и состояние текущей партии.

Функция градиентов модели вычисляет суммарные потери и градиенты, выполняя эти операции.

  • Извлеките прогнозы из сети с помощью forward (Deep Learning Toolbox).

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

  • Вычислите функцию потерь для всех шести прогнозов из сети.

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

  • Вычислите градиенты обучаемых с учетом общей потери.

function [gradients,loss,state] = modelGradients(net,pillarFeatures,...
    pillarIndices,boxLabels,gridParams,anchorBoxes,...
    numClasses,executionEnvironment)
      
    numAnchors = size(anchorBoxes,2);
    
    % Extract the predictions from the network.
    YPredictions = cell(size(net.OutputNames));
    [YPredictions{:},state] = forward(net,pillarIndices,pillarFeatures);
    
    % Generate target for predictions from the ground truth data.
    YTargets = generatePointPillarTargets(YPredictions,boxLabels,pillarIndices,...
        gridParams,anchorBoxes,numClasses);
    YTargets = cellfun(@ dlarray,YTargets,'UniformOutput',false);
    if (executionEnvironment=="auto" && canUseGPU) || executionEnvironment=="gpu"
        YTargets = cellfun(@ gpuArray,YTargets,'UniformOutput',false);
    end
     
    [angLoss,occLoss,locLoss,szLoss,hdLoss,clfLoss] = ...
        computePointPillarLoss(YPredictions,YTargets,gridParams,...
        numClasses,numAnchors);
    
    % Compute the total loss.
    loss = angLoss + occLoss + locLoss + szLoss + hdLoss + clfLoss;
    
    % Compute the gradients of the learnables with regard to the loss.
    gradients = dlgradient(loss,net.Learnables);
 
end

function [pillarFeatures,pillarIndices,labels] = helperCreateBatchData(...
    features,indices,groundTruthBoxes,groundTruthClasses,classNames)
% Return pillar features and indices combined along the batch dimension
% and bounding boxes concatenated along batch dimension in labels.
    
    % Concatenate features and indices along batch dimension.
    pillarFeatures = cat(4,features{:,1});
    pillarIndices = cat(4,indices{:,1});
    
    % Get class IDs from the class names.
    classNames = repmat({categorical(classNames')},size(groundTruthClasses));
    [~,classIndices] = cellfun(@(a,b)ismember(a,b),groundTruthClasses,...
        classNames,'UniformOutput',false);
    
    % Append the class indices and create a single array of responses.
    combinedResponses = cellfun(@(bbox,classid) [bbox,classid],...
        groundTruthBoxes,classIndices,'UniformOutput',false);
    len = max(cellfun(@(x)size(x,1),combinedResponses));
    paddedBBoxes = cellfun(@(v) padarray(v,[len-size(v,1),0],0,'post'),...
        combinedResponses,'UniformOutput',false);
    labels = cat(4,paddedBBoxes{:,1});
end

function helperDownloadPandasetData(outputFolder,lidarURL)
% Download the data set from the given URL to the output folder.

    lidarDataTarFile = fullfile(outputFolder,'Pandaset_LidarData.tar.gz');
    
    if ~exist(lidarDataTarFile,'file')
        mkdir(outputFolder);
        
        disp('Downloading PandaSet Lidar driving data (5.2 GB)...');
        websave(lidarDataTarFile,lidarURL);
        untar(lidarDataTarFile,outputFolder);
    end
    
    % Extract the file.
    if (~exist(fullfile(outputFolder,'Lidar'),'dir'))...
            &&(~exist(fullfile(outputFolder,'Cuboids'),'dir'))
        untar(lidarDataTarFile,outputFolder);
    end

end

function helperDownloadPretrainedPointPillarsNet(outputFolder,pretrainedNetURL)
% Download the pretrained PointPillars network.

    preTrainedMATFile = fullfile(outputFolder,'trainedPointPillarsPandasetNet.mat');
    preTrainedZipFile = fullfile(outputFolder,'trainedPointPillarsPandasetNet.zip');
    
    if ~exist(preTrainedMATFile,'file')
        if ~exist(preTrainedZipFile,'file')
            disp('Downloading pretrained detector (8.4 MB)...');
            websave(preTrainedZipFile,pretrainedNetURL);
        end
        unzip(preTrainedZipFile,outputFolder);   
    end       
end

function lossPlotter = helperConfigureTrainingProgressPlotter(f)
% This function configures training progress plots for various losses.
    figure(f);
    clf
    ylabel('Total Loss');
    xlabel('Iteration');
    lossPlotter = animatedline;
end

function retValue = helperCheckForNaN(gradients,loss)
% The last convolution head 'occupancy|conv2d' is known to contain NaNs 
% the gradients. This function checks whether gradient values contain 
% NaNs. Add other convolution head values to the condition if NaNs 
% are present in the gradients. 
    gradValue = gradients.Value((gradients.Layer == 'occupancy|conv2d') & ...
        (gradients.Parameter == 'Bias'));
    if (sum(isnan(extractdata(loss)),'all') > 0) || ...
            (sum(isnan(extractdata(gradValue{1,1})),'all') > 0)
        retValue = true;
    else
        retValue = false;
    end
end

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

Ссылки

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

[2] Хесай и масштаб. PandaSet. https://scale.com/open-datasets/pandaset.