TensorFlow 2 和 Keras 高级深度学习:11~13(2)https://developer.aliyun.com/article/1426964
“算法 11.12.1”NMS 和软 NMS
要求:边界框预测:B = {b[1], b[2], …, b[n]}
要求:边界框类别的置信度或分数:B = {b[1], b[2], …, b[n]}
要求:最小 NMS IoU 阈值:N[t]
D <- {}
;S <- {}
- 当
B ≠ empty
,执行 m <- argmax P
M <- b[m]
;N <- p[m]
,D <- D ∪ M
;B <- B - M
;S <- S ∪ N
;P <- P - N
;- 对于步骤
b[i] ∈ B
,执行 - 如果
soft_NMS = True
p[i] = p[i] exp(-IOU(M, b[i])^2 / σ)
- 否则如果
IOU(M, b[i]) >= N[t]
,那么 B = B - b[i]
;P = P - p[i]
- 结束
- 结束
- 结束
- 返回
D, S
“列表 11.12.1”:boxes.py
def nms(args, classes, offsets, anchors): """Perform NMS (Algorithm 11.12.1).
Arguments: args: User-defined configurations classes (tensor): Predicted classes offsets (tensor): Predicted offsets Returns: objects (tensor): class predictions per anchor indexes (tensor): indexes of detected objects filtered by NMS scores (tensor): array of detected objects scores filtered by NMS """
# get all non-zero (non-background) objects objects = np.argmax(classes, axis=1) # non-zero indexes are not background nonbg = np.nonzero(objects)[0]
# D and S indexes in Line 1 indexes = [] while True: # list of zero probability values scores = np.zeros((classes.shape[0],)) # set probability values of non-background scores[nonbg] = np.amax(classes[nonbg], axis=1)
# max probability given the list # Lines 3 and 4 score_idx = np.argmax(scores, axis=0) score_max = scores[score_idx]
# get all non max probability & set it as new nonbg # Line 5 nonbg = nonbg[nonbg != score_idx]
# if max obj probability is less than threshold (def 0.8) if score_max < args.class_threshold: # we are done break # Line 5 indexes.append(score_idx) score_anc = anchors[score_idx] score_off = offsets[score_idx][0:4] score_box = score_anc + score_off score_box = np.expand_dims(score_box, axis=0) nonbg_copy = np.copy(nonbg)
# get all overlapping predictions (Line 6) # perform Non-Max Suppression (NMS) for idx in nonbg_copy: anchor = anchors[idx] offset = offsets[idx][0:4] box = anchor + offset box = np.expand_dims(box, axis=0) iou = layer_utils.iou(box, score_box)[0][0] # if soft NMS is chosen (Line 7) if args.soft_nms: # adjust score: Line 8 iou = -2 * iou * iou classes[idx] *= math.exp(iou) # else NMS (Line 9), (iou threshold def 0.2) elif iou >= args.iou_threshold: # remove overlapping predictions with iou>threshold # Line 10 nonbg = nonbg[nonbg != idx]
# Line 2, nothing else to process if nonbg.size == 0: break
# get the array of object scores scores = np.zeros((classes.shape[0],)) scores[indexes] = np.amax(classes[indexes], axis=1)
return objects, indexes, scores
假设我们具有训练有素的 SSD 网络和一种抑制冗余预测的方法,则下一节将讨论对测试数据集的验证。 基本上,我们想知道我们的 SSD 是否可以对从未见过的图像执行对象检测。
13. SSD 模型验证
在对 SSD 模型进行 200 个周期的训练之后,可以验证表现。 用于评估的三个可能指标:1)IoU,2)精度和 3)召回。
第一个指标是平均 IoU(mIoU)。 给定真实情况测试数据集,计算真实情况边界框和预测边界框之间的 IoU。 在执行 NMS 之后,对所有真实情况和预测的边界框执行此操作。 所有 IoU 的平均值计算为 mIoU:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FLATH4OK-1681704403416)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/adv-dl-tf2-keras/img/B14853_11_074.png)] (Equation 11.13.1)
其中n_box
是地面真值边界框b[i]
的数量和n_pred
是预测边界框d[j]
的数量。 请注意,该度量标准无法验证两个重叠的边界框是否属于同一类。 如果需要,则可以轻松修改代码。“列表 11.13.1”显示了代码实现。
第二个度量是精度,如“公式 11.3.2”所示。 它是正确预测的对象类别的数量(真阳性或 TP)除以正确预测的对象类别的数量(真阳性或 TP)与错误预测的对象类别的数量(假阳性或 FP)之和。 精度是衡量 SSD 正确识别图像中对象的表现的指标。 精度越接近 1.0 越好。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zmRJcdN2-1681704403416)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/adv-dl-tf2-keras/img/B14853_11_075.png)] (Equation 11.3.2)
第三个度量是召回,如“公式 11.3.3”所示。 它是正确预测的对象类别的数量(真阳性或 TP)除以正确预测的对象类别的数量(真阳性或 TP)加上错过的对象数量(假阴性或 FN)之和。 召回率是衡量 SSD 在不对图像中的对象进行错误分类方面有多出色的度量。 召回率越接近 1.0,则越好。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vhFx1W9G-1681704403416)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/adv-dl-tf2-keras/img/B14853_11_076.png)] (Equation 11.3.3)
如果我们对测试数据集中的所有图像取均值,则它们称为平均精度和平均召回率。 在目标检测中,使用不同 mIoU 的精度和召回曲线来衡量表现。 为了简单起见,我们仅针对特定类别阈值(默认值为 0.5)计算这些指标的值。 感兴趣的读者可以参考 Pascal VOC [7]文章,以获取有关对象检测指标的更多详细信息。
评价结果示于“表 11.13.1”。 结果可以通过运行:
- 无规范化:
python3 ssd-11.6.1.py --restore-weights=ResNet56v2-4layer-extra_anchors-drinks-200.h5 --evaluate
- 无规范化,平滑 L1:
python3 ssd-11.6.1.py --restore-weights=ResNet56v2-4layer-smooth_l1-extra_anchors-drinks-200.h5 --evaluate
- 具有规范化:
python3 ssd-11.6.1.py --restore-weights=ResNet56v2-4layer-norm-extra_anchors-drinks-200.h5 --evaluate --normalize
- 具有规范化,平滑 L1:
python3 ssd-11.6.1.py --restore-weights=ResNet56v2-4layer-norm-smooth_l1-extra_anchors-drinks-200.h5 --evaluate --normalize
- 具有规范化,平滑 L1,焦点损失:
python3 ssd-11.6.1.py --restore-weights=ResNet56v2-4layer-norm-improved_loss-extra_anchors-drinks-200.h5 --evaluate --normalize
权重在 GitHub 上可用。
在 mIoU 上,最佳表现是非归一化偏移选项,而归一化偏移设置具有最高的平均精度和召回率。 考虑到训练数据集中只有 1,000 张图像,表现并不是最新技术。 也没有应用数据扩充。
从结果来看,使用损失函数的改进会降低表现。 使用平滑 L1 或焦距损失函数或同时使用两者时,会发生这种情况。“图 11.13.1”至“图 11.13.5”显示了样本预测。 可以通过执行以下操作获得图像上的对象检测:
python3 ssd-11.6.1.py –-restore-weights=<weights_file> --image-file=<target_image_file> --evaluate
例如,要在dataset/drinks/0010050.jpg
上运行对象检测:
python3 ssd-11.6.1.py --restore-weights=ResNet56v2-4layer-extra_anchors-drinks-200.h5 --image-file=dataset/drinks/0010050.jpg --evaluate
如果模型权重文件名中包含单词norm
,请附加--normalize option
。
“列表 11.13.1”:ssd-11.6.1.py
def evaluate_test(self): # test labels csv path path = os.path.join(self.args.data_path, self.args.test_labels) # test dictionary dictionary, _ = build_label_dictionary(path) keys = np.array(list(dictionary.keys())) # sum of precision s_precision = 0 # sum of recall s_recall = 0 # sum of IoUs s_iou = 0 # evaluate per image for key in keys: # ground truth labels labels = np.array(dictionary[key]) # 4 boxes coords are 1st four items of labels gt_boxes = labels[:, 0:-1] # last one is class gt_class_ids = labels[:, -1] # load image id by key image_file = os.path.join(self.args.data_path, key) image = skimage.img_as_float(imread(image_file)) image, classes, offsets = self.detect_objects(image) # perform nms _, _, class_ids, boxes = show_boxes(args, image, classes, offsets, self.feature_shapes, show=False)
boxes = np.reshape(np.array(boxes), (-1,4)) # compute IoUs iou = layer_utils.iou(gt_boxes, boxes) # skip empty IoUs if iou.size ==0: continue # the class of predicted box w/ max iou maxiou_class = np.argmax(iou, axis=1)
# true positive tp = 0 # false positiove fp = 0 # sum of objects iou per image s_image_iou = [] for n in range(iou.shape[0]): # ground truth bbox has a label if iou[n, maxiou_class[n]] > 0: s_image_iou.append(iou[n, maxiou_class[n]]) # true positive has the same class and gt if gt_class_ids[n] == class_ids[maxiou_class[n]]: tp += 1 else: fp += 1
# objects that we missed (false negative) fn = abs(len(gt_class_ids) - tp) s_iou += (np.sum(s_image_iou) / iou.shape[0]) s_precision += (tp/(tp + fp)) s_recall += (tp/(tp + fn))
n_test = len(keys) print_log("mIoU: %f" % (s_iou/n_test), self.args.verbose) print_log("Precision: %f" % (s_precision/n_test), self.args.verbose) print_log("Recall: %f" % (s_recall/n_test), self.args.verbose)
结果如下,在“表 11.13.1”中:
未归一化的偏移 | 未归一化的偏移,平滑 L1 | 归一化的偏移 | 归一化偏移,平滑 L1 | 归一化偏移,平滑 L1,焦点损失 | |
IoU | 0.64 | 0.61 | 0.53 | 0.50 | 0.51 |
平均精度 | 0.87 | 0.86 | 0.90 | 0.85 | 0.85 |
平均召回率 | 0.87 | 0.85 | 0.87 | 0.83 | 0.83 |
表 11.13.1 测试数据集上 SSD 的表现基准。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-P0UnLuyt-1681704403416)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/adv-dl-tf2-keras/img/B14853_11_13.png)]
图 11.13.1 来自测试数据集的图像上的示例预测示例(未归一化的偏移量)。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ka8fNttv-1681704403417)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/adv-dl-tf2-keras/img/B14853_11_14.png)]
图 11.13.2 来自测试数据集的图像上的示例预测示例(未归一化的偏移量,平滑 L1)。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YfIsIxJM-1681704403417)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/adv-dl-tf2-keras/img/B14853_11_15.png)]
图 11.13.3 来自测试数据集的图像预测示例(标准化偏移)。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-n51XnBv5-1681704403417)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/adv-dl-tf2-keras/img/B14853_11_16.png)]
图 11.13.4 对来自测试数据集的图像进行的预测示例(标准化偏移,平滑 L1)。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7qvjg7K3-1681704403417)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/adv-dl-tf2-keras/img/B14853_11_17.png)]
图 11.13.5 对来自测试数据集的图像进行的预测示例(归一化偏移,平滑 L1,聚焦损失)。
本节中的结果验证了我们的 SSD 模型。 一个重要的经验教训是,只要我们理解了问题,无论问题多么复杂,我们都可以逐步构建一个可行的解决方案。 SSD 是迄今为止我们在本书中介绍过的最复杂的模型。 它需要许多工具,模块以及大量数据准备和管理才能工作。
14. 总结
在本章中,讨论了多尺度单发对象检测的概念。 使用以接收场斑块的质心为中心的锚框,可以计算地面真值边界框偏移量。 代替原始像素误差,归一化像素误差会鼓励更适合优化的有限范围。
每个锚框都分配有地面实况类别标签。 如果锚点框不与对象重叠,则为其分配背景类,并且其偏移量不包括在偏移量损失计算中。 已经提出了焦点损失以改善类别损失函数。 可以使用平滑的 L1 损失函数代替默认的 L1 偏置损失函数。
对测试数据集的评估表明,使用默认损失函数的归一化偏移可实现平均精度和召回率方面的最佳表现,而当消除偏移归一化时,mIoU 会得到改善。 通过增加训练图像的数量和变化可以提高性能。
在“第 12 章”中,“语义分割”建立在本章中开发的概念的基础上。 特别是,我们重用 ResNet 骨干网络来构建分段网络和 IoU 指标进行验证。
15. 参考
Krizhevsky Alex, Ilya Sutskever, and Geoffrey E. Hinton. "Imagenet classification with deep convolutional neural networks." Advances in neural information processing systems. 2012.
Liu Wei, et al. "SSD: Single Shot MultiBox Detector." European conference on computer vision. Springer, Cham, 2016.
Girshick Ross. "Fast R-CNN." Proceedings of the IEEE international conference on computer vision. 2015.
Lin Tsung-Yi, et al. "Focal loss for Dense Object Detection. "Proceedings of the IEEE international conference on computer vision. 2017.
Dutta, et al. VGG Image Annotator http://www.robots.ox.ac.uk/~vgg/software/via/
Bodla Navaneeth, et al. "Soft-NMS--Improving Object Detection With One Line of Code." Proceedings of the IEEE international conference on computer vision. 2017.
Everingham Mark, et al. "The Pascal Visual Object Classes (VOC) challenge." International journal of computer vision 88.2 (2010): 303-338.
"Huber Loss." https://en.wikipedia.org/wiki/Huber_loss
十二、语义分割
在“第 11 章”,“对象检测”中,我们讨论了对象检测作为一种重要的计算机视觉算法,具有多种实际应用。 在本章中,我们将讨论另一种称为语义分割的相关算法。 如果对象检测的目的是对图像中的每个对象同时执行定位和标识,则在语义分割中,目的是根据每个像素的对象类别对它们进行分类。
进一步扩展类比,在对象检测中,我们使用边界框显示结果。 在语义分割中,同一对象的所有像素都属于同一类别。 在视觉上,同一对象的所有像素将具有相同的颜色。 例如,属于*汽水**类别的所有像素均为蓝色。 非苏打罐对象的像素将具有不同的颜色。
类似于对象检测,语义分割有许多实际应用。 在医学成像中,它可用于分离和测量正常细胞与异常细胞的区域。 在卫星成像中,语义分段可用于度量森林覆盖率或灾难期间的洪水程度。 通常,语义分割可用于识别属于同一类对象的像素。 识别每个对象的各个实例并不重要。
好奇的读者可能会想知道,一般而言,不同的分割算法与特别是语义分割算法之间有什么区别? 在以下部分中,我们将对不同的分割算法进行限定。
总而言之,本章的目的是为了提出:
- 不同类型的分割算法
- 全卷积网络(FCN)作为语义分割算法的实现
tf.keras
中 FCN 的实现和评估
我们将从讨论不同的分割算法开始。
1. 分割
分割算法将图像划分为像素或区域集。 分区的目的是为了更好地理解图像表示的内容。 像素组可以表示图像中特定应用感兴趣的对象。 我们划分的方式区分了不同的分割算法。
在某些应用中,我们对给定图像中的特定可数对象感兴趣。 例如,在自主导航中,我们对车辆,交通标志,行人和道路上的其他物体的实例感兴趣。 这些可计数对象统称为,称为事物。 所有其他像素都集中在一起作为背景。 这种类型的细分称为实例细分。
在其他应用中,我们对可数对象不感兴趣,而对无定形的不可数区域感兴趣,例如天空,森林,植被,道路,草地,建筑物和水体。 这些对象统称为东西。 这种类型的分段称为语义分段。
大致上,事物和事物共同构成了整个图像。 如果算法可以识别事物像素和填充像素,则其称为全光分割,如 Kirilov 等人所定义 [1]。
但是,事物与事物之间的区别并不严格。 应用可能将可数对象统称为东西。 例如,在百货商店中,不可能识别机架上的服装实例。 它们可以作为布料一起集中在一起。
“图 12.1.1”显示了不同类型的细分之间的区别。 输入的图像在桌子的顶部显示了两个汽水罐和两个果汁罐。 背景杂乱无章。 假设我们只对汽水罐和果汁罐感兴趣,在实例细分中,我们为每个对象实例分配唯一的颜色以分别区分四个对象。 对于语义分割,我们假设将所有的汽水罐都塞在一起,将果汁罐作为另一罐塞在一起,将背景作为最后的罐塞在一起。 基本上,我们为每种物料分配了唯一的颜色。 最后,在全景分割中,我们假设只有背景才是背景,而我们只对苏打水和果汁罐感兴趣。
对于这本书,我们仅探讨语义分割。 按照“图 12.1.1”中的示例,我们将为“第 11 章”,“对象检测”中使用的对象分配唯一的填充类别:1)水瓶,2)汽水罐和 3)果汁罐。 第四个也是最后一个类别是背景。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4EpPHowM-1681704403417)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/adv-dl-tf2-keras/img/B14853_12_01.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CvkEohUM-1681704403418)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/adv-dl-tf2-keras/img/B14853_12_02.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6ejSRZgI-1681704403418)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/adv-dl-tf2-keras/img/B14853_12_03.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wyWO65mS-1681704403418)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/adv-dl-tf2-keras/img/B14853_12_04.png)]
图 12.1.1:显示不同分割算法的四幅图像。 彩色效果最佳。 原始图像可以在这个页面中找到。
2. 语义分割网络
从上一节中,我们了解到语义分割网络是一个像素级分类器。 网络框图显示在“图 12.2.1”中。 但是,与简单分类器不同(例如,“第 1 章”,“Keras 深度神经网络”和“第 2 章”,“MNIST 分类器简介”) 其中只有一个分类器生成one-hot vector
作为输出,在语义分段中,我们有并行运行的并行分类器。 每个人都在生成自己的单热点向量预测。 分类器的数量等于输入图像中的像素数量或图像宽度与高度的乘积。 每个one-hot vector
预测的维数等于感兴趣的填充对象类别的数量。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GYBo75Cb-1681704403418)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/adv-dl-tf2-keras/img/B14853_12_05.png)]
图 12.2.1:可以将语义分割网络视为按像素分类器。 彩色效果最佳。 原始图像可以在这个页面中找到
例如,假设我们对以下四个类别感兴趣:0)背景,1)水瓶,2)汽水罐和 3)果汁罐,我们可以在“图 12.2.2”中看到,每个对象类别有四个像素。
相应地,使用 4 维one-hot vector
对每个像素进行分类。 我们使用阴影表示像素的类别。 利用这一知识,我们可以想象一个语义分割网络预测image_width x image_height
4 维一热向量作为输出,每个像素一个 4 维一热向量:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-q7jsUldG-1681704403418)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/adv-dl-tf2-keras/img/B14853_12_06.png)]
图 12.2.2:四个不同的样本像素。 使用 4 维一热向量,每个像素根据其类别进行分类。 彩色效果最佳。 原始图像可以在这个页面中找到
了解了语义分割的概念后,我们现在可以介绍神经网络像素级分类器。 Long 等人的《全卷积网络(FCN)》启发了我们的语义分段网络架构 [2]。FCN 的关键思想是在生成最终预测时使用多个比例的特征映射。
我们的语义分段网络显示在“图 12.2.3”中。 它的输入是 RGB 图像(例如640 x 480 x 3
),并且输出具有类似尺寸的张量,但最后一个尺寸是填充类别的数量(例如,对于 4 种填充类别而言是640 x 480 x 4
)。 出于可视化目的,我们通过为每种类别分配颜色来将输出映射到 RGB:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EroFLU5M-1681704403419)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/adv-dl-tf2-keras/img/B14853_12_07.png)]
图 12.2.3:语义分割的网络架构。 除非另有说明,否则核大小为 3。 除非另有说明,否则跨步为 1。 彩色效果最佳。 原始图像可以在这个页面中找到
类似于“第 11 章”,“对象检测”中讨论的 SSD,我们采用骨干网作为特征提取器。 我们在 SSD 中使用类似的 ResNetv2 网络。 ResNet 主干网执行两次最大池化,以到达第一组特征映射,其尺寸为输入图像的 1/4。 通过使用连续的Conv2D(strides=2)-BN-ReLU
层生成其他特征映射集,从而生成具有输入图像尺寸(1/8, 1/16, 1/32)
的特征映射。
Zhao 等人的《金字塔场景解析网络(PSPNet)》进行了改进,进一步增强了我们的语义分割网络架构 [3]。 在 PSPNet 中,每个特征映射由另一个卷积层进一步处理。 此外,还使用了第一组特征映射。
FCN 和 PSPNet 都对特征金字塔进行了上采样,以达到与第一组特征映射相同的大小。 之后,使用Concatenate
层将所有上采样特征融合在一起。 然后级联层通过步长等于 2 的转置卷积处理两次,以恢复原始图像的宽度和高度。 最后,使用核大小为 1 且过滤器等于 4(换句话说,类别数)和Softmax
层的转置卷积生成按像素分类预测。
在下一节中,我们将讨论细分网络的tf.keras
实现。 我们可以重用“第 11 章”,“对象检测”中的 SSD 中的某些网络块,以加快实现速度。
3. Keras 中的语义分割网络
如图“图 12.2.3”所示,我们已经有了语义细分网络的一些关键构建块。 我们可以重用“第 2 章”,“深度神经网络”中介绍的 ResNet 模型。 我们只需要构建特征的金字塔以及上采样和预测层。
借用我们在“第 2 章”,“深度神经网络”中开发的 ResNet 模型,并在“第 11 章”,“对象检测”中重用了该模型, 我们提取具有四个级别的特征金字塔。“列表 12.3.1”显示了从 ResNet 提取特征的金字塔。 conv_layer()
只是创建Conv2D(strides=2)-BN-ReLU
层的辅助函数。
“列表 12.3.1”:resnet.py
:
特征的金字塔函数:
def features_pyramid(x, n_layers): """Generate features pyramid from the output of the last layer of a backbone network (e.g. ResNetv1 or v2)
Arguments: x (tensor): Output feature maps of a backbone network n_layers (int): Number of additional pyramid layers
Return: outputs (list): Features pyramid """ outputs = [x] conv = AveragePooling2D(pool_size=2, name='pool1')(x) outputs.append(conv) prev_conv = conv n_filters = 512
# additional feature map layers for i in range(n_layers - 1): postfix = "_layer" + str(i+2) conv = conv_layer(prev_conv, n_filters, kernel_size=3, strides=2, use_maxpool=False, postfix=postfix) outputs.append(conv) prev_conv = conv
return outputs
“列表 12.3.1”只是特征金字塔的一半。 剩下的一半是每组特征之后的卷积。 另一半显示在“列表 12.3.2”中,以及金字塔各层的上采样。 例如,图像尺寸为 1/8 的特征会被上采样 2 倍,以使其尺寸与图像尺寸为 1/4 的第一组特征相匹配。 在同一清单中,我们还建立了完整的分割模型,从骨干网络到特征金字塔,再连接上采样特征金字塔,最后进一步进行特征提取,上采样和预测。 我们在输出层使用n
维(例如 4 维)Softmax
层执行逐像素分类。
“列表 12.3.2”:model.py
:
构建语义分割网络:
def build_fcn(input_shape, backbone, n_classes=4): """Helper function to build an FCN model. Arguments: backbone (Model): A backbone network such as ResNetv2 or v1 n_classes (int): Number of object classes including background. """
inputs = Input(shape=input_shape) features = backbone(inputs)
main_feature = features[0] features = features[1:] out_features = [main_feature] feature_size = 8 size = 2 # other half of the features pyramid # including upsampling to restore the # feature maps to the dimensions # equal to 1/4 the image size for feature in features: postfix = "fcn_" + str(feature_size) feature = conv_layer(feature, filters=256, use_maxpool=False, postfix=postfix) postfix = postfix + "_up2d" feature = UpSampling2D(size=size, interpolation='bilinear', name=postfix)(feature) size = size * 2 feature_size = feature_size * 2 out_features.append(feature)
# concatenate all upsampled features x = Concatenate()(out_features) # perform 2 additional feature extraction # and upsampling x = tconv_layer(x, 256, postfix="up_x2") x = tconv_layer(x, 256, postfix="up_x4") # generate the pixel-wise classifier x = Conv2DTranspose(filters=n_classes, kernel_size=1, strides=1, padding='same', kernel_initializer='he_normal', name="pre_activation")(x) x = Softmax(name="segmentation")(x)
model = Model(inputs, x, name="fcn")
return model
给定分割网络模型,我们使用学习速度为1e-3
的 Adam 优化器和分类交叉熵损失函数来训练网络。“列表 12.3.3”显示了模型构建和训练函数调用。 在 40 个周期之后,学习率每 20 个周期减半。 我们使用AccuracyCallback
监视网络表现,类似于“第 11 章”,“对象检测”中的 SSD 网络。 回调使用类似于对象检测平均 IoU 的平均 IoU(mIoU)指标计算表现。 表现最佳的平均值 IoU 的权重保存在文件中。 通过调用fit_generator()
将网络训练 100 个周期。
“列表 12.3.3”:fcn-12.3.1.py
:
语义分割网络的初始化和训练:
def build_model(self): """Build a backbone network and use it to create a semantic segmentation network based on FCN. """
# input shape is (480, 640, 3) by default self.input_shape = (self.args.height, self.args.width, self.args.channels)
# build the backbone network (eg ResNet50) # the backbone is used for 1st set of features # of the features pyramid self.backbone = self.args.backbone(self.input_shape, n_layers=self.args.layers)
# using the backbone, build fcn network # output layer is a pixel-wise classifier self.n_classes = self.train_generator.n_classes self.fcn = build_fcn(self.input_shape, self.backbone, self.n_classes)
def train(self): """Train an FCN""" optimizer = Adam(lr=1e-3) loss = 'categorical_crossentropy' self.fcn.compile(optimizer=optimizer, loss=loss)
log = "# of classes %d" % self.n_classes print_log(log, self.args.verbose) log = "Batch size: %d" % self.args.batch_size print_log(log, self.args.verbose)
# prepare callbacks for saving model weights # and learning rate scheduler # model weights are saved when test iou is highest # learning rate decreases by 50% every 20 epochs # after 40th epoch accuracy = AccuracyCallback(self) scheduler = LearningRateScheduler(lr_scheduler)
callbacks = [accuracy, scheduler] # train the fcn network self.fcn.fit_generator(generator=self.train_generator, use_multiprocessing=True, callbacks=callbacks, epochs=self.args.epochs, workers=self.args.workers)
多线程数据生成器类DataGenerator
与“第 11 章”,“对象检测”中使用的类类似。 如“列表 12.3.4”所示,对__data_generation(self, keys)
签名方法进行了修改,以生成一对图像张量及其相应的按像素方向的真实情况标签或分割蒙版 。 在下一节中,我们将讨论如何生成基本事实标签。
“列表 12.3.4”:data_generator.py
:
DataGenerator
类用于语义分割的数据生成方法:
def __data_generation(self, keys): """Generate train data: images and segmentation ground truth labels
Arguments: keys (array): Randomly sampled keys (key is image filename)
Returns: x (tensor): Batch of images y (tensor): Batch of pixel-wise categories """ # a batch of images x = [] # and their corresponding segmentation masks y = []
for i, key in enumerate(keys): # images are assumed to be stored # in self.args.data_path # key is the image filename image_path = os.path.join(self.args.data_path, key) image = skimage.img_as_float(imread(image_path)) # append image to the list x.append(image) # and its corresponding label (segmentation mask) labels = self.dictionary[key] y.append(labels)
return np.array(x), np.array(y)
语义分割网络现已完成。 使用tf.keras
,我们讨论了其架构实现,初始化和训练。
在运行训练程序之前,我们需要训练和测试带有地面真实性标签的数据集。 在的下一部分中,我们将讨论将在本章中使用的语义分割数据集。
4. 示例数据集
我们可以使用在“第 11 章”,“对象检测”中使用的数据集。 回想一下,我们使用了一个小型数据集,其中包含使用便宜的 USB 相机(A4TECH PK-635G)收集的 1,000 640 x 480
RGB 训练图像和 50 640 x 480
RGB 测试图像。 但是,我们没有使用边界框和类别进行标记,而是使用多边形形状跟踪了每个对象类别的边缘。 我们使用相同的数据集标注器 VGG 图像标注器(VIA)[4]手动跟踪边缘并分配以下标签:1)水瓶,2)汽水罐和 3)果汁罐。
“图 12.4.1”显示了标记过程的示例 UI。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-N7yGjN4J-1681704403419)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/adv-dl-tf2-keras/img/B14853_12_08.png)]
图 12.4.1:使用 VGG 图像标注器(VIA)进行语义分割的数据集标记过程
威盛标签软件将标签保存在 JSON 文件中。 对于训练和测试数据集,这些是:
segmentation_train.json segmentation_test.json
无法原样使用存储在 JSON 文件中的多边形区域。 每个区域都必须转换成分割蒙版,即张量,其尺寸为img_w x img_h x px – wise_category
。 在此数据集中,分割蒙版的尺寸为640 x 480 x 4
。类别 0 为背景,其余为 1)对于水瓶,2)对于苏打罐,以及 3)表示果汁罐。 在utils
文件夹中,我们创建了一个generate_gt_segmentation.py
工具,用于将 JSON 文件转换为分段掩码。 为了方便起见,用于训练和测试的地面真实数据存储在压缩数据集中,该数据集是从上一章下载的:
segmentation_train.npy segmentation_test.npy
每个文件都包含image filename: segmentation mask
格式的真实情况数据字典,该字典在训练和验证期间加载。“图 12.4.2”显示了使用彩色像素可视化的“图 12.4.1”中图像的分割蒙版的示例。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uul4zA3D-1681704403419)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/adv-dl-tf2-keras/img/B14853_12_09.png)]
图 12.4.2:可视化图 12.4.1 中所做标注的分段蒙版
现在,我们准备训练和验证语义分割网络。 在下一节中,我们将显示在本节中标注的数据集上语义分割的结果。
5. 语义分割验证
要训练语义分段网络,请运行以下命令:
python3 fcn-12.3.1.py --train
在每个周期,也会执行验证以确定表现最佳的参数。 对于语义分割,可以使用两个度量。 首先是平均 IOU。 这类似于上一章中目标检测中的平均 IoU。 区别在于针对每个填充类别在真实情况分割掩码和预测的分割掩码之间计算 IoU。 这包括背景。 平均 IoU 只是测试数据集所有 IoU 的平均值。
“图 12.5.1”显示了在每个周期使用 mIoU 的语义分割网络的表现。 最大 mIoU 为 0.91。 这个比较高。 但是,我们的数据集只有四个对象类别:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Kmd8DxsN-1681704403419)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/adv-dl-tf2-keras/img/B14853_12_10.png)]
图 12.5.1:使用 mIoU 进行测试数据集训练期间的语义分割表现
第二个指标是平均像素精度。 这类似于在分类器预测上计算准确率的方式。 不同之处在于,分割网络具有的预测数量等于图像中的像素数量,而不是具有一个预测。 对于每个测试输入图像,计算平均像素精度。 然后,计算所有测试图像的平均值。
“图 12.5.2”显示了在每个周期使用平均像素精度的语义分割网络的表现。 最大平均像素精度为 97.9%。 我们可以看到平均像素精度与 mIoU 之间的相关性:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BMLxZq5w-1681704403419)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/adv-dl-tf2-keras/img/B14853_12_11.png)]
图 12.5.2:使用测试数据集的平均像素精度在训练期间的语义分割表现
“图 12.5.3”显示了输入图像,地面实况语义分割掩码和预测的语义分割掩码的样本:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5Cu4KIyk-1681704403420)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/adv-dl-tf2-keras/img/B14853_12_12.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yzP6TGWV-1681704403420)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/adv-dl-tf2-keras/img/B14853_12_13.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dhxjWb8h-1681704403420)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/adv-dl-tf2-keras/img/B14853_12_14.png)]
图 12.5.3:样本输入,基本事实和语义细分的预测。 我们将黑色分配为背景类,而不是紫色,如先前所用
总体而言,我们基于 FCN 并经过 PSPNet 的思想改进的语义分割网络的表现相对较好。 我们的语义分割网络绝不是最优化的。 可以减少特征金字塔中的过滤器数量,以最大程度地减少参数的数量,该参数约为 1110 万。 探索增加特征金字塔中的级别数也很有趣。 读者可以通过执行以下命令来运行验证:
python3 fcn-12.3.1.py --evaluate --restore-weights=ResNet56v2-3layer-drinks-best-iou.h5
在下一章中,我们将介绍无监督的学习算法。 考虑到监督学习中所需的昂贵且费时的标签,强烈地开发了无监督学习技术。 例如,在本章的语义分割数据集中,一个人花了大约 4 天的手工标签。 如果深度学习始终需要人工标记,那么它就不会前进。
6. 总结
在本章中,讨论了分割的概念。 我们了解到细分有不同类别。 每个都有自己的目标应用。 本章重点介绍语义分段的网络设计,实现和验证。
我们的语义分割网络受到 FCN 的启发,FCN 已成为许多现代,最先进的分割算法(例如 Mask-R-CNN [5])的基础。 PSPNet 的构想进一步增强了我们的网络,该构想在 ImageNet 2016 解析挑战赛中获得第一名。
使用 VIA 标记工具,使用与“第 11 章”,“对象检测”中使用的相同图像集生成用于语义分割的新数据集标签。 分割蒙版标记属于同一对象类的所有像素。
我们使用平均 IoU 和平均像素准确率指标对语义分割网络进行了训练和验证。 测试数据集上的表现表明,它可以有效地对测试图像中的像素进行分类。
如本章最后一部分所述,由于所涉及的成本和时间,深度学习领域正在意识到监督学习的局限性。 下一章重点介绍无监督学习。 它利用了通信领域信息理论中使用的互信息概念。
7. 参考
Kirillov, Alexander, et al.: Panoptic Segmentation. Proceedings of the IEEE conference on computer vision and pattern recognition. 2019.
Long, Jonathan, Evan Shelhamer, and Trevor Darrell: Fully Convolutional Networks for Semantic Segmentation. Proceedings of the IEEE conference on computer vision and pattern recognition. 2015.
Zhao, Hengshuang, et al.: Pyramid Scene Parsing Network. Proceedings of the IEEE conference on computer vision and pattern recognition. 2017.
Dutta, et al.: VGG Image Annotator http://www.robots.ox.ac.uk/~vgg/software/via/
He Kaiming, et al.: Mask R-CNN. Proceedings of the IEEE international conference on computer vision. 2017.
十三、使用互信息的无监督学习
许多机器学习任务(例如分类,检测和分段)都依赖于标记的数据。 网络在这些任务上的表现直接受到标记质量和数据量的影响。 问题在于产生足够数量的高质量标注数据既昂贵又费时。
为了继续机器学习的发展,新算法应减少对人类标签的依赖。 理想情况下,网络应该从无标签数据中学习,由于互联网的发展以及诸如智能手机和物联网(IoT)。 从未标记的数据中学习是无监督学习的领域。 在某些情况下,无监督学习也称为自我监督学习,以强调使用纯净的未标记数据进行训练和缺乏人工监督。 在本文中,我们将使用术语无监督学习。
在机器学习中,有一些方法可以从未标记的数据中学习。 可以使用深度神经网络和无监督学习中的新思想来改善这些方法的表现。 当处理高度非结构化的数据(例如文本,图像,音频和视频)时,尤其如此。
在无监督学习中成功的方法之一是最大化给定神经网络中两个随机变量之间的互信息。 在信息论领域,互信息(MI)是两个随机变量之间依存性的量度。
MI 最近已成功地从未标记的数据中提取了有用的信息,可以帮助学习下游任务。 例如,MI 能够对潜在代码向量进行聚类,从而使分类任务成为简单的线性分离问题。
总之,本章的目的是介绍:
- 互信息的概念
- 使用神经网络估计 MI
- 下游任务的离散和连续随机变量上的 MI 最大化
- Keras 中 MI 估计网络的实现
我们将从介绍互信息的概念开始。
1. 互信息
互信息是对两个随机变量X
和Y
之间依赖性的度量。 有时,MI 也定义为通过观察Y
得出的有关X
的信息量。 MI 也被称为信息获取或观察Y
时X
不确定性的降低。
与相关性相反,MI 可以测量X
和Y
之间的非线性统计依赖性。 在深度学习中,MI 是一种合适的方法,因为大多数现实世界中的数据都是非结构化的,并且输入和输出之间的依赖关系通常是非线性的。 在深度学习中,最终目标是对输入数据和预先训练的模型执行特定任务,例如分类,翻译,回归或检测。 这些任务也称为下游任务。
由于 MI 可以发现输入,中间特征,表示和输出中的相关性的重要方面,这些方面本身就是随机变量,因此共享信息通常可以提高下游任务中模型的表现。
在数学上,两个随机变量X
和Y
之间的 MI 可以定义为:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Eo7gkclX-1681704403420)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/adv-dl-tf2-keras/img/B14853_13_001.png)] (Equation 13.1.1)
哪里:
P
(X
,Y
)是 X 和 Y 在样本空间X
xY
上的联合分布 。P
(X
)P
(Y
)是边际分布P
(X
)和P
(Y
)分别位于样本空间X
和Y
上。
换句话说,MI 是联合分布与边际分布乘积之间的 Kullback-Leibler(KL)散度。 回顾“第 5 章”,“改进的 GAN” ,KL 是两个分布之间距离的度量。 在 MI 的上下文中,KL 距离越大,两个随机变量X
和Y
之间的 MI 越高。 通过扩展,MI 越高,X
对Y
的依赖性越高。
由于 MI 等于边际分布的联合与乘积之间的 KL 散度,因此它暗示它大于或等于零:I(X; Y) > 0
。 当X
和Y
是独立随机变量时,MI 完全等于零。 当X
和Y
是独立的时,观察一个随机变量(例如Y
)不会提供关于另一个随机变量的信息(例如X
)。 因此,MI 是X
和Y
独立程度的度量。
如果X
和Y
是离散随机变量,则通过扩展 KL 散度,MI 可以计算为:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4AfGtDhV-1681704403420)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/adv-dl-tf2-keras/img/B14853_13_003.png)] (Equation 13.1.2)
哪里:
P
(X
,Y
)是联合概率质量函数(PMF)。P
(X
)和P
(Y
)是边际 PMF。
如果联合和边际分布已知,则 MI 可以进行精确计算。
如果X
和Y
是连续随机变量,则通过扩展 KL 散度,MI 可以表示为:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7WHdKRLF-1681704403421)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/adv-dl-tf2-keras/img/B14853_13_004.png)] (Equation 13.1.3)
哪里:
p
(x
,y
)是联合概率密度函数(PDF)。p
(x
)和p
(y
)是边缘 PDF。
连续随机变量的 MI 通常很难处理,并且可以通过变分方法进行估计。 在本章中,我们将讨论估计两个连续随机变量之间的 MI 的技术。
在讨论用于计算互信息的技术之前,让我们首先解释一下 MI 与熵之间的关系。 熵在“第 6 章”,“纠缠表示 GAN”中非正式引入,并在 InfoGAN 中得到了应用。
2. 互信息和熵
MI 也可以用熵来解释。 回想一下“第 6 章”,“纠缠表示 GAN” ,熵H
(X
)是对预期信息量的度量。 随机变量X
的:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fVRJV5vd-1681704403421)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/adv-dl-tf2-keras/img/B14853_13_005.png)] (Equation 13.2.1)
“公式 13.2.1”表示熵还是不确定性的量度。 不确定事件的发生给我们带来了更多的惊喜或信息。 例如,有关员工意外晋升的新闻具有大量信息或熵。
使用“公式 13.2.1”,MI 可以表示为:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-q5Biwk8v-1681704403421)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/adv-dl-tf2-keras/img/B14853_13_006.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yModEcTY-1681704403421)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/adv-dl-tf2-keras/img/B14853_13_007.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1ZZYZlgO-1681704403421)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/adv-dl-tf2-keras/img/B14853_13_008.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qfl2scsb-1681704403422)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/adv-dl-tf2-keras/img/B14853_13_009.png)] (Equation 13.2.2)
“公式 13.2.2”表示 MI 随着边际熵增加而增加,但随联合熵而减少。 就熵而言,MI 的一个更常见的表达式如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yF8Wfaav-1681704403422)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/adv-dl-tf2-keras/img/B14853_13_010.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VGKjZsA8-1681704403422)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/adv-dl-tf2-keras/img/B14853_13_011.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TC92wV3q-1681704403422)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/adv-dl-tf2-keras/img/B14853_13_012.png)] (Equation 13.2.3)
“公式 13.2.3”告诉我们,MI 随随机变量的熵增加而减小,而随另一个随机变量的条件熵而减小。 或者,如果我们知道Y
,则 MI 是的信息减少量或X
的不确定性。
等效地,
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZsbcHsqv-1681704403422)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/adv-dl-tf2-keras/img/B14853_13_013.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wcA0aoKu-1681704403423)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/adv-dl-tf2-keras/img/B14853_13_014.png)] (Equation 13.2.4)
“公式 13.2.4”表示 MI 是对称的:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pYiz6YJe-1681704403423)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/adv-dl-tf2-keras/img/B14853_13_015.png)] (Equation 13.2.5)
MI 也可以用X
和Y
的条件熵表示:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ENBUyNlB-1681704403423)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/adv-dl-tf2-keras/img/B14853_13_016.png)] (Equation 13.2.6)
使用贝叶斯定理:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kwQffrHa-1681704403424)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/adv-dl-tf2-keras/img/B14853_13_017.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ttTCx9Zl-1681704403424)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/adv-dl-tf2-keras/img/B14853_13_018.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zfpOr0A2-1681704403424)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/adv-dl-tf2-keras/img/B14853_13_019.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1BYCocAP-1681704403424)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/adv-dl-tf2-keras/img/B14853_13_020.png)] (Equation 13.2.7)
“图 13.2.1”总结了到目前为止我们讨论的 MI 与条件熵和边际熵之间的所有关系:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ve42dwG2-1681704403424)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/adv-dl-tf2-keras/img/B14853_13_01.png)]
图 13.2.1 维恩图显示了 MI 与条件熵和边际熵之间的关系
MI 的另一种有趣解释是根据“公式 13.2.3”,可以将其重写为:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-evr9MmOl-1681704403425)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/adv-dl-tf2-keras/img/B14853_13_021.png)] (Equation 13.2.8)
由于H(X | Y)
是观察到Y
时的X
的不确定性,因此“公式 13.2.8”告诉我们, 如果可以最大化 MI,则可以确定X
给定Y
。 在“图 13.2.1”中,新月形H(X | Y)
的面积随着代表 MI 的圆之间的交点增加而减小。
再举一个的具体例子,假设X
是一个随机变量,表示观察到在给定随机字节中的 0 到 255 之间的数字。 假设分布均匀,则转换为P(X) = 1/256
的概率。 以 2 为底的X
的熵为:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QgvLqfqs-1681704403425)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/adv-dl-tf2-keras/img/B14853_13_023.png)]
假设随机变量Y
代表随机字节的 4 个最高有效位。 如果我们观察到 4 个最高有效位全为零,则数字 0 到 15 包含P(X) = 1/16
,其余数字具有P(X) = 0
。条件熵在基数 2 中是:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-l3uZjjPW-1681704403425)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/adv-dl-tf2-keras/img/B14853_13_025.png)]
这为我们提供了I(X; Y) = 8 - 4 = 4
的 MI。 注意,随机变量X
的不确定性或预期信息量在知道Y
后降低。X
和Y
共享的互信息为 4,这也等于两个随机变量共享的位数。“图 13.2.2”说明了两种情况,其中所有位都是随机的,而四个最高有效位都为 0。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5tWiSOy4-1681704403425)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/adv-dl-tf2-keras/img/B14853_13_02.png)]
图 13.2.2 当所有位未知时与某些位已知时的熵
鉴于我们已经对 MI 和熵有了很好的了解,我们现在可以将此概念用作无监督学习的一种方法。
3. 通过最大化离散随机变量的互信息来进行无监督学习
深度学习中的经典问题是监督分类。 在“第 1 章”,“Keras 简介”和“第 2 章”,“深度神经网络”中,我们了解到,在监督分类下,我们需要标记输入图像。 我们对 MNIST 和 CIFAR10 数据集都进行了分类。 对于 MNIST,三层 CNN 和密集层可实现高达 99.3% 的精度。 对于使用 ResNet 或 DenseNet 的 CIFAR10,我们可以实现大约 93% 至 94% 的精度。 MNIST 和 CIFAR10 都被标记为数据集。
与监督学习不同,本章的目标是执行无监督学习。 我们的重点是没有标签的分类。 这个想法是,如果我们学习如何对所有训练数据的潜在代码向量进行聚类,那么线性分离算法可以对每个测试输入数据潜在向量进行分类。
为了学习没有标签的潜在代码向量的聚类,我们的训练目标是在输入图像X
和其潜在代码Y
之间最大化 MI。X
和Y
都是随机变量。 这个想法是外观相似的图像将具有聚集到相同区域的潜在向量。 线性分配问题可以很容易地将彼此远离的区域分开。 因此,可以以无监督的方式完成分类问题。 数学上,目标是最大化:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NMaX5waA-1681704403425)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/adv-dl-tf2-keras/img/B14853_13_027.png)] (Equation 13.2.3)
直观地,一旦我们观察到Y
,我们对X
充满信心。 “公式 13.2.3”的问题在于,我们无法很好地估计要测量的密度P(X | Y) H(X | Y)
。
Ji 等人的不变信息聚类(IIC)[1] 建议从联合和边际分布直接测量I(X; Y)
。 目的是使用“公式 13.1.2”测量引用同一输入的两个潜在代码随机变量之间的 MI。 假设输入X
编码为Z
:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aYfM64Z4-1681704403425)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/adv-dl-tf2-keras/img/B14853_13_029.png)]
将相同的输入X
转换为X_bar = G(X)
,以便X
仍可清晰地归类为与X
相同的类别。 在图像处理中,G
可以是常见的操作,例如小旋转,随机裁剪和剪切。 有时,只要结果图像的含义相同,就可以接受诸如对比度和亮度调整,边缘检测,少量噪声添加以及归一化之类的操作。 例如,如果X
是狗的图像,则在G
之后,X_bar
显然仍是狗。
使用相同编码器网络的潜在代码向量为:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-so6Nju79-1681704403426)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/adv-dl-tf2-keras/img/B14853_13_035.png)]
因此,我们可以用两个随机变量Z
和Z_bar
将“公式 13.1.2”重写为:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Yy27MoWl-1681704403426)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/adv-dl-tf2-keras/img/B14853_13_037.png)] (Equation 13.3.1)
其中P(Z)
和P(Z_bar)
可以解释为Z
和Z_bar
的边际分布。 对于离散随机变量,Z
和Z_bar
都是P(Z)
和P(Z_bar)
都是分类分布。 我们可以想象,编码器输出是 softmax ,其维数等于训练和测试数据分布中的类数N
。 例如,对于 MNIST,编码器输出是与训练和测试数据集中的 10 位数字相对应的 10 维一热向量。
为了确定“公式 13.3.1”中的每个项,我们首先估计P(Z, Z_bar)
。 IIC 假设Z
和Z_bar
是独立的,因此联合分布可以估计为:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Fl5aFwZk-1681704403426)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/adv-dl-tf2-keras/img/B14853_13_045.png)] (Equation 13.3.2)
这将创建一个N x N
矩阵P(Z, Z_bar)
,其中每个元素Z[ij]
对应于同时观察两个随机变量(Z[i], Z_bar[j])
的概率。 如果对大批量进行此估计,则大样本均值将估计联合概率。
由于我们将使用 MI 来估计密度函数,因此 IIC 将采样限制为(Z[i], Z_bar[i])
。 本质上,对于每个样本x[i]
,我们计算其潜在代码P(Z[i]) = E(X[i])
。 然后,我们将x[i]
转换,并计算其潜在代码P(Z_bar[i]) = E(X_bar[i])
。 联合分布计算如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TwTf38WQ-1681704403426)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/adv-dl-tf2-keras/img/B14853_13_051.png)] (Equation 13.3.3)
其中M
是批量大小。 由于我们对x[i]
和x_bar[i]
使用相同的编码器E
,因此联合分布应该对称。 我们通过执行以下命令来增强对称性:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UZusGNEF-1681704403426)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/adv-dl-tf2-keras/img/B14853_13_054.png)] (Equation 13.3.4)
给定P(Z, Z_bar)
,边际分布可以计算为:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tr8LeTFx-1681704403427)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/adv-dl-tf2-keras/img/B14853_13_056.png)] (Equation 13.3.5)
我们按行求和矩阵的所有条目。 类似地:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tfCszIvw-1681704403427)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/adv-dl-tf2-keras/img/B14853_13_057.png)] (Equation 13.3.6)
我们按矩阵汇总矩阵的所有条目。
给定“公式 13.3.1”中的所有项,我们可以训练神经网络编码器E
,该编码器使用损失函数来最大化 MI 或最小化负 MI:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4fE3cETW-1681704403427)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/adv-dl-tf2-keras/img/B14853_13_059.png)] (Equation 13.3.7)
在实现无监督聚类之前,让我们再次反思目标–最大化I(Z; Z_bar)
。 由于X
和X_bar = G(X)
及其对应的潜在代码向量Z
和Z_bar
共享相同的信息,因此神经网络编码器E
应该学习映射X
和X_bar
成为潜在向量Z
和Z_bar
,它们具有几乎相同的值以最大化其 MI。 在 MNIST 的背景下,看起来相似的数字将具有潜在代码向量,它们聚集在空间的同一区域中。
如果潜在代码向量是 softmax 的输出,则表明我们正在执行无监督聚类,可以使用线性分配算法将其转换为分类器。 在本章中,我们将介绍两种可能的线性分配算法,这些算法可用于将无监督的聚类转换为无监督的分类。
在下一节中,我们将讨论可用于实现无监督聚类的编码器网络模型。 特别是,我们将介绍可用于估计P(Z)
和P(Z_bar)
的编码器网络。
TensorFlow 2 和 Keras 高级深度学习:11~13(4)https://developer.aliyun.com/article/1426966