# TensorFlow 2 和 Keras 高级深度学习：11~13（3）

TensorFlow 2 和 Keras 高级深度学习：11~13（2）https://developer.aliyun.com/article/1426964

“算法 11.12.1”NMS 和软 NMS

1. D <- {}S <- {}
2. B ≠ empty，执行
3. m <- argmax P
4. M <- b[m]N <- p[m]
5. D <- D ∪ MB <- B - MS <- S ∪ NP <- P - N
6. 对于步骤b[i] ∈ B，执行
7. 如果soft_NMS = True
8. p[i] = p[i] exp(-IOU(M, b[i])^2 / σ)
9. 否则如果IOU(M, b[i]) >= N[t]，那么
10. B = B - b[i]P = P - p[i]
11. 结束
12. 结束
13. 结束
14. 返回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:
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

## 13. SSD 模型验证

• 无规范化：
• 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

python3 ssd-11.6.1.py –-restore-weights=<weights_file>
--image-file=<target_image_file> --evaluate

python3 ssd-11.6.1.py --restore-weights=ResNet56v2-4layer-extra_anchors-drinks-200.h5 --image-file=dataset/drinks/0010050.jpg --evaluate

“列表 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, 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)

 未归一化的偏移 未归一化的偏移，平滑 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

## 15. 参考

1. Krizhevsky Alex, Ilya Sutskever, and Geoffrey E. Hinton. "Imagenet classification with deep convolutional neural networks." Advances in neural information processing systems. 2012.
2. Liu Wei, et al. "SSD: Single Shot MultiBox Detector." European conference on computer vision. Springer, Cham, 2016.
3. Girshick Ross. "Fast R-CNN." Proceedings of the IEEE international conference on computer vision. 2015.
4. Lin Tsung-Yi, et al. "Focal loss for Dense Object Detection. "Proceedings of the IEEE international conference on computer vision. 2017.
5. Dutta, et al. VGG Image Annotator http://www.robots.ox.ac.uk/~vgg/software/via/
6. Bodla Navaneeth, et al. "Soft-NMS--Improving Object Detection With One Line of Code." Proceedings of the IEEE international conference on computer vision. 2017.
7. Everingham Mark, et al. "The Pascal Visual Object Classes (VOC) challenge." International journal of computer vision 88.2 (2010): 303-338.
8. "Huber Loss." https://en.wikipedia.org/wiki/Huber_loss

## 十二、语义分割

• 不同类型的分割算法
• 全卷积网络FCN）作为语义分割算法的实现
• tf.keras中 FCN 的实现和评估

## 1. 分割

“图 12.1.1”显示了不同类型的细分之间的区别。 输入的图像在桌子的顶部显示了两个汽水罐和两个果汁罐。 背景杂乱无章。 假设我们只对汽水罐和果汁罐感兴趣，在实例细分中，我们为每个对象实例分配唯一的颜色以分别区分四个对象。 对于语义分割，我们假设将所有的汽水罐都塞在一起，将果汁罐作为另一罐塞在一起，将背景作为最后的罐塞在一起。 基本上，我们为每种物料分配了唯一的颜色。 最后，在全景分割中，我们假设只有背景才是背景，而我们只对苏打水和果汁罐感兴趣。

## 2. 语义分割网络

Zhao 等人的《金字塔场景解析网络（PSPNet）》进行了改进，进一步增强了我们的语义分割网络架构 [3]。 在 PSPNet 中，每个特征映射由另一个卷积层进一步处理。 此外，还使用了第一组特征映射。

FCN 和 PSPNet 都对特征金字塔进行了上采样，以达到与第一组特征映射相同的大小。 之后，使用Concatenate层将所有上采样特征融合在一起。 然后级联层通过步长等于 2 的转置卷积处理两次，以恢复原始图像的宽度和高度。 最后，使用核大小为 1 且过滤器等于 4（换句话说，类别数）和Softmax层的转置卷积生成按像素分类预测。

## 3. Keras 中的语义分割网络

“列表 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,
kernel_initializer='he_normal',
name="pre_activation")(x)
x = Softmax(name="segmentation")(x)
model = Model(inputs, x, name="fcn")
return model

