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

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

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

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

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

Этот пример использует подмножество PandaSet, который содержит 2 560 предварительно обработанных организованных облаков точек. Каждое облако точек задано как 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 1 856 5 массивами:

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

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

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

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

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

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

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

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

Создайте imageDatastore и pixelLabelDatastore

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

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

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

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 функция, заданная в разделе Supporting 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 функция, заданная в разделе Supporting Functions этого примера. Эта функция случайным образом инвертирует многоканальное 2D изображение и сопоставленные метки в горизонтальном направлении. Примените увеличение данных только к обучающему набору данных.

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

Архитектура сети Define

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

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

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

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

analyzeNetwork(lgraph);

Задайте опции обучения

Используйте Adam алгоритм оптимизации, чтобы обучить сеть. Используйте 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. Если вы обучаете сеть, можно использовать центральный процессор или графический процессор. Используя графический процессор требует Parallel Computing Toolbox™ и поддерживаемого устройства графического процессора. Для получения информации о поддерживаемых устройствах смотрите Поддержку графического процессора Релизом (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 функция, заданная в разделе Supporting 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).

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 укажите, что больше обучающих данных требуется для лучшей эффективности.

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

Функция, чтобы увеличить данные

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

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

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

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 облаке точек

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

Функция, чтобы задать палитру лидара

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

Функция, чтобы отобразить пиксельную шкалу палитры метки

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

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

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] Ву, Bichen, Сюаньюй Чжоу, Сычэн Чжао, Сянюй Юэ и Курт Койцер. “SqueezeSegV2: Улучшенная Структура модели и Безнадзорная Доменная Адаптация к Дорожно-объектной Сегментации от Облака точек LiDAR”. На 2 019 Международных конференциях по вопросам Робототехники и Автоматизации (ICRA), 4376–82. Монреаль, Qc, Канада: IEEE, 2019.https://doi.org/10.1109/ICRA.2019.8793495.

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