本章阐述了如何基于深度学习实现语义分割,涵盖训练阶段与推理阶段的具体应用。
通过 semantic segmentation语义分割,我们利用深度学习(DL)网络将输入图像的每个像素分配到一个类别。
语义分割的结果是一个输出图像,其中像素值表示输入图像中对应像素被分配的类别。因此,在 HALCON 中,输出图像的尺寸与输入图像相同。对于一般的深度学习网络,表示更复杂特征的深层特征图通常比输入图像尺寸更小(参见 深度学习 中“网络与训练过程”一节)。为获得与输入相同尺寸的输出,HALCON 采用包含两个组件的分割网络:编码器和解码器。编码器确定输入图像的特征,例如用于基于深度学习的分类。由于这些信息以压缩格式“编码”存储,需要解码器将其还原为预期结果——本例中即为将每个像素分配至特定类别。需注意的是,在像素分类过程中,同一类别的重叠实例不会被识别为独立个体。
边缘检测 是语义分割的特殊情况,模型被训练用于区分两个类别:“edge”和“background”。更多信息请参阅 “解决方案指南 I - 基础篇”。
基于深度学习的语义分割功能已集成于 HALCON 更通用的深度学习模型中。有关该模型的详细信息,请参阅 深度学习 / 模型 一章。应用深度学习所需的具体系统要求,请参阅 HALCON “安装指南”。
以下各节将介绍语义分割所需的一般工作流程、相关数据与参数信息,以及评估指标的说明。
本节描述基于深度学习的语义分割任务的一般工作流程。该流程分为四个部分:数据预处理、模型训练、训练模型评估以及新图像推理。在此我们假设您的数据集已完成标注,详见下文“数据”部分。可参考 HDevelop 示例系列 segment_pill_defects_deep_learning 了解应用实例。示例 segment_edges_deep_learning_with_retraining 则完整展示了边缘提取应用的工作流程。
本部分介绍如何对数据进行预处理。具体步骤也可在 HDevelop 示例 segment_pill_defects_deep_learning_1_preprocess.hdev 中查看。
需要传输的是训练数据集中哪些图像所包含的信息。该操作通过以下函数实现:
read_dl_dataset_segmentation。
由此创建了一个名为 DLDataset 的字典,它作为数据库存储了关于数据的所有必要信息。有关数据及其传输方式的更多信息,请参阅下文的“数据”部分以及 深度学习 / 模型 一章。
将字典 DLDataset 表示的数据集进行拆分。可通过以下函数实现:
split_dl_dataset。
生成的分割结果将通过键 split 保存至 DLDataset 中每个样本条目中。
现在您可以对数据集进行预处理。为此,您可以使用以下函数:
preprocess_dl_dataset。
本函数还提供了如何实施定制化预处理函数的指导。
要使用此函数,需指定预处理参数,例如图像尺寸。对于后者,应选择能清晰识别待分割区域的最小图像尺寸。将所有参数及其值存储在字典 DLPreprocessParam中,为此可使用以下函数:
create_dl_preprocess_param。
我们建议保存此字典 DLPreprocessParam,以便在后续推理阶段能够访问预处理参数值。
在数据集预处理过程中,preprocess_dl_dataset 还会为训练数据集生成权重图像 weight_image。该图像为每个类别分配其在训练过程中像素获得的权重(“class weights”),具体详见下文“模型参数与超参数”一节。
本部分介绍如何训练深度学习语义分割模型。具体步骤也可在 HDevelop 示例 segment_pill_defects_deep_learning_2_train.hdev 中查看。
必须读取网络使用算子
模型参数需要进行设置通过算子
此类参数例如 'image_dimensions' 和 'class_ids',详见 文档。get_dl_model_param
您可随时获取当前参数值使用算子
设置训练参数并将其存储在字典 TrainParam 中。这些参数包括:
超参数,概述请参见下文“模型参数与超参数”一节及 深度学习 一章。
用于可能的数据增强的参数(可选)。
用于训练期间评估的参数。
用于训练结果可视化的参数。
用于序列化的参数。
可通过以下函数实现
create_dl_train_param。
训练模型。可以通过以下函数实现
train_dl_model。
该函数需要:
模型句柄 DLModelHandle
包含数据信息的字典 DLDataset
包含训练参数的字典 'TrainParam'
训练应运行的 epochs(周期) 次数信息。
若使用 train_dl_model 函数,则会可视化总损失值及可选的评估指标。
本部分对语义分割模型进行评估。具体步骤亦可在 HDevelop 示例 segment_pill_defects_deep_learning_3_evaluate.hdev 中查看。
设置可能影响评估的模型参数,例如 'batch_size',使用算子
该评估可通过以下函数便捷完成
evaluate_dl_model。
字典 EvaluationResult 存储了请求的评估指标。您可以可视化评估结果使用函数
dev_display_segmentation_evaluation。
本部分涵盖深度学习语义分割模型的应用。具体步骤亦可在 HDevelop 示例 segment_pill_defects_deep_learning_4_infer.hdev 中查看。
设置参数,例如 'batch_size' 使用算子
为每张图像生成一个数据字典 DLSample。这可通过以下函数实现
gen_dl_samples_from_images。
对图像进行预处理,如同训练时所做的那样。我们建议使用以下函数进行操作
preprocess_dl_samples。
在预处理步骤中保存字典 DLPreprocessParam 后,可直接将其作为输入来指定所有参数值。
应用模型使用算子
从字典 'DLResultBatch' 中检索结果。可通过对分割图像应用算子 ,选取特定类别的区域。
threshold
我们将用于训练和评估的数据与用于推理的数据区分开来。后者仅包含原始图像,前者则包含带有信息标注和真值标注的图像。您需要为每个像素提供信息,定义其所属类别(通过 segmentation_image 实现,具体说明见下文)。
作为基本概念,该模型通过字典处理数据,即它接收输入数据时采用字典 DLSample,并分别返回字典 DLResult 和 DLTrainResult。有关数据处理的更多信息,请参阅 深度学习 / 模型。
训练数据用于针对特定任务训练网络。该数据集包含图像及其对应信息,需以模型可处理的形式提供。关于图像要求,请参阅下文“图像”部分的详细说明。图像及其真值标注信息通过字典 DLDataset 提供,每个样本均配有对应的 segmentation_image,该图像为每个像素定义了类别。
不同类别是网络区分出的集合或分类。它们被设置在字典 DLDataset 中,并通过算子 传递给模型。set_dl_model_param
在 语义分割 中,我们特别提醒您注意两种特殊情况:“background”类别以及声明为“ignore”的类别:
'background' 背景类别:
网络将背景类别视为普通类别处理。设置背景类别并非必需。但若数据集中存在某些您不关注的类别(尽管网络仍需学习这些类别),可将其统一标记为“background”。此举将使背景类别的多样性得到提升。更多信息请参阅函数 preprocess_dl_samples。
'ignore' 忽略类别:
可以将一个或多个类别标记为“ignore”。分配到“ignore”类别的像素将被损失函数忽略,同时在所有度量和评估中也被忽略。有关损失函数的更多信息,请参阅 深度学习 一章中的“网络与训练过程”一节。 网络不会将任何像素分类到标记为“ignore”的类别中。此外,标记为该类别的像素将与其他像素相同,被网络归类至非“ignore”类别。如下图所示示例,这意味着网络将同时处理“border”类别的像素,但不会将任何像素归类至“border”类别。可通过 参数 set_dl_model_param'ignore_class_ids' 声明类别为“ignore”。
在 边缘提取 中仅区分两类:“border”边界与“background”背景。“border”类与普通类标注方式相同。因此仅标注一类,该类称为“border”。
DLDataset
本词典作为数据库使用,即存储网络所需的所有数据信息,例如图像名称与路径、类别等。通用概念及关键条目请参阅 深度学习 / 模型 文档。仅适用于语义分割的键涉及
segmentation_image(参见下方条目)。通过 segmentation_dir 和
segmentation_file_name 键,您可指定图像的命名规则及存储位置。
segmentation_image
为了使网络能够学习不同类别成员的外观特征,你需要为训练数据集中每张图像的每个像素标注其所属类别。具体实现方式是:对于输入图像中的每个像素点,将其对应的分类信息以像素值的形式存储在相应的
segmentation_image 中。这些标注即为真实标注。
| ( 1) | ( 2) |
segmentation_image 示意图。为便于可视化,采用灰度值表示数字。
(1) 输入图像。
(2) 对应的 segmentation_image 提供类别标注,
0:background(白色),1:orange,2:lemon,3:apple,4: border(黑色)作为独立类别以便声明为“ignore”。
您需要足够的训练数据将其划分为三个子集:一个用于训练,一个用于验证,一个用于测试神经网络。这些子集最好是独立且同分布的(参见 深度学习 一章中的“数据”一节)。划分时可使用 split_dl_data_set 函数。
无论应用场景如何,网络对图像均有尺寸、灰度值范围及类型等要求。具体数值取决于网络本身,不同网络的具体参数请参阅 文档。对于已加载的网络,可通过 read_dl_model 查询参数。为满足这些要求,您可能需要对图像进行预处理。对整个样本(包括图像)的标准预处理已在 get_dl_model_parampreprocess_dl_samples 中实现,本函数还提供了如何实现自定义预处理函数的指导。
网络输出取决于任务:
作为输出,该算子将返回一个名为 的字典,其中包含总损失的当前值以及模型中所有其他损失的值。
DLTrainResult
作为输出,网络将为每个样本返回一个名为 的字典。对于语义分割任务,该字典将为每张输入图像包含以下两张图像的句柄:
DLResult
segmentation_image:一张图像,其中每个像素的值对应于其所属像素被分配到的类别(见下图)。
segmentation_confidence:一张图像,其中每个像素都包含该像素在输入图像中分类结果的置信度值(见下图)。
| ( 1) | ( 2) |
segmentation_image:即使声明为“ignore”的类别的像素(见上图)也会被分类。(2) segmentation_confidence。
除了 深度学习 中介绍的通用 DL 超参数外,还存在另一个与语义分割相关的超参数:
'class weights',详见下文说明。
对于语义分割模型,模型参数以及超参数(除“class weights”外)均通过 进行设置。模型参数的详细说明请参见 set_dl_model_param。get_dl_model_param
请注意,由于内存占用较大,通常只能进行小批量训练。因此训练速度较慢,建议使用高于分类任务的动量参数。HDevelop 示例文件 segment_pill_defects_deep_learning_2_train.hdev 为 HALCON中 分割网络的训练提供了良好的初始参数值。
通过超参数“class weights”,您可以在训练过程中为每个类别分配其像素的权重。通过为不同类别赋予不同权重,可强制网络以不同重要性学习各类别。这在某些场景下尤为有用,例如缺陷检测——当某类缺陷在图像中仅占极小比例时,若该缺陷类别在图像中占据主导地位。在此类场景中,若网络将所有像素均判定为背景(即“非缺陷”),通常能获得较好的损失值。为不同类别分配差异化权重有助于重新平衡分布。简言之,您可通过调整损失值,使训练重点集中在您认定的关键像素上。
网络通过 weight_image 获取这些权重,该图像为每个训练样本创建。在 weight_image 中,每个像素值对应输入图像在训练过程中对应像素获得的权重。可通过以下两种方法创建这些图像:
calculate_dl_segmentation_class_weights 可帮助您创建类权重。该函数采用逆类频率权重概念。
gen_dl_segmentation_weight_images 使用类权重生成 weight_image。
此步骤必须在训练前完成。通常在预处理阶段进行,属于预处理函数 preprocess_dl_dataset 的一部分。请注意,该超参数在函数中被称为 class_weights 或
。下图展示了不同权重设置下图像的呈现效果。
ClassWeights
请注意,当将图像的特定区域权重设为 0.0 时,这些像素不会对损失值产生影响(有关损失值的更多信息,请参阅 深度学习 中“网络及其训练”一节)。
| ( 1) | ( 2) |
weight_image 的示意图。为便于可视化,采用灰度值表示数值。(1) segmentation_image 定义图像中每个像素的类别:0:background(白色),1:orange,2:lemon,3:apple,4:border(黑色),该类别被声明为“ignore”。(2) 对应 weight_image 提供类权重,background:1.0,orange:30.0,lemon:75.0。声明为“ignore”的类别像素(此处为边界类)将被忽略并赋予权重 0.0。
对于语义分割,HALCON支持以下评估指标。请注意,计算图像的此类指标时需要相关的真值信息。下文所述的所有单张图像评估指标( mean_iou)均可扩展至任意数量的图像集。具体实现方式是将所有输出图像组合成一张大型图像,以此为基础进行指标计算。需注意:计算过程中将忽略所有标记为“ignore”类别的像素。
pixel_accuracy像素精度即所有被正确预测类别标签的像素与总像素数量之比。
| ( 1) | ( 2) | ( 3) |
pixel_accuracy 的可视化示例:(1) segmentation_image 定义每个像素的真实类别(参见上文“数据”部分)。声明为“ignore”类别的像素以黑色标注。(2) 输出图像中,声明为“ignore”类别的像素同样被分类。(3) 像素精度即橙色区域总面积之比。注:标记为“ignore”类别的像素将被忽略。
class_pixel_accuracy每类像素准确率仅考虑单个类别的像素。其定义为正确预测像素数与该类别标注像素总数之比。
若某类未出现,则其 class_pixel_accuracy 值设为 -1 且不计入平均值 mean_accuracy 的计算。
mean_accuracy
平均准确率定义为所有出现类别的类像素准确率(class_pixel_accuracy)的平均值。
class_iou特定类别的交并比(intersection over union,IoU)表示正确预测像素与标注像素和预测像素并集之比。从视觉上理解,即为区域交集面积与区域并集面积之比,详见下图。
若某类未出现,则其 class_iou 值设为 -1 且不计入 mean_iou 的计算。
| ( 1) | ( 2) | ( 3) |
class_iou 的可视化示例,此处仅展示苹果类别的结果。(1) segmentation_image 定义了每个像素的真实类别(参见“数据”章节)。标记为“ignore”的类别像素以黑色显示。(2) 输出图像,其中标记为“ignore”的类别像素同样被分类。
(3) 交并比值即为苹果类像素区域的交集面积与并集面积之比。需注意:标记为“ignore”类别的像素将被排除计算。
mean_iou
平均交并比定义为所有出现类别的每类交并比(class_iou)的平均值。需注意,每个出现类别对该指标的影响均等,与其所含像素数量无关。
frequency_weighted_iou至于平均交并比,首先计算每类交并比。但每个出现类别对该指标的贡献会根据其所属像素比例进行加权。需注意像素较多的类别可能主导该指标。
pixel_confusion_matrix混淆矩阵的概念在 深度学习 一章的“监督训练”一节中进行了阐述。该概念适用于语义分割任务,其中实例为单个像素。