Семантическая сегментация облака точек Lidar SqueezeSegV2 используя нейронную сеть для глубокого обучения

В этом примере показано, как обучить SqueezeSegV2 сеть семантической сегментации на 3-D организованных данных облака точек лидара.

SqueezeSegV2 [1] является сверточной нейронной сетью (CNN) для выполнения сквозной семантической сегментации организованного лидара облака точек. Процедура обучения, показанная в этом примере, требует 2-D сферических проективных изображений в качестве входов для нейронной сети для глубокого обучения.

В этом примере используется набор данных PandaSet из Hesai и Scale [2]. PandaSet содержит 4800 неорганизованные сканы облака точек лидара различных городских сцен, захваченных с помощью датчика Pandar 64. Набор данных обеспечивает семантические метки сегментации для 42 различных классов, включая автомобиль, дорогу и пешехода.

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

Этот пример использует подмножество PandaSet, которое содержит 2560 предварительно обработанных организованных облаков точек. Каждое облако точек задано как матрица 64 на 1856. Соответствующая основная истина содержит метки семантической сегментации для 12 классов. Облака точек хранятся в формате PCD, а достоверные данные хранятся в формате PNG. Размер набора данных составляет 5,2 ГБ. Выполните этот код, чтобы загрузить набор данных.

url = 'https://ssd.mathworks.com/supportfiles/lidar/data/Pandaset_LidarData.tar.gz';
outputFolder = fullfile(tempdir,'Pandaset');
lidarDataTarFile = fullfile(outputFolder,'Pandaset_LidarData.tar.gz');
if ~exist(lidarDataTarFile, 'file')
    mkdir(outputFolder);
    disp('Downloading Pandaset Lidar driving data (5.2 GB)...');
    websave(lidarDataTarFile, url);
    untar(lidarDataTarFile,outputFolder);
end
% Check if tar.gz file is downloaded, but not uncompressed.
if (~exist(fullfile(outputFolder,'Lidar'), 'file'))...
        &&(~exist(fullfile(outputFolder,'semanticLabels'), 'file'))
    untar(lidarDataTarFile,outputFolder);
end
lidarData =  fullfile(outputFolder,'Lidar');
labelsFolder = fullfile(outputFolder,'semanticLabels');

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

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

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

Загрузите предварительно обученную сеть, чтобы не ждать завершения обучения. Если вы хотите обучить сеть, установите doTraining переменная в true.

doTraining = false;
pretrainedNetURL = ...
'https://ssd.mathworks.com/supportfiles/lidar/data/trainedSqueezeSegV2PandasetNet.zip';
if ~doTraining
    downloadPretrainedSqueezeSegV2Net(outputFolder, pretrainedNetURL);
end

Подготовка данных к обучению

Загрузка облаков точек лидара и меток классов

Используйте helperTransformOrganizedPointCloudToTrainingData вспомогательная функция, присоединенная к этому примеру, для генерации обучающих данных из лидара облаков точек. Функция использует данные облака точек для создания пятиканальных входных изображений. Каждое обучающее изображение задается как массив 64 на 1856 на 5:

  • Высота каждого изображения составляет 64 пикселя.

  • Ширина каждого изображения составляет 1856 пикселей.

  • Каждое изображение имеет пять каналов. Пять каналов определяют координаты 3-D облака точек, интенсивность и область значений: r=x2+y2+z2.

Далее приводится визуальное представление обучающих данных.

Сгенерируйте пятиканальные обучающие изображения.

imagesFolder = fullfile(outputFolder,'images');
helperTransformOrganizedPointCloudToTrainingData(lidarData,imagesFolder);
Preprocessing data 100% complete

Пятиканальные изображения сохраняются как файлы MAT.

Обработка может занять некоторое время. Код приостанавливает выполнение MATLAB ® до завершения обработки.

Создайте mageDatastore и p ixelLabelDatastore

Создайте imageDatastore извлечь и сохранить пять каналов 2-D сферических изображений с помощью imageDatastore и вспомогательной функции helperImageMatReader, которая является пользовательским средством чтения файлов MAT. Эта функция присоединена к этому примеру как вспомогательный файл.

imds = imageDatastore(imagesFolder, ...
    'FileExtensions', '.mat', ...
    'ReadFcn', @helperImageMatReader);