“列表 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"""
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)

“列表 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)
# 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)

## 4. 示例数据集

“图 12.4.1”显示了标记过程的示例 UI。

segmentation_train.json
segmentation_test.json

segmentation_train.npy
segmentation_test.npy

## 5. 语义分割验证

python3 fcn-12.3.1.py --train

“图 12.5.1”显示了在每个周期使用 mIoU 的语义分割网络的表现。 最大 mIoU 为 0.91。 这个比较高。 但是，我们的数据集只有四个对象类别：

“图 12.5.2”显示了在每个周期使用平均像素精度的语义分割网络的表现。 最大平均像素精度为 97.9%。 我们可以看到平均像素精度与 mIoU 之间的相关性：

“图 12.5.3”显示了输入图像，地面实况语义分割掩码和预测的语义分割掩码的样本：

python3 fcn-12.3.1.py --evaluate
--restore-weights=ResNet56v2-3layer-drinks-best-iou.h5

## 7. 参考

1. Kirillov, Alexander, et al.: Panoptic Segmentation. Proceedings of the IEEE conference on computer vision and pattern recognition. 2019.
2. 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.
3. Zhao, Hengshuang, et al.: Pyramid Scene Parsing Network. Proceedings of the IEEE conference on computer vision and pattern recognition. 2017.
4. Dutta, et al.: VGG Image Annotator http://www.robots.ox.ac.uk/~vgg/software/via/
5. He Kaiming, et al.: Mask R-CNN. Proceedings of the IEEE international conference on computer vision. 2017.

## 十三、使用互信息的无监督学习

MI 最近已成功地从未标记的数据中提取了有用的信息，可以帮助学习下游任务。 例如，MI 能够对潜在代码向量进行聚类，从而使分类任务成为简单的线性分离问题。

• 互信息的概念
• 使用神经网络估计 MI
• 下游任务的离散和连续随机变量上的 MI 最大化
• Keras 中 MI 估计网络的实现

## 1. 互信息

• PXY）是 X 和 Y 在样本空间XxY上的联合分布 。
• PXPY）是边际分布PX）和PY）分别位于样本空间XY上。

• PXY）是联合概率质量函数PMF）。
• PX）和PY）是边际 PMF。

• pxy）是联合概率密度函数PDF）。
• px）和py）是边缘 PDF。

## 2. 互信息和熵

MI 也可以用熵来解释。 回想一下“第 6 章”，“纠缠表示 GAN” ，熵HX）是对预期信息量的度量。 随机变量X的：

“公式 13.2.1”表示熵还是不确定性的量度。 不确定事件的发生给我们带来了更多的惊喜或信息。 例如，有关员工意外晋升的新闻具有大量信息或熵。

“公式 13.2.2”表示 MI 随着边际熵增加而增加，但随联合熵而减少。 就熵而言，MI 的一个更常见的表达式如下：

“公式 13.2.3”告诉我们，MI 随随机变量的熵增加而减小，而随另一个随机变量的条件熵而减小。 或者，如果我们知道Y，则 MI 是的信息减少量或X的不确定性。

“公式 13.2.4”表示 MI 是对称的：

MI 也可以用XY的条件熵表示：

“图 13.2.1”总结了到目前为止我们讨论的 MI 与条件熵和边际熵之间的所有关系：

MI 的另一种有趣解释是根据“公式 13.2.3”，可以将其重写为：

## 3. 通过最大化离散随机变量的互信息来进行无监督学习

Ji 等人的不变信息聚类IIC）[1] 建议从联合和边际分布直接测量I(X; Y)。 目的是使用“公式 13.1.2”测量引用同一输入的两个潜在代码随机变量之间的 MI。 假设输入X编码为Z

TensorFlow 2 和 Keras 高级深度学习：11~13（4）https://developer.aliyun.com/article/1426966

|
3月前
|

TensorFlow Lite，ML Kit 和 Flutter 移动深度学习：6~11（3）
TensorFlow Lite，ML Kit 和 Flutter 移动深度学习：6~11（3）
80 0
|
3月前
|

TensorFlow Lite，ML Kit 和 Flutter 移动深度学习：6~11（5）
TensorFlow Lite，ML Kit 和 Flutter 移动深度学习：6~11（5）
67 0
|
2天前
|

|
2月前
|

Python中的深度学习：TensorFlow与PyTorch的选择与使用
Python中的深度学习：TensorFlow与PyTorch的选择与使用
44 0
|
2月前
|

29 0
|
2月前
|

61 1
|
2月前
|

【深度学习】因果推断与机器学习的高级实践 | 数学建模
【深度学习】因果推断与机器学习的高级实践 | 数学建模
56 0
|
3月前
|

【TensorFlow】深度学习框架概述&TensorFlow环境配置
【1月更文挑战第26天】【TensorFlow】深度学习框架概述&TensorFlow环境配置
61 0
|
3月前
|

TensorFlow Lite，ML Kit 和 Flutter 移动深度学习：6~11（4）
TensorFlow Lite，ML Kit 和 Flutter 移动深度学习：6~11（4）
119 0
|
3月前
|

TensorFlow Lite，ML Kit 和 Flutter 移动深度学习：1~5
TensorFlow Lite，ML Kit 和 Flutter 移动深度学习：1~5
67 0