定义使用 Tversky 损失的自定义像素分类层
此示例说明如何定义和创建使用 Tversky 损失的自定义像素分类层。
此层可用于训练语义分割网络。要了解有关创建自定义深度学习层的详细信息,请参阅定义自定义深度学习层。
Tversky 损失
Tversky 损失基于 Tversky 指数,用于测量两个分割图像之间的重叠 [1]。一个图像 较其对应真实值 之间的 Tversky 指数 由下式给出
对应于类, 对应于不在 类中。
是沿 的前两个维度的元素数目。
和 是控制每个类的假正和假负对损失的贡献的加权因子。
基于类数目 的损失 由下式给出
分类层模板
在 MATLAB® 中将分类层模板复制到一个新文件中。此模板提供分类层的大致结构,并包括用于定义层行为的函数。示例的后续部分将说明如何完成 tverskyPixelClassificationLayer
。
classdef tverskyPixelClassificationLayer < nnet.layer.ClassificationLayer properties % Optional properties end methods function loss = forwardLoss(layer, Y, T) % Layer forward loss function goes here end end end
声明层属性
默认情况下,自定义输出层具有以下属性:
Name
- 层名称,指定为字符向量或字符串标量。要将此层包括在层图中,您必须指定非空的唯一层名称。如果您使用此层训练串行网络并且Name
设置为''
,则软件会在训练时自动指定名称。Description
- 层的单行描述,指定为字符向量或字符串标量。当层显示在Layer
数组中时,会出现此描述。如果没有指定层描述,则软件将显示层类名。Type
- 层的类型,指定为字符向量或字符串标量。当层显示在Layer
数组中时,会显示Type
的值。如果未指定层类型,则软件将显示'Classification layer'
或'Regression layer'
。
自定义分类层还具有以下属性:
Classes
- 输出层的类,指定为分类向量、字符串数组、字符向量元胞数组或'auto'
。如果Classes
是'auto'
,则软件会在训练时自动设置类。如果您指定字符串数组或字符向量元胞数组str
,则软件会将输出层的类设置为categorical(str,str)
。默认值为'auto'
。
如果层没有其他属性,则您可以省略 properties
部分。
Tversky 损失必须具有一个小常量值以防止除以零错误。指定属性 Epsilon
以保留此值。它还需要两个可变属性:Alpha
和 Beta
,分别控制假正和假负的加权。
classdef tverskyPixelClassificationLayer < nnet.layer.ClassificationLayer properties(Constant) % Small constant to prevent division by zero. Epsilon = 1e-8; end properties % Default weighting coefficients for false positives and false negatives Alpha = 0.5; Beta = 0.5; end ... end
创建构造函数
创建用于构造层并初始化层属性的函数。将创建层所必需的所有变量指定为构造函数的输入。
指定可选的输入参数 name,以便在创建层时赋给 Name
属性。
function layer = tverskyPixelClassificationLayer(name, alpha, beta) % layer = tverskyPixelClassificationLayer(name) creates a Tversky % pixel classification layer with the specified name. % Set layer name layer.Name = name; % Set layer properties layer.Alpha = alpha; layer.Beta = beta; % Set layer description layer.Description = 'Tversky loss'; end
创建前向损失函数
创建名为 forwardLoss
的函数,该函数返回网络做出的预测和训练目标之间的加权交叉熵损失。forwardLoss
的语法是 loss = forwardLoss(layer,Y,T)
,其中 Y
是前一个层的输出,T
表示训练目标。
对于语义分割问题,T
的维度与 Y
的维度相匹配,其中 Y
是 4 维数组,大小为 H
×W
×K
×N
,其中 K
是类的数量,N
是小批量大小。
Y
的大小取决于前一个层的输出。为了确保 Y
与 T
的大小相同,您必须在输出层之前包含一个输出正确大小的层。例如,为了确保 Y
是 K
个类的预测分数的四维数组,您可以包含一个大小为 K
的全连接层或一个具有 K
个滤波器的卷积层,后跟一个 softmax 层,然后是输出层。
function loss = forwardLoss(layer, Y, T) % loss = forwardLoss(layer, Y, T) returns the Tversky loss between % the predictions Y and the training targets T. Pcnot = 1-Y; Gcnot = 1-T; TP = sum(sum(Y.*T,1),2); FP = sum(sum(Y.*Gcnot,1),2); FN = sum(sum(Pcnot.*T,1),2); numer = TP + layer.Epsilon; denom = TP + layer.Alpha*FP + layer.Beta*FN + layer.Epsilon; % Compute Tversky index lossTIc = 1 - numer./denom; lossTI = sum(lossTIc,3); % Return average Tversky index loss N = size(Y,4); loss = sum(lossTI)/N; end
后向损失函数
由于 forwardLoss
函数完全支持自动微分,因此无需为后向损失创建函数。
有关支持自动微分的函数列表,请参阅List of Functions with dlarray Support。
完成的层
tverskyPixelClassificationLayer.m
中提供了完成的层,它作为支持文件包含在示例中。
classdef tverskyPixelClassificationLayer < nnet.layer.ClassificationLayer % This layer implements the Tversky loss function for training % semantic segmentation networks. % References % Salehi, Seyed Sadegh Mohseni, Deniz Erdogmus, and Ali Gholipour. % "Tversky loss function for image segmentation using 3D fully % convolutional deep networks." International Workshop on Machine % Learning in Medical Imaging. Springer, Cham, 2017. % ---------- properties(Constant) % Small constant to prevent division by zero. Epsilon = 1e-8; end properties % Default weighting coefficients for False Positives and False % Negatives Alpha = 0.5; Beta = 0.5; end methods function layer = tverskyPixelClassificationLayer(name, alpha, beta) % layer = tverskyPixelClassificationLayer(name, alpha, beta) creates a Tversky % pixel classification layer with the specified name and properties alpha and beta. % Set layer name. layer.Name = name; layer.Alpha = alpha; layer.Beta = beta; % Set layer description. layer.Description = 'Tversky loss'; end function loss = forwardLoss(layer, Y, T) % loss = forwardLoss(layer, Y, T) returns the Tversky loss between % the predictions Y and the training targets T. Pcnot = 1-Y; Gcnot = 1-T; TP = sum(sum(Y.*T,1),2); FP = sum(sum(Y.*Gcnot,1),2); FN = sum(sum(Pcnot.*T,1),2); numer = TP + layer.Epsilon; denom = TP + layer.Alpha*FP + layer.Beta*FN + layer.Epsilon; % Compute tversky index lossTIc = 1 - numer./denom; lossTI = sum(lossTIc,3); % Return average tversky index loss. N = size(Y,4); loss = sum(lossTI)/N; end end end
GPU 兼容性
tverskyPixelClassificationLayer
中的 forwardLoss
使用的 MATLAB 函数都支持 gpuArray
输入,因此该层与 GPU 兼容。
检查输出层有效性
创建层的一个实例。
layer = tverskyPixelClassificationLayer('tversky',0.7,0.3);
使用 checkLayer
检查层的有效性。将有效输入大小指定为层的典型输入的单个观测值的大小。该层需要一个 H
×W
×K
×N
数组输入,其中 K
是类的数量,N
是小批量中的观测值数目。
numClasses = 2;
validInputSize = [4 4 numClasses];
checkLayer(layer,validInputSize, 'ObservationDimension',4)
Skipping GPU tests. No compatible GPU device found. Skipping code generation compatibility tests. To check validity of the layer for code generation, specify the 'CheckCodegenCompatibility' and 'ObservationDimension' options. Running nnet.checklayer.TestOutputLayerWithoutBackward ........ Done nnet.checklayer.TestOutputLayerWithoutBackward __________ Test Summary: 8 Passed, 0 Failed, 0 Incomplete, 2 Skipped. Time elapsed: 0.56419 seconds.
测试摘要报告通过、失败、不完整和跳过的测试数量。
在语义分割网络中使用自定义层
创建一个使用 tverskyPixelClassificationLayer
的语义分割网络。
layers = [ imageInputLayer([32 32 1]) convolution2dLayer(3,64,'Padding',1) batchNormalizationLayer reluLayer maxPooling2dLayer(2,'Stride',2) convolution2dLayer(3,64,'Padding',1) reluLayer transposedConv2dLayer(4,64,'Stride',2,'Cropping',1) convolution2dLayer(1,2) softmaxLayer tverskyPixelClassificationLayer('tversky',0.3,0.7)];
使用 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);
使用数据存储 combine
关联图像和像素标签数据。
ds = combine(imds,pxds);
设置训练选项并训练网络。
options = trainingOptions('adam', ... 'InitialLearnRate',1e-3, ... 'MaxEpochs',100, ... 'LearnRateDropFactor',5e-1, ... 'LearnRateDropPeriod',20, ... 'LearnRateSchedule','piecewise', ... 'MiniBatchSize',50); net = trainNetwork(ds,layers,options);
Training on single CPU. Initializing input data normalization. |========================================================================================| | Epoch | Iteration | Time Elapsed | Mini-batch | Mini-batch | Base Learning | | | | (hh:mm:ss) | Accuracy | Loss | Rate | |========================================================================================| | 1 | 1 | 00:00:02 | 50.32% | 1.2933 | 0.0010 | | 13 | 50 | 00:00:23 | 98.83% | 0.0990 | 0.0010 | | 25 | 100 | 00:00:42 | 99.32% | 0.0550 | 0.0005 | | 38 | 150 | 00:01:02 | 99.38% | 0.0461 | 0.0005 | | 50 | 200 | 00:01:21 | 99.48% | 0.0397 | 0.0003 | | 63 | 250 | 00:01:41 | 99.47% | 0.0380 | 0.0001 | | 75 | 300 | 00:02:00 | 99.54% | 0.0344 | 0.0001 | | 88 | 350 | 00:02:20 | 99.51% | 0.0352 | 6.2500e-05 | | 100 | 400 | 00:02:39 | 99.56% | 0.0330 | 6.2500e-05 | |========================================================================================| Training finished: Max epochs completed.
通过分割测试图像并显示分割结果来评估训练的网络。
I = imread('triangleTest.jpg');
[C,scores] = semanticseg(I,net);
B = labeloverlay(I,C);
montage({I,B})
参考资料
[1] Salehi, Seyed Sadegh Mohseni, Deniz Erdogmus, and Ali Gholipour."Tversky loss function for image segmentation using 3D fully convolutional deep networks."International Workshop on Machine Learning in Medical Imaging.Springer, Cham, 2017.
另请参阅
checkLayer
| trainingOptions
| trainNetwork
| pixelLabelDatastore
(Computer Vision Toolbox) | semanticseg
(Computer Vision Toolbox)
相关主题
- 定义自定义深度学习层
- Getting Started with Semantic Segmentation Using Deep Learning (Computer Vision Toolbox)
- 使用深度学习进行语义分割