Создайте хранилище datastore метки пикселя с помощью pixelLabelDatastore для хранения пиксельных меток из изображений меток пикселей. Объект сопоставляет каждую пиксельную метку с именем класса. В этом примере растительность, земля, дорога, дорожная разметка, тротуар, автомобили, грузовики, другие транспортные средства, пешеходный, дорожный барьер, знаки и создания являются объектами интереса; все другие пиксели являются фоном. Задайте эти классы и присвойте уникальный идентификатор метки каждому классу.

classNames = ["unlabelled"
              "Vegetation"
              "Ground"
              "Road"
              "RoadMarkings"
              "SideWalk"
              "Car"
              "Truck"
              "OtherVehicle"
              "Pedestrian"
              "RoadBarriers"
              "Signs"
              "Buildings"];
numClasses = numel(classNames);
% Specify label IDs from 1 to the number of classes.
labelIDs = 1 : numClasses;
pxds = pixelLabelDatastore(labelsFolder, classNames, labelIDs);

Загрузите и отобразите одно из маркированных изображений путем наложения его на соответствующее изображение интенсивности с помощью helperDisplayLidarOverlaidImage function, заданная в разделе Support Functions этого примера.

% Point cloud (channels 1, 2, and 3 are for location, channel 4 is for intensity, and channel 5 is for range).
I = read(imds);
labelMap = read(pxds);
figure;
helperDisplayLidarOverlaidImage(I, labelMap{1,1}, classNames);
title('Ground Truth');

Подготовка наборов для обучения, валидации и тестирования

Используйте helperPartitionLidarSegmentationDataset вспомогательная функция, присоединенная к этому примеру, чтобы разделить данные на наборы для обучения, валидации и тестирования. Можно разделить обучающие данные в соответствии с процентом, заданным trainingDataPercentage. Разделите остальную часть данных в соотношении 2:1 на данные валидации и проверки. Значение по умолчанию trainingDataPercentage является 0.7.

[imdsTrain, imdsVal, imdsTest, pxdsTrain, pxdsVal, pxdsTest] = ...
helperPartitionLidarSegmentationDataset(imds, pxds, 'trainingDataPercentage', 0.75);

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

trainingData = combine(imdsTrain, pxdsTrain);
validationData = combine(imdsVal, pxdsVal);

Увеличение количества данных

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

Увеличение обучающих данных при помощи transform функция с пользовательскими операциями предварительной обработки, заданными helperAugmentData function, заданная в разделе Support Functions этого примера. Эта функция случайным образом разворачивает многоканальное 2-D изображение и связанные с ним метки в горизонтальном направлении. Применить увеличение данных только к набору обучающих данных.

augmentedTrainingData = transform(trainingData, @(x) helperAugmentData(x));

Определение сетевой архитектуры

Создайте стандартную SqueezeSegV2 сеть [1] с помощью squeezesegv2Layers функция. В SqueezeSegV2 сети подсеть энкодера состоит из FireModules, перемежающихся слоями max-pooling. Эта схема последовательно уменьшает разрешение входного изображения. В сложение SqueezeSegV2 сеть использует функцию фокусных потерь, чтобы уменьшить эффект несбалансированного распределения классов на точность сети. Для получения дополнительной информации о том, как использовать функцию фокусных потерь в семантической сегментации, смотрите focalLossLayer.

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

inputSize = [64 1856 5];
lgraph = squeezesegv2Layers(inputSize, ...
numClasses,'NumEncoderModules',4,'NumContextAggregationModules',2);

Используйте analyzeNetwork (Deep Learning Toolbox) функция для отображения интерактивной визуализации сетевой архитектуры.

analyzeNetwork(lgraph);

Настройка опций обучения

Используйте dam A алгоритм оптимизации для обучения сети. Используйте trainingOptions функция для задания гиперпараметров.

maxEpochs = 30;
initialLearningRate = 1e-3;
miniBatchSize = 8;
l2reg = 2e-4;
options = trainingOptions('adam', ...
    'InitialLearnRate', initialLearningRate, ...
    'L2Regularization', l2reg, ...
    'MaxEpochs', maxEpochs, ...
    'MiniBatchSize', miniBatchSize, ...
    'LearnRateSchedule', 'piecewise', ...
    'LearnRateDropFactor', 0.1, ...
    'LearnRateDropPeriod', 10, ...
    'ValidationData', validationData, ...
    'Plots', 'training-progress', ...
    'VerboseFrequency', 20);

Примечание: Уменьшите miniBatchSize значение для управления использованием памяти при обучении.

