TensorFlow 2 和 Keras 高级深度学习:11~13(2)

简介: TensorFlow 2 和 Keras 高级深度学习:11~13(2)

TensorFlow 2 和 Keras 高级深度学习:11~13(1)https://developer.aliyun.com/article/1426963

5. SSD 模型架构

“图 11.5.1”显示了 SSD 的模型架构,该模型实现了多尺度单发目标检测的概念框架。 网络接受 RGB 图像,并输出几个预测级别。 基本或骨干网络提取用于分类和偏移量预测的下游任务的特征。 ResNet50 是骨干网络的一个很好的例子,它类似于“第 2 章”,“深度神经网络”中讨论,实现和评估的内容。 在骨干网络之后,对象检测任务由执行其余的网络,我们将其称为 SSD 头

骨干网络可以是具有冻结权重的预训练网络(例如,以前为 ImageNet 分类而训练),也可以是与对象检测一起训练的网络。 如果使用预先训练的基础网络,则可以利用重用以前从大型数据集中学习的特征提取过滤器的优势。 此外,由于冻结了骨干网参数,因此可以加快学习速度。 仅训练对象检测中的顶层。 在这本书中,骨干网是与对象检测联合训练的,因为我们假设我们不一定需要访问预先训练的骨干网。

骨干网网络通常使用跨步 2 或通过最大池化实现几轮下采样。 对于 ResNet50,这是 4 倍。 基本网络变为(w/2^4, h/2^4) = (w/16, h/16)之后,特征映射的结果尺寸。 如果图像的宽度和高度均可以被 16 整除,则尺寸是精确的。

例如,对于640 x 480的图像,生成的特征映射的尺寸为40 x 30 = 1200。 如前几节所述,这是基础网络之后长宽比等于 1 的锚点框的数量。 此数字乘以每个锚定框的大小数。 在前面的部分中,由于长宽比,有 6 种不同的尺寸,而长宽比为 1 时,还有一个其他尺寸。

在本书中,我们将纵横比限制为a[i ∈ {0, 1, 3}] = 1, 2, 1/2。 因此,将只有 4 种不同的大小。 对于640 x 480图像,第一组锚框的锚框总数为n[1] = 4,800

在“图 11.5.1”中,指示密集网格以表明对于第一组预测,存在大量预测(例如:40 x 30 x 4),从而导致大量补丁 。 尽管每个锚点框有 4 种尺寸,但为清楚起见,仅显示了与宽高比 1 对应的16 x 16锚点框。

此锚框也是40 x 30 x n_filter特征映射中每个元素的接受字段大小。n_filter是骨干网最后卷积层中过滤器的数量。 对于每个锚框,都将预测类别和偏移量。

总共有n[1]类和n[1]偏移量预测。 单热类预测的维数等于要检测的对象类别的数量,背景为 1。 每个偏移量变量预测的尺寸为 4,对应于(x, y)到预测边界框的 2 个角的偏移量。

类预测器由卷积层组成,该卷积层由使用 softmax 进行分类交叉熵损失的激活层终止。 偏移量预测值是具有线性激活的独立卷积层。

在基础网络之后可以应用其他特征提取模块。 每个特征提取器块都是Conv2D(strides=2)-BN-ELU的形式。 在特征提取块之后,特征映射的大小减半,并且过滤器的数量增加一倍。 例如,基本网络之后的第一个特征提取器块具有20 x 15 x 2 n_filter特征映射。 根据该特征映射,使用卷积层进行n[2]类和n[2]偏移量预测。n[2] = 20 x 15 x 4 = 1,200

可以继续添加具有类和偏移量预测变量的特征提取块的过程。 在前面的部分中,对于640 x 480的图像,最大可达2 x 1 x 2^5 n_filter特征映射产生n[6]类和n[6]抵消了其中n[6] = 2 x 1 x 4 = 8的预测。 到 6 层特征提取和预测块。 在第 6 个块之后,一个640 x 480图像的锚点映射预测总数为 9,648。

