0 - Abstract

  深度神经网络(DNNs)最近在图像分类任务上表现出了突出的性能。在这篇文章中,我们进一步深入探究使用DNNs进行目标检测的问题,这个问题不仅需要对物体进行分类,并且还需要对各种各样类别的物体进行精确定位。我们提出了简单但依然有效的将目标检测问题形式化为回归问题从而来对物体边界框进行定位。我们提出了一个多尺度推理程序(模型?),它可以通过应用少量网络层来产生高分辨率的具有小误差的目标检测。并在Pascal VOC上展示了当前最好方法的效果。

1 - Introduction

  随着我们更加关注完整图像的理解,更加精确和细致的目标识别变得越来越重要。在本文内容中,我们不仅关注图像的分类,同时也关注图像中包含的目标的类别的精确评估及其坐标,该问题成为目标检测问题。

  目标检测的主要改进归功于目标表示以及机器学习模型的提升。一个当前最先进的检测系统突出例子是the Deformable Part-based Model(DPM)。它是基于仔细设计的表示以及目标在运动学上的分解而构建起来的图解模型。对图解模型进行分离的学习使得能够对于各种各样的目标类别构造高精度的基于部分(part-based)模型。

  结合人工手工设计表示的浅层分离训练模型是关于目标分类的相关问题的最佳范例之一。然而,在过去几年里,深度神经网络(DNNs)作为有利的机器学习模型而出现了。

  DNNs展示了与传统分类方法的主要区别。首先,它们的深度架构使得它们相比浅层网络能够学习更加复杂的模型。这种表示性以及健壮性训练算法使得模型能够脱离手工设计特征而学习到有效的目标表示。这通过了ImageNet的上千个类别的分类任务挑战进行了经验上的证明。

  在这篇文章中,我们探索DNNs对于目标检测问题的能力,这其中我们不仅解决分类任务,也尝试进行精确目标定位。我们在此提出的这个问题是具有挑战性的,因为我们想要使用有限的计算资源在同一幅图像中检测出潜在的许多具有不同尺寸的目标实例。

  我们提出一种形式化,其能够对于给定的一张图像预测出多个目标的边界框。更准确地说,我们将基于DNN的回归形式化为输出目标边界框的二进制掩码(以及部分盒子 and portions of the box as well),如图1所示。此外,我们实现了一个简单的边界框推理去从掩码中提取检测结果。为了提高定位的准确率,我们DNN掩码生成器应用在完整图像的多尺度表示以及小数量的大图片切片上,后续跟着一个精心制作的步骤(见于图2)。用这种方法,只需要经过一些DNN回归我们就获得了当前最佳的边界框定位性能。

图1:基于DNN的回归模型的目标检测框图

  

图2:在对多个尺度和大图像框的目标掩码进行回归后,我们进行目标边界框提取。获得的边界框通过在子图像(通过当前对象边界框进行裁剪)上重复应用相同的程序来进行确认。为了简洁起见,我们只显示了完整的对象掩码,但我们使用了所有五个对象的掩码。

  在这篇文章中,我们证明了基于DNN的回归模型是有能力学习特征的,其不只是胜任分类任务,也能够捕获有效的几何信息。我们使用用来做分类任务的通用架构,而将其最后一层替换成一个回归层。是我们有几分惊喜同时也有效的是该网络在一定程度能够在编码的同时保持不变性并且也能够捕获目标的位置。

  其次,我们介绍了多尺度边界框推理加上一个精心设计的步骤来产生精确的检测。用这种方法,我们能够应用DNN来预测一个低分辨率的受限于输出层尺寸掩码而在像素方面的准确率上只有少量的误差——每一张输入图片只应用了少量次数的该网络。

  另外,现在的方法很简单。它不需要手工设计一个模型去捕获部分的以及它们之间明确的联系的信息。这种简单性的优点不仅容易适用于广泛的类别,而且对于更大范围的目标检测中显示了更好的性能——不管对于固定的还是变化的对象。在Sec. 7中在Pascal VOC挑战上比较了该模型与当前最先进的检测结果。

