HALCON 21.11:深度学习笔记---语义分割/边缘提取(12)
HALCON 21.11.0.0中,实现了深度学习方法。
本章介绍了如何使用基于深度学习的语义分割,包括训练和推理阶段。
通过语义分割,我们使用深度学习(DL)网络将输入图像的每个像素分配到一个类。
语义分割的例子:输入图像的每个像素都被分配给一个类,但是类“apple”的三个不同实例和类“orange”的两个不同实例都不是可区分的对象
语义分割的结果是一个输出图像,其中的像素值表示输入图像中对应像素的指定类别。因此,在HALCON中,输出图像与输入图像大小相同。对于一般的DL网络,代表更复杂特征的更深层次的特征映射通常比输入图像要小(参见深度学习中的“网络和训练过程”一节)。为了获得与输入相同大小的输出,HALCON使用了包含两个组件的分割网络:一个编码器和一个解码器。编码器确定输入图像的特征已经完成,例如,用于基于深度学习的分类。由于该信息是以压缩格式“编码”的,因此解码器需要将信息重构为所需的结果,在这种情况下,就是将每个像素赋值给一个类。请注意,在对像素进行分类时,同一个类的重叠实例不会被区分为截然不同的。
边缘提取是语义分割的一种特殊情况,在这种情况下,训练模型区分两类:“边缘”和“背景”。有关更多信息,请参阅“解决方案指南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,它作为数据库并存储关于数据的所有必要信息。有关数据及其传输方式的更多信息,请参见下面的“数据”一节和“深度学习/模型”一章。
- 使用函数split_dl_dataset分割字典DLDataset表示的数据集。分割结果将保存在DLDataset的每个样例条目的键分割上。
- 使用函数preprocess_dl_dataset预处理数据集。本程序还提供了如何实现自定义预处理过程的指导。要使用这个函数,要指定预处理参数,如图像大小。对于后者,你应该选择尽可能小的图像大小,这样要分割的区域仍然可以很好地识别。可以使用create_dl_preprocess_param函数将所有参数及其值存储在一个DLPreprocessParam字典中。我们建议保存这个字典DLPreprocessParam,以便在以后的推理阶段中访问预处理参数值。在数据集的预处理过程中,也会通过preprocess_dl_dataset为训练数据集生成图像weight_image。它们为每个类分配其像素在训练期间获得的权重(“类权重”)(参见下面的“模型参数和超参数”一节)。
模型训练
这一部分说明如何训练一个DL语义分割模型。在HDevelop示例segment_pill_defects_deep_learning_2_train.hdev中也显示了单个步骤。
- 通过函数read_dl_model读取网络。
- 通过函数set_dl_model_param设置模型参数。例如,'image_dimensions'和'class_ids',请参阅get_dl_model_param的文档。始终可以使用函数get_dl_model_param检索当前参数值。
- 使用函数create_dl_train_param设置训练参数并将其存储在字典'TrainingParam'中。这些参数包括:
超参数,请参阅下面的“模型参数和超参数”一节和深度学习一章;
可能的数据增强参数(可选);
训练期间的评估参数;
训练结果可视化参数;
序列化参数。 - 使用函数train_dl_model训练模型。这个函数包括:
模型句柄DLModelHandle;
包含数据信息DLDataset的字典;
包含训练参数'TrainParam'的字典;
训练要进行多少个epoch的信息。
在使用train_dl_model过程的情况下,总损失和可选的评价措施是可视化的。
评估训练模型
这一部分说明如何评价语义分割模型。在HDevelop示例segment_pill_defects_deep_learning_3_evaluate.hdev中也显示了单个步骤。
- 使用函数set_dl_model_param设置可能影响计算的模型参数,例如'batch_size'。
- 利用函数evaluate_dl_model可以方便地进行评价。
- 字典EvaluationResults保存所要求的评估度量。您可以使用函数dev_display_segmentation_evaluation可视化您的评估结果。
新图像推理
本部分介绍DL语义分割模型的应用。HDevelop示例segment_pill_defects_deep_learning_4_infer.hdev中也显示了单个步骤。
- 使用操作符set_dl_model_param设置参数,如'batch_size'。
- 使用函数gen_dl_samples_from_images为每个图像生成一个数据字典DLSample。
- 使用函数preprocess_dl_samples像训练时那样对图像进行预处理。在预处理步骤中保存字典DLPreprocessParam时,可以直接使用它作为输入来指定所有参数值。
- 使用函数apply_dl_model应用模型。
- 从字典'DLResultBatch'中检索结果。特定类的区域可以通过在分割图像上使用算子阈值来选择。
数据
我们区分用于培训和评估的数据和用于推断的数据。后者由裸图像组成。前者是包含图片及其信息和ground truth注释的图片。您可以为每个像素定义它所属的类(通过segmentation_image,请参阅下面的进一步解释)。
作为基本概念,模型通过字典处理数据,这意味着它通过字典DLSample接收输入数据,并分别返回字典DLResult和DLTrainResult。关于数据处理的更多信息可以在深度学习/模型一章找到。
为训练和评估提供数据
训练数据用于为您的特定任务训练网络。数据集由图像和相应的信息组成。它们必须以模型能够处理它们的方式提供。关于图像要求,请在下面的“图像”部分找到更多信息。关于图像及其ground truth注释的信息通过字典DLDataset提供,对于每个样本都提供相应的segmentation_image,并为每个像素定义类。
类
不同的类别是由网络划分的集合或类别。它们在字典DLDataset中设置,并通过操作符set_dl_model_param传递给模型。
在语义分割中,我们提醒你注意两种特殊情况:类“background”和类声明为“ignore”:
'background'类:网络像对待其他类一样对待背景类。没必要一定有一个背景类。但是如果你对你的数据集中的某些类不感兴趣,虽然他们必须通过网络学习,你可以把他们都设置为“背景”。因此,类背景将会更加多样化。有关更多信息,请参阅preprocess_dl_samples过程。
'ignore'类:可以声明一个或多个类为'ignore'。分配给'ignore'类的像素会被忽略,所有度量和评估也会被忽略。请参阅深度学习章节中的“网络和训练过程”一节,了解更多关于损失的信息。网络不会将任何像素分类到声明为“ignore”的类中。同样,被标记为属于这个类的像素将被网络像其他像素一样分类到一个非“ignore”类。在下面的图片中给出的例子中,这意味着网络也将对类“border”的像素进行分类,但它不会将任何像素分类到类“border”中。可以使用set_dl_model_param的参数“ignore_class_ids”将类声明为“ignore”。
在边缘提取中,只区分两个类:“edge”和“background”。类'edge'就像一个普通的类一样被标记。因此,只有一个类被标记,这个类被称为“edge”。
DLDataset
这个字典作为一个数据库,它存储了所有关于网络数据的必要信息,例如图片的名称和路径,类,…关于一般概念和关键条目,请参阅深度学习/模型的文档。键segmentation_image只适用于语义分割的关注(见下面的条目)。通过键segmentation_dir和segmentation_file_name,您可以提供它们的命名方式和保存位置的信息。
segmentation_image
为了让网络能够学习不同类的成员看起来如何不同,需要告诉训练数据集中每幅图像的每个像素它属于哪个类。这是通过将类编码为像素值的输入图像的每个像素存储在相应的segmentation_image中来实现的。这些批注就是ground truth批注。
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_param来查询它们。为了满足这些要求,您可能需要对图像进行预处理。整个样本的标准预处理,也在preprocess_dl_samples中实现。本程序还提供了如何实现自定义预处理过程的指导。
网络输出
作为训练输出:操作符将返回一个字典DLTrainResult,其中包含总损失的当前值以及模型中包含的所有其他损失的值。
作为推理和求值输出:网络将为每个样本返回一个字典DLResult。对于语义分割,本字典将为每个输入图像包含以下两张图像的句柄:
segmentation_image:图像,其中每个像素都有一个值,对应于它对应的像素被分配给的类(见下图)。
segmentation_confidence:图像,其中每个像素都有输入图像中对应像素分类后的置信度值(见下图)。
不同数据图像。为了可见性,灰色值用于表示数字。(1) segmentation_image:将声明为'ignore'的类像素(见上图)进行分类。(2) segmentation_confidence
模型参数和超参数
除了深度学习中解释的一般DL超参数外,还有一个与语义分割相关的超参数:'class weights',见下面的解释。
对于语义分割模型,使用set_dl_model_param设置模型参数以及超参数(“class weights”除外)。模型参数在get_dl_model_param中有更详细的解释。
注意,由于使用内存较大,通常只有小批量的训练是可能的。因此,训练相当缓慢,我们建议使用比分类更高的动量进行训练。HDevelop示例segment_pill_defects_deep_learning_train.hdev为HALCON中分割网络的训练提供了良好的初始参数值。
'class weights':通过超参数“class weights”,你可以为每个类分配其像素在训练期间获得的权重。给这些独特的类赋予不同的权重,就有可能迫使网络学习具有不同重要性的类。这在一个类控制图像的情况下是有用的,例如,缺陷检测,缺陷只占图像中的一小部分。在这种情况下,网络将每个像素分类为背景(因此,“非缺陷”)将获得良好的损失结果。为不同的类分配不同的权重有助于重新平衡分布。简而言之,你可以将损失集中在训练上,尤其是那些你认为重要的像素。
该网络通过为每个训练样本创建的图像weight_image获得这些权重。在weight_image中,每个像素值对应于输入图像对应像素在训练时获得的权重。您可以通过以下两个步骤来创建这些图像:
calculate_class_weights_segmentation帮助您创建类权重。该过程使用逆类频率权的概念。
gen_dl_segmentation_weight_images使用类weights并生成weight_image。
这一步必须在训练前完成。它通常是在预处理期间完成的,是过程preprocess_dl_dataset的一部分。注意,这个超参数在过程中被称为class_weights或classWeights。下图显示了具有不同权重的图像的说明。
注意,将图像的特定部分的权重设为0.0,这些像素并不会导致损失(请参阅深度学习中的“网络及其训练”一节了解更多关于损失的信息)。
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支持以下评估方法。注意,为计算图像的这种度量,需要相关的ground truth信息。下面对单个图像解释的所有测量值(例如,mean_iou)也可以对任意数量的图像进行计算。为此,设想由输出图像的集合形成的单一的大图像,并对其进行度量计算。注意,类中声明为'ignore'的所有像素在计算度量值时都会被忽略。
pixel_accuracy
像素精度只是用正确的类标签预测的所有像素与像素总数的比率。
pixel_accuracy的可视化示例
(1)segmentation_image为每个像素定义ground truth类(参见上面的“数据”部分),声明为“ignore”的类的像素被画成黑色
(2)输出图像,也像素类声明为“忽略”得到分类
(3)像素精度是总橙色区域之间的比率。注意,标记为'ignore'类的一部分的像素会被忽略
class_pixel_accuracy
每类像素精度只考虑单个类的像素。它被定义为正确预测的像素与使用该类标记的像素总数之间的比率。
如果一个类没有出现,它将获得class_pixel_accuracy值-1,并且不会影响平均值mean_accuracy。
mean_accuracy
平均精度定义为所有发生的类的每类平均像素精度class_pixel_accuracy。
class_iou
交并比(IoU)给出了一个特定类的正确预测像素与注释和预测像素的并集的比率。从视觉上看,这是区域的交集和并集之间的比率,见下图。
如果一个类没有出现,它将得到一个class_iou值-1,并且不会对mean_iou做出贡献。
每个类的IoU的可视示例class_iou,这里仅用于类apple
(1)为每个像素定义ground truth类的segmentation_image(见“数据”部分)。声明为“ignore”的类的像素被画成黑色
(2)输出图像,也像素类声明为“忽略”得到分类
(3)交集在并集上的交集是苹果像素面积的交集与并集的比率。注意,标记为'ignore'类的一部分的像素会被忽略
mean_iou
平均IoU定义为所有发生类的平均每类IoU。请注意,每个出现的类都对这个度量有相同的影响,这与它们包含的像素数无关。
frequency_weighted_iou
对于平均IoU,首先计算每类IoU。但是,每个出现的类对这个度量的贡献是由属于该类的像素的比例加权的。注意,具有许多像素的类可以主导这个度量。
pixel_confusion_matrix
在“深度学习”一章的“监督训练”一节中解释了混淆矩阵的概念。它适用于实例为单个像素的语义分割。
转载自:https://blog.csdn.net/liubing8609/article/details/121532815