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

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

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

Этот пример использует собранное использование набора данных сцен магистрали Изгнания датчик OS1. Это содержит организованные сканы облака точек лидара магистральных сцен и соответствующих меток основной истины для объектов автомобиля и грузовика. Размер файла данных составляет приблизительно 760 Мбайт.

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

Выполните этот код, чтобы загрузить магистральный набор данных сцен. Этот пример использует набор данных, который содержит 1 617 облаков точек, сохраненных как pointCloud объекты в массиве ячеек. Соответствующие достоверные данные, который присоединен к примеру, содержат информацию об ограничительной рамке автомобилей и грузовиков в каждом облаке точек.

url = 'https://www.mathworks.com/supportfiles/lidar/data/WPI_LidarData.tar.gz';

outputFolder = fullfile(tempdir,'WPI');
lidarDataTarFile = fullfile(outputFolder,'WPI_LidarData.tar.gz');

if ~exist(lidarDataTarFile, 'file')
    mkdir(outputFolder);
    
    disp('Downloading WPI Lidar driving data (760 MB)...');
    websave(lidarDataTarFile, url);
    untar(lidarDataTarFile,outputFolder);
end

% Check if tar.gz file is downloaded, but not uncompressed.
if ~exist(fullfile(outputFolder, 'WPI_LidarData.mat'), 'file')
    untar(lidarDataTarFile,outputFolder);
end
lidarData = load(fullfile(outputFolder, 'WPI_LidarData.mat'));

groundTruthData = load('WPI_LidarGroundTruth.mat');

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

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

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

doTraining = false;
if ~doTraining && ~exist('trainedSqueezeSegV2Net.mat','file')
    disp('Downloading pretrained network (2 MB)...');
    pretrainedURL = 'https://www.mathworks.com/supportfiles/lidar/data/trainedSqueezeSegV2Net.mat';
    websave('trainedSqueezeSegV2Net.mat', pretrainedURL);
end

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

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

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

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

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

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

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

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

imagesFolder = fullfile(outputFolder, 'images');
labelsFolder = fullfile(outputFolder, 'labels');

helperGenerateLidarData(lidarData, groundTruthData, imagesFolder, labelsFolder);
Preprocessing data 100% complete

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

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

Создайте ImageDatastore и PixelLabelDatastore

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

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

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

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

numClasses = numel(classNames);

% Specify label IDs from 1 to the number of classes.
labelIDs = 1 : numClasses;

pxds = pixelLabelDatastore(labelsFolder, classNames, labelIDs);

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

imageNumber = 228;

% Point cloud (channels 1, 2, and 3 are for location, and channel 4 is for intensity).
I = readimage(imds, imageNumber);

labelMap = readimage(pxds, imageNumber);
figure;
helperDisplayLidarOverlayImage(I, labelMap, classNames);
title('Ground Truth');

Подготовка учебных, проверочных и тестовых наборов

Используйте helperPartitionLidarData поддерживая функцию, присоединенную к этому примеру, чтобы разделить данные в обучение, валидацию и наборы тестов, которые содержат 970, 216, и 431 изображение, соответственно.

[imdsTrain, imdsVal, imdsTest, pxdsTrain, pxdsVal, pxdsTest] = ...
    helperPartitionLidarData(imds, pxds);

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

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

Увеличение данных

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

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

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

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

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

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

inputSize = [64 1024 5];

lgraph = squeezesegv2Layers(inputSize, numClasses);

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

analyzeNetwork(lgraph)

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

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

maxEpochs = 30;
initialLearningRate= 5e-4;
miniBatchSize = 8;
l2reg = 2e-4;

options = trainingOptions('rmsprop', ...
    'InitialLearnRate', initialLearningRate, ...
    'L2Regularization', l2reg, ...
    'MaxEpochs', maxEpochs, ...
    'MiniBatchSize', miniBatchSize, ...
    'LearnRateSchedule', 'piecewise', ...
    'LearnRateDropFactor', 0.1, ...
    'LearnRateDropPeriod', 10, ...
    'ValidationData', validationData, ...
    'Plots', 'training-progress', ...
    'VerboseFrequency', 20);

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

Обучение сети

