Этот пример показывает, как задать и создать пользовательский слой классификации пикселей, который использует потерю Игры в кости.
Этот слой может использоваться, чтобы обучить семантические сети сегментации. Чтобы узнать больше о создании пользовательских слоев глубокого обучения, смотрите, Задают Пользовательские Слои Глубокого обучения.
Потеря Игры в кости основана на коэффициенте подобия Sørensen-игры-в-кости для измерения перекрытия между двумя сегментированными изображениями. Обобщенная потеря Игры в кости [1,2], , поскольку между одним изображением и соответствующая наземная истина дают
,
где количество классов, число элементов по первым двум измерениям , и класс определенный фактор взвешивания, который управляет вкладом, который каждый класс делает к потере. обычно обратная область ожидаемой области:
Это взвешивание помогает противостоять влиянию более крупных областей на счете Игры в кости, облегчающем для сети изучить, как сегментировать меньшие области.
Скопируйте шаблон слоя классификации в новый файл в MATLAB®. Этот шаблон обрисовывает в общих чертах структуру слоя классификации и включает функции, которые задают поведение слоя. Остальная часть примера показывает, как завершить dicePixelClassificationLayer.
classdef dicePixelClassificationLayer < nnet.layer.ClassificationLayer properties % Optional properties end methods function loss = forwardLoss(layer, Y, T) % Layer forward loss function goes here. end function dLdY = backwardLoss(layer, Y, T) % Layer backward loss function goes here. end end end
По умолчанию пользовательские выходные слои имеют следующие свойства:
Имя Имя слоя, заданное как вектор символов или скаляр строки. Чтобы включать этот слой в график слоя, необходимо задать непустое уникальное имя слоя. Если вы обучаете серийную сеть с этим слоем, и Name установлен в '', то программное обеспечение автоматически присваивает имя в учебное время.
Описание Короткое описание слоя, заданного как вектор символов или скаляр строки. Это описание появляется, когда слой отображен в массиве Layer. Если вы не задаете описание слоя, то программное обеспечение отображает имя класса слоя.
Ввод Тип слоя, заданного как вектор символов или скаляр строки. Значение Type появляется, когда слой отображен в массиве Layer. Если вы не задаете тип слоя, то программное обеспечение отображает 'Classification layer' или 'Regression layer'.
Пользовательские слои классификации также имеют следующее свойство:
Классы Классы выходного слоя, заданного как категориальный вектор, массив строк, массив ячеек из символьных векторов или 'auto'. Если Classes является 'auto', то программное обеспечение автоматически устанавливает классы в учебное время. Если вы задаете массив строк или массив ячеек из символьных векторов str, то программное обеспечение устанавливает классы выходного слоя к categorical(str,str). Значением по умолчанию является 'auto'.
Если слой не имеет никаких других свойств, то можно не использовать раздел properties.
Потеря Игры в кости требует, чтобы маленькое постоянное значение предотвратило деление на нуль. Задайте свойство, Epsilon, чтобы содержать это значение.
classdef dicePixelClassificationLayer < nnet.layer.ClassificationLayer properties(Constant) % Small constant to prevent division by zero. Epsilon = 1e-8; end ... end
Создайте функцию, которая создает слой и инициализирует свойства слоя. Задайте любые переменные, требуемые создать слой как входные параметры к функции конструктора.
Задайте дополнительное имя входного параметра, чтобы присвоить свойству Name при создании.
function layer = dicePixelClassificationLayer(name) % layer = dicePixelClassificationLayer(name) creates a Dice % pixel classification layer with the specified name. % Set layer name. layer.Name = name; % Set layer description. layer.Description = 'Dice loss'; end
Создайте функцию с именем forwardLoss, который возвращает взвешенную перекрестную энтропийную потерю между прогнозами, сделанными сетью и учебными целями. Синтаксисом для forwardLoss является loss = forwardLoss(layer, Y, T), где Y является вывод предыдущего слоя, и T представляет учебные цели.
Для семантических проблем сегментации размерности T совпадают с размерностью Y, где Y является 4-D массивом размера H-by-W-by-K-by-N, где K является количеством классов, и N является мини-пакетным размером.
Размер Y зависит от вывода предыдущего слоя. Чтобы гарантировать, что Y одного размера как T, необходимо включать слой, который выводит правильный размер перед выходным слоем. Например, чтобы гарантировать, что Y является 4-D массивом музыки прогноза к классам K, можно включать полносвязный слой размера K или сверточный слой с фильтрами K, сопровождаемыми softmax слоем перед выходным слоем.
function loss = forwardLoss(layer, Y, T) % loss = forwardLoss(layer, Y, T) returns the Dice loss between % the predictions Y and the training targets T. % Weights by inverse of region size. W = 1 ./ sum(sum(T,1),2).^2; intersection = sum(sum(Y.*T,1),2); union = sum(sum(Y.^2 + T.^2, 1),2); numer = 2*sum(W.*intersection,3) + layer.Epsilon; denom = sum(W.*union,3) + layer.Epsilon; % Compute Dice score. dice = numer./denom; % Return average Dice loss. N = size(Y,4); loss = sum((1-dice))/N; end
Создайте обратную функцию потерь, которая возвращает производные потери Игры в кости относительно прогнозов Y. Синтаксисом для backwardLoss является loss = backwardLoss(layer, Y, T), где Y является вывод предыдущего слоя, и T представляет учебные цели.
Размерности Y и T совпадают с входными параметрами в forwardLoss.
function dLdY = backwardLoss(layer, Y, T) % dLdY = backwardLoss(layer, Y, T) returns the derivatives of % the Dice loss with respect to the predictions Y. % Weights by inverse of region size. W = 1 ./ sum(sum(T,1),2).^2; intersection = sum(sum(Y.*T,1),2); union = sum(sum(Y.^2 + T.^2, 1),2); numer = 2*sum(W.*intersection,3) + layer.Epsilon; denom = sum(W.*union,3) + layer.Epsilon; N = size(Y,4); dLdY = (2*W.*Y.*numer./denom.^2 - 2*W.*T./denom)./N; end
Завершенный слой обеспечивается в dicePixelClassificationLayer.m.
classdef dicePixelClassificationLayer < nnet.layer.ClassificationLayer % This layer implements the generalized dice loss function for training % semantic segmentation networks. properties(Constant) % Small constant to prevent division by zero. Epsilon = 1e-8; end methods function layer = dicePixelClassificationLayer(name) % layer = dicePixelClassificationLayer(name) creates a Dice % pixel classification layer with the specified name. % Set layer name. layer.Name = name; % Set layer description. layer.Description = 'Dice loss'; end function loss = forwardLoss(layer, Y, T) % loss = forwardLoss(layer, Y, T) returns the Dice loss between % the predictions Y and the training targets T. % Weights by inverse of region size. W = 1 ./ sum(sum(T,1),2).^2; intersection = sum(sum(Y.*T,1),2); union = sum(sum(Y.^2 + T.^2, 1),2); numer = 2*sum(W.*intersection,3) + layer.Epsilon; denom = sum(W.*union,3) + layer.Epsilon; % Compute Dice score. dice = numer./denom; % Return average Dice loss. N = size(Y,4); loss = sum((1-dice))/N; end function dLdY = backwardLoss(layer, Y, T) % dLdY = backwardLoss(layer, Y, T) returns the derivatives of % the Dice loss with respect to the predictions Y. % Weights by inverse of region size. W = 1 ./ sum(sum(T,1),2).^2; intersection = sum(sum(Y.*T,1),2); union = sum(sum(Y.^2 + T.^2, 1),2); numer = 2*sum(W.*intersection,3) + layer.Epsilon; denom = sum(W.*union,3) + layer.Epsilon; N = size(Y,4); dLdY = (2*W.*Y.*numer./denom.^2 - 2*W.*T./denom)./N; end end end
Для совместимости графического процессора функции уровня должны поддержать входные параметры и возвратить выходные параметры типа gpuArray. Любые другие функции, используемые слоем, должны сделать то же самое.
Функции MATLAB использовали в forwardLoss и backwardLoss в dicePixelClassificationLayer вся поддержка входные параметры gpuArray, таким образом, слоем является совместимый графический процессор.
Создайте экземпляр слоя.
layer = dicePixelClassificationLayer('dice');Проверяйте валидность слоя слоя с помощью checkLayer. Задайте допустимый входной размер, чтобы быть размером одного наблюдения за типичным входом к слою. Слой ожидает H-by-W-by-K-by-N входные параметры массивов, где K является количеством классов, и N является количеством наблюдений в мини-пакете.
numClasses = 2;
validInputSize = [4 4 numClasses];
checkLayer(layer,validInputSize, 'ObservationDimension',4)Running nnet.checklayer.OutputLayerTestCase .......... ....... Done nnet.checklayer.OutputLayerTestCase __________ Test Summary: 17 Passed, 0 Failed, 0 Incomplete, 0 Skipped. Time elapsed: 1.6227 seconds.
Тестовые сводные отчеты количество переданных, отказавших, неполные, и пропущенные тесты.
Создайте семантическую сеть сегментации, которая использует dicePixelClassificationLayer.
layers = [
imageInputLayer([32 32 1])
convolution2dLayer(3,64,'Padding',1)
reluLayer
maxPooling2dLayer(2,'Stride',2)
convolution2dLayer(3,64,'Padding',1)
reluLayer
transposedConv2dLayer(4,64,'Stride',2,'Cropping',1)
convolution2dLayer(1,2)
softmaxLayer
dicePixelClassificationLayer('dice')]layers =
10x1 Layer array with layers:
1 '' Image Input 32x32x1 images with 'zerocenter' normalization
2 '' Convolution 64 3x3 convolutions with stride [1 1] and padding [1 1 1 1]
3 '' ReLU ReLU
4 '' Max Pooling 2x2 max pooling with stride [2 2] and padding [0 0 0 0]
5 '' Convolution 64 3x3 convolutions with stride [1 1] and padding [1 1 1 1]
6 '' ReLU ReLU
7 '' Transposed Convolution 64 4x4 transposed convolutions with stride [2 2] and output cropping [1 1]
8 '' Convolution 2 1x1 convolutions with stride [1 1] and padding [0 0 0 0]
9 '' Softmax softmax
10 'dice' Classification Output Dice loss
Загрузите данные тренировки для семантической сегментации с помощью imageDatastore и pixelLabelDatastore.
dataSetDir = fullfile(toolboxdir('vision'),'visiondata','triangleImages'); imageDir = fullfile(dataSetDir,'trainingImages'); labelDir = fullfile(dataSetDir,'trainingLabels'); imds = imageDatastore(imageDir); classNames = ["triangle" "background"]; labelIDs = [255 0]; pxds = pixelLabelDatastore(labelDir, classNames, labelIDs);
Сопоставьте изображение и пиксельные данные о метке с помощью pixelLabelImageDatastore.
ds = pixelLabelImageDatastore(imds,pxds);
Установите опции обучения и обучите сеть.
options = trainingOptions('sgdm', ... 'InitialLearnRate',1e-2, ... 'MaxEpochs',100, ... 'LearnRateDropFactor',1e-1, ... 'LearnRateDropPeriod',50, ... 'LearnRateSchedule','piecewise', ... 'MiniBatchSize',128); net = trainNetwork(ds,layers,options);
Training on single GPU. Initializing image normalization. |========================================================================================| | Epoch | Iteration | Time Elapsed | Mini-batch | Mini-batch | Base Learning | | | | (hh:mm:ss) | Accuracy | Loss | Rate | |========================================================================================| | 1 | 1 | 00:00:03 | 27.89% | 0.8346 | 0.0100 | | 50 | 50 | 00:00:34 | 89.67% | 0.6384 | 0.0100 | | 100 | 100 | 00:01:09 | 94.35% | 0.5024 | 0.0010 | |========================================================================================|
Оцените обучивший сеть путем сегментации тестового изображения и отображения результата сегментации.
I = imread('triangleTest.jpg');
[C,scores] = semanticseg(I,net);
B = labeloverlay(I,C);
figure
imshow(imtile({I,B}))![]()
Crum, Уильям Р., Оскар Камара и Дерек ЛГ Хилл. "Обобщенное перекрытие измеряется для оценки и валидации в медицинском анализе изображения". Транзакции IEEE на медицинской обработке изображений 25.11 (2006): 1451-1461.
Sudre, Кэрол Х., и др. "Обобщенные Игры в кости накладываются как функция потерь глубокого обучения для очень несбалансированных сегментаций". Глубокое обучение в Медицинском Анализе изображения и Многомодальном Изучении для Клинической Поддержки принятия решений. Спрингер, Хан, 2017. 240-248.
checkLayer | pixelLabelDatastore | semanticseg | trainNetwork | trainingOptions