在前面的部分中,锚定框的比例因子大小按降序排列:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Kwi0SDYz-1681704403414)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/adv-dl-tf2-keras/img/B14853_11_050.png)] Equation 11.5.1)

这样做是为了使讨论清晰。 在本节中,应该意识到比例因子的大小实际上是从骨干网之后的特征映射大小开始的。 实际上,缩放因子应按升序排列:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RijKrcyO-1681704403414)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/adv-dl-tf2-keras/img/B14853_11_051.png)] (Equation 11.5.2)

这意味着如果将特征提取块的数量减少到 4,则缩放因子为:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-p2TVElVq-1681704403414)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/adv-dl-tf2-keras/img/B14853_11_052.png)] (Equation 11.5.3)

如果特征映射的宽度或高度不能被 2 整除(例如:15),则将应用天花板函数(例如:ceil(15/2) = 8)。 但是,在原始的 SSD [2]实现中,所使用的缩放因子被简化为[0.2, 0.9]范围,该范围通过缩放因子的数量或特征提取块的数量n_layers进行线性缩放:

s = np.linspace(0.2, 0.9, n_layers + 1)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Z9eIC3eZ-1681704403414)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/adv-dl-tf2-keras/img/B14853_11_09.png)]

图 11.5.1 SSD 模型架构。请注意,对于w/16 x h/16网格,锚框的数量可能不准确。 网格显示了锚框的紧密包装。

讨论了 SSD 模型架构之后,现在让我们看一下如何在 Keras 中实现 SSD 模型架构。

6. Keras 中的 SSD 模型架构

与前面章节中的代码示例不同,SSD 的tf.keras实现更加复杂。 与 SSD 的其他tf.keras实现相比,本章中提供的代码示例重点介绍多尺度目标检测的关键概念。 可以进一步优化代码实现的某些部分,例如缓存地面真锚框类,偏移量和掩码。 在我们的示例中,每次从文件系统加载图像时,线程都会计算出地面真实值。

“图 11.6.1”显示了包含 SSD 的tf.keras实现的代码块的概述。 ssd-11.6.1.py中的 SSD 对象可以构建,训练和评估 SSD 模型。 它借助model.pyresnet.py以及data_generator.py中的多线程数据生成器,位于 SSD 模型创建器的顶部。 SSD 模型实现了“图 11.5.1”中所示的 SSD 架构。 每个主要模块的实现将在后续部分中详细讨论。

SSD 模型使用 ResNet 作为其骨干网络。 它在resnet.py中调用 ResNet V1 或 V2 模型创建者。 与前几章中的示例不同,SSD 使用的数据集由数千个高分辨率图像组成。 多线程数据生成器将加载文件,并且将这些文件从文件系统排队。 它还计算锚点箱的地面真值标签。 如果没有多线程数据生成器,则在训练期间图像的加载和排队以及地面真值的计算将非常缓慢。

有许多小的但重要的例程在后台运行。 这些都集中存储在工具块中。 这些例程创建锚框,计算 IoU,建立真实情况标签,运行非最大抑制,绘制标签和框,在视频帧上显示检测到的对象,提供损失函数等。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ohoB0hD1-1681704403415)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/adv-dl-tf2-keras/img/B14853_11_10.png)]

图 11.6.1 实现 SSD 的代码块。

7. Keras 中的 SSD 对象

“列表 11.7.1”(很快显示)显示了 SSD 类。 说明了两个主要例程:

  1. 使用build_model()创建 SSD 模型
  2. 通过build_generator()实例化数据生成器

build_model首先根据训练标签创建数据字典。 字典存储图像文件名以及每个图像中每个对象的地面真实边界框坐标和类。 之后,构建骨干网和 SSD 网络模型。 模型创建的最重要产品是self.ssd – SSD 的网络模型。