doTraining аргумент установлен в false (значение по умолчанию), чтобы загрузить предварительно обученную сеть. Можно обучить сеть сами путем установки doTraining аргумент к true. Если вы обучаете сеть, можно использовать центральный процессор или графический процессор. Используя графический процессор требует Parallel Computing Toolbox™, и CUDA® включил NVIDIA®, графический процессор с вычисляет возможность 3.0 или выше..

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

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

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

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

ptCloud = pcread('ousterLidarDrivingData.pcd');
I = helperPointCloudToImage(ptCloud);
predictedResult = semanticseg(I, net);

figure;
helperDisplayLidarOverlayImage(I, predictedResult, classNames);
title('Semantic Segmentation Result');

Используйте helperDisplayLidarOverlayPointCloud функция, заданная в разделе Supporting Functions этого примера, чтобы отобразить результат сегментации на ptCloud объект.

figure;
helperDisplayLidarOverlayPointCloud(ptCloud, predictedResult, numClasses);
view([95.71 24.14])
title('Semantic Segmentation Result on Point Cloud');

Оцените сеть

Запустите semanticseg функция на целом наборе тестов, чтобы измерить точность сети. Установите MiniBatchSize к 8 для того, чтобы уменьшать использование памяти при сегментации изображений. Можно увеличить или уменьшить это значение в зависимости от суммы памяти графического процессора, которую вы имеете в своей системе.

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

semanticseg функция возвращает результаты сегментации на наборе тестовых данных как PixelLabelDatastore объект. Функция пишет данные о метке фактического пикселя для каждого тестового изображения в imdsTest возразите против диска в месте, заданном 'WriteLocation' аргумент.

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

metrics = evaluateSemanticSegmentation(pxdsResults, pxdsTest, 'Verbose', false);

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

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

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

       0.99376          0.71176       0.63813      0.98912        0.90017  

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

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

    background    0.99756     0.99463      0.98424  
    car           0.71507     0.52999      0.77356  
    truck         0.42264     0.38977      0.75395  

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

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

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

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

function out = augmentData(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 сферическом изображении

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

function helperDisplayLidarOverlayImage(lidarImage, labelMap, classNames)
%helperDisplayLidarOverlayImage Overlay labels over the intensity image. 
%
%  helperDisplayLidarOverlayImage(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 = helperLidarColorMap();

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

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

function helperDisplayLidarOverlayPointCloud(ptCloud, labelMap, numClasses)
%helperDisplayLidarOverlayPointCloud Overlay labels over point cloud object.
%
%  helperDisplayLidarOverlayPointCloud(ptCloud, labelMap, numClasses)
%  displays the overlaid pointCloud object. ptCloud is the organized
%  3-D point cloud input. labelMap contains pixel labels and numClasses
%  is the number of predicted classes.

sz = size(labelMap);

% Apply the color red to cars.
carClassCar = zeros(sz(1), sz(2), numClasses, 'uint8');
carClassCar(:,:,1) = 255*ones(sz(1), sz(2), 'uint8');

% Apply the color blue to trucks.
truckClassColor = zeros(sz(1), sz(2), numClasses, 'uint8');
truckClassColor(:,:,3) = 255*ones(sz(1), sz(2), 'uint8');

% Apply the color gray to the background.
backgroundClassColor = 153*ones(sz(1), sz(2), numClasses, 'uint8');

% Extract indices from the labels.
carIndices = labelMap == 'car';
truckIndices = labelMap == 'truck';
backgroundIndices = labelMap == 'background';

% Extract a point cloud of different classes.
carPointCloud = select(ptCloud, carIndices, 'OutputSize','full');
truckPointCloud = select(ptCloud, truckIndices, 'OutputSize','full');
backgroundPointCloud = select(ptCloud, backgroundIndices, 'OutputSize','full');

% Apply 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);

% Plot the colored point cloud. Set an ROI for better visualization.
ax = pcshow(coloredCloud);
set(ax,'XLim',[-35.0 35.0],'YLim',[-32.0 32.0],'ZLim',[-3.0 8.0], ...
    'XColor','none','YColor','none','ZColor','none');
set(get(ax,'parent'), 'units','normalized');
end

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

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

function cmap = helperLidarColorMap()

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

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

Ссылки

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