В этом примере показано, как обучить сеть семантической сегментации PointSeg на 3-D организованных данных об облаке точек лидара.
PointSeg [1] является сверточной нейронной сетью (CNN) для выполнения сквозной семантической сегментации дорожных объектов на основе организованного облака точек лидара. При помощи методов, таких как atrous пространственное объединение пирамиды (ASPP) и блоки squeeze-excitation, сеть обеспечивает улучшенные результаты сегментации. Метод обучения, показанный в этом примере, требует 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
переменная к истине.
doTraining = false; if ~doTraining && ~exist('trainedPointSegNet.mat','file') disp('Downloading pretrained network (14 MB)...'); pretrainedURL = 'https://www.mathworks.com/supportfiles/lidar/data/trainedPointSegNet.mat'; websave('trainedPointSegNet.mat', pretrainedURL); end
Downloading pretrained network (14 MB)...
Используйте helperGenerateTrainingData
поддерживание функции, присоединенной к этому примеру, чтобы сгенерировать обучающие данные от облаков точек лидара. Функция использует облако точек и данные об ограничительной рамке, чтобы создать входные изображения с пятью каналами и пиксельные изображения метки. Чтобы создать пиксельные изображения метки, функция выбирает точки в ограничительной рамке и помечает их ID класса ограничительной рамки. Каждое учебное изображение задано как 64 1 024 5 массивами:
Высота каждого изображения составляет 64 пикселя.
Ширина каждого изображения составляет 1 024 пикселя.
Каждое изображение имеет 5 каналов. Пять каналов задают 3-D координаты облака точек, интенсивности и области значений: .
Визуальное представление обучающих данных следует.
Сгенерируйте учебные изображения с пятью каналами и пиксельные изображения метки.
imagesFolder = fullfile(outputFolder, 'images'); labelsFolder = fullfile(outputFolder, 'labels'); helperGenerateTrainingData(lidarData, groundTruthData, imagesFolder, labelsFolder);
Preprocessing data 100.00% complete
Изображения с пятью каналами сохранены как файлы MAT. Пиксельные метки сохранены как файлы PNG.
Примечание: Обработка может занять время. Код приостанавливает выполнение MATLAB®, пока обработка не завершена.
mageDatastore
и 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 = 225; % Point cloud (channels 1, 2, and 3 are for location, 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));
Чтобы видеть распределение меток класса в наборе данных, используйте countEachLabel
функция.
tbl = countEachLabel(pxds); tbl(:,{'Name','PixelCount','ImagePixelCount'})
ans=3×3 table
Name PixelCount ImagePixelCount
______________ __________ _______________
{'background'} 1.0473e+08 1.0597e+08
{'car' } 9.7839e+05 8.4738e+07
{'truck' } 2.6017e+05 1.9726e+07
Классы в этом наборе данных являются неустойчивыми, который является распространенной проблемой в автомобильных наборах данных, содержащих уличные сцены. Фоновый класс покрывает больше области, чем классы автомобиля и грузовика. Если не обработанный правильно, эта неустойчивость может быть вредна для процесса обучения, потому что изучение смещается в пользу доминирующих классов.
Используйте эти веса, чтобы откорректировать неустойчивость класса. Используйте пиксельные количества метки от tbl.PixelCount
свойство и вычисляет веса класса медианной частоты.
imageFreq = tbl.PixelCount ./ tbl.ImagePixelCount; classWeights = median(imageFreq) ./ imageFreq
classWeights = 3×1
0.0133
1.1423
1.0000
Создайте сеть PointSeg с помощью createPointSeg
поддерживание функции, которая присоединена к примеру. Код возвращает график слоев, который вы используете, чтобы обучить сеть.
inputSize = [64 1024 5]; lgraph = createPointSeg(inputSize, classNames, classWeights);
Используйте analyzeNetwork
(Deep Learning Toolbox) функция, чтобы отобразить интерактивную визуализацию сетевой архитектуры.
analyzeNetwork(lgraph)
Используйте rmsprop
алгоритм оптимизации, чтобы обучить сеть. Задайте гиперпараметры для алгоритма при помощи trainingOptions
функция.
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
к использованию управляющей памяти, когда обучение.
Используйте trainNetwork
(Deep Learning Toolbox) функция, чтобы обучить сеть PointSeg, если doTraining
true
. В противном случае загрузите предварительно обученную сеть.
Если вы обучаете сеть, можно использовать центральный процессор или графический процессор. Используя графический процессор требует Parallel Computing Toolbox™, и CUDA® включил NVIDIA®, графический процессор с вычисляет возможность 3.0 или выше.
if doTraining [net, info] = trainNetwork(trainingData, lgraph, options); else pretrainedNetwork = load('trainedPointSegNet.mat'); net = 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 этого примера, чтобы отобразить результат сегментации по 3-D объекту 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.99209 0.83752 0.67895 0.98685 0.91654
Метрики набора данных предоставляют общий обзор производительности сети. Чтобы видеть удар, каждый класс имеет на общей производительности, смотрите метрики для каждого класса с помощью metrics.ClassMetrics
свойство.
metrics.ClassMetrics
ans=3×3 table
Accuracy IoU MeanBFScore
________ _______ ___________
background 0.99466 0.99212 0.98529
car 0.75977 0.50096 0.82682
truck 0.75814 0.54378 0.77119
Несмотря на то, что сетевая общая производительность хороша, метрики класса показывают, что смещенные классы (автомобиль и грузовик) не сегментируются, а также классы с богатыми данными (фон). Можно улучшать производительность сети путем обучения сети на большем количестве маркированных данных, содержащих классы автомобиля и грузовика.
augmentData
функционируйте случайным образом инвертирует 2D сферическое изображение и сопоставленные метки в горизонтальном направлении.
function out = augmentData(inp) %augmentData 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
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); % Display the color bar. helperPixelLabelColorbar(cmap, classNames); end
helperDisplayLidarOverPointCloud
функционируйте накладывает результат сегментации по 3-D организованному облаку точек.
function helperDisplayLidarOverlayPointCloud(ptCloud, labelMap, numClasses) %helperDisplayLidarOverlayPointCloud Overlay labels over a 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 for each class. 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 8], ... '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] Ван, Юань, Тяньюэ Ши, Пэн Юнь, Лэй Тай и Мин Лю. “PointSeg: Семантическая Сегментация в реальном времени На основе 3D Облака точек LiDAR”. ArXiv:1807.06288 [Cs], 25 сентября 2018. http://arxiv.org/abs/1807.06288.