2 - Relatd Work

  目标检测的一个非常值得学习的案例是deformable part-based model,这是最突出的例子。这个方法综合了一系列的分离训练部分和一个称为形象化架构的模型(pictorial structure)。它可以理解为一个二层模型——parts为第一层,而star model为第二层。与统一的网络层DNNs相反的是,其工作是需要利用领域知识的——parts是基于手动设计Histogram of Gradients(HOG)的描述形式并且parts的架构是根据运动学上的动机设计的。

  已经提出的基于部分的模型和传统模型的用于目标检测和分析的深度架构被称为组成模型,其中目标被表示为图像基元的网络层组成部分。一个显著的例子是$And/Or$图,其目标被建模为一棵树,其中$And$结点表示不同部分而$Or$结点表示同一部份的不同模式。类似于DNNs,$And/Or$图包括了多个层,其中低部分的层表示小部分的统一的图像基元,而高部分的层表示目标的部分。类似的组成模型比DNNs更容易进行解释。在另一方面,它们需要进行推理,而本文提出的DNN模型只需要单纯的前向传播而没有潜在变量需要推理。

  检测任务的组成模型的更深层样例是基于片段作为基元的,使用Gabor过滤器或者大规模的HOG过滤器来关注其形状。这类方法由于训练的差异性而需要使用专门设计的学习程序从而具有传统上的挑战性。此外,在推理时间里,它们综合了自底向上和自顶向下的处理过程。

  神经网络(NNs)能够被抽象考虑为组成模型,相比于上述模型,其结点相更具统一性和可推理性。将NNs应用于视觉问题上已经有数十年的历史了,其中卷积NNs成为了最具有代表性的样例。直到最近,这些模型才在大规模图像分类任务中以DNNs的形式出现。然而它们应用于检测是受限的。语法分析作为目标检测的更进一步的细节,已经尝试使用多层卷积网络。医学图像分析使用了DNNs进行处理。然而这两种方法都是使用NNs要么在每个像素上要么在超像素上作为局部部分分类。而我们的方法使用整张图片作为输入并且通过回归来进行定位。这样,这是一种NNs更加有效的应用。

  与我们最相似的方法跟我们有着相似的高层次目标表示但是使用了不一样的特征、损失函数以及不用额外的机制去相同类别的多个实例间的联系从而使用了更小的网络。

3 - DNN-based Detection

  用于目标掩码的基于DNN的回归方法的核心如图1所示。基于这个回归模型,我们能够对于整个和部分目标生成掩码。一个单一的DNN回归能够给我们一张图片中多个目标的掩码。为了进一步提高定位的精度,我们将DNN定位器应用于一个小规模的大子窗口集合。整体的流如图2表示,并且在其下面进行解释。

4 - Detection as DNN Regression

  我们的网络基于[14]提出的卷积DNN。它一共包含了7个层,前面五个层为卷积层,最后两个层为全连接层。每一个成使用一个线性调整单元作为非线性变化。其中的三个卷积层有额外加入的最大池化层。更进一步的细节我们参考[14]。

  我们应用上述的统一架构来进行定位。我们不是采用softmax分类器作为最后一层,而是使用了回归层,它可以产生一个对象的二进制掩码$DNN(x;\Theta )\in R^N$,其中$\Theta$是网络的参数,$N$是全部像素的总数量。因为网络的输出具有固定的维度,我们对于一个固定尺寸$N=d \times d$预测一个掩码。在经过放缩到图像尺寸之后,二进制掩码表示了一个或者多个目标:如果这个像素位于一个给定类别的目标的边界框之内,其值应为1,否则为0。

  这个网络被训练来最小化对于图片x预测一个真实边界掩码$m \in [0, 1]^N$的$L_2$误差:

$$\mathop{min}\limits_{\Theta}\sum_{(x,m)\in D}\begin{Vmatrix}(Diag(m+\lambda I)^{1/2}(DNN(x;\Theta)-m))\end{Vmatrix}^2_2$$

  其中的总和包括一个包含采用二进制掩码表示的目标边界框的训练集合D。

  因为我们的基础网络是高度非凸的,因此我们的优化不能得到保证,所以有时候必须根据真实边界框掩码来对每一个输出使用不同的权重调整损失函数。一个直觉是,大多数的目标相比于图片尺寸显得很小,因此网络很容易被简单的解决方案所困,即为每一个输出都分配零值。为了避免这种不好的行为,通过一个参数$\lambda \in R^{+}$来增加真实边界框掩码中与输出相应的非零值的权重是有用的:如果$\lambda$选择一个小的值,输出中有真实数值0的部分的误差惩罚将小于真实数值为1的部分,因此这激励网络即时在信号很弱的情况下(目标很小)也尽力去预测非零的数值。

  在我们的思想中,我们使用感受野为$255 \times 255$的网络,并且其输出预测一个尺寸为$d \times d$的掩码,其中$d=24$。