标签存储在 csv 文件中。 对于本书中使用的示例训练图像,标签以以下格式保存在dataset/drinks/labels_train.csv中:

frame,xmin,xmax,ymin,ymax,class_id
0001000.jpg,310,445,104,443,1
0000999.jpg,194,354,96,478,1
0000998.jpg,105,383,134,244,1
0000997.jpg,157,493,89,194,1
0000996.jpg,51,435,207,347,1
0000995.jpg,183,536,156,283,1
0000994.jpg,156,392,178,266,2
0000993.jpg,207,449,119,213,2
0000992.jpg,47,348,213,346,2

“列表 11.7.1”:ssd-11.6.1.py

class SSD:
    """Made of an ssd network model and a dataset generator.
    SSD defines functions to train and validate 
    an ssd network model.
Arguments:
        args: User-defined configurations
Attributes:
        ssd (model): SSD network model
        train_generator: Multi-threaded data generator for training
    """
    def __init__(self, args):
        """Copy user-defined configs.
        Build backbone and ssd network models.
        """
        self.args = args
        self.ssd = None
        self.train_generator = None
        self.build_model()
def build_model(self):
        """Build backbone and SSD models."""
        # store in a dictionary the list of image files and labels
        self.build_dictionary()
        # 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 number of feature layers is equal to n_layers
        # feature layers are inputs to SSD network heads
        # for class and offsets predictions
        self.backbone = self.args.backbone(self.input_shape,
                                           n_layers=self.args.layers)
# using the backbone, build ssd network
        # outputs of ssd are class and offsets predictions
        anchors, features, ssd = build_ssd(self.input_shape,
                                           self.backbone,
                                           n_layers=self.args.layers,
                                           n_classes=self.n_classes)
        # n_anchors = num of anchors per feature point (eg 4)
        self.n_anchors = anchors
        # feature_shapes is a list of feature map shapes
        # per output layer - used for computing anchor boxes sizes
        self.feature_shapes = features
        # ssd network model
        self.ssd = ssd
def build_dictionary(self):
        """Read input image filenames and obj detection labels
        from a csv file and store in a dictionary.
        """
        # train dataset path
        path = os.path.join(self.args.data_path,
                            self.args.train_labels)
# build dictionary: 
        # key=image filaname, value=box coords + class label
        # self.classes is a list of class labels
        self.dictionary, self.classes = build_label_dictionary(path)
        self.n_classes = len(self.classes)
        self.keys = np.array(list(self.dictionary.keys()))
def build_generator(self):
        """Build a multi-thread train data generator."""
self.train_generator = \
                DataGenerator(args=self.args,
                              dictionary=self.dictionary,
                              n_classes=self.n_classes,
                              feature_shapes=self.feature_shapes,
                              n_anchors=self.n_anchors,
                              shuffle=True)

“列表 11.7.2”显示了 SSD 对象中的另一种重要方法train()。 指示了使用默认损失函数或改进的损失函数的选项,如先前部分所述。 还有一个选项可以选择仅平滑 L1。

self.ssd.fit_generator()是此函数中最重要的调用。 它借助多线程数据生成器启动有监督的训练。 在每个周期,都会执行两个回调函数。 首先,将模型权重保存到文件中。 然后,对于 ResNet 模型,以与“第 2 章”,“深度神经网络”相同的方式使用的改进的学习率调度器称为:

“列表 11.7.2”:ssd-11.6.1.py

def train(self):
        """Train an ssd network."""
        # build the train data generator
        if self.train_generator is None:
            self.build_generator()
optimizer = Adam(lr=1e-3)
        # choice of loss functions via args
        if self.args.improved_loss:
            print_log("Focal loss and smooth L1", self.args.verbose)
            loss = [focal_loss_categorical, smooth_l1_loss]
        elif self.args.smooth_l1:
            print_log("Smooth L1", self.args.verbose)
            loss = ['categorical_crossentropy', smooth_l1_loss]
        else:
            print_log("Cross-entropy and L1", self.args.verbose)
            loss = ['categorical_crossentropy', l1_loss]
