Этот пример показывает, как задать и создать пользовательский слой классификации пикселей, который использует потерю Игры в кости.
Этот слой может использоваться, чтобы обучить семантические сети сегментации. Чтобы узнать больше о создании пользовательских слоев глубокого обучения, смотрите, Задают Пользовательские Слои Глубокого обучения (Deep Learning Toolbox).
Потеря Игры в кости основана на коэффициенте подобия 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.