Обучите сеть

Можно обучить сеть самостоятельно, установив doTraining аргумент в true. Если вы обучаете сеть, можно использовать CPU или GPU. Для использования графический процессор требуется Parallel Computing Toolbox™ и поддерживаемый графический процессор. Для получения информации о поддерживаемых устройствах смотрите Поддержку GPU by Release (Parallel Computing Toolbox). В противном случае загружает предварительно обученную сеть

if doTraining
    [net, info] = trainNetwork(trainingData, lgraph, options);
else
    load(fullfile(outputFolder,'trainedSqueezeSegV2PandasetNet.mat'),'net');
end

Предсказание результатов на облаке тестовых точек

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

Отобразите рисунок с сегментацией как наложение.

I = read(imdsTest);
predictedResult = semanticseg(I, net);
figure;
helperDisplayLidarOverlaidImage(I, predictedResult, classNames);
title('Semantic Segmentation Result');

Используйте helperDisplayLabelOverlaidPointCloud функция, заданная в разделе Support Functions этого примера, для отображения результата сегментации в облаке точек.

figure;
helperDisplayLabelOverlaidPointCloud(I, predictedResult);                          
view([39.2 90.0 60]);
title('Semantic Segmentation Result on Point Cloud');

Оценка сети

Используйте evaluateSemanticSegmentation функция для вычисления метрики семантической сегментации из результатов тестового набора.

outputLocation = fullfile(tempdir, 'output');
if ~exist(outputLocation,'dir')
    mkdir(outputLocation);
end
pxdsResults = semanticseg(imdsTest, net, ...
    'MiniBatchSize', 4, ...
    'WriteLocation', outputLocation, ...
    'Verbose', false);
metrics = evaluateSemanticSegmentation(pxdsResults, pxdsTest, 'Verbose', false);

Можно измерить сумму перекрытия для класса с помощью метрики «перекресток по соединению» (IoU).

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

metrics.DataSetMetrics
ans=1×5 table
    GlobalAccuracy    MeanAccuracy    MeanIoU    WeightedIoU    MeanBFScore
    ______________    ____________    _______    ___________    ___________

       0.89724          0.61685       0.54431      0.81806        0.74537  

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

metrics.ClassMetrics 
ans=13×3 table
                    Accuracy      IoU      MeanBFScore
                    ________    _______    ___________

    unlabelled         0.94      0.9005      0.99911  
    Vegetation      0.77873     0.64819      0.95466  
    Ground          0.69019     0.59089      0.60657  
    Road            0.94045     0.83663      0.99084  
    RoadMarkings    0.37802     0.34149      0.77073  
    SideWalk         0.7874     0.65668      0.93687  
    Car              0.9334     0.81065      0.95448  
    Truck           0.30352     0.27401      0.37273  
    OtherVehicle    0.64397     0.58108      0.47253  
    Pedestrian      0.26214     0.20896      0.45918  
    RoadBarriers    0.23955     0.21971      0.19433  
    Signs           0.17276     0.15613      0.44275  
    Buildings       0.94891     0.85117      0.96929  

Хотя общая эффективность сети хороша, метрики классов для некоторых классов, таких как RoadMarkings и Truck указать, что для повышения эффективности требуется больше обучающих данных.

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

Функция для увеличения данных

The helperAugmentData функция случайным образом разворачивает сферическое изображение и связанные с ним метки в горизонтальном направлении.

function out = helperAugmentData(inp)
% Apply random horizontal flipping.
out = cell(size(inp));
% Randomly flip the five-channel image and pixel labels horizontally.
I = inp{1};
sz = size(I);
tform = randomAffine2d('XReflection',true);
rout = affineOutputView(sz,tform,'BoundsStyle','centerOutput');
out{1} = imwarp(I,tform,'OutputView',rout);
out{2} = imwarp(inp{2},tform,'OutputView',rout);
end

Функция для отображения карты сегментации лидара, наложенной на 2-D сферическое изображение

The helperDisplayLidarOverlaidImage функция накладывает карту семантической сегментации на канал интенсивности 2-D сферического изображения. Функция также изменяет размер наложенного изображения для лучшей визуализации.