self.ssd.compile(optimizer=optimizer, loss=loss)
# prepare callbacks for saving model weights
        # and learning rate scheduler
        # learning rate decreases by 50% every 20 epochs
        # after 60th epoch
        checkpoint = ModelCheckpoint(filepath=filepath,
                                     verbose=1,
                                     save_weights_only=True)
        scheduler = LearningRateScheduler(lr_scheduler)
callbacks = [checkpoint, scheduler]
        # train the ssd network
        self.ssd.fit_generator(generator=self.train_generator,
                               use_multiprocessing=True,
                               callbacks=callbacks,
                               epochs=self.args.epochs,
                               workers=self.args.workers)

在下一部分中,我们将讨论 Keras 中 SSD 架构实现的其他详细信息。 特别是 SSD 模型和多线程数据生成器的实现。

8. Keras 中的 SSD 模型

“列表 11.8.1”显示了 SSD 模型创建函数build_ssd()。 该模型在“图 11.5.1”中进行了说明。 该函数通过调用base_outputs = backbone(inputs)从骨干网或基础网络检索输出特征的n_layers

在本书中,backbone()build_resnet()build_resnet()可以生成的 ResNet 模型类似于“第 2 章”,“深度神经网络”中讨论的残差网络。 build_resnet()函数可以由构建基础网络的任何函数名称代替。

如图“图 11.5.1”所示,返回值base_outputs是输出特征的列表,这些特征将作为类别和偏移预测层的输入。 例如,第一输出base_outputs[0]用于生成n[1]类预测和n[1]偏移量预测。

build_ssd()for循环中,类别预测是classes变量,而偏移量预测是offsets变量。 在for循环迭代之后,将类别预测连接,并最终合并为一个具有以下尺寸的classes变量:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XSiT2ATp-1681704403415)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/adv-dl-tf2-keras/img/B14853_11_055.png)]

offsets变量执行相同的过程。 结果尺寸为:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hILIvRYc-1681704403415)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/adv-dl-tf2-keras/img/B14853_11_056.png)]

其中n_mini_batch是迷你批量大小,n_anchor_box是锚定框的数量。 for循环迭代的次数等于n_layers。 该数目也等于锚定框缩放因子的所需数目或 SSD 头的特征提取块的数目。

函数build_ssd()返回每个特征点或区域的锚框数量,每个前类的特征形状,偏移量预测层以及 SSD 模型本身。

“列表 11.8.1”:model.py

def build_ssd(input_shape,
              backbone,
              n_layers=4,
              n_classes=4,
              aspect_ratios=(1, 2, 0.5)):
    """Build SSD model given a backbone
    Arguments:
        input_shape (list): input image shape
        backbone (model): Keras backbone model
        n_layers (int): Number of layers of ssd head
        n_classes (int): Number of obj classes
        aspect_ratios (list): annchor box aspect ratios
    Returns:
        n_anchors (int): Number of anchor boxes per feature pt
        feature_shape (tensor): SSD head feature maps
        model (Keras model): SSD model
    """ 
    # number of anchor boxes per feature map pt
    n_anchors = len(aspect_ratios) + 1
inputs = Input(shape=input_shape)
    # no. of base_outputs depends on n_layers
    base_outputs = backbone(inputs)
    outputs = []
    feature_shapes = []              
    out_cls = []                     
    out_off = []
for i in range(n_layers):
        # each conv layer from backbone is used
        # as feature maps for class and offset predictions
        # also known as multi-scale predictions
        conv = base_outputs if n_layers==1 else base_outputs[i]
        name = "cls" + str(i+1)
        classes  = conv2d(conv,
                          n_anchors*n_classes,
                          kernel_size=3,
                          name=name)
# offsets: (batch, height, width, n_anchors * 4)
        name = "off" + str(i+1)
        offsets  = conv2d(conv,
                          n_anchors*4,
                          kernel_size=3,
                          name=name)
