В этом примере показано, как обучить сеть семантической сегментации PointSeg на 3-D данных облака точек лидара.
PointSeg [1] является сверточной нейронной сетью (CNN) для выполнения сквозной семантической сегментации дорожных объектов на основе организованного лидара облака точек. При использовании таких методов, как atrous spatial pyramid uling (ASPP) и блоки сжатия и возбуждения, сеть обеспечивает улучшенные результаты сегментации. Процедура обучения, показанная в этом примере, требует 2-D сферических проективных изображений в качестве входов для нейронной сети для глубокого обучения.
Этот пример использует набор данных сцены шоссе, собранный с помощью датчика OS1 Ouster. Он содержит организованные сканы облака точек лидара сцен шоссе и соответствующие основные истины для объектов автомобиля и грузовика. Размер файла данных составляет приблизительно 760 МБ.
Выполните этот код, чтобы загрузить набор данных сцены шоссе. Набор данных содержит 1617 облаков точек, сохраненных как 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('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
вспомогательная функция, присоединенная к этому примеру, для генерации обучающих данных из лидара облаков точек. Функция использует облако точек и данные ограничивающего прямоугольника, чтобы создать пятиканальные входные изображения и изображения пиксельных меток. Чтобы создать изображения меток пикселей, функция выбирает точки внутри ограничивающего прямоугольника и помечает их идентификатором класса ограничивающих прямоугольников. Каждое обучающее изображение задается как массив 64 на 1024 на 5:
Высота каждого изображения составляет 64 пикселя.
Ширина каждого изображения составляет 1024 пикселя.
Каждое изображение имеет 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
и P ixelLabelDatastore
Используйте imageDatastore
объект для извлечения и хранения пяти каналов 2-D сферических изображений с помощью helperImageMatReader
вспомогательная функция, являющаяся пользовательской программой чтения файлов MAT. Эта функция присоединена к этому примеру как вспомогательный файл.
imds = imageDatastore(imagesFolder, ... 'FileExtensions', '.mat', ... 'ReadFcn', @helperImageMatReader);
Используйте pixelLabelDatastore
объект для хранения пиксельных меток из изображений меток. Объект сопоставляет каждую пиксельную метку с именем класса. В этом примере легковые и грузовые автомобили являются единственными объектами интереса; все другие пиксели являются фоном. Задайте эти классы (автомобиль, грузовик и фон) и присвойте уникальный идентификатор метки каждому классу.
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
function, заданная в разделе Support 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
function, заданная в разделе Support Functions этого примера. Эта функция случайным образом переворачивает сферическое 2-D изображение и связанные с ним метки в горизонтальном направлении. Применить увеличение данных только к набору обучающих данных.
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
. В противном случае загружает предварительно обученную сеть
Если вы обучаете сеть, можно использовать CPU или GPU. Для использования GPU требуется Parallel Computing Toolbox™ и графический процессор с поддержкой CUDA ® NVIDIA ®. Для получения дополнительной информации смотрите Поддержку GPU by Release (Parallel Computing Toolbox).
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
вспомогательная функция, заданная в разделе Вспомогательные функции этого примера, для отображения результата сегментации над 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);
The semanticseg
функция возвращает результаты сегментации на наборе тестовых данных как PixelLabelDatastore
объект. Функция записывает фактические данные о пиксельных метках для каждого тестового изображения в imdsTest
объект на диск в расположении, заданном 'WriteLocation'
аргумент.
Используйте evaluateSemanticSegmentation
функция для вычисления метрики семантической сегментации из результатов тестового набора.
metrics = evaluateSemanticSegmentation(pxdsResults, pxdsTest, 'Verbose', false);
Можно измерить сумму перекрытия для класса с помощью метрики «перекресток по соединению» (IoU).
The 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
Несмотря на то, что общая эффективность сети хороша, метрики класса показывают, что смещенные классы (автомобиль и грузовик) не сегментируются, как и классы с обильными данными (фон). Можно улучшить эффективность сети путем обучения сети на более маркированных данных, содержащих классы автомобилей и грузовиков.
The augmentData
функция случайным образом разворачивает 2-D сферическое изображение и связанные с ним метки в горизонтальном направлении.
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
The helperDisplayLidarOverlayImage
функция накладывает карту семантической сегментации на канал интенсивности 2-D сферического изображения. Функция также изменяет размер наложенного изображения для лучшей визуализации.
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
The 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
The 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
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
[1] Ван, Юань, Тяньюэ Ши, Пэн Юн, Лэй Тай и Мин Лю. PointSeg: семантическая сегментация в реальном времени на основе 3D LiDAR Point Cloud ". ArXiv:1807.06288 [Cs], 25 сентября 2018 года. http://arxiv.org/abs/1807.06288.