function helperDisplayLidarOverlaidImage(lidarImage, labelMap, classNames)
% helperDisplayLidarOverlaidImage Overlay labels over the intensity image. 
%
%  helperDisplayLidarOverlaidImage(lidarImage, labelMap, classNames)
%  displays the overlaid image. lidarImage is a five-channel lidar input.
%  labelMap contains pixel labels and classNames is an array of label
%  names.
% Read the intensity channel from the lidar image.
intensityChannel = uint8(lidarImage(:,:,4));
% Load the lidar color map.
cmap = helperPandasetColorMap;
% Overlay the labels over the intensity image.
B = labeloverlay(intensityChannel,labelMap,'Colormap',cmap,'Transparency',0.4);
% Resize for better visualization.
B = imresize(B,'Scale',[3 1],'method','nearest');
imshow(B);
helperPixelLabelColorbar(cmap, classNames);
end

Функция для отображения карты сегментации Лидара, наложенной на 3-D Облако Точек

The helperDisplayLabelOverlaidPointCloud функция накладывает результат сегментации на 3-D организованное облако точек.

function helperDisplayLabelOverlaidPointCloud(I,predictedResult)
% helperDisplayLabelOverlaidPointCloud Overlay labels over point cloud object.
%  helperDisplayLabelOverlaidPointCloud(I, predictedResult)
%  displays the overlaid pointCloud object. I is the 5 channels organized
%  input image. predictedResult contains pixel labels.
ptCloud = pointCloud(I(:,:,1:3),'Intensity',I(:,:,4));
cmap = helperPandasetColorMap;
B = ...
labeloverlay(uint8(ptCloud.Intensity),predictedResult,'Colormap',cmap,'Transparency',0.4);
pc = pointCloud(ptCloud.Location,'Color',B);
figure;
ax = pcshow(pc);
set(ax,'XLim',[-70 70],'YLim',[-70 70]);
zoom(ax,3.5);
end

Функция для определения Палитры Лидара

The helperPandasetColorMap функция задает палитру, используемую набором данных лидара.

function cmap = helperPandasetColorMap
cmap = [[30,30,30];      % Unlabeled
        [0,255,0];       % Vegetation
        [255, 150, 255]; % Ground
        [255,0,255];     % Road
        [255,0,0];       % Road Markings
        [90, 30, 150];   % Sidewalk
        [245,150,100];   % Car
        [250, 80, 100];  % Truck
        [150, 60, 30];   % Other Vehicle
        [255, 255, 0];   % Pedestrian
        [0, 200, 255];   % Road Barriers
        [170,100,150];   % Signs
        [30, 30, 255]];  % Building
cmap = cmap./255;
end

Функция для отображения пиксельных Шкал палитры о метке

The helperPixelLabelColorbar функция добавляет шкалу палитры к текущей оси. Шкала палитры форматирована, чтобы отображать имена классов с цветом.

function helperPixelLabelColorbar(cmap, classNames)
colormap(gca, cmap);
% Add a colorbar to the current figure.
c = colorbar('peer', gca);
% Use class names for tick marks.
c.TickLabels = classNames;
numClasses = size(classNames, 1);
% Center tick labels.
c.Ticks = 1/(numClasses * 2):1/numClasses:1;
% Remove tick marks.
c.TickLength = 0;
end

Функция для загрузки предварительно обученной модели

The downloadPretrainedSqueezeSegV2Net функция загружает предварительно обученную модель.

function downloadPretrainedSqueezeSegV2Net(outputFolder, pretrainedNetURL)
    preTrainedMATFile = fullfile(outputFolder,'trainedSqueezeSegV2PandasetNet.mat');
    preTrainedZipFile = fullfile(outputFolder,'trainedSqueezeSegV2PandasetNet.zip');
    
    if ~exist(preTrainedMATFile,'file')
        if ~exist(preTrainedZipFile,'file')
            disp('Downloading pretrained model (5 MB)...');
            websave(preTrainedZipFile, pretrainedNetURL);
        end
        unzip(preTrainedZipFile, outputFolder);   
    end       
end

Ссылки

[1] У, Бичэнь, Сюаньюй Чжоу, Сычэн Чжао, Сянъюй Юэ и Курт Кейцер. «SqueezeSegV2: улучшенная структура модели и неконтролируемая адаптация области для сегментации дорог и объектов из облака точек лИДАР». В 2019 году Международная конференция по робототехнике и автоматизации (ICRA), 4376-82. Монреаль, QC, Канада: IEEE, 2019.https://doi.org/10.1109/ICRA.2019.8793495.

[2] Хесаи и шкала. PandaSet. https://scale.com/open-datasets/pandaset