shape = np.array(K.int_shape(offsets))[1:]
        feature_shapes.append(shape)
        # reshape the class predictions, yielding 3D tensors of 
        # shape (batch, height * width * n_anchors, n_classes)
        # last axis to perform softmax on them
        name = "cls_res" + str(i+1)
        classes = Reshape((-1, n_classes),
                          name=name)(classes)
# reshape the offset predictions, yielding 3D tensors of
        # shape (batch, height * width * n_anchors, 4)
        # last axis to compute the (smooth) L1 or L2 loss
        name = "off_res" + str(i+1)
        offsets = Reshape((-1, 4),
                          name=name)(offsets)
        # concat for alignment with ground truth size
        # made of ground truth offsets and mask of same dim
        # needed during loss computation
        offsets = [offsets, offsets]
        name = "off_cat" + str(i+1)
        offsets = Concatenate(axis=-1,
                              name=name)(offsets)
# collect offset prediction per scale
        out_off.append(offsets)
name = "cls_out" + str(i+1)
#activation = 'sigmoid' if n_classes==1 else 'softmax'
        #print("Activation:", activation)
classes = Activation('softmax',
                             name=name)(classes)
# collect class prediction per scale
        out_cls.append(classes)
if n_layers > 1:
        # concat all class and offset from each scale
        name = "offsets"
        offsets = Concatenate(axis=1,
                              name=name)(out_off)
        name = "classes"
        classes = Concatenate(axis=1,
                              name=name)(out_cls)
    else:
        offsets = out_off[0]
        classes = out_cls[0]
outputs = [classes, offsets]
    model = Model(inputs=inputs,
                  outputs=outputs,
                  name='ssd_head')
return n_anchors, feature_shapes, model

如前面所述,与 MNIST 和 CIFAR-10 等小型数据集不同,SSD 中使用的映像很大。 因此,不可能将图像加载到张量变量中。 在下一节中,我们将介绍一个多线程数据生成器,该生成器将使我们能够从文件系统并发加载图像,并避免内存瓶颈。

9. Keras 中的数据生成器模型

SSD 需要大量带标签的高分辨率图像来进行对象检测。 与之前的章节中使用的数据集可以加载到到内存中以训练模型不同,SSD 实现了多线程数据生成器。 多线程生成器的任务是加载图像的多个迷你批量及其相应的标签。 由于具有多线程,GPU 可以保持繁忙,因为一个线程向其提供数据,而其余的 CPU 线程处于队列中,准备从文件系统中馈入另一批数据或加载一批图像并计算基本真值 。“列表 11.9.1”显示了 Keras 中的数据生成器模型。

DataGenerator类继承自 Keras 的Sequence类,以确保它支持多处理。 DataGenerator保证在一个周期内使用整个数据集。

给定批量大小的整个周期的长度由__len__()方法返回。 对小批量数据的每个请求都可以通过__getitem__()方法来满足。 在每个周期之后,如果self.shuffleTrue,则调用on_epoch_end()方法以随机播放整个批量。

“列表 11.9.1”:data_generator.py

class DataGenerator(Sequence):
    """Multi-threaded data generator.
    Each thread reads a batch of images and their object labels
Arguments:
        args: User-defined configuration
        dictionary: Dictionary of image filenames and object labels
        n_classes (int): Number of object classes
        feature_shapes (tensor): Shapes of ssd head feature maps
        n_anchors (int): Number of anchor boxes per feature map pt
        shuffle (Bool): If dataset should be shuffled bef sampling
    """
    def __init__(self,
                 args,
                 dictionary,
                 n_classes,
                 feature_shapes=[],
                 n_anchors=4,
                 shuffle=True):
        self.args = args
        self.dictionary = dictionary
        self.n_classes = n_classes
        self.keys = np.array(list(self.dictionary.keys()))
        self.input_shape = (args.height,
                            args.width,
                            args.channels)
        self.feature_shapes = feature_shapes
        self.n_anchors = n_anchors
        self.shuffle = shuffle
        self.on_epoch_end()
        self.get_n_boxes()
