精华内容
下载资源
问答
  • DenseNet算法详解

    万次阅读 多人点赞 2017-07-15 08:24:15
    论文:Densely Connected Convolutional Networks ...代码的github链接:https://github.com/liuzhuang13/DenseNet文章详解: 这篇文章是CVPR2017的oral,非常厉害。文章提出的DenseNet(Dense Convolution

    论文:Densely Connected Convolutional Networks
    论文链接:https://arxiv.org/pdf/1608.06993.pdf
    代码的github链接:https://github.com/liuzhuang13/DenseNet
    MXNet版本代码(有ImageNet预训练模型): https://github.com/miraclewkf/DenseNet

    文章详解:
    这篇文章是CVPR2017的oral,非常厉害。文章提出的DenseNet(Dense Convolutional Network)主要还是和ResNet及Inception网络做对比,思想上有借鉴,但却是全新的结构,网络结构并不复杂,却非常有效!众所周知,最近一两年卷积神经网络提高效果的方向,要么深(比如ResNet,解决了网络深时候的梯度消失问题)要么宽(比如GoogleNet的Inception),而作者则是从feature入手,通过对feature的极致利用达到更好的效果和更少的参数。博主虽然看过的文章不算很多,但是看完这篇感觉心潮澎湃,就像当年看完ResNet那篇文章一样!

    先列下DenseNet的几个优点,感受下它的强大:
    1、减轻了vanishing-gradient(梯度消失)
    2、加强了feature的传递
    3、更有效地利用了feature
    4、一定程度上较少了参数数量

    在深度学习网络中,随着网络深度的加深,梯度消失问题会愈加明显,目前很多论文都针对这个问题提出了解决方案,比如ResNet,Highway Networks,Stochastic depth,FractalNets等,尽管这些算法的网络结构有差别,但是核心都在于:create short paths from early layers to later layers。那么作者是怎么做呢?延续这个思路,那就是在保证网络中层与层之间最大程度的信息传输的前提下,直接将所有层连接起来!

    先放一个dense block的结构图。在传统的卷积神经网络中,如果你有L层,那么就会有L个连接,但是在DenseNet中,会有L(L+1)/2个连接。简单讲,就是每一层的输入来自前面所有层的输出。如下图:x0是input,H1的输入是x0(input),H2的输入是x0和x1(x1是H1的输出)……

    这里写图片描述

    DenseNet的一个优点是网络更窄,参数更少,很大一部分原因得益于这种dense block的设计,后面有提到在dense block中每个卷积层的输出feature map的数量都很小(小于100),而不是像其他网络一样动不动就几百上千的宽度。同时这种连接方式使得特征和梯度的传递更加有效,网络也就更加容易训练。原文的一句话非常喜欢:Each layer has direct access to the gradients from the loss function and the original input signal, leading to an implicit deep supervision.直接解释了为什么这个网络的效果会很好。前面提到过梯度消失问题在网络深度越深的时候越容易出现,原因就是输入信息和梯度信息在很多层之间传递导致的,而现在这种dense connection相当于每一层都直接连接input和loss,因此就可以减轻梯度消失现象,这样更深网络不是问题。另外作者还观察到这种dense connection有正则化的效果,因此对于过拟合有一定的抑制作用,博主认为是因为参数减少了(后面会介绍为什么参数会减少),所以过拟合现象减轻。

    这篇文章的一个优点就是基本上没有公式,不像灌水文章一样堆复杂公式把人看得一愣一愣的。文章中只有两个公式,是用来阐述DenseNet和ResNet的关系,对于从原理上理解这两个网络还是非常重要的。

    第一个公式是ResNet的。这里的l表示层,xl表示l层的输出,Hl表示一个非线性变换。所以对于ResNet而言,l层的输出是l-1层的输出加上对l-1层输出的非线性变换。

    这里写图片描述

    第二个公式是DenseNet的。[x0,x1,…,xl-1]表示将0到l-1层的输出feature map做concatenation。concatenation是做通道的合并,就像Inception那样。而前面resnet是做值的相加,通道数是不变的。Hl包括BN,ReLU和3*3的卷积。

    这里写图片描述

    所以从这两个公式就能看出DenseNet和ResNet在本质上的区别,太精辟。

    前面的Figure 1表示的是dense block,而下面的Figure 2表示的则是一个DenseNet的结构图,在这个结构图中包含了3个dense block。作者将DenseNet分成多个dense block,原因是希望各个dense block内的feature map的size统一,这样在做concatenation就不会有size的问题。

    这里写图片描述

    这个Table1就是整个网络的结构图。这个表中的k=32,k=48中的k是growth rate,表示每个dense block中每层输出的feature map个数。为了避免网络变得很宽,作者都是采用较小的k,比如32这样,作者的实验也表明小的k可以有更好的效果。根据dense block的设计,后面几层可以得到前面所有层的输入,因此concat后的输入channel还是比较大的。另外这里每个dense block的3*3卷积前面都包含了一个1*1的卷积操作,就是所谓的bottleneck layer,目的是减少输入的feature map数量,既能降维减少计算量,又能融合各个通道的特征,何乐而不为。另外作者为了进一步压缩参数,在每两个dense block之间又增加了1*1的卷积操作。因此在后面的实验对比中,如果你看到DenseNet-C这个网络,表示增加了这个Translation layer,该层的1*1卷积的输出channel默认是输入channel到一半。如果你看到DenseNet-BC这个网络,表示既有bottleneck layer,又有Translation layer。

    这里写图片描述

    再详细说下bottleneck和transition layer操作。在每个Dense Block中都包含很多个子结构,以DenseNet-169的Dense Block(3)为例,包含32个1*1和3*3的卷积操作,也就是第32个子结构的输入是前面31层的输出结果,每层输出的channel是32(growth rate),那么如果不做bottleneck操作,第32层的3*3卷积操作的输入就是31*32+(上一个Dense Block的输出channel),近1000了。而加上1*1的卷积,代码中的1*1卷积的channel是growth rate*4,也就是128,然后再作为3*3卷积的输入。这就大大减少了计算量,这就是bottleneck。至于transition layer,放在两个Dense Block中间,是因为每个Dense Block结束后的输出channel个数很多,需要用1*1的卷积核来降维。还是以DenseNet-169的Dense Block(3)为例,虽然第32层的3*3卷积输出channel只有32个(growth rate),但是紧接着还会像前面几层一样有通道的concat操作,即将第32层的输出和第32层的输入做concat,前面说过第32层的输入是1000左右的channel,所以最后每个Dense Block的输出也是1000多的channel。因此这个transition layer有个参数reduction(范围是0到1),表示将这些输出缩小到原来的多少倍,默认是0.5,这样传给下一个Dense Block的时候channel数量就会减少一半,这就是transition layer的作用。文中还用到dropout操作来随机减少分支,避免过拟合,毕竟这篇文章的连接确实多。

    实验结果:
    作者在不同数据集上采用的DenseNet网络会有一点不一样,比如在Imagenet数据集上,DenseNet-BC有4个dense block,但是在别的数据集上只用3个dense block。其他更多细节可以看论文3部分的Implementation Details。训练的细节和超参数的设置可以看论文4.2部分,在ImageNet数据集上测试的时候有做224*224的center crop。

    Table2是在三个数据集(C10,C100,SVHN)上和其他算法的对比结果。ResNet[11]就是kaiming He的论文,对比结果一目了然。DenseNet-BC的网络参数和相同深度的DenseNet相比确实减少了很多!参数减少除了可以节省内存,还能减少过拟合。这里对于SVHN数据集,DenseNet-BC的结果并没有DenseNet(k=24)的效果好,作者认为原因主要是SVHN这个数据集相对简单,更深的模型容易过拟合。在表格的倒数第二个区域的三个不同深度L和k的DenseNet的对比可以看出随着L和k的增加,模型的效果是更好的。

    这里写图片描述

    Figure3是DenseNet-BC和ResNet在Imagenet数据集上的对比,左边那个图是参数复杂度和错误率的对比,你可以在相同错误率下看参数复杂度,也可以在相同参数复杂度下看错误率,提升还是很明显的!右边是flops(可以理解为计算复杂度)和错误率的对比,同样有效果。

    这里写图片描述

    Figure4也很重要。左边的图表示不同类型DenseNet的参数和error对比。中间的图表示DenseNet-BC和ResNet在参数和error的对比,相同error下,DenseNet-BC的参数复杂度要小很多。右边的图也是表达DenseNet-BC-100只需要很少的参数就能达到和ResNet-1001相同的结果。

    这里写图片描述

    另外提一下DenseNet和stochastic depth的关系,在stochastic depth中,residual中的layers在训练过程中会被随机drop掉,其实这就会使得相邻层之间直接连接,这和DenseNet是很像的。

    总结:
    博主读完这篇文章真的有点相见恨晚的感觉,半年前就在arxiv上挂出来了,听说当时就引起了轰动,后来又被选为CVPR2017的oral,感觉要撼动ResNet的地位了,再加上现在很多分类检测的网络都是在ResNet上做的,这岂不是大地震了。惊讶之余来总结下这篇文章,该文章提出的DenseNet核心思想在于建立了不同层之间的连接关系,充分利用了feature,进一步减轻了梯度消失问题,加深网络不是问题,而且训练效果非常好。另外,利用bottleneck layer,Translation layer以及较小的growth rate使得网络变窄,参数减少,有效抑制了过拟合,同时计算量也减少了。DenseNet优点很多,而且在和ResNet的对比中优势还是非常明显的。

    展开全文
  • DenseNet详解

    万次阅读 多人点赞 2018-08-27 16:47:24
    其它机器学习、深度学习算法的全面系统讲解可以...作为CVPR2017年的Best Paper, DenseNet脱离了加深网络层数(ResNet)和加宽网络结构(Inception)来提升网络性能的定式思维,从特征的角度考虑,通过特征重用和旁路(Byp...

    其它机器学习、深度学习算法的全面系统讲解可以阅读《机器学习-原理、算法与应用》,清华大学出版社,雷明著,由SIGAI公众号作者倾力打造。

    一、概述

    作为CVPR2017年的Best Paper, DenseNet脱离了加深网络层数(ResNet)和加宽网络结构(Inception)来提升网络性能的定式思维,从特征的角度考虑,通过特征重用和旁路(Bypass)设置,既大幅度减少了网络的参数量,又在一定程度上缓解了gradient vanishing问题的产生.结合信息流和特征复用的假设,DenseNet当之无愧成为2017年计算机视觉顶会的年度最佳论文.

    卷积神经网络在沉睡了近20年后,如今成为了深度学习方向最主要的网络结构之一.从一开始的只有五层结构的LeNet, 到后来拥有19层结构的VGG, 再到首次跨越100层网络的Highway Networks与ResNet, 网络层数的加深成为CNN发展的主要方向之一.

    随着CNN网络层数的不断增加,gradient vanishing和model degradation问题出现在了人们面前,BatchNormalization的广泛使用在一定程度上缓解了gradient vanishing的问题,而ResNet和Highway Networks通过构造恒等映射设置旁路,进一步减少了gradient vanishing和model degradation的产生.Fractal Nets通过将不同深度的网络并行化,在获得了深度的同时保证了梯度的传播,随机深度网络通过对网络中一些层进行失活,既证明了ResNet深度的冗余性,又缓解了上述问题的产生. 虽然这些不同的网络框架通过不同的实现加深的网络层数,但是他们都包含了相同的核心思想,既将feature map进行跨网络层的连接.

    DenseNet作为另一种拥有较深层数的卷积神经网络,具有如下优点:

    (1) 相比ResNet拥有更少的参数数量.

    (2) 旁路加强了特征的重用.

    (3) 网络更易于训练,并具有一定的正则效果.

    (4) 缓解了gradient vanishing和model degradation的问题.

    何恺明先生在提出ResNet时做出了这样的假设:若某一较深的网络多出另一较浅网络的若干层有能力学习到恒等映射,那么这一较深网络训练得到的模型性能一定不会弱于该浅层网络.通俗的说就是如果对某一网络中增添一些可以学到恒等映射的层组成新的网路,那么最差的结果也是新网络中的这些层在训练后成为恒等映射而不会影响原网络的性能.同样DenseNet在提出时也做过假设:与其多次学习冗余的特征,特征复用是一种更好的特征提取方式.

     

    二、DenseNet

    假设输入为一个图片 X_{0} , 经过一个L层的神经网络, 其中第i层的非线性变换记为 H_{i} (*), H_{i} (*)可以是多种函数操作的累加如BN、ReLU、Pooling或Conv等. 第i层的特征输出记作 X_{i} .

    ResNet

    传统卷积前馈神经网络将第i层的输出 X_{i} 作为i+1层的输入,可以写作X_{i} = H_{i} ( X_{i-1} ). ResNet增加了旁路连接,可以写作

    X_{l} = X_{l} ( X_{l-1} )+ X_{l-1}

    ResNet的一个最主要的优势便是梯度可以流经恒等函数来到达靠前的层.但恒等映射和非线性变换输出的叠加方式是相加, 这在一定程度上破坏了网络中的信息流.

    Dense Connectivity

    为了进一步优化信息流的传播,DenseNet提出了图示的网络结构

    如图所示,第i层的输入不仅与i-1层的输出相关,还有所有之前层的输出有关.记作:

    X_{l} = H_{l} ([ X_{0} , X_{1} ,…, X_{l-1} ]),

    其中[]代表concatenation(拼接),既将 X_{0} 到 X_{l-1} 层的所有输出feature map按Channel组合在一起.这里所用到的非线性变换H为BN+ReLU+ Conv(3×3)的组合.

    Pooling Layers

    由于在DenseNet中需要对不同层的feature map进行cat操作,所以需要不同层的feature map保持相同的feature size,这就限制了网络中Down sampling的实现.为了使用Down sampling,作者将DenseNet分为多个Denseblock,如下图所示:

    在同一个Denseblock中要求feature size保持相同大小,在不同Denseblock之间设置transition layers实现Down sampling, 在作者的实验中transition layer由BN + Conv(1×1) +2×2 average-pooling组成.

    Growth rate

    在Denseblock中,假设每一个非线性变换H的输出为K个feature map, 那么第i层网络的输入便为K0+(i-1)×K, 这里我们可以看到DenseNet和现有网络的一个主要的不同点:DenseNet可以接受较少的特征图数量作为网络层的输出,如下图所示

    原因就是在同一个Denseblock中的每一层都与之前所有层相关联,如果我们把feature看作是一个Denseblock的全局状态,那么每一层的训练目标便是通过现有的全局状态,判断需要添加给全局状态的更新值.因而每个网络层输出的特征图数量K又称为Growth rate,同样决定着每一层需要给全局状态更新的信息的多少.我们之后会看到,在作者的实验中只需要较小的K便足以实现state-of-art的性能.

    Bottleneck Layers

    虽然DenseNet接受较少的k,也就是feature map的数量作为输出,但由于不同层feature map之间由cat操作组合在一起,最终仍然会是feature map的channel较大而成为网络的负担.作者在这里使用1×1 Conv(Bottleneck)作为特征降维的方法来降低channel数量,以提高计算效率.经过改善后的非线性变换变为BN-ReLU-Conv(1×1)-BN-ReLU-Conv(3×3),使用Bottleneck layers的DenseNet被作者称为DenseNet-B.在实验中,作者使用1×1卷积生成channel数量为4k的feature map.

    Compression

    为了进一步优化模型的简洁性,我们同样可以在transition layer中降低feature map的数量.若一个Denseblock中包含m个feature maps,那么我们使其输出连接的transition layer层生成⌊θm⌋个输出feature map.其中θ为Compression factor, 当θ=1时,transition layer将保留原feature维度不变.

    作者将使用compression且θ=0.5的DenseNet命名为DenseNet-C, 将使用Bottleneck和compression且θ=0.5的DenseNet命名为DenseNet-BC

     

    三、 算法分析

    (1) Model compactness

    由于DenseNet对输入进行cat操作,一个直观的影响就是每一层学到的feature map都能被之后所有层直接使用,这使得特征可以在整个网络中重用,也使得模型更加简洁.

    从上图中我们可以看出DenseNet的参数效率:左图包含了对多种DenseNet结构参数和最终性能的统计,我们可以看出当模型实现相同的test error时,原始的DenseNet往往要比DenseNet-BC拥有2-3倍的参数量.中间图为DenseNet-BC与ResNet的对比,在相同的模型精度下,DenseNet-BC只需要ResNet约三分之一的参数数量.右图为1001层超过10M参数量的ResNet与100层只有0.8M参数量的DenseNet-BC在训练时的对比,虽然他们在约相同的训练epoch时收敛,但DenseNet-BC却只需要ResNet不足十分之一的参数量.

    (2) Implicit Deep Supervision

    解释DenseNet为何拥有如此高性能的另一个原因是网络中的每一层不仅接受了原始网络中来自loss的监督,同时由于存在多个bypass与shortcut,网络的监督是多样的.Deep supervision的优势同样在deeply-supervised nets (DSN)中也被证实.(DSN中每一个Hidden layer都有一个分类器,强迫其学习一些有区分度的特征).与DSN不同的是,DenseNet拥有单一的loss function, 模型构造和梯度计算更加简易.

    (3) Feature Reuse

    在设计初,DenseNet便被设计成让一层网络可以使用所有之前层网络feature map的网络结构,为了探索feature的复用情况,作者进行了相关实验.作者训练的L=40,K=12的DenseNet,对于任意Denseblock中的所有卷积层,计算之前某层feature map在该层权重的绝对值平均数.这一平均数表明了这一层对于之前某一层feature的利用率,下图为由该平均数绘制出的热力图:

    从图中我们可以得出以下结论:

    a) 一些较早层提取出的特征仍可能被较深层直接使用

    b) 即使是Transition layer也会使用到之前Denseblock中所有层的特征

    c) 第2-3个Denseblock中的层对之前Transition layer利用率很低,说明transition layer输出大量冗余特征.这也为DenseNet-BC提供了证据支持,既Compression的必要性.

    d) 最后的分类层虽然使用了之前Denseblock中的多层信息,但更偏向于使用最后几个feature map的特征,说明在网络的最后几层,某些high-level的特征可能被产生.

     

    四、实验结果

    作者在多个benchmark数据集上训练了多种DenseNet模型,并与state-of-art的模型(主要是ResNet和其变种)进行对比:

    由上表我们可以看出,DenseNet只需要较小的Growth rate(12,24)便可以实现state-of-art的性能,结合了Bottleneck和Compression的DenseNet-BC具有远小于ResNet及其变种的参数数量,且无论DenseNet或者DenseNet-BC,都在原始数据集和增广数据集上实现了超越ResNet的性能.

     

    推荐阅读

    [1]机器学习-波澜壮阔40年【获取码】SIGAI0413.

    [2]学好机器学习需要哪些数学知识?【获取码】SIGAI0417.

    [3] 人脸识别算法演化史【获取码】SIGAI0420.

    [4]基于深度学习的目标检测算法综述 【获取码】SIGAI0424.

    [5]卷积神经网络为什么能够称霸计算机视觉领域?【获取码】SIGAI0426.

    [6] 用一张图理解SVM的脉络【获取码】SIGAI0428.

    [7] 人脸检测算法综述【获取码】SIGAI0503.

    [8] 理解神经网络的激活函数 【获取码】SIGAI2018.5.5.

    [9] 深度卷积神经网络演化历史及结构改进脉络-40页长文全面解读【获取码】SIGAI0508.

    [10] 理解梯度下降法【获取码】SIGAI0511.

    [11] 循环神经网络综述—语音识别与自然语言处理的利器【获取码】SIGAI0515

    [12] 理解凸优化 【获取码】 SIGAI0518

    [13] 【实验】理解SVM的核函数和参数 【获取码】SIGAI0522

    [14]【SIGAI综述】行人检测算法 【获取码】SIGAI0525

    [15] 机器学习在自动驾驶中的应用—以百度阿波罗平台为例(上)【获取码】SIGAI0529

    [16]理解牛顿法【获取码】SIGAI0531

    [17] 【群话题精华】5月集锦—机器学习和深度学习中一些值得思考的问题【获取码】SIGAI 0601

    [18] 大话Adaboost算法 【获取码】SIGAI0602

    [19] FlowNet到FlowNet2.0:基于卷积神经网络的光流预测算法【获取码】SIGAI0604

    [20] 理解主成分分析(PCA)【获取码】SIGAI0606

    [21] 人体骨骼关键点检测综述 【获取码】SIGAI0608

    [22]理解决策树 【获取码】SIGAI0611

    [23] 用一句话总结常用的机器学习算法【获取码】SIGAI0611

    [24] 目标检测算法之YOLO 【获取码】SIGAI0615

    [25] 理解过拟合 【获取码】SIGAI0618

    [26]理解计算:从√2到AlphaGo ——第1季 从√2谈起 【获取码】SIGAI0620

    [27] 场景文本检测——CTPN算法介绍 【获取码】SIGAI0622

    [28] 卷积神经网络的压缩和加速 【获取码】SIGAI0625

    [29] k近邻算法 【获取码】SIGAI0627

    [30]自然场景文本检测识别技术综述 【获取码】SIGAI0627

    [31] 理解计算:从√2到AlphaGo ——第2季 神经计算的历史背景 【获取码】SIGAI0704

    [32] 机器学习算法地图【获取码】SIGAI0706

    [33] 反向传播算法推导-全连接神经网络【获取码】SIGAI0709

    [34] 生成式对抗网络模型综述【获取码】SIGAI0709.

    [35]怎样成为一名优秀的算法工程师【获取码】SIGAI0711.

    [36] 理解计算:从根号2到AlphaGo——第三季 神经网络的数学模型【获取码】SIGAI0716

    [37]【技术短文】人脸检测算法之S3FD 【获取码】SIGAI0716

    [38] 基于深度负相关学习的人群计数方法【获取码】SIGAI0718

    [39] 流形学习概述【获取码】SIGAI0723

    [40] 关于感受野的总结 【获取码】SIGAI0723

    [41] 随机森林概述 【获取码】SIGAI0725

    [42] 基于内容的图像检索技术综述——传统经典方法【获取码】SIGAI0727

    [43] 神经网络的激活函数总结【获取码】SIGAI0730

    [44] 机器学习和深度学习中值得弄清楚的一些问题【获取码】SIGAI0802

    [45] 基于深度神经网络的自动问答系统概述【获取码】SIGAI0806

    [46] 机器学习与深度学习核心知识点总结 写在校园招聘即将开始时 【获取 码】SIGAI0808

    [47] 理解Spatial Transformer Networks【获取码】SIGAI0810

    [48]AI时代大点兵-国内外知名AI公司2018年最新盘点【获取码】SIGAI0813

    [49] 理解计算:从√2到AlphaGo ——第2季 神经计算的历史背景 【获取码】SIGAI0815

    [50] 基于内容的图像检索技术综述--CNN方法 【获取码】SIGAI0817

    [51]文本表示简介 【获取码】SIGAI0820

    [52]机器学习中的最优化算法总结【获取码】SIGAI0822

    [53]【AI就业面面观】如何选择适合自己的舞台?【获取码】SIGAI0823

    [54]浓缩就是精华-SIGAI机器学习蓝宝书【获取码】SIGAI0824


    原创声明:本文为 SIGAI 原创文章,仅供个人学习使用,未经允许,不能用于商业目的

    展开全文
  • 从PointNet到PointNet++理论及代码详解1. 点云是什么1.1 三维数据的表现形式1.2 为什么使用点云1.3 点云上以往的相关工作2. PointNet2.1 基于点云的置换不变性2.1.1 由对称函数到PointNet(vanilla)2.1.2 理论证明2.2...

    Pytorch代码:https://github.com/yanx27/Pointnet2_pytorch
    更详细的代码解析:这里

    1. 点云是什么

    1.1 三维数据的表现形式

    在这里插入图片描述三维数据的表述形式一般分为四种:

    • 点云:由 N N N D D D维的点组成,当这个 D = 3 D=3 D=3的时候一般代表着 ( x , y , z ) (x,y,z) (x,y,z)的坐标,当然也可以包括一些法向量、强度等别的特征。这是今天主要讲述的数据类型。
    • Mesh:由三角面片和正方形面片组成。
    • 体素:由三维栅格将物体用0和1表征。
    • 多角度的RGB图像或者RGB-D图像

    1.2 为什么使用点云

    点云由很多优势,也越来越受到雷达自动驾驶的青睐。

    • 点云更接近于设备的原始表征(即雷达扫描物体直接产生点云)
    • 点云的表达方式更加简单,一个物体仅用一个 N × D N \times D N×D的矩阵表示
      在这里插入图片描述

    1.3 点云上以往的相关工作

    在PointNet出现以前,点云上的深度学习模型大致分为三类(这里不细述):

    • 基于3DCNN的体素模型:先将点云映射到体素空间上,在通过3DCNN进行分类或者分割。但是缺点是计算量受限制,目前最好的设备也大致只能处理 32 × 32 × 32 32\times32\times32 32×32×32的体素;另外由于体素网格的立方体性质,点云表面很多特征都没有办法被表述出来,因此模型效果差。
    • 将点云映射到2D空间中利用CNN分类
    • 利用传统的人工点云特征分类,例如:
      • normal 法向量
      • intensity 激光雷达的采样的时候一种特性强度信息的获取是激光扫描仪接受装置采集到的回波强度,此强度信息与目标 的表面材质、粗糙度、入射角方向,以及仪器的发射能量,激光波长有关
      • local density 局部稠密度
      • local curvature 局部曲率
      • linearity, planarity and scattering propesed by Dimensionality based scale selection in 3D lidar point clouds
      • verticality feature proposed by Weakly supervised segmentation-aided classification of urban scenes from 3d LiDAR point clouds

    2. PointNet

    要想设计好的网络,首先要根据点云的特性来实现特定的网络性能,而PointNet就是这么做的。点云具有两个非常重要的特性:
    在这里插入图片描述

    2.1 基于点云的置换不变性

    2.1.1 由对称函数到PointNet(vanilla)

    点云实际上拥有置换不变性的特点,那么什么是置换不变性呢,简单地说就是点的排序不影响物体的性质,如下图所示:
    在这里插入图片描述
    当一个 N × D N \times D N×D N N N的维度上随意的打乱之后,其表述的其实是同一个物体。因此针对点云的置换不变性,其设计的网络必须是一个对称的函数
    在这里插入图片描述
    我们经常看到的SUMMAX等函数其实都是对称函数。

    因此我们可以利用max函数设计一个很简单的点云网络,如下:
    在这里插入图片描述
    但是这样的网络有一个问题,就是每个点损失的特征太多了,输出的全局特征仅仅继承了三个坐标轴上最大的那个特征,因此我们不妨先将点云上的每一个点映射到一个高维的空间(例如1024维),目的是使得再次做MAX操作,损失的信息不会那么多。
    在这里插入图片描述
    此时我们发现,当我们将点云的每个点先映射到一个冗余的高维空间后,再去进行max的对称函数操作,损失的特征就没那么多了。由此,就可以设计出这PointNet的雏形,称之为PointNet(vanilla)
    在这里插入图片描述

    2.1.2 理论证明

    论文中其实有给出理论的证明,大致的意思是:任意一个在Hausdorff空间上连续的函数,都可以被这样的PointNet(vanilla)无限的逼近。
    在这里插入图片描述

    2.2 基于点云的旋转不变性

    点云的旋转不变性指的是,给予一个点云一个旋转,所有的 x , y , z x,y,z x,y,z坐标都变了,但是代表的还是同一个物体。
    在这里插入图片描述
    因此对于普通的PointNet(vanilla),如果先后输入同一个但是经过不同旋转角度的物体,它可能不能很好地将其识别出来。在论文中的方法是新引入了一个T-Net网络去学习点云的旋转,将物体校准,剩下来的PointNet(vanilla)只需要对校准后的物体进行分类或者分割即可。
    在这里插入图片描述
    由图可以看出,由于点云的旋转非常的简单,只需要对一个 N × D N\times D N×D的点云矩阵乘以一个 D × D D \times D D×D的旋转矩阵即可,因此对输入点云学习一个 3 × 3 3 \times 3 3×3的矩阵,即可将其矫正;同样的将点云映射到K维的冗余空间后,再对K维的点云特征做一次校对,只不过这次校对需要引入一个正则化惩罚项,希望其尽可能接近于一个正交矩阵。
    在这里插入图片描述
    在这里插入图片描述

    2.3 网络总体结构

    满足了以上两个点云的特性之后,就可以顺理成章的设计出PointNet的网络结构了。
    在这里插入图片描述
    具体来说,对于每一个 N × 3 N\times 3 N×3的点云输入,网络先通过一个T-Net将其在空间上对齐(旋转到正面),再通过MLP将其映射到64维的空间上,再进行对齐,最后映射到1024维的空间上。这时对于每一个点,都有一个1024维的向量表征,而这样的向量表征对于一个3维的点云明显是冗余的,因此这个时候引入最大池化操作,将1024维所有通道上都只保留最大的那一个,这样得到的 1 × 1024 1\times 1024 1×1024的向量就是 N N N个点云的全局特征

    如果做的是分类的问题,直接将这个全局特征再进过MLP去输出每一类的概率即可;但如果是分割问题,由于需要输出的是逐点的类别,因此其将全局特征拼接在了点云64维的逐点特征上,最后通过MLP,输出逐点的分类概率。

    2.4 实验结果和网络的鲁棒性

    pointnet当时不论是分割还是分类的结果都超过了当时的体素系列网络,同时由于参数少等特点,训练快,属于轻量级网络。
    在这里插入图片描述
    不仅如此,论文对PointNet对点云的点的缺失鲁棒性做了实验,实验证明,当PointNet缺失了60%左右的点的时候,其网络的效果都不怎么减少:
    在这里插入图片描述
    通过研究是哪些点最大程度激活了神经元的值,论文发现,能够最大程度激活网络的点都是物体的主干点(下图第二行),将其上采样,很容易能得到原始的结构。因此这就是PointNet网络的缺失鲁棒性的来源。
    在这里插入图片描述

    2.5 代码解析

    PointNet的代码实际上仅由两部分组成,就是T-Net和一个Encoder-Decoder结构

    先看T-Net的代码:

    class T_Net(nn.Module):
        def __init__(self):
            super(T_Net, self).__init__()
            # 这里需要注意的是上文提到的MLP均由卷积结构完成
            # 比如说将3维映射到64维,其利用64个1x3的卷积核
            self.conv1 = torch.nn.Conv1d(3, 64, 1)
            self.conv2 = torch.nn.Conv1d(64, 128, 1)
            self.conv3 = torch.nn.Conv1d(128, 1024, 1)
            self.fc1 = nn.Linear(1024, 512)
            self.fc2 = nn.Linear(512, 256)
            self.fc3 = nn.Linear(256, 9)
            self.relu = nn.ReLU()
    
            self.bn1 = nn.BatchNorm1d(64)
            self.bn2 = nn.BatchNorm1d(128)
            self.bn3 = nn.BatchNorm1d(1024)
            self.bn4 = nn.BatchNorm1d(512)
            self.bn5 = nn.BatchNorm1d(256)
    
    
        def forward(self, x):
            batchsize = x.size()[0]
            x = F.relu(self.bn1(self.conv1(x)))
            x = F.relu(self.bn2(self.conv2(x)))
            x = F.relu(self.bn3(self.conv3(x)))
            x = torch.max(x, 2, keepdim=True)[0]
            x = x.view(-1, 1024)
    
            x = F.relu(self.bn4(self.fc1(x)))
            x = F.relu(self.bn5(self.fc2(x)))
            x = self.fc3(x)
    
            iden = Variable(torch.from_numpy(np.array([1,0,0,0,1,0,0,0,1]).astype(np.float32))).view(1,9).repeat(batchsize,1)
            if x.is_cuda:
                iden = iden.cuda()
            x = x + iden
            x = x.view(-1, 3, 3) # 输出为Batch*3*3的张量
            return x
    

    再看PointNet的主体:

    class PointNetEncoder(nn.Module):
        def __init__(self, global_feat = True):
            super(PointNetEncoder, self).__init__()
            self.stn = T_Net()
            self.conv1 = torch.nn.Conv1d(3, 64, 1)
            self.conv2 = torch.nn.Conv1d(64, 128, 1)
            self.conv3 = torch.nn.Conv1d(128, 1024, 1)
            self.bn1 = nn.BatchNorm1d(64)
            self.bn2 = nn.BatchNorm1d(128)
            self.bn3 = nn.BatchNorm1d(1024)
            self.global_feat = global_feat
        def forward(self, x):
       	    '''生成全局特征'''
            n_pts = x.size()[2]
            trans = self.stn(x)
            x = x.transpose(2,1)
            x = torch.bmm(x, trans) # batch matrix multiply 即乘以T-Net的结果
            x = x.transpose(2,1)
            x = self.conv1(x)
    
            x = F.relu(self.bn1(x))
            pointfeat = x
            x_skip = self.conv2(x)
    
            x = F.relu(self.bn2(x_skip))
            x = self.bn3(self.conv3(x))
            x = torch.max(x, 2, keepdim=True)[0]
            x = x.view(-1, 1024)
            if self.global_feat:
                return x, trans
            else:
                x = x.view(-1, 1024, 1).repeat(1, 1, n_pts)
                return torch.cat([x, pointfeat], 1), trans
    
    class PointNetCls(nn.Module):
        def __init__(self, k = 2):
            super(PointNetCls, self).__init__()
            self.k = k
            self.feat = PointNetEncoder(global_feat=False)
            self.conv1 = torch.nn.Conv1d(1088, 512, 1)
            self.conv2 = torch.nn.Conv1d(512, 256, 1)
            self.conv3 = torch.nn.Conv1d(256, 128, 1)
            self.conv4 = torch.nn.Conv1d(128, self.k, 1)
            self.bn1 = nn.BatchNorm1d(512)
            self.bn2 = nn.BatchNorm1d(256)
            self.bn3 = nn.BatchNorm1d(128)
    
        def forward(self, x):
        	'''分类网络'''
            batchsize = x.size()[0]
            n_pts = x.size()[2]
            x, trans = self.feat(x)
            x = F.relu(self.bn1(self.conv1(x)))
            x = F.relu(self.bn2(self.conv2(x)))
            x = F.relu(self.bn3(self.conv3(x)))
            x = self.conv4(x)
            x = x.transpose(2,1).contiguous()
            x = F.log_softmax(x.view(-1,self.k), dim=-1)
            x = x.view(batchsize, n_pts, self.k)
            return x
    
    
    class PointNetPartSeg(nn.Module):
        def __init__(self,num_class):
            super(PointNetPartSeg, self).__init__()
            self.k = num_class
            self.feat = PointNetEncoder(global_feat=False)
            self.conv1 = torch.nn.Conv1d(1088, 512, 1)
            self.conv2 = torch.nn.Conv1d(512, 256, 1)
            self.conv3 = torch.nn.Conv1d(256, 128, 1)
            self.conv4 = torch.nn.Conv1d(128, self.k, 1)
            self.bn1 = nn.BatchNorm1d(512)
            self.bn1_1 = nn.BatchNorm1d(1024)
            self.bn2 = nn.BatchNorm1d(256)
            self.bn3 = nn.BatchNorm1d(128)
    
        def forward(self, x):
            '''分割网络'''
            batchsize = x.size()[0]
            n_pts = x.size()[2]
            x, trans = self.feat(x)
            x = F.relu(self.bn1(self.conv1(x)))
            x = F.relu(self.bn2(self.conv2(x)))
            x = F.relu(self.bn3(self.conv3(x)))
            x = self.conv4(x)
            x = x.transpose(2,1).contiguous()
            x = F.log_softmax(x.view(-1,self.k), dim=-1)
            x = x.view(batchsize, n_pts, self.k)
            return x, trans
    

    3. PointNet++

    3.1 PointNet的缺点

    PointNet++的提出源于PointNet的缺点——缺失局部特征。
    在这里插入图片描述
    从很多实验结果都可以看出,PointNet对于场景的分割效果十分一般,由于其网络直接暴力地将所有的点最大池化为了一个全局特征,因此局部点与点之间的联系并没有被网络学习到。在分类和物体的Part Segmentation中,这样的问题还可以通过中心化物体的坐标轴部分地解决,但在场景分割中,这就导致效果十分一般了。

    3.2 Multi-Scale PointNet

    作者在第二代PointNet中主要借鉴了CNN的多层感受野的思想。CNN通过分层不断地使用卷积核扫描图像上的像素并做内积,使得越到后面的特征图感受野越大,同时每个像素包含的信息也越多。而PointNet++就是仿照了这样的结构,具体如下:
    在这里插入图片描述
    其先通过在整个点云的局部采样并划一个范围,将里面的点作为局部的特征,用PointNet进行一次特征的提取。因此,通过了多次这样的操作以后,原本的点的个数变得越来越少,而每个点都是有上一层更多的点通过PointNet提取出来的局部特征,也就是每个点包含的信息变多了。文章将这样的一个层成为Set Abstraction。在这里插入图片描述

    3.3 Set Abstraction的实现细节

    一个Set Abstraction主要由三部分组成:

    • Sampling:利用FPS(最远点采样)随机采样点
    • Grouping:利用Ball Query划一个R为半径的圈,将每个圈里面的点云作为一簇
    • PointNet: 对Sampling+Grouping以后的点云进行局部的全局特征提取

    其中Sampling+Grouping的代码如下:(全部代码可以看文章开头的Github)

    def farthest_point_sample(xyz, npoint):
        """
        Input:
            xyz: pointcloud data, [B, N, C]
            npoint: number of samples
        Return:
            centroids: sampled pointcloud data, [B, npoint, C]
        """
        device = xyz.device
        B, N, C = xyz.shape
        S = npoint
        centroids = torch.zeros(B, S, dtype=torch.long).to(device)
        distance = torch.ones(B, N).to(device) * 1e10
        farthest = torch.randint(0, N, (B,), dtype=torch.long).to(device)
        batch_indices = torch.arange(B, dtype=torch.long).to(device)
        for i in range(S):
            centroids[:, i] = farthest
            centroid = xyz[batch_indices, farthest, :].view(B, 1, 3)
            dist = torch.sum((xyz - centroid) ** 2, -1)
            mask = dist < distance
            distance[mask] = dist[mask]
            farthest = torch.max(distance, -1)[1]
        return centroids
    
    
    def query_ball_point(radius, nsample, xyz, new_xyz):
        """
        Input:
            radius: local region radius
            nsample: max sample number in local region
            xyz: all points, [B, N, C]
            new_xyz: query points, [B, S, C]
        Return:
            group_idx: grouped points index, [B, S, nsample]
        """
        device = xyz.device
        B, N, C = xyz.shape
        _, S, _ = new_xyz.shape
        K = nsample
        group_idx = torch.arange(N, dtype=torch.long).to(device).view(1, 1, N).repeat([B, S, 1])
        sqrdists = square_distance(new_xyz, xyz)
        group_idx[sqrdists > radius ** 2] = N
        group_idx = group_idx.sort(dim=-1)[0][:, :, :K]
        group_first = group_idx[:, :, 0].view(B, S, 1).repeat([1, 1, K])
        mask = group_idx == N
        group_idx[mask] = group_first[mask]
        return group_idx
    
    
    def sample_and_group(npoint, radius, nsample, xyz, points):
        """
        Input:
            npoint:
            radius:
            nsample:
            xyz: input points position data, [B, N, C]
            points: input points data, [B, N, D]
        Return:
            new_xyz: sampled points position data, [B, 1, C]
            new_points: sampled points data, [B, 1, N, C+D]
        """
        B, N, C = xyz.shape
        S = npoint
    
        new_xyz = index_points(xyz, farthest_point_sample(xyz, npoint))
        idx = query_ball_point(radius, nsample, xyz, new_xyz)
        grouped_xyz = index_points(xyz, idx)
        grouped_xyz -= new_xyz.view(B, S, 1, C)
        if points is not None:
            grouped_points = index_points(points, idx)
            new_points = torch.cat([grouped_xyz, grouped_points], dim=-1)
        else:
            new_points = grouped_xyz
        return new_xyz, new_points
    

    3.4 分类网络

    分类网络只要通过这样逐层的提取局部特征,最后总结出全局特征就可以输出分类结果了,如图:
    在这里插入图片描述

    3.5 分割网络

    分割网络相比而言较为复杂,其会先将点云提取一个全局的特征,再通过这个全局的特征逐步上采样,大致的流程如下:
    在这里插入图片描述
    作者在论文中讨论了上采样的一些方法,当然最简单的就是简单的广播复制Broadcasting,即将每个点的附近的点的特征都变成和这个点一样,但是这样的方法会使得没有办法处理一些范围相冲突的点,或者范围没有覆盖到的点,如图:
    在这里插入图片描述在这里插入图片描述
    因此在论文中作者采用的是线性差值的方法,具体的公式如下:
    在这里插入图片描述
    简单来说就是距离越远的点权重越小,最后对于每一个点的权重再做一个全局的归一化。最后分割网络的结构长成这个样子:
    在这里插入图片描述
    需要注意的是,与图像分割网络U-Net类似,对于相同的点个数的层,作者采用了直连的方式将Encoder里面的特征拼接到了Decoder的特征后。

    3.6 原始方法的不足及改进

    通过上述方法实现的PointNet++虽然在点云上的分类和分割效果有了一定的提升,但是作者发现,其在点云的缺失鲁邦性上似乎变得更差了。其原因是因为激光收集点云的时候总是在近的地方密集,在远的地方稀疏,因此当Sampling和Grouping的操作在稀疏的地方进行的时候,一个点可能代表了很多很多的局部特征,因此一旦缺失,网络的性能就会极大的受影响(如下图左)。
    在这里插入图片描述
    从这张图可以看出,当点云的个数缺失到20%的时候,PointNet++的性能甚至还不如PointNet。
    在这里插入图片描述
    作者对其的改进是通过引入了不同分辨率/尺度的Grouping去对局部做PointNet求局部的全局特征,最后再将不同尺度的特征拼接起来;同时也通过在训练的时候随机删除一部分的点来增加模型的缺失鲁棒性。
    在这里插入图片描述
    最终结果如下,可以发现新的PointNet++在点缺失到80%左右都具有良好的表现:
    在这里插入图片描述

    3.7 代码解析

    PointNet++的代码结构也比较规整,其难点主要在SA层FP层的构建上,先来看总体的框架(以分割网络为例):

    class PointNet2PartSeg(nn.Module): 
        def __init__(self, num_classes):
            super(PointNet2PartSeg, self).__init__()
            self.sa1 = PointNetSetAbstraction(npoint=512, radius=0.2, nsample=64, in_channel=3, mlp=[64, 64, 128], group_all=False)
            self.sa2 = PointNetSetAbstraction(npoint=128, radius=0.4, nsample=64, in_channel=128 + 3, mlp=[128, 128, 256], group_all=False)
            self.sa3 = PointNetSetAbstraction(npoint=None, radius=None, nsample=None, in_channel=256 + 3, mlp=[256, 512, 1024], group_all=True)
            self.fp3 = PointNetFeaturePropagation(in_channel=1280, mlp=[256, 256])
            self.fp2 = PointNetFeaturePropagation(in_channel=384, mlp=[256, 128])
            self.fp1 = PointNetFeaturePropagation(in_channel=128, mlp=[128, 128, 128])
            self.conv1 = nn.Conv1d(128, 128, 1)
            self.bn1 = nn.BatchNorm1d(128)
            self.drop1 = nn.Dropout(0.5)
            self.conv2 = nn.Conv1d(128, num_classes, 1)
    
        def forward(self, xyz):
            # Set Abstraction layers
            l1_xyz, l1_points = self.sa1(xyz, None)
            l2_xyz, l2_points = self.sa2(l1_xyz, l1_points)
            l3_xyz, l3_points = self.sa3(l2_xyz, l2_points)
            # Feature Propagation layers
            l2_points = self.fp3(l2_xyz, l3_xyz, l2_points, l3_points)
            l1_points = self.fp2(l1_xyz, l2_xyz, l1_points, l2_points)
            l0_points = self.fp1(xyz, l1_xyz, None, l1_points)
            # FC layers
            feat =  F.relu(self.bn1(self.conv1(l0_points)))
            x = self.drop1(feat)
            x = self.conv2(x)
            x = F.log_softmax(x, dim=1)
            x = x.permute(0, 2, 1)
            return x, feat
    

    其Set Abstraction层的代码:

    class PointNetSetAbstraction(nn.Module):
        def __init__(self, npoint, radius, nsample, in_channel, mlp, group_all):
            super(PointNetSetAbstraction, self).__init__()
            self.npoint = npoint
            self.radius = radius
            self.nsample = nsample
            self.mlp_convs = nn.ModuleList()
            self.mlp_bns = nn.ModuleList()
            last_channel = in_channel
            for out_channel in mlp:
                self.mlp_convs.append(nn.Conv2d(last_channel, out_channel, 1))
                self.mlp_bns.append(nn.BatchNorm2d(out_channel))
                last_channel = out_channel
            self.group_all = group_all
    
        def forward(self, xyz, points):
            """
            Input:
                xyz: input points position data, [B, C, N]
                points: input points data, [B, D, N]
            Return:
                new_xyz: sampled points position data, [B, C, S]
                new_points_concat: sample points feature data, [B, D', S]
            """
            xyz = xyz.permute(0, 2, 1)
            if points is not None:
                points = points.permute(0, 2, 1)
    
            if self.group_all:
                new_xyz, new_points = sample_and_group_all(xyz, points)
            else:
                new_xyz, new_points = sample_and_group(self.npoint, self.radius, self.nsample, xyz, points)
    
            new_points = new_points.permute(0, 3, 2, 1)
            for i, conv in enumerate(self.mlp_convs):
                bn = self.mlp_bns[i]
                new_points =  F.relu(bn(conv(new_points))) 
    
            new_points = torch.max(new_points, 2)[0]
            new_xyz = new_xyz.permute(0, 2, 1)
            return new_xyz, new_points
    
    

    其Feature Propagation层的代码:

    class PointNetFeaturePropagation(nn.Module):
        def __init__(self, in_channel, mlp):
            super(PointNetFeaturePropagation, self).__init__()
            self.mlp_convs = nn.ModuleList()
            self.mlp_bns = nn.ModuleList()
            last_channel = in_channel
            for out_channel in mlp:
                self.mlp_convs.append(nn.Conv1d(last_channel, out_channel, 1))
                self.mlp_bns.append(nn.BatchNorm1d(out_channel))
                last_channel = out_channel
    
        def forward(self, xyz1, xyz2, points1, points2):
            """
            Input:
                xyz1: input points position data, [B, C, N]
                xyz2: sampled input points position data, [B, C, S]
                points1: input points data, [B, D, N]
                points2: input points data, [B, D, S]
            Return:
                new_points: upsampled points data, [B, D', N]
            """
            xyz1 = xyz1.permute(0, 2, 1)
            xyz2 = xyz2.permute(0, 2, 1)
    
            points2 = points2.permute(0, 2, 1)
            B, N, C = xyz1.shape
            _, S, _ = xyz2.shape
    
            if S == 1:
                interpolated_points = points2.repeat(1, N, 1)
            else:
                dists = square_distance(xyz1, xyz2)
                dists, idx = dists.sort(dim=-1)
                dists, idx = dists[:, :, :3], idx[:, :, :3]  # [B, N, 3]
                dists[dists < 1e-10] = 1e-10
                weight = 1.0 / dists  # [B, N, 3]
                weight = weight / torch.sum(weight, dim=-1).view(B, N, 1)  # [B, N, 3]
                interpolated_points = torch.sum(index_points(points2, idx) * weight.view(B, N, 3, 1), dim=2)
    
            if points1 is not None:
                points1 = points1.permute(0, 2, 1)
                new_points = torch.cat([points1, interpolated_points], dim=-1)
            else:
                new_points = interpolated_points
    
            new_points = new_points.permute(0, 2, 1)
            for i, conv in enumerate(self.mlp_convs):
                bn = self.mlp_bns[i]
                new_points =  F.relu(bn(conv(new_points))) 
            return new_points
    

    4.总结

    最后小小的总结一下,PointNet系列基本是近两年来所有点云分割网络的baseline,大部分state-of-art的网络也是通过以这两个网络为基础构造出来的。其优点非常的明显,就是参数量小;但其缺点就是对于局部的特征的抓取还不是特别的完善,这也是未来可以改进的地方。如果有想法的朋友欢迎交流!

    展开全文
  • 在DOS窗口、gitbush以及一些可以使用的命令行工具的界面上,输入:net stop mysql、net start mysql时,总是提示:服务名无效。 出现提示如下: 原因是:因为net start +服务名,启动的是win下注册的服务。...

    在DOS窗口、gitbush以及一些可以使用的命令行工具的界面上,输入:net stop mysql、net start mysql时,总是提示:服务名无效。

    出现提示如下:

     

    原因是:因为net start +服务名,启动的是win下注册的服务。此时,系统中并没有注册mysql到服务中。即当前路径下没有mysql服务。

    如何将MySQL注册到win服务里面?!!!(步骤如下)

    1. 来到MySQL的安装路径下bin

     

    2. 在命令行中输入mysqld --install

    成功:出现Service successfully install代表你已经安装成功,

     

    不成功:

     

    如果出现以上文字的时候,你需要用管理员的身份运行DOS窗口,这样就可以成功了

    3. 执行 net start mysql出现:

     

    删除mysql下的data文件,重新执行 mysqld --initialize 就可以在当前路径下生成data文件夹,再执行net start mysql 就可以启动mysql

    快速以管理员身份打开DOS:

    用管理员身份打开DOS命令窗口:在当前文件夹下bin下,先按住Shift+单击鼠标右键以管理员身份运行Dos窗口就可以。

     

    展开全文
  • GoogLeNet系列解读

    万次阅读 多人点赞 2016-02-25 15:56:29
    本文介绍的是著名的网络结构GoogLeNet及其延伸版本,目的是试图领会其中的思想而不是单纯关注结构。GoogLeNet Incepetion V1 Motivation Architectural Details GoogLeNet Conclusion GoogLeNet Inception V2 ...
  • Pytorch复现U-Net, R2U-Net, Attention U-Net, Attention R2U-Net

    万次阅读 多人点赞 2019-01-19 13:52:06
    Pytorch复现U-Net, R2U-Net, Attention U-Net, Attention R2U-Net 项目地址:pytorch Implementation of U-Net, R2U-Net, Attention U-Net, Attention R2U-Net U-Net, R2U-Net, Attention U-Net, Attention R2U-...
  • net start mysql 启动MySQL服务报错 发生系统错误 5 解决方法
  • CenterNet

    万次阅读 2019-04-21 15:55:55
    我们介绍一篇很好的 one-stage 目标检测论文:CenterNet: Keypoint Triplets for Object Detection,该论文是由 中科院,牛津大学以及华为诺亚方舟实验室联合提出。截至目前,据我们所知,CenterNet 应该是 one-...
  • CornerNet 算法笔记

    万次阅读 多人点赞 2018-10-12 20:22:08
    论文:CornerNet: Detecting Objects as Paired Keypoints 论文链接:https://arxiv.org/abs/1808.01244 代码链接:https://github.com/umich-vl/CornerNet 这篇发表在ECCV2018上的目标检测文章给人一种眼前一亮...
  • 解决NET:ERR_CERT_AUTHORITY_INVALID 错误

    万次阅读 2020-03-15 08:44:31
    NET:ERR_CERT_AUTHORITY_INVALID message in Chrome. 从错误信息来看,这是由于网站的证书问题导致的,该证书应该是自签名证书。接下来尝试 导入该证书。 注意: 如果是外部网站,以及自己认不到的网站,请不要按...
  • DenseNet

    千次阅读 2017-09-22 19:44:22
    2017CVPR Best Paper: 《Densely Connected Convolutional Networks》Github项目主页: https://github.com/liuzhuang13/DenseNet知乎上的一些讨论: 如何评价Densely Connected Convolutional Networks?DenseNet...
  • net view

    千次阅读 2019-11-27 17:21:10
    net view 根据主名机查 MAC 地址 nbtstat -a hostname 查看 IP 与 MAC 地址映射表 来获取 IP arp -a 根据 IP 查主机名 nbtstat -A IP net view 提示 6118错误 解决方法 1、win+R ,输入services.msc ...
  • 此操作系统不支持.netframework4.7.1

    万次阅读 2018-10-02 17:52:16
    在使用.netframework4.7.1安装程序安装的时候出现了错误:此操作系统不支持.netframework,但是其实不是不支持,需要把Windows更新到最新的系统之后那么就可以成功安装了,此时需要使用到一个安装程序,那就是Windows...
  • GoogLeNet

    千次阅读 2017-10-30 17:50:50
    GoogLeNet最早出现在2014年的《Going deeper with convolutions》,之所以叫GoogLeNet,而不是GoogleNet,文章说是为了向早期的LeNet致敬。GoogLeNet是谷歌团队为了参加ILSVRC 2014(ImageNet Large Scale Visual ...
  • U-Net网络详解

    万次阅读 多人点赞 2019-07-07 10:02:26
    U-Net: Convolutional Networks for Biomedical Image Segmentation 原文地址:https://zhuanlan.zhihu.com/p/43927696 前言 U-Net是比较早的使用全卷积网络进行语义分割的算法之一,论文中使用包含压缩路径和...
  • VGGNet介绍

    万次阅读 多人点赞 2018-07-09 17:13:26
    VGGNet介绍1 简要概括 VGGNet由牛津大学计算机视觉组合和Google DeepMind公司研究员一起研发的深度卷积神经网络。它探索了卷积神经网络的深度和其性能之间的关系,通过反复的堆叠3*3的小型卷积核和2*2的最大池化层...
  • net语言学习教程_0基础学net语言也可以,空闲时间学习,不耽误上班.2019年net语言新课程已经上线,多种课程任您选,随到随学,互动性强,效果好! NET语言学习介绍 NET学习课程说明 NET视频教程目录 NET学习教程百度网盘...
  • V-Net、U-net、AttentionGatedVNet

    万次阅读 2018-07-24 09:12:06
    Nassir Navab等人发表在IEEE 3D Vison上的论文V-Net,是U-Net[1]的3D版本,其实U-Net作者自己也发表了3D U-Net[2]。 论文贡献:第一,3D图像分割end2ent模型(基于3D卷积),用于MRI前列腺容积医学图像分割。第二...
  • (绝对详细)CenterNet训练自己的数据(pytorch0.4.1)

    万次阅读 多人点赞 2019-08-29 17:05:45
    我的任务是在行人头肩数据上训练并测试centernet网络,先证明一下我是真的训练了哈,这是用centernet检测的一张结果(训练了10个epochs的结果,大家放心使用,网络功能还是很强大的): 我参考的这篇博客,对我自己...
  • pointnet和pointnet++

    千次阅读 2018-08-17 15:48:11
    pointnet++是pointnet的改进版本,两者都可以做点云分类和点云分割 代码:pointnet系列 pointnet: 分类: 输入:B*N*(d+C) d为坐标xyz,C为点属性(在modelnet40数据集没有点属性)图中为B*N*3 transform:...
  • 千万不要用efficientnet做bone net

    千次阅读 2019-08-14 08:41:41
    前面有写过一篇文章convolution backbone network——EfficientNet解读,说efficientnet很好,然而最近用他做bonenet的时候,发现太消耗GPU显存了,efficient_b4在1080ti测试都out of memorey 了,所以不推荐用,还是...
  • ElasticNet算法解析

    万次阅读 2019-05-26 21:41:09
    ElasticNet又叫弹性网络回归,要理解ElasticNet回归,首先要理解岭回归和Lasso回归。 线性回归 ElasticNet Sklearn中的ElasticNet回归 Sklearn库中有sklearn.linear_model.ElasticNetCV和sklearn.linear_model....
  • AD原理图编译WARNING:Net XXX has no driving source

    万次阅读 多人点赞 2020-05-23 15:45:30
    WARNING:Net XXX has no driving source 这篇博客填一下以前一篇关于Altium designer ERROR的坑原文章 本次文章以基于AT89C51的函数信号发生器为例:https://blog.csdn.net/toyjis/article/details/105886632 在我们...
  • cmd net命令详解与图片示意

    万次阅读 2018-11-07 11:22:07
    net命令大全,net命令用法,net网络命令,net命令使用,net命令集,net命令介绍,net常用命令,net命令的使用技巧,net命令如何使用 下面对NET命令的不同参数的使用技巧介绍如下: 1、Net ViewI  作用:显示域列表、...
  • VGGNet

    千次阅读 2017-08-17 21:13:42
    感觉VGGNet就是加深版的AlexNet,都是卷积与池化的叠加,最后再加两层全连接,然后softmax输出。VGGNet有5段卷积,每段卷积由2~3个卷积层后加一个最大池化组成。卷积核的数量也随着层数的增加而增多。VGGNet也沿用了...
  • EfficientNet算法笔记

    万次阅读 多人点赞 2019-06-04 19:57:19
    论文:EfficientNet: Rethinking Model Scaling for Convolutional Neural Networks 论文链接:https://arxiv.org/abs/1905.11946 代码链接:...
  • PointNet++点云处理TensorFlow版

    千人学习 2020-08-29 12:25:24
    PointNet网络模型是直接对三维点云数据进行深度学习的开山之作,PointNet++是对PointNet的改进技术。PointNet++是点云处理深度学习里程碑式的工作,启发了很多后续研究。 原作的PointNet++代码使用Python2.7和...
  • HowNet情感词典

    热门讨论 2016-04-15 11:09:57
    知网的HowNet情感词典,txt文件,感觉比较详细
  • pytorch笔记:Efficientnet微调

    千次阅读 多人点赞 2019-07-08 17:20:18
    efficientnet-b5为例 from efficientnet_pytorch import EfficientNet model = EfficientNet.from_pretrained('efficientnet-b5') print(model) 只修改网络的最后几层: (_conv_head): Conv2dStaticSamePadding( ...
  • ASP.NET Core 如何支持Log4Net扩展? 就是一个日志组件的集成使用,大概分为以下步骤: 1.nuget引入log4net程序集;Microsoft.Extensions.Logging.Log4Net.AspNetCore程序集合 2.增加配置文件,配置文件内容如下 <...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,285,172
精华内容 514,068
关键字:

net