从零开始码一个皮卡丘检测器-CNN目标检测入门教程(上)

简介: 跟所有的图像相关的网络一样,我们需要一个主干网络来提取特征,同时也是作为第一个预测特征层。网络在当前层产生大量的预设框,和与之对应的每个方框的分类概率(背景,猫,狗等等)以及真正的物体和预设框的偏移量。

本文先为大家介绍目前流行的目标检测算法SSD (Single-Shot MultiBox Object Detection)和实验过程中的数据集。训练、测试过程及结果参见《从零开始码一个皮卡丘检测器-CNN目标检测入门教程(下)》

目标检测通俗的来说是为了找到图像或者视频里的所有目标物体。在下面这张图中,两狗一猫的位置,包括它们所属的类(狗/猫),需要被正确的检测到。

从零开始码一个皮卡丘检测器-CNN目标检测入门教程(上)

所以和图像分类不同的地方在于,目标检测需要找到尽量多的目标物体,而且要准确的定位物体的位置,一般用矩形框来表示。

在接下来的章节里,我们先介绍一个流行的目标检测算法,SSD (Single-Shot MultiBox Object Detection).

友情提示:本章节特别长,千万不要在蹲坑的时候点开。
本文中涉及MXNet 0.11最新的发布的gluon接口,参考 MXNet 0.11发布,加入动态图接口Gluon,还有两位CMU教授的亲笔教程(https://zhuanlan.zhihu.com/p/28648399)

SSD:  Single Shot MultiBox Detector

顾名思义,算法的核心是用卷积神经网络一次前向推导求出大量多尺度(几百到几千)的方框来表示目标检测的结果。网络的结构用下图表示。

从零开始码一个皮卡丘检测器-CNN目标检测入门教程(上)

跟所有的图像相关的网络一样,我们需要一个主干网络来提取特征,同时也是作为第一个预测特征层。网络在当前层产生大量的预设框,和与之对应的每个方框的分类概率(背景,猫,狗等等)以及真正的物体和预设框的偏移量。在完成当前层的预测后,我们会下采样当前特征层,作为新的预测层,重新产生新的预设框,分类概率,偏移量。这个过程往往会重复好几次,直到预测特征层到达全局尺度( 从零开始码一个皮卡丘检测器-CNN目标检测入门教程(上) )。

接下来我们用例子解释每个细节实现。

预设框 Default anchor boxes

预设框的形状和大小可以由参数控制,我们往往设置一堆预设框,以期望任意图像上的物体都能有一个预设框能大致重合,由于每个预设框需要对应的预测网络预测值,所以希望对于每个物体都有100%重合的预设框是不现实的,可能会需要几十万甚至几百万的预设框,但是采样的预设框越多,重合概率越好,用几千到上万个预设框基本能实现略大于70%的最好重合率,同时保证了检测的速度。

为了保证重合覆盖率,对于每个特征层上的像素点,我们用不同的大小和长宽比来采样预设框。 假设在某个特定的特征层( 从零开始码一个皮卡丘检测器-CNN目标检测入门教程(上) ),每个预设框的中心点就是特征像素点的中心,然后我们用如下的公式采样预设框:

  • 预设框的中心为特征像素点的中心 从零开始码一个皮卡丘检测器-CNN目标检测入门教程(上)

  • 对于长宽比 从零开始码一个皮卡丘检测器-CNN目标检测入门教程(上) ,  尺寸从零开始码一个皮卡丘检测器-CNN目标检测入门教程(上) , 生成的预设框大小 从零开始码一个皮卡丘检测器-CNN目标检测入门教程(上) 。

  • 对于长宽比 从零开始码一个皮卡丘检测器-CNN目标检测入门教程(上) 同时 从零开始码一个皮卡丘检测器-CNN目标检测入门教程(上) , 生成的预设框大小 从零开始码一个皮卡丘检测器-CNN目标检测入门教程(上) , 其中 从零开始码一个皮卡丘检测器-CNN目标检测入门教程(上) 是第一个预设的尺寸。

这里例子里,我们用事先实现的层MultiBoxPrior产生预设框,输入 从零开始码一个皮卡丘检测器-CNN目标检测入门教程(上) 个预设尺寸,和 从零开始码一个皮卡丘检测器-CNN目标检测入门教程(上) 个预设的长宽比,输出为 从零开始码一个皮卡丘检测器-CNN目标检测入门教程(上) 个方框而不是 从零开始码一个皮卡丘检测器-CNN目标检测入门教程(上) 个。 当然我们完全可以使用其他的算法产生不同的预设框,但是实践中我们发现上述的方法覆盖率和相应需要的预设框数量比较合适。

import mxnet as mx

from mxnet import nd

from mxnet.contrib.ndarray import MultiBoxPrior


n=40

#  输入形状: batch x channel x height x weight

x=nd.random_uniform(shape=(1,3,n,n))


y=MultiBoxPrior(x,sizes=[.5,.25,.1],ratios=[1,2,.5])


# 取位于 (20,20) 像素点的第一个预设框

# 格式为 (x_min, y_min, x_max, y_max)

boxes=y.reshape((n,n,-1,4))

print('The first anchor box at row 21, column 21:',boxes[20,20,0,:])

The first anchor box at row 21, column 21:
[ 0.26249999  0.26249999  0.76249999  0.76249999]
<NDArray 4 @cpu(0)>

看着数字不够直观的话,我们把框框画出来。取最中心像素的所有预设框,画在图上的话,我们看到已经可以覆盖几种尺寸和位置的物体了。把所有位置的组合起来,就是相当可观的预设框集合了。

import matplotlib.pyplot as plt

def box_to_rect(box,color,linewidth=3):

    """convert an anchor box to a matplotlib rectangle"""

    box=box.asnumpy()

    returnplt.Rectangle(

        (box[0],box[1]),(box[2]-box[0]),(box[3]-box[1]),

        fill=False,edgecolor=color,linewidth=linewidth)

colors=['blue','green','red','black','magenta']

plt.imshow(nd.ones((n,n,3)).asnumpy())

anchors=boxes[20,20,:,:]

for i in range(anchors.shape[0]):

    plt.gca().add_patch(box_to_rect(anchors[i,:]*n,colors[i]))

plt.show()

从零开始码一个皮卡丘检测器-CNN目标检测入门教程(上)

分类预测 Predict classes

这个部分的目标很简单,就是预测每个预设框对应的分类。我们用 从零开始码一个皮卡丘检测器-CNN目标检测入门教程(上) , Padding (填充)  从零开始码一个皮卡丘检测器-CNN目标检测入门教程(上) 的卷积来预测分类概率,这样可以做到卷积后空间上的形状不会变化,而且由于卷积的特点,每个卷积核会扫过每个预测特征层的所有像素点,得到 从零开始码一个皮卡丘检测器-CNN目标检测入门教程(上) 个预测值, 从零开始码一个皮卡丘检测器-CNN目标检测入门教程(上) 对应了空间上所有的像素点,每个通道对应特定的预设框 从零开始码一个皮卡丘检测器-CNN目标检测入门教程(上) 。假设有10个正类,每个像素5个预设框,那么我们就需要 从零开始码一个皮卡丘检测器-CNN目标检测入门教程(上) 个通道。 具体的来说,对于每个像素第 从零开始码一个皮卡丘检测器-CNN目标检测入门教程(上) 个预设框:

  • 通道 从零开始码一个皮卡丘检测器-CNN目标检测入门教程(上) 的值对应背景(非物体)的得分

  • 通道 从零开始码一个皮卡丘检测器-CNN目标检测入门教程(上) 对应了第 从零开始码一个皮卡丘检测器-CNN目标检测入门教程(上) 类的得分

from mxnet.gluon import nn

def class_predictor(num_anchors,num_classes):

    """return a layer to predict classes"""

    returnnn.Conv2D(num_anchors*(num_classes+1),3,padding=1)


cls_pred=class_predictor(5,10)

cls_pred.initialize()

x=nd.zeros((2,3,20,20))

print('Class prediction',cls_pred(x).shape)

Class prediction (2, 55, 20, 20)

预测预设框偏移 Predict anchor boxes

为了找到物体准确的位置,光靠预设框本身是不行的,我们还需要预测偏移量以便把真正的物体框出来。

假设  从零开始码一个皮卡丘检测器-CNN目标检测入门教程(上)  是某个预设框, 从零开始码一个皮卡丘检测器-CNN目标检测入门教程(上) 是目标物体的真实矩形框,我们需要预测的偏移为 从零开始码一个皮卡丘检测器-CNN目标检测入门教程(上) ,全都是长度为4的向量, 我们求得偏移

  • 从零开始码一个皮卡丘检测器-CNN目标检测入门教程(上)

  • 从零开始码一个皮卡丘检测器-CNN目标检测入门教程(上)

  • 从零开始码一个皮卡丘检测器-CNN目标检测入门教程(上)

  • 从零开始码一个皮卡丘检测器-CNN目标检测入门教程(上)

所有的偏移量都除以预设框的长或宽是为了更好的收敛。

类似分类概率,我们同样用 从零开始码一个皮卡丘检测器-CNN目标检测入门教程(上) 填充 从零开始码一个皮卡丘检测器-CNN目标检测入门教程(上) 的卷积来预测偏移。这次不同的是,对于每个预设框,我们只需要 从零开始码一个皮卡丘检测器-CNN目标检测入门教程(上) 个通道来预测偏移量, 一共需要 从零开始码一个皮卡丘检测器-CNN目标检测入门教程(上) 个通道,第  从零开始码一个皮卡丘检测器-CNN目标检测入门教程(上)  个预设框对应的偏移量存在通道 从零开始码一个皮卡丘检测器-CNN目标检测入门教程(上) 到通道  从零开始码一个皮卡丘检测器-CNN目标检测入门教程(上)  之间。

def box_predictor(num_anchors):

    """return a layer to predict delta locations"""

    returnnn.Conv2D(num_anchors*4,3,padding=1)


box_pred=box_predictor(10)

box_pred.initialize()

x=nd.zeros((2,3,20,20))

print('Box prediction',box_pred(x).shape)

Box prediction (2, 40, 20, 20)

下采样特征层 Down-sample features

每次我们下采样特征层到一半的长宽,用Pooling(池化)操作就可以轻松的做到,当然也可以用stride(步长)为2的卷积直接得到。在下采样之前,我们会希望增加几层卷积层作为缓冲,防止特征值对应多尺度带来的混乱,同时又能增加网络的深度,得到更好的抽象。

def down_sample(num_filters):

    """stack two Conv-BatchNorm-Relu blocks and then a pooling layer

    to halve the feature size"""

    out=nn.HybridSequential()

    for_inrange(2):

        out.add(nn.Conv2D(num_filters,3,strides=1,padding=1))

        out.add(nn.BatchNorm(in_channels=num_filters))

        out.add(nn.Activation('relu'))

    out.add(nn.MaxPool2D(2))

    return out


blk=down_sample(10)

blk.initialize()

x=nd.zeros((2,3,20,20))

print('Before',x.shape,'after',blk(x).shape)


Before (2, 3, 20, 20) after (2, 10, 10, 10)

整合多个特征层预测值 Manage predictions from multiple layers

SSD算法的一个关键点在于它用到了多尺度的特征层来预测不同大小的物体。相对来说,浅层的特征层的空间尺度更大,越到网络的深层,空间尺度越小,最后我们往往下采样直到 从零开始码一个皮卡丘检测器-CNN目标检测入门教程(上) ,用来预测全图大小的物体。所以每个特征层产生的预设框,分类概率,框偏移量需要被整合起来统一在全图与真实的物体比较。 为了做到一一对应,我们统一把所有的预设框, 分类概率,框偏移量 平铺再连接。得到的是按顺序排列但是摊平的所有预测值和预设框。

# 随便创建一个大小为 20x20的预测层

feat1=nd.zeros((2,8,20,20))

print('Feature map 1',feat1.shape)

cls_pred1=class_predictor(5,10)

cls_pred1.initialize()

y1=cls_pred1(feat1)

print('Class prediction for feature map 1',y1.shape)

# 下采样

ds=down_sample(16)

ds.initialize()

feat2=ds(feat1)

print('Feature map 2',feat2.shape)

cls_pred2=class_predictor(3,10)

cls_pred2.initialize()

y2=cls_pred2(feat2)

print('Class prediction for feature map 2',y2.shape)

Feature map 1 (2, 8, 20, 20)
Class prediction for feature map 1 (2, 55, 20, 20)
Feature map 2 (2, 16, 10, 10)
Class prediction for feature map 2 (2, 33, 10, 10)

def flatten_prediction(pred):

    return nd.flatten(nd.transpose(pred,axes=(0,2,3,1)))


def concat_predictions(preds):

    return nd.concat(*preds,dim=1)


flat_y1=flatten_prediction(y1)

print('Flatten class prediction 1',flat_y1.shape)

flat_y2=flatten_prediction(y2)

print('Flatten class prediction 2',flat_y2.shape)

print('Concat class predictions',concat_predictions([flat_y1,flat_y2]).shape)

Flatten class prediction 1 (2, 22000)
Flatten class prediction 2 (2, 3300)
Concat class predictions (2, 25300)

我们总是确保在 从零开始码一个皮卡丘检测器-CNN目标检测入门教程(上) 上连接,以免打乱一一对应的关系。

主干网络 Body network

主干网络用来从原始图像输入提取特征。 一般来说我们会用预先训练好的用于分类的高性能网络(VGG, ResNet等)来提取特征。

在这里我们就简单地堆叠几层卷积和下采样层作为主干网络的演示。

from mxnet import gluon

def body():

    """return the body network"""

    out=nn.HybridSequential()

    for nfilters in [16,32,64]:

        out.add(down_sample(nfilters))

    return out


bnet=body()

bnet.initialize()

x=nd.zeros((2,3,256,256))

print('Body network',[y.shape for y in bnet(x)])

Body network [(64, 32, 32), (64, 32, 32)]

设计一个简单的SSD示意网络 Create a toy SSD model

我们这里介绍一个示意用的简单SSD网络,出于速度的考量,输入图像尺寸定为 从零开始码一个皮卡丘检测器-CNN目标检测入门教程(上) 。

def toy_ssd_model(num_anchors,num_classes):

    """return SSD modules"""

    downsamples=nn.Sequential()

    class_preds=nn.Sequential()

    box_preds=nn.Sequential()


    downsamples.add(down_sample(128))

    downsamples.add(down_sample(128))

    downsamples.add(down_sample(128))


    for scale in range(5):

        class_preds.add(class_predictor(num_anchors,num_classes))

        box_preds.add(box_predictor(num_anchors))


    return body(),downsamples,class_preds,box_preds


print(toy_ssd_model(5,2))

(HybridSequential(
(0): HybridSequential(
(0): Conv2D(16, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(1): BatchNorm(fix_gamma=False, axis=1, momentum=0.9, eps=1e-05, in_channels=16)
(2): Activation(relu)
(3): Conv2D(16, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(4): BatchNorm(fix_gamma=False, axis=1, momentum=0.9, eps=1e-05, in_channels=16)
(5): Activation(relu)
(6): MaxPool2D(size=(2, 2), stride=(2, 2), padding=(0, 0), ceil_mode=False)
)
(1): HybridSequential(
(0): Conv2D(32, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(1): BatchNorm(fix_gamma=False, axis=1, momentum=0.9, eps=1e-05, in_channels=32)
(2): Activation(relu)
(3): Conv2D(32, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(4): BatchNorm(fix_gamma=False, axis=1, momentum=0.9, eps=1e-05, in_channels=32)
(5): Activation(relu)
(6): MaxPool2D(size=(2, 2), stride=(2, 2), padding=(0, 0), ceil_mode=False)
 )
(2): HybridSequential(
(0): Conv2D(64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(1): BatchNorm(fix_gamma=False, axis=1, momentum=0.9, eps=1e-05, in_channels=64)
(2): Activation(relu)
(3): Conv2D(64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(4): BatchNorm(fix_gamma=False, axis=1, momentum=0.9, eps=1e-05, in_channels=64)
(5): Activation(relu)
(6): MaxPool2D(size=(2, 2), stride=(2, 2), padding=(0, 0), ceil_mode=False)
)
), Sequential(
(0): HybridSequential(
(0): Conv2D(128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(1): BatchNorm(fix_gamma=False, axis=1, momentum=0.9, eps=1e-05, in_channels=128)
(2): Activation(relu)
(3): Conv2D(128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(4): BatchNorm(fix_gamma=False, axis=1, momentum=0.9, eps=1e-05, in_channels=128)
(5): Activation(relu)
(6): MaxPool2D(size=(2, 2), stride=(2, 2), padding=(0, 0), ceil_mode=False)
)
(1): HybridSequential(
(0): Conv2D(128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(1): BatchNorm(fix_gamma=False, axis=1, momentum=0.9, eps=1e-05, in_channels=128)
(2): Activation(relu)
(3): Conv2D(128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(4): BatchNorm(fix_gamma=False, axis=1, momentum=0.9, eps=1e-05, in_channels=128)
(5): Activation(relu)
(6): MaxPool2D(size=(2, 2), stride=(2, 2), padding=(0, 0), ceil_mode=False)
)
(2): HybridSequential(
(0): Conv2D(128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(1): BatchNorm(fix_gamma=False, axis=1, momentum=0.9, eps=1e-05, in_channels=128)
(2): Activation(relu)
(3): Conv2D(128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(4): BatchNorm(fix_gamma=False, axis=1, momentum=0.9, eps=1e-05, in_channels=128)
(5): Activation(relu)
(6): MaxPool2D(size=(2, 2), stride=(2, 2), padding=(0, 0), ceil_mode=False)
)
), Sequential(
(0): Conv2D(15, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(1): Conv2D(15, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(2): Conv2D(15, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(3): Conv2D(15, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(4): Conv2D(15, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
), Sequential(
(0): Conv2D(20, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(1): Conv2D(20, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(2): Conv2D(20, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(3): Conv2D(20, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(4): Conv2D(20, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
))

网络前向推导 Forward

既然我们已经设计完网络结构了,接下来可以定义网络前向推导的步骤。

首先得到主干网络的输出,然后对于每一个特征预测层,推导当前层的预设框,分类概率和偏移量。最后我们把这些输入摊平,连接,作为网络的输出。

从零开始码一个皮卡丘检测器-CNN目标检测入门教程(上)

打包收工 Put all things together

from mxnet import gluon

class ToySSD(gluon.Block):
    def __init__(self, num_classes, **kwargs):
        super(ToySSD, self).__init__(**kwargs)
        # 5个预测层,每层负责的预设框尺寸不同,由小到大,符合网络的形状
        self.anchor_sizes = [[.2, .272], [.37, .447], [.54, .619], [.71, .79], [.88, .961]]
        # 每层的预设框都用 1,2,0.5作为长宽比候选
        self.anchor_ratios = [[1, 2, .5]] * 5
        self.num_classes = num_classes

        with self.name_scope():
            self.body, self.downsamples, self.class_preds, self.box_preds = toy_ssd_model(4, num_classes)

    def forward(self, x):
        default_anchors, predicted_classes, predicted_boxes = toy_ssd_forward(x, self.body, self.downsamples,
            self.class_preds, self.box_preds, self.anchor_sizes, self.anchor_ratios)
         # 把从每个预测层输入的结果摊平并连接,以确保一一对应
         anchors = concat_predictions(default_anchors)
         box_preds = concat_predictions(predicted_boxes)
         class_preds = concat_predictions(predicted_classes)
         # 改变下形状,为了更方便地计算softmax
         class_preds = nd.reshape(class_preds, shape=(0, -1, self.num_classes + 1))

         return anchors, class_preds, box_preds

网络输出示意 Outputs of ToySSD

# 新建一个2个正类的SSD网络

net = ToySSD(2)

net.initialize()

x = nd.zeros((1, 3, 256, 256))

default_anchors, class_predictions, box_predictions = net(x)

print('Outputs:', 'anchors', default_anchors.shape, 'class prediction', class_predictions.shape, 'box prediction', box_predictions.shape)

Outputs: anchors (1, 5444, 4) class prediction (1, 5444, 3) box prediction (1, 21776)

数据集 Dataset

聊了半天怎么构建一个虚无的网络,接下来看看真正有意思的东西。

我们用3D建模批量生成了一个皮卡丘的数据集,产生了1000张图片作为这个展示用的训练集。这个数据集里面,皮神会以各种角度,各种姿势出现在各种背景图中,就像Pokemon Go里增强现实那样炫酷。

因为是生成的数据集,我们自然可以得到每只皮神的真实坐标和大小,用来作为训练的真实标记。

从零开始码一个皮卡丘检测器-CNN目标检测入门教程(上)

下载数据集 Download dataset

下载提前准备好的数据集并验证

from mxnet.test_utils import download

import os.path as osp

def verified(file_path, sha1hash):
    import hashlib
    sha1 = hashlib.sha1()
    with open(file_path, 'rb') as f:
        while True:
            data = f.read(1048576)
            if not data:
                break
            sha1.update(data)
    matched = sha1.hexdigest() == sha1hash
    if not matched:
        print('Found hash mismatch in file {}, possibly due to incomplete download.'.format(file_path))
    return matched


url_format = 'https://apache-mxnet.s3-accelerate.amazonaws.com/gluon/datasets/pikachu/{}'

hashes = {'train.rec': 'e6bcb6ffba1ac04ff8a9b1115e650af56ee969c8',
         'train.idx': 'dcf7318b2602c06428b9988470c731621716c393',
         'val.rec': 'd6c33f799b4d058e82f2cb5bd9a976f69d72d520'}

for k, v in hashes.items():
    fname = 'pikachu_' + k
    target = osp.join('data', fname)
    url = url_format.format(k)
    if not osp.exists(target) or not verified(target, v):
        print('Downloading', target, url)
        download(url, fname=fname, dirname='data', overwrite=True)

加载数据 Load dataset

加载数据可以用mxnet.image.ImageDetIter,同时还提供了大量数据增强的选项,比如翻转,随机截取等等。

从零开始码一个皮卡丘检测器-CNN目标检测入门教程(上)

DataBatch: data shapes: [(32, 3, 256, 256)] label shapes: [(32, 1, 5)]

示意图 Illustration

加载的训练数据还可以显示出来看看到底是怎么样的。

import numpy as np


img = batch.data[0][0].asnumpy()  # 取第一批数据中的第一张,转成numpy

img = img.transpose((1, 2, 0))  # 交换下通道的顺序

img += np.array([123, 117, 104])

img = img.astype(np.uint8)  # 图片应该用0-255的范围

# 在图上画出真实标签的方框

for label in batch.label[0][0].asnumpy():
    if label[0] < 0:
        break
    print(label)
    xmin, ymin, xmax, ymax = [int(x * data_shape) for x in label[1:5]]
    rect = plt.Rectangle((xmin, ymin), xmax - xmin, ymax - ymin, fill=False, edgecolor=(1, 0, 0), linewidth=3)
    plt.gca().add_patch(rect)

plt.imshow(img)

plt.show()

[ 0. 0.75724518  0.34316057  0.93332517  0.70017999]

从零开始码一个皮卡丘检测器-CNN目标检测入门教程(上)




本文作者:Non
本文转自雷锋网禁止二次转载, 原文链接
目录
相关文章
|
机器学习/深度学习 计算机视觉 异构计算
从零开始码一个皮卡丘检测器-CNN目标检测入门教程(下)
目标检测不同于分类任务,需要考虑的不只是全图尺度的单一分类,而是需要检测到不同大小,不同位置的物体,难度自然提升了许多,用扫窗之类的传统方法早已不适合神经网络这种需要大量计算需求的新结构。幸好我们可以用本章节介绍的方法,利用卷积网络的特性,一次推导得到全部的预测结果,相对来说快速且准确。
1119 0
|
11天前
|
机器学习/深度学习 人工智能 自然语言处理
深度学习中的卷积神经网络(CNN)及其应用
【9月更文挑战第24天】本文将深入探讨深度学习中的一种重要模型——卷积神经网络(CNN)。我们将通过简单的代码示例,了解CNN的工作原理和应用场景。无论你是初学者还是有经验的开发者,这篇文章都将为你提供有价值的信息。
36 1
|
16天前
|
机器学习/深度学习 人工智能 自动驾驶
深度学习中的卷积神经网络(CNN)及其在图像识别中的应用
【9月更文挑战第19天】在人工智能的浩瀚星海中,卷积神经网络(CNN)如同一颗璀璨的星辰,照亮了图像处理的天空。本文将深入CNN的核心,揭示其在图像识别领域的强大力量。通过浅显易懂的语言和直观的比喻,我们将一同探索CNN的奥秘,并见证它如何在现实世界中大放异彩。
|
4天前
|
机器学习/深度学习 人工智能 算法框架/工具
深度学习中的卷积神经网络(CNN)及其在图像识别中的应用
【9月更文挑战第31天】本文旨在通过浅显易懂的语言和直观的比喻,为初学者揭开深度学习中卷积神经网络(CNN)的神秘面纱。我们将从CNN的基本原理出发,逐步深入到其在图像识别领域的实际应用,并通过一个简单的代码示例,展示如何利用CNN进行图像分类。无论你是编程新手还是深度学习的初学者,这篇文章都将为你打开一扇通往人工智能世界的大门。
|
5天前
|
机器学习/深度学习 人工智能 自然语言处理
深度学习中的卷积神经网络(CNN)入门与实践
【8月更文挑战第62天】本文以浅显易懂的方式介绍了深度学习领域中的核心技术之一——卷积神经网络(CNN)。文章通过生动的比喻和直观的图示,逐步揭示了CNN的工作原理和应用场景。同时,结合具体的代码示例,引导读者从零开始构建一个简单的CNN模型,实现对图像数据的分类任务。无论你是深度学习的初学者还是希望巩固理解的开发者,这篇文章都将为你打开一扇通往深度学习世界的大门。
|
16天前
|
机器学习/深度学习 人工智能 算法
深度学习中的卷积神经网络(CNN)入门与实践
【9月更文挑战第19天】在这篇文章中,我们将探索深度学习的一个重要分支——卷积神经网络(CNN)。从基础概念出发,逐步深入到CNN的工作原理和实际应用。文章旨在为初学者提供一个清晰的学习路径,并分享一些实用的编程技巧,帮助读者快速上手实践CNN项目。
|
15天前
|
机器学习/深度学习 自动驾驶 TensorFlow
深入理解卷积神经网络(CNN)在图像识别中的应用
【9月更文挑战第20天】本文旨在通过直观的解释和代码示例,向初学者介绍卷积神经网络(CNN)的基本概念及其在图像识别领域的应用。文章将首先解释什么是CNN以及它如何工作,然后通过一个简单的Python代码示例展示如何构建一个基本的CNN模型。最后,我们将讨论CNN在现实世界问题中的潜在应用,并探讨其面临的挑战和发展方向。
36 2
|
15天前
|
机器学习/深度学习 人工智能 算法
深入浅出卷积神经网络(CNN)
【9月更文挑战第20天】在人工智能的璀璨星河中,卷积神经网络(CNN)如同一颗耀眼的星辰,以其独特的魅力照亮了图像处理的天空。本文将带你遨游CNN的宇宙,从其诞生之初的微弱光芒,到成为深度学习领域的超级巨星,我们将一同探索它的结构奥秘、工作原理以及在实际场景中的惊艳应用。你将发现,CNN不仅仅是一段段代码和算法的堆砌,它更是一种让机器“看”懂世界的强大工具。让我们扣好安全带,一起深入CNN的世界,体验技术与创新交织的精彩旅程。
|
16天前
|
机器学习/深度学习 人工智能 TensorFlow
深入探索深度学习中的卷积神经网络(CNN)
【9月更文挑战第19天】本文将深入浅出地介绍卷积神经网络(CNN)在深度学习领域的应用和原理,旨在为初学者提供一个清晰的理解框架。通过实例演示,我们将展示如何利用Python和TensorFlow库构建一个简单的CNN模型,用于图像分类任务。此外,文章还将探讨CNN在不同应用场景下的优化策略和挑战。
|
21天前
|
机器学习/深度学习 人工智能 TensorFlow
深度学习入门:理解卷积神经网络(CNN)
【9月更文挑战第14天】本文旨在为初学者提供一个关于卷积神经网络(CNN)的直观理解,通过简单的语言和比喻来揭示这一深度学习模型如何识别图像。我们将一起探索CNN的基本组成,包括卷积层、激活函数、池化层和全连接层,并了解它们如何协同工作以实现图像分类任务。文章末尾将给出一个简单的代码示例,帮助读者更好地理解CNN的工作原理。
38 7

热门文章

最新文章

下一篇
无影云桌面