def __len__(self):
        """Number of batches per epoch"""
        blen = np.floor(len(self.dictionary) / self.args.batch_size)
        return int(blen)
def __getitem__(self, index):
        """Get a batch of data"""
        start_index = index * self.args.batch_size
        end_index = (index+1) * self.args.batch_size
        keys = self.keys[start_index: end_index]
        x, y = self.__data_generation(keys)
        return x, y
def on_epoch_end(self):
        """Shuffle after each epoch"""
        if self.shuffle == True:
            np.random.shuffle(self.keys)
def get_n_boxes(self):
        """Total number of bounding boxes"""
        self.n_boxes = 0
        for shape in self.feature_shapes:
            self.n_boxes += np.prod(shape) // self.n_anchors
        return self.n_boxes

数据生成器的大部分工作都是通过__data_generation()方法完成的,如“列表 11.9.2”所示。 给定一个小批量,该方法执行:

  • imread()从文件系统读取图像。
  • labels = self.dictionary[key]访问词典中存储的边界框和类标签。 前四个项目是边界框偏移量。 最后一个是类标签。
  • anchor_boxes()生成锚框。
  • iou()计算相对于地面真值边界框的每个锚点框的 IoU。
  • get_gt_data()为每个锚框分配地面真实等级和偏移量。

样本数据扩充函数也包括在内,但此处不再讨论,例如添加随机噪声,强度重新缩放和曝光调整。 __data_generation()返回输入x和输出y对,其中张量x存储输入图像,而张量y捆绑类,偏移量 ,和面具一起。

“列表 11.9.2”:data_generator.py

import layer_utils
from skimage.io import imread
    def __data_generation(self, keys):
        """Generate train data: images and 
        object detection ground truth labels
Arguments:
            keys (array): Randomly sampled keys
                (key is image filename)
Returns:
            x (tensor): Batch images
            y (tensor): Batch classes, offsets, and masks
        """
        # train input data
        x = np.zeros((self.args.batch_size, *self.input_shape))
        dim = (self.args.batch_size, self.n_boxes, self.n_classes)
        # class ground truth
        gt_class = np.zeros(dim)
        dim = (self.args.batch_size, self.n_boxes, 4)
        # offsets ground truth
        gt_offset = np.zeros(dim)
        # masks of valid bounding boxes
        gt_mask = np.zeros(dim)
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))
            # assign image to a batch index
            x[i] = image
            # a label entry is made of 4-dim bounding box coords
            # and 1-dim class label
            labels = self.dictionary[key]
            labels = np.array(labels)
            # 4 bounding box coords are 1st four items of labels
            # last item is object class label
            boxes = labels[:,0:-1]
            for index, feature_shape in enumerate(self.feature_shapes):
                # generate anchor boxes
                anchors = anchor_boxes(feature_shape,
                                       image.shape,
                                       index=index,
                                       n_layers=self.args.layers)
                # each feature layer has a row of anchor boxes 
                anchors = np.reshape(anchors, [-1, 4])
                # compute IoU of each anchor box 
                # with respect to each bounding boxes
                iou = layer_utils.iou(anchors, boxes)
# generate ground truth class, offsets & mask
                gt = get_gt_data(iou,
                                 n_classes=self.n_classes,
                                 anchors=anchors,
                                 labels=labels,
                                 normalize=self.args.normalize,
                                 threshold=self.args.threshold)
                gt_cls, gt_off, gt_msk = gt
                if index == 0:
                    cls = np.array(gt_cls)
                    off = np.array(gt_off)
                    msk = np.array(gt_msk)
                else:
                    cls = np.append(cls, gt_cls, axis=0)
                    off = np.append(off, gt_off, axis=0)
                    msk = np.append(msk, gt_msk, axis=0)
gt_class[i] = cls
            gt_offset[i] = off
            gt_mask[i] = msk
y = [gt_class, np.concatenate((gt_offset, gt_mask), axis=-1)]
return x, y

现在我们有一个多线程生成器,我们可以用它来从文件系统加载图像。 在下一节中,我们将演示如何通过拍摄目标对象的图像并对其进行标记来构建自定义数据集。

10. 示例数据集

使用便宜的 USB 相机(A4TECH PK-635G)收集了一个由 1,000 640 X 480 RGB 训练图像和 50 640 X 480 RGB 测试图像组成的小型数据集。 使用 VGG 图像标注器VIA)[5]标记数据集图像,以检测三个对象:1)汽水罐,2)果汁罐和 3)水瓶。“图 11.10.1”显示了标记过程的示例 UI。

可以在GitHub存储库的utils/video_capture.py中找到用于收集图像的工具脚本。 该脚本每 5 秒自动捕获一次图像,因此可以加快数据收集过程。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DXlDpg8P-1681704403415)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/adv-dl-tf2-keras/img/B14853_11_11.png)]

图 11.10.1 使用 VGG 图像标注器(VIA)进行数据集标记的过程

数据收集和标记是一项耗时的活动。 在行业中,通常将其外包给第三方标注公司。 使用自动数据标记软件是加快数据标记任务的另一种选择。

有了这个示例数据集,我们现在可以训练我们的对象检测网络。

11. SSD 模型训练

可以从以下链接下载包含 csv 格式标签的 train 和测试数据集

在顶层文件夹(即“第 11 章”,“对象检测”)中,创建数据集文件夹,将下载的文件复制到此处,然后运行以下命令将其解压缩:

mkdir dataset
cp drinks.tar.gz dataset
cd dataset
tar zxvf drinks.tar.gz
cd..

通过执行以下步骤,将 SSD 模型训练 200 个周期:

python3 ssd-11.6.1.py --train

可以根据 GPU 内存调整默认的批量大小--batch-size=4。 在 1080Ti 上,批量大小为 2。在 32GB V100 上,每个 GPU 可以为 4 或 8。 --train代表模型训练选项。

为了支持边界框偏移量的归一化,包含--normalize选项。 为了使用改进的损失函数,添加了--improved_loss选项。 如果仅需要平滑的 L1(无焦点损失),请使用–smooth-l1。 为了显示:

  • L1,无规范化:
  • python3 ssd-11.1.1.py –-train
  • 改进的损失函数,无规范化:
  • python3 ssd-11.1.1.py –-train --improved-loss
  • 改进的损失函数,具有规范化:
  • python3 ssd-11.1.1.py –-train –improved-loss --normalize
  • 平滑 L1,具有规范化:
  • python3 ssd-11.1.1.py –-train –-smooth-l1 --normalize

训练完 SSD 网络之后,我们需要解决另一个问题。 我们如何处理给定对象的多个预测? 在测试训练好的模型之前,我们将首先讨论非最大抑制NMS)算法。

12. 非最大抑制(NMS)算法

模型训练完成后,网络将预测边界框偏移量和相应的类别。 在某些情况下,两个或更多边界框引用同一对象,从而创建冗余预测。 图 11.12.1 中的汽水罐表示了这种情况。 为了删除多余的预测,将调用 NMS 算法。 本书涵盖了经典 NMS 和软 NMS [6],如“算法 11.12.1”中所示。 两种算法都假定边界框和相应的置信度得分或概率是已知的。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RQWgzBKI-1681704403416)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/adv-dl-tf2-keras/img/B14853_11_12.png)]

图 11.12.1 网络预测了汽水罐对象的两个重叠边界框。 只选择一个有效的边界框,即得分为 0.99 的边界框。

在经典 NMS 中,基于概率选择最终边界框,并将其存储在列表D中,并带有相应的分数S。 所有边界框和相应的概率都存储在初始列表BP中。 在第 3 行和第 4 行中,将具有最高分数p[m]的边界框用作参考,b[m]

参考边界框被添加到最终选择的边界框D的列表中,并从列表B中删除,如第 5 行所示。 并且列表SP中删除。 对于其余边界框,如果 IoUb[m]大于或等于设置的阈值N[t],将其从B中删除。 其相应的分数也从P中删除。

步骤在第 6 和 9-11 行中显示。 这些步骤将删除所有分数较小的冗余边界框。 在检查完所有其余的边界框之后,重复从第 3 行开始的过程。 该过程继续进行,直到边界框B的列表为空。 该算法返回选定的边界框D和相应的分数S

经典 NMS 的问题是边界盒包含另一个对象,但其中的 IoUb[m]会从列表中删除。 Soft NMS [6]提出,与其从列表中彻底删除,不如以b[m],如第 8 行所示。

重叠的边界框具有第二次机会。 IoU 较小的边界框在将来的迭代中具有更高的生存机会。 在将来的选择中,它实际上可能证明它包含一个与b[m]不同的对象。 如“算法 11.12.1”中所示,Soft NMS 是传统 NMS 的便捷替代。 无需重新训练 SSD 网络。 与经典 NMS 相比,Soft NMS 具有更高的平均精度。

“列表 11.12.1”说明了经典 NMS 和软 NMS。 除了最终的边界框和相应的分数外,还返回相应的对象。 当其余边界框的最大分数小于某个阈值(例如:0.2)时,该代码将实现 NMS 的提前终止。

TensorFlow 2 和 Keras 高级深度学习:11~13(3)https://developer.aliyun.com/article/1426965

相关文章
|
6天前
|
机器学习/深度学习 API 语音技术
|
3月前
|
机器学习/深度学习 存储 人工智能
TensorFlow Lite,ML Kit 和 Flutter 移动深度学习:6~11(3)
TensorFlow Lite,ML Kit 和 Flutter 移动深度学习:6~11(3)
80 0
|
3月前
|
机器学习/深度学习 Dart TensorFlow
TensorFlow Lite,ML Kit 和 Flutter 移动深度学习:6~11(5)
TensorFlow Lite,ML Kit 和 Flutter 移动深度学习:6~11(5)
67 0
|
2月前
|
机器学习/深度学习 PyTorch TensorFlow
Python中的深度学习:TensorFlow与PyTorch的选择与使用
Python中的深度学习:TensorFlow与PyTorch的选择与使用
|
2月前
|
机器学习/深度学习 人工智能 API
人工智能应用工程师技能提升系列2、——TensorFlow2——keras高级API训练神经网络模型
人工智能应用工程师技能提升系列2、——TensorFlow2——keras高级API训练神经网络模型
30 0
|
2月前
|
机器学习/深度学习 数据可视化 TensorFlow
基于tensorflow深度学习的猫狗分类识别
基于tensorflow深度学习的猫狗分类识别
61 1
|
2月前
|
机器学习/深度学习 人工智能 算法
【深度学习】因果推断与机器学习的高级实践 | 数学建模
【深度学习】因果推断与机器学习的高级实践 | 数学建模
|
3月前
|
机器学习/深度学习 PyTorch TensorFlow
【TensorFlow】深度学习框架概述&TensorFlow环境配置
【1月更文挑战第26天】【TensorFlow】深度学习框架概述&TensorFlow环境配置
|
3月前
|
机器学习/深度学习 存储 编解码
TensorFlow Lite,ML Kit 和 Flutter 移动深度学习:6~11(4)
TensorFlow Lite,ML Kit 和 Flutter 移动深度学习:6~11(4)
119 0
|
3月前
|
机器学习/深度学习 人工智能 API
TensorFlow Lite,ML Kit 和 Flutter 移动深度学习:1~5
TensorFlow Lite,ML Kit 和 Flutter 移动深度学习:1~5
69 0