5 - Precise Object Localization via DNN-generated Masks

  虽然前面提到的方法有能力生成高质量的掩码,但是它们也有几个额外的挑战。第一,一个简单的目标掩码不能有效地区分不同物体。第二,由于输出尺寸的限制,我们生成的掩码比原始图像小了许多。举个例子,对于一张尺寸为$400 \times 400$的图像并且$d=24$,每一个输出会关联到原始图像中的一个$16 \times 16$的单元,这使得定位一个目标不够精确,特别是对于一个小目标。最后,因为我们使用整张图像作为输入,小目标只会影响一小部分的输入神经元因此使得其很难去识别。在下面,我们解释我们怎么解决这些问题。

5.1 - Multiple Masks for Robust Localization

  为了解决多个接触目标(multiple touching objects),我们生成了多个掩码,每一个掩码代表了一整个目标或者目标的部分。因为我们最后的目的是去产生一个边界框,所以我们使用一个网络去预测目标边界框掩码以及四个额外的网络去预测边界框的四个部分:上下左右,可以被描述为$m^h,h \in {full,bottom,top,left,right}$。这五个预测是过于完备的,但是也在一些掩码中帮助减少了不确定性以及解决错误。更进一步,如果两个相同类型的目标被放置于彼此旁边,然后当至少有两个生成五个掩码而不会使得目标合并就可以识别出它们。这将可以允许检测多个目标。

  在训练的时候,我们需要将目标边界框转换为这五个掩码。因为掩码能够比原始图像小很多,我们需要根据网络输出的尺寸按比例缩小真实的边界框掩码。用$T(i,j)$表示网络输出$(i,j)$预测的在图像中存在目标的矩形位置。这个举行的左上角在$(\frac{d_1}{d}(i-1),\frac{d_2}{d}(j-1))$并且尺寸为$\frac{d_1}{d} \times \frac{d_1}{d}$,其中$d$是输出掩码的尺寸并且$d_1,d_2$是图像的高度和宽度。在训练过程中我们使用$m(i,j)$去预测边界框$bb(h)$和$T(i,j)$相互覆盖的部分:

$$m^h(i,j;bb)=\frac{area(bb(h) \cap T(i,j))}{area(T(i,j))}\ (1)$$

  其中$b(full)$对应于真实目标边界框。对于余下的值$h$,$bb(h)$与原始边界框的四个值相对应。

  注意到我们使用了整个目标边界框以及边界框的上下左右去定义五个不同的覆盖类型。对于真实边界框$bb$的结果$m^h(bb)$是在对于类别$h$的网络中使用的。

  在这一点上,值得注意的是可以训练一个输出层产生上述五种信息的网络来预测所有的掩码。这支持扩展性。用这种方法,五个定位器将共享大部分层因此能够共享特征,这看起来更自然,因为它们本来就用来处理相同目标的。一种更加激进的方法是对于多种不同的类别使用同一个定位器,这似乎也是可行的。

5.2 - Object Localization from DNN output

  为了完成检测过程,我们需要去对每一张图像评估一系列边界框。虽然输出的分辨率小于输入图像,但是我们将二进制掩码调整大小为与输入图像一样的分辨率。任务的目的是在输出的掩码做表中评估出边界框$bb=(i,j,k,l)$的左上角参数$(i,j)$以及右下角参数$(k,l)$。

  为了实现这个目的,我们使用了分数$S$来结合掩码表示每一个边界框的认可度从而来推断出得分最高的边界框。一个自然而然的认可度衡量是通过掩码和边界框覆盖率来计算的:

$$S(bb,m)=\frac{1}{area(bb)}\sum_{(i,j)}m(i,j)area(bb\cap T(i,j))\ (2)$$

  我们对所有网络输出的索引$(i,j)$以及表示为$m=DNN(x)$的网络输出求和。如果我们在全部五种掩码类型上扩展上面的分数,最后的分数公式如下:

$$S(bb)=\sum_{h \in halves}(S(bb(h),m^h)-S(bb(\bar{h}),m^h))\ (3)$$

  其中$halves={full,bottom,top,left,right}$表明了整一个边界框以及它的四个部分。$h$表明其中一个$h$是另一个$h$的对边,例如,一个上部的掩码应该被上部掩码覆盖而不是下部。对于$h=full$,我们用$h$表示矩形回归边界$bb$,如果它超出了$bb$则分数会得到惩罚。综上所述,一个边界框如果包含了全部五个掩码,则它的分数将会很高。

  我们使用公式(3)在可能的边界框中尽可能的搜索。我们考虑了平均尺寸为图片尺寸的$[0.1,...,0.9]$的边界框以及在训练图像中通过k-means聚类评估的对于目标的边界框的10种不同宽高比例。我们在图像上通过5像素的步长移动上述90个边界框。注意到公式(3)中,在计算了图像的掩码m之后,可以用四个操作进行有效的计算。操作的确切数量是5(2×#pixels+20×#boxes$),其中第一部分是计算整体掩码计算的复杂性,第二部分则是用于计算边界框分数。

  为了最后产生一系列检测目标,我们使用了两种类别的过滤器。第一种是通过公式(2)来保证边界框的有效分数,例如高于0.5。我们通过训练一个保留正确分类到当前检测器的DNN分类器来对它们进行进一步筛选。最后,我们应用了非极大值抑制。

5.3 - Multi-scale Refinement of DNN Localizer

  对于网络输出的不足和问题有:(i)应用DNN定位器在不同尺度以及一小部分较大的子窗口上面;(ii)使用DNN定位器对高层推理边界框的目标检测进行确认(见于图2)。

  在不同尺度上使用大窗口,我们产生了几个掩码并且将它们合并层更高层次的掩码,每一个尺度对应一个掩码。合适的尺度范围取决于图像的分辨率以及定位器的接收域尺度,我们希望图像能够被更高像素级别的网络输出所覆盖,同时我们希望每一个目标落于至少一个窗口并且这些窗口的数量尽可能少。

  为了实现上述目的,我们使用了三种尺度:整个图像以及两个其它尺度以至于其窗口的尺寸是前面给定尺度的窗口尺寸的一半。我们使用每一种尺寸的窗口覆盖图片,这些窗口的重合度很小——它们面积的20%。这些窗口的数量相对较少并且在几个尺度上覆盖了图像。最重要的是,最小尺度的窗口允许最高分辨率的定位。

  在推理过程红,我们将DNN应用于所有窗口。注意到这不同于滑动窗口方法,因为我们需要对每一张图片使用多个窗口评估,通常是小于40个窗口。对于每一个尺度产生的目标掩码采用非极大值抑制融合。这给我们提供了三种不同尺寸图像的掩码,每一个观察者观察不同大小的目标。对于每一个尺度,我们应用Sec. 5.2提到的边界框推理去获得一系列的目标检测结果。在我们的实现中,我们对于每一个尺度取最好的5个检测结果,一共15个检测结果。

  为了进一步提高定位效果,我们经过了第二阶段的DNN回归过程,将其称为确认阶段。DNN定位器应用于初始检测阶段识别出来的窗口——15个边界框中的每一个放大1.2倍(应该是裁剪其周围1.2倍的图像)然后被作为确认网络的输入。在高分辨率的图像中应用定位器能够有效地提高检测精度。

  完整的算法由算法1进行概述。

6 - DNN Training

  我们网络的一个引人注目的特点就是其简易性:分类器被简单的替换成一个掩码生成器而不用其它前置的平滑的或者卷积架构。然而,它需要在一个巨大数量的训练数据集上进行训练:每一个位置几乎都需要有不同尺寸的目标出现过。

  为了训练掩码生成器,我们从每一张图片中生成几千个样本,并把样本划分为60%负样本以及40%正样本。如果一个样本没有横切任何一个目标的边界框,则将其考虑为负样本。正样本是那些覆盖了一些目标边界框的至少80%区域的样本。当裁剪图象的宽度均匀分布在规定的最小尺度和整个图像的宽度之间时,这些裁剪图像被作为样本。

  我们使用和分类器相似的准备步骤进行训练,只在最后微调我们的检测结果。加之,我们从每张图片中取样几千个样本:60%负样本和40%正样本。负样本是那些和真实目标边界框的Jaccard-similarity小于0.2的样本,而正样本是大于0.6的样本,并且给其打上了最相似类别目标的类别。加入额外的负类可以充当一个正规化的作用并且提高过滤器的质量。在两种情况中,没一个类别的样本数量都有1000万规模。

  因为相比于分类任务,训练定位任务更加困难,保证低层次过滤器的高质量权重初始化是非常重要的。为了实现这个目的,我们首先将网络训练成为用来做分类任务的,并且将其权重重用于定位任务。为了实现定位任务,我们对整个网络进行微调,包括卷积层。

  网络使用随机梯度来训练,并且使用ADAGRAD来自动评估网络层的学习率。

7 - Experiments

  Dataset:我们在Pascal Visual Object Challenge (VOC) 2007测试数据集上评估了上述方法的性能。这个数据集包括了在超过20个类别上的大约5000张测试图片。因为我们的方法的参数数量很多,我们让其在大约有11000张图片的VOC2012训练和验证数据集上进行训练。在测试的时候,该算法为一张图片产生一个集合的识别结果,结果包括边界框以及该边界框内包含目标的类别标签。我们在每一种类别上使用正确率-召回率曲线以及平均正确率(AP)来衡量算法的性能。

  Evaluation:在完整VOC2007数据集上的完整评估见于表1。我们将我们的方法(称为DetectorNet)与相关的其它三种方法进行比较。第一种方法是DNN分类器的滑动窗口版本。在训练这个网络为一个21通道的分类器(VOC类别数+背景)之后,我们使用在10个不同的尺度上的8个像个5个像素的相位定量来生成边界框。最小的尺度是图片尺寸的1/10,而最大的是覆盖整张图像。这使得每一张图像能够生成大约150000个边界框。每一个边界框被映射到$255 \times 255$的接收域。检测分数由softmax分类器计算。我们通过非极大值抑制减少了边界框的数量,把其中Jaccard similarity小于0.5的边界框抛弃掉。在初始训练之后,我们使用了两个循环在训练集上进行硬负样本挖掘。这使得我们的初始训练集增加了两百万个样本并且减少了错误正样本的比率。

表1:在Pascal VOC2007测试集中的平均准确率

  第二种方法是一个由[19]提出的三层组成模型,其可以视为一个深层架构。这种方法作为VOC2011的获胜者其表现出了很好的性能。最后,我们与DPM进行了比较。

  虽然我们的比较有点不太公平,因为我们在更大的VOC2012训练数据集上进行训练,但我们展示了大多数模型的最好效果:我们在8个类别和其它类别中都表现出色。注意到,其可以通过调整滑动窗口而使得其表现与DetectorNet同等水平,但是网络评估的绝对数量使得这个方法是不可行的,而DetectorNet只需要(#windows×#mask types)~120裁剪图像/类别来做评估。在一个12核机器上,我们的实现对于每一个类别的每一张图像需要5~6秒进行处理。

  与被广泛引用的DPM方法相反,DetectorNet擅长于可变形的物体,例如鸟、猫、羊和狗。这说明它能够以更好的方式处理更少的刚性对象,并且其在例如汽车、公交车等刚性对象上表现很好。

  我们在图3中展示了目标检测的例子,其中检测边界框和五个生成掩码都是可见的。这可以看到,DetectorNet具有了不仅能够找到大目标,并且能够找到小目标的能力。生成的掩码很好的定位并且几乎没有超出目标之外。类似于这种高质量的回馈是难以去思想的,但是在这种情况下是可能的因为DNN的表达能力以及其自然的内容合并能力。

  

图3:对于每一张图像,我们在其右侧展示了它的两个热图:第一张是与DNN full相应的输出,第二张是以红绿蓝黄将四个部分掩码进行编码。此外,我们显示了评估的目标边界框。除了最后一行之外所有例子都正确检测了。

  常见的误检测是因为相似的目标(例如图3最后一行左边目标)或者不精确定位(例如图3最后一行右侧目标)。第二个问题是因为训练集中对于其的模糊不清的定位——例如在一些图像中只有鸟的头部可见而另一些鸟的整个身体都能看到。在一些情况下我们发现如果脸和身体都出现在一张图像中它们会被一起检测到(只打一个边界框?)。

  最后,确认步骤极大的提高了检测的质量。则能够从图4看出,我们展示了DetectorNet在检测第一步以及经过确认步骤之后的准确率 vs 召回率对比。一个容易看到的显而易见的提高主要是由于更好的定位真实正样本分数的提高。

8 - Conclusion

  在这个工作中,我们利用了DNNs的表达性来做目标检测。我们展示了简单地将检测任务抽象为一个基于DNN的目标掩码回归任务,将其运用到多尺度由粗到精的程序,其可以产生不错的结果。这些结果在训练时会产生一些计算花销——要在每一个目标类别和掩码类别上训练网络。更进一步的工作,我们通过使用一个简单的网络去检测不同类别的目标从而减少开销并且能够扩展到更多数量的类别。

  

Deep Neural Networks for Object Detection(翻译)的更多相关文章

  1. Paper Reading:Deep Neural Networks for Object Detection

    发表时间:2013 发表作者:(Google)Szegedy C, Toshev A, Erhan D 发表刊物/会议:Advances in Neural Information Processin ...

  2. Coursera, Deep Learning 4, Convolutional Neural Networks, week3, Object detection

    学习目标 Understand the challenges of Object Localization, Object Detection and Landmark Finding Underst ...

  3. On Explainability of Deep Neural Networks

    On Explainability of Deep Neural Networks « Learning F# Functional Data Structures and Algorithms is ...

  4. 目标检测--Scalable Object Detection using Deep Neural Networks(CVPR 2014)

    Scalable Object Detection using Deep Neural Networks 作者: Dumitru Erhan, Christian Szegedy, Alexander ...

  5. 论文翻译:2018_Source localization using deep neural networks in a shallow water environment

    论文地址:https://asa.scitation.org/doi/abs/10.1121/1.5036725 深度神经网络在浅水环境中的源定位 摘要: 深度神经网络(DNNs)在表征复杂的非线性关 ...

  6. Must Know Tips/Tricks in Deep Neural Networks

    Must Know Tips/Tricks in Deep Neural Networks (by Xiu-Shen Wei)   Deep Neural Networks, especially C ...

  7. Must Know Tips/Tricks in Deep Neural Networks (by Xiu-Shen Wei)

    http://lamda.nju.edu.cn/weixs/project/CNNTricks/CNNTricks.html Deep Neural Networks, especially Conv ...

  8. (转)Understanding, generalisation, and transfer learning in deep neural networks

    Understanding, generalisation, and transfer learning in deep neural networks FEBRUARY 27, 2017   Thi ...

  9. Paper Reading: Relation Networks for Object Detection

    Relation Networks for Object Detection笔记  写在前面:关于这篇论文的背景知识,请参考我前面的两篇随笔(<关于目标检测>和<关于注意力机制> ...

随机推荐

  1. C sockets Errno

    在Windows下进行网络编程,免不了出现各种错误.在Linux下可以使用errno查看错误,但是根据stackoverflow上说,windows下应该使用: FormatMessage() WSA ...

  2. php php-fpm安装 nginx配置php

    centos 6.2 linux下安装php5.6.6源码 PHP在 5.3.3 之后已经把php-fpm并入到php的核心代码中了. 所以php-fpm不需要单独的下载安装.要想php支持php-f ...

  3. django_admin用法

    Django内置的admin Django内置的Admin是对于model中对应的数据表进行增删改查提供的组件,使用方式有: 依赖APP: django.contrib.auth django.con ...

  4. 剑指Offer_编程题_10

    题目描述 我们可以用2*1的小矩形横着或者竖着去覆盖更大的矩形.请问用n个2*1的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法? class Solution { public: int r ...

  5. flask模版继承和block

    模版继承和block的目的就是为了减少前端代码量 flask_ones.py #encoding:utf-8 from flask import Flask,url_for,redirect,rend ...

  6. SQL语法基础之CREATE语句

    SQL语法基础之CREATE语句 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.查看帮助信息 1>.使用“?”来查看MySQL命令的帮助信息 mysql> ? CR ...

  7. Gson入门教程【原】

    gson一个jar包就能纵横天下,不像Json-lib.jar依赖其它jar包. 点击右边图片下载jar包       或以下链接 http://central.maven.org/maven2/co ...

  8. Spring Boot 启动:No active profile set, falling back to default profiles: default

    启动 Spring Boot 失败,但是没有出现多余的异常信息: 检查之后发现是依赖的问题(之前依赖的是 spring-boot-starter),修改即可: 方法二: pom.xml加上下面两个依赖 ...

  9. 上传文件服务与web服务分离

    业务场景:1. 后端服务为java web应用,使用tomcat容器,多实例集群化部署.2. 前端使用nginx作为后端应用的反向代理. 业务需求:现在需要在java web应用端上传文件,同时还要能 ...

  10. 回顾一下C++ 编写DLL

    项目模版使用Win32工程创建的dll项目 一.原始代码 使用depends查看导出函数 二.不同编译方式区别 C方式编译(extern "C"): __stdcall调用约定:输 ...