约瑟夫·雷德蒙、桑托什·迪瓦拉*、罗斯·吉尔希克、阿里·法尔哈迪*
华盛顿大学 艾伦人工智能研究所 Facebook人工智能研究
http://pjreddie.com/yolo/
我们提出了YOLO,一种新的物体检测方法。先前关于对象检测的工作将分类器重新用于每种形式的检测。相反,我们将目标检测作为一个回归问题来框定空间分离的边界框和相关的类概率。单个神经网络在一次评估中直接从完整图像预测边界框和类概率。由于整个检测流水线是一个单一的网络,因此可以直接对检测性能进行端到端优化。
我们的统一架构速度极快。我们的基本YOLO模型以每秒45帧的速度实时处理图像。网络的一个较小版本,快速YOLO,每秒处理惊人的155帧,同时仍能实现其他实时检测器的两倍的mAP。与最先进的检测系统相比,YOLO定位误差更大,但不太可能预测背景中的假阳性。最后,YOLO学会了物体的非常普遍的表示。当从自然图像到其他领域(如艺术品)的通用化时,它优于其他检测方法,包括DPM和R-CNN。
人类瞥一眼一幅图像,立刻知道图像中有什么物体,它们在哪里,以及它们是如何相互作用的。人类的视觉系统快速而准确,允许我们用很少的意识去完成复杂的任务,比如开车。快速、精确的物体检测算法将允许计算机在没有特殊传感器的情况下驾驶汽车,使辅助设备能够向人类用户传递实时场景信息,并解锁潜在的通用目的,响应机器人系统。
当前的检测系统重新使用分类器来执行检测。为了检测一个对象,这些系统为该对象取一个分类器,并在测试图像中的不同位置和比例对其进行评估。像可变形零件模型(DPM)这样的系统使用滑动窗口方法,其中分类器在整个图像上均匀间隔的位置运行。
最近的一些方法,如R-CNN,使用区域建议方法,首先在一个图像中生成潜在的边界框,然后在这些建议的框上运行分类器。分类后,后处理用于细化绑定框,消除重复检测,并基于场景中的其他对象来重新设置边界框。这些复杂的管道速度慢且难以优化,因为每个单独的组件都必须单独训练。
我们将目标检测重新定义为一个单一的回归问题,直接从图像像素到边界框坐标和类概率。使用我们的系统,你只需看一次(YOLO)图像,就可以预测存在什么物体,它们在哪里。
YOLO非常简单:见图1。单卷积网络同时预测多个边界框和这些框的类概率。YOLO对整个图像进行训练,并直接优化检测性能。这种统一的模型比传统的物体检测方法有几个好处。
图1::YOLO检测系统。使用YOLO处理图像既简单又直接。我们的系统(1)将输入图像的大小调整到448 × 448,(2)对图像运行单个卷积网络,以及(3)通过模型的置信度来阈值化结果检测。
首先,YOLO速度极快。因为我们将检测作为一个回归问题,所以我们不需要复杂的管道。我们只需在测试时对新图像运行神经网络来预测检测结果。在Titan X图形处理器上不执行批处理的情况下,我们的基本网络以每秒45帧的速度运行,而快速版本的运行速度超过150 fps。这意味着我们可以用不到25毫秒的延迟实时处理流式视频。此外,YOLO的平均精度是其他实时系统的两倍以上。有关我们系统在网络摄像头上实时运行的演示,请查看我们的项目网页:http://pjreddie.com/yolo/.
第二,YOLO在作出预测时,对这张照片进行了全局范围的解释。与基于滑动窗口和区域提议的技术不同,YOLO在训练和测试期间看到整个图像,因此它隐含地编码关于类以及他们外观的上下文信息。Fast R-CNN,一种顶级检测方法,因为看不到更大的上下文,所以会把图像中的背景碎片误认为是物体。与Fast R-CNN相比,YOLO的背景误差不到一半。
第三,YOLO学习对象的概括表示。当在自然图像上训练并在艺术作品上测试时,YOLO的表现远远优于顶级的检测方法,如DPM和R-CNN。由于YOLO是高度通用的,当应用于新领域或意外输入时,它不太可能崩溃。
YOLO在精确度上仍然落后于最先进的检测系统。虽然它能快速识别信息中的对象,但它很难精确定位某些对象,尤其是小对象。我们在实验中进一步研究了这些权衡。
我们所有的训练和测试代码都是开源的,还可以下载各种预处理模型。
我们将目标检测的独立组件统一到单个神经网络中。我们的网络使用整个图像的特征来预测每个边界框。它还可以同时预测一个图像中所有类的所有边界框。这意味着我们的网络对整个图像和图像中的所有对象进行全局推理。YOLO设计在保持高平均精度的同时,支持端到端的训练和实时的速度。
我们的系统将输入图像分成一个S × S网格。如果对象的中心落入网格单元,该网格单元负责检测该对象。
每个网格单元预测B个边界框和这些框的置信度得分。这些置信度得分反映了模型对盒箱包含对象的置信度,以及它认为盒箱预测的准确性。通常我们把置信度定义为
如果该单元格中不存在对象,置信度得分应该为零。否则,我们希望置信度得分等于预测框和真实目标之间的交集。
每个边界框由5个预测组成:x、y、w、h和置信度。(x,y)坐标表示相对于网格单元边界的框的中心。宽度和高度是相对于整个图像预测的。最后,置信度的预测代表预测框和任何真实框之间的IOU。
每个网格单元还预测C个条件类概率。这些概率以包含对象的网格单元为条件。我们只预测
每个网格单元一组类别概率,而不考虑框的数量B。
在测试时,我们将条件类概率和单个盒子置信度的预测相乘,
它给我们每个盒子的特定类别的置信度分数。这些分数既编码了该类出现在框中的概率,也编码了预测框与对象的匹配程度。
图二:模型。我们的系统将检测建模为一种回归问题。它将图像分成一个S × S网格,并为每个网格单元预测B个边界框、这些框的置信度和C个类概率。这些预测被编码为一个S × S × (B * 5 + C)的张量。
为了在PASCAL VOC上评估YOLO,我们使用了S = 7,B = 2。PASCAL VOC有20个标签类,所以C= 20。我们最终的预测是一个7 × 7 × 30的张量。
我们将该模型实现为一个卷积神经网络,并在PASCAL VOC数据集上对其进行评估。网络的初始卷积层从图像中提取特征,而全连接层预测输出的概率和坐标。
我们的网络架构受到图像分类的GoogLeNet模型的启发。我们的网络有24个卷积层,后面是两个全连接层。我们不使用GoogLeNet使用的初始模块,仅使用1 × 1的还原层,然后是3 × 3的卷积层,这类似于Lin等人的[22]。整个网络如图3所示。
图3:网络架构。我们的检测网络有24个卷积层,后面是两个全连接层。交替1 × 1卷积层减少了前面的层的特征空间。我们在ImageNet分类任务中以一半分辨率(224 × 224输入图像)预处理卷积层,然后将分辨率加倍以进行检测。
我们还训练了YOLO的快速版本,旨在推进快速目标检测的边界。快速YOLO使用的神经网络具有较少的卷积层(9层而不是24层)和较少的滤波器。除了网络规模之外,YOLO和Fast YOLO之间的所有训练和测试参数都是相同的。
我们网络的最终输出是预测的7 × 7 × 30的张量。
我们在ImageNet 1000级竞争数据集上预训练卷积层。对于预训练,我们使用图3中的前20个卷积层,然后是一个平均池层和一个全连接层。我们对该网络进行了大约一周的训练,并在ImageNet 2012验证集上实现了88%的单一作物的前5名准确率,与Caffe’s Model Zoo中的GoogLeNet模型相当。我们使用Darknet框架进行所有的训练和推理。
然后我们转换模型进行检测。Ren等人表明,将卷积层和全连接层添加到预训练的网络可以提高性能[29]。按照他们的例子,我们添加了四个卷积层和两个全连接层,它们具有随机初始化的权重。检测通常需要细粒度的视觉信息,因此我们将网络的输入分辨率从224 × 224提高到448 × 448。
我们的最后一层预测类概率和边界框坐标。我们通过图像宽度和高度标准化边界框的宽度和高度,使它们在0和1之间。我们将边界框x和y坐标参数化为特定网格单元位置的偏移量,因此它们也在0和1之间。
我们对最后一层使用线性激活函数,所有其他层使用以下leaky矫正线性激活:
我们针对输出中的平方和误差对我们的模型进行优化。我们使用平方和误差是因为它易于优化,但是它并不完全符合我们最大化平均精度的目标。它将定位误差与可能不理想的分类误差同等加权。此外,在每个图像中,许多网格单元不包含任何目标。这将这些单元格的“置信度”分数推向零,通常会超过包含对象的单元格的梯度。这可能导致模型不稳定,导致训练早期出现分歧。
为了弥补这一点,我们增加了边界框坐标预测的损失,并减少了不包含目标的框的置信预测的损失。我们使用两个参数λcoord和λnoobj来实现这一点。我们设置λcoord = 5,λnoobj = 5。
平方和误差同样加权大盒子和小盒子中的误差。我们的误差度量应该反映大盒子里的小偏差小于小盒子。为了部分解决这个问题,我们预测边界框宽度和高度的平方根,而不是直接预测宽度和高度。
YOLO预测每个网格单元有多个边界框。在训练时,我们只想要一个负责每个目标的边界框预测器。我们指定一个预测器来“负责”预测一个对象,基于哪个预测具有与真实目标最大的当前IOU。这导致边界框预测器之间的专门化。每个预测器在预测特定大小、长宽比或目标类别方面都变得更好,从而提高整体召回率。
在训练期间,我们优化以下多部分损失函数:
其中 表示对象是否出现在单元i中, 指出单元格i中的第j个边界框预测器对该预测“负责”。
请注意,损失函数仅在对象出现在网格单元中时惩罚分类错误(因此前面讨论的条件分类概率)。如果预测器对真实框“负责”(即,在该网格单元中具有任何预测器中最高的IOU),它也仅惩罚边界框坐标误差。
我们针对PASCAL VOC 2007年和2012年的训练和验证数据集对网络进行了大约135个周期的训练。在PASCAL VOC 2012上进行测试时,我们还将PASCAL VOC 2007测试数据加入训练。在整个训练过程中,我们使用64个批次,动量为0.9,衰减为0.0005。
我们的学习率计划如下:在第一个时期,我们慢慢地将学习率从0.001提高到0.01。如果我们以高的学习率开始,我们的模型经常会因为不稳定的梯度而偏离。我们继续以0.01的学习率训练75个周期,然后以0.001的学习率训练30个周期,最后以0.0001的学习率训练30个周期。
为了避免过度拟合,我们使用dropout和广泛的数据扩充。在第一个连接层之间的速率为0.5的dropout层,防止了层之间的适应。对于数据扩充,我们引入了随机缩放和最多原始图像大小20%的转换。我们还将在HSV颜色空间中将图像的曝光和饱和度随机调整至1.5倍。
就像训练一样,对于一张测试图片的预测检测仅需要进行网络评估。在PASCAL VOC上,网络可预测每个图像98个边界框,并预测每个框的类概率。与基于分类器的方法不同,YOLO仅需进行一次网络评估,因此测试时间非常快。
网格设计在边界框预测中强制执行空间分集。通常,很明显,一个对象属于哪个网格单元,并且网络仅为每个对象预测一个框。
但是,一些大目标或多个单元格边界附近的对象可以被多个单元格很好地定位。非最大抑制可用于修复这些多次检测。尽管对于R-CNN或DPM而言,性能并不是很关键,但非最大抑制会在mAP中增加23%。
YOLO在边界框预测上施加了强大的空间约束,因为每个网格单元只能预测两个框并且只能具有一个类。这种空间限制限制了我们的模型可以预测的附近物体的数量。我们的模型与成组出现的小目标(例如成群的鸟)作斗争。由于我们的模型学会了根据数据预测边界框,因此很难将其推广到具有新的或不同的长宽比或配置的对象。我们的模型还使用相对粗略的特征来预测边界框,因为我们的体系结构具有来自输入图像的多个下采样层。最后,虽然我们训练的是近似检测性能的损失函数,但损失函数在小边界框与大边界框中对待错误的方式相同。大边框中的小错误通常是良性的,但小边框中的小错误对IOU的影响更大。错误的主要来源是错误的定位。
对象检测是计算机视觉中的核心问题。检测管线通常从输入图像中提取一组鲁棒特征开始(Haar ,SIFT ,HOG,卷积特征)。然后,使用分类器或定位器识别特征空间中的对象。这些分类器或定位器以滑动窗口的方式在整个图像上或图像的某些区域子集上运行。我们将YOLO检测系统与几个顶级检测框架进行了比较,突出了关键的异同。
**变形零件模型:**可变形零件模型(DPM)使用滑动窗口方法进行对象检测。DPM使用不相交的管道来提取静态特征,对区域进行分类,预测高分区域的边界框等。我们的系统用单个卷积神经网络替换了所有这些不同的部分。网络同时执行特征提取,边界框预测,非最大抑制和上下文推理。网络代替静态功能,而是使用在线训练功能并针对检测任务对其进行优化。与DPM相比,我们的统一体系结构可导致更快,更准确的模型。
R-CNN: R-CNN及其变体使用区域建议代替滑动窗口来找到图像中的对象。选择性搜索生成潜在的边界框,卷积网络提取特征,SVM对框进行打分,线性模型调整边界框,非最大抑制消除重复的检测。这个复杂的流水线的每个阶段都必须独立地精确调整,并且结果系统非常慢,在测试时间每个图像花费40秒钟以上的时间。
**YOLO与R-CNN有一些相似之处:**每个网格单元都会提出潜在的边界框,并使用卷积特征对这些框进行评分。但是,我们的系统在网格单元建议上施加了空间限制,这有助于减轻对同一对象的多次检测。我们的系统还提出了更少的边界框,每个图像只有98个边界框,而选择性搜索的边界框有大约2000个。最后,我们的系统将这些单独的组件组合为一个共同优化的模型。
其他快速检测器: Fast R-CNN 和 Faster R-CNN 专注于通过共享计算和使用神经网络而非选择搜索来提议区域来加快R-CNN框架。尽管它们在R-CNN上提供了速度和准确性方面的改进,但两者仍不足以实现实时性能。
许多研究工作集中在加速DPM管道。它们加快了HOG计算,使用级联并将计算推入GPU的速度。但是,实际上实时运行的只有30Hz DPM。
YOLO并没有尝试优化大型检测管道的各个组件,而是完全淘汰了该管道,并且设计合理。
像面孔或人这样的单一类别的检测器可以进行高度优化,因为它们必须处理更少的变化。YOLO是一种通用检测器,可学会同时检测各种物体。
深度MultiBox: 与R-CNN不同,Szegedy等人训练卷积神经网络来预测感兴趣区域,而不是使用选择性搜索。MultiBox还可以通过用单个类别预测替换置信度预测来执行单个对象检测。但是,MultiBox无法执行常规的对象检测,并且仍然只是较大检测管道中的一部分,需要进一步的图像补丁分类。YOLO和MultiBox都使用卷积网络来预测图像中的边界框,但是YOLO是一个完整的检测系统。
OverFeat: Sermanet等训练一个卷积神经网络来执行定位,并使该定位器执行检测。OverFeat有效地执行滑动窗口检测,但它仍然是不相交的系统。OverFeat针对定位而不是检测性能进行优化。像DPM一样,定位程序只能在进行预测时看到定位信息。OverFeat无法推理全局上下文,因此需要进行大量后期处理才能产生连贯的检测结果。
MultiGrasp: 我们的工作在设计上类似于Redmon等人的抓握检测工作。我们用于边界框预测的网格方法基于Multigrasp系统,用于回归分析。但是,抓握检测比对象检测要简单得多。MultiGrasp只需要为包含一个对象的图像预测单个可抓握区域。不必估计物体的大小,位置或边界或预测其类别,仅需找到适合抓握的区域即可。YOLO预测图像中多个类别的多个对象的边界框和类别概率。
首先,我们将YOLO与PASCAL VOC 2007上的其他实时检测系统进行比较。为了了解YOLO和R-CNN变体之间的区别,我们探索了YOLO和Fast R-CNN(R-CNN的最高性能版本之一)在VOC 2007上的错误。基于不同的错误配置文件,我们证明了YOLO可用于对Fast R-CNN检测进行评分,并减少背景假阳性引起的错误,从而显着提高性能。我们还将介绍VOC 2012的结果,并将其mAP与当前的最新方法进行比较。最后,我们证明了YOLO在两个艺术品数据集上比其他检测器能更好地推广到新领域。
许多目标检测方面的研究工作都集中在快速建立标准检测管线上。但是,只有Sadeghi等人实际上产生了一个实时运行的检测系统(每秒30帧或更高)。我们将YOLO与他们以30Hz或100Hz运行的DPM的GPU实现进行了比较。尽管其他工作尚未达到实时里程碑,但我们还比较了它们的相对mAP和速度,以检查目标检测系统中可用的精度-性能折衷。
Fast YOLO 是 PASCAL 上最快的目标检测方法; 据我们所知,它是现存最快的物体检测器。凭借52.7%的mAP,它的准确度是以前实时检测工作的两倍以上。YOLO将mAP提升至63.4%,同时仍保持实时性能。
我们还使用VGG-16训练YOLO。该模型比YOLO更准确,但速度也要慢得多。与其他依赖VGG-16的检测系统相比,它很有用,但是由于它比实时检测慢,因此本文的其余部分将重点放在我们更快的模型上。
Fastest DPM 可以在不牺牲很多mAP的情况下有效地加快DPM的速度,但是它仍将实时性能降低了2倍。与神经网络方法相比,它还受到DPM检测精度相对较低的限制。
R-CNN减R用静态边界框建议替换“选择性搜索” 。尽管它比R-CNN快得多,但它仍然缺乏实时性,并且由于没有好的建议而对准确性造成重大影响。
Fast R-CNN 可以加快 R-CNN 的分类速度,但是它仍然依赖于选择性搜索,每个图像可能需要2秒钟左右的时间来生成边界框建议。因此,它具有较高的mAP,但在0.5 fps 时仍离实时性还很远。
最近的Faster R-CNN用神经网络取代了选择性搜索,以提出边界框,类似于Szegedy等人的方法。在我们的测试中,他们最准确的模型达到了 7 fps,而较小的,精度较低的模型则以18 fps运行。Faster R-CNN的VGG-16版本高出10 mAP,但比YOLO慢6倍。ZeilerFergus Faster R-CNN仅比YOLO慢2.5倍,但准确性也较低。
表1:PASCAL VOC 2007上的实时系统。比较快速检测器的性能和速度。Fast YOLO是有记录的 PASCAL VOC 检测器中最快的检测器,但其准确度仍是任何其他实时检测器的两倍。YOLO比快速版本的精度高10 mAP,但仍远远高于实时速度。
为了进一步检查YOLO和最新检测器之间的差异,我们查看了VOC 2007的详细结果细节。我们将YOLO与Fast RCNN进行了比较,因为Fast R-CNN是在PASCAL上性能最高的检测器之一 ,并且其检测器是公开可用的。
我们使用Hoiem等人的方法论和工具。对于测试时间的每个类别,我们查看该类别的前N个预测。每个预测都是正确的,或者是根据错误的类型进行分类的:
•正确:正确的类且IOU> 0.5
•定位:正确的类,0.1
•其他:类错误,IOU> 0.1
•背景:任何对象的IOU <0.1
图4显示了所有20个类的平均每种错误类型的细节:
图4:错误分析:Fast R-CNN与YOLO的对比
这些图表显示了在不同类别的前N个检测中定位和背景错误的百分比(该类别中的N个对象)。
YOLO努力正确地定位目标。定位错误占YOLO错误的比例比所有其他来源的总和还多。Fast R-CNN产生的定位错误少得多,但是背景错误却多得多。最高检测到的13.6%是不包含任何对象的误报。Fast R-CNN预测背景检测的可能性几乎是YOLO的3倍。
使用YOLO所产生的背景错误要比Fast R-CNN少得多。通过使用YOLO消除Fast R-CNN的背景检测,我们可以显着提高性能。对于R-CNN预测的每个边界框,我们都会检查YOLO是否预测了类似的框。如果是这样,我们将根据YOLO预测的概率和两个框之间的重叠来对该预测进行增强。
最佳的Fast R-CNN模型在VOC 2007测试集上的mAP达到了71.8%。与YOLO结合使用时,它的mAP增长3.2%,达到75.0%。我们还尝试将顶级Fast R-CNN模型与Fast R-CNN的其他几个版本结合使用。这些结合的mAP在0.3到0.6%之间有小幅增加,有关详细信息,请参见表2。
表2:在VOC 2007上进行的模型组合实验。我们研究了将各种模型与Fast R-CNN的最佳版本进行组合的效果。其他版本的Fast R-CNN仅带来很小的好处,而YOLO可以显着提升性能。
YOLO的推动不只是模型集成的副产品,因为组合不同版本的Fast R-CNN几乎没有好处。恰恰是因为YOLO在测试时犯了各种错误,所以它在提高Fast R-CNN的性能方面是如此有效。不幸的是,这种组合无法从YOLO的速度中受益,因为我们分别运行每个模型然后组合结果。但是,由于YOLO如此之快,与Fast R-CNN相比,它不会增加任何可观的计算时间。
在VOC 2012测试集上,YOLO的mAP得分为57.9%。这比当前的技术水平要低,更接近于使用VGG 16的原始R-CNN,请参见表3。与最接近的竞争对手相比,我们的系统在处理小物体时遇到困难。在瓶子、绵羊和电视、显示器等类别上,YOLO的得分比R-CNN或Feature Edit低8-10%。但是,在其他类别(如猫和火车)上,YOLO可获得更高的性能。
我们的Fast R-CNN + YOLO组合模型是性能最高的检测方法之一。与YOLO的组合使Fast R-CNN获得2.3%的提升,使其在公共排行榜上的排名上升了5位。
表3:P ASCAL VOC 2012排行榜。
截至2015年11月6日,YOLO与完整的comp4(允许外部数据)公共排行榜进行了比较。显示了各种检测方法的平均精度和每类平均精度。YOLO是唯一的实时检测器。Fast R-CNN + YOLO是得分最高的方法,比Fast R-CNN高2.3%。
用于目标检测的学术数据集从同一分布中提取训练和测试数据。在实际应用中,很难预测所有可能的用例,并且测试数据可能与系统之前看到的有所不同。我们将YOLO与Picasso数据集和People-Art数据集上的其他检测系统进行比较,这两个数据集用于测试艺术品上的人物检测。
图5显示了YOLO和其他检测方法之间的比较性能。作为参考,我们为仅在VOC 2007数据上训练所有模型的人员提供了VOC 2007检测AP。对于Picasso数据集,模型在VOC 2012上进行训练,而对于People-Art数据集,模型在VOC 2010上进行训练。
图5:Picasso和People-Art数据集的一般化结果。
图(b)关于VOC 2007, Picasso和People-Art数据集的定量结果。Picasso数据集同时评估AP和最佳F1分数。
R-CNN在VOC 2007上具有较高的AP。但是,R-CNN在应用于艺术品时会大幅下降。R-CNN将选择性搜索用于边界框建议,该建议针对自然图像进行了调整。R-CNN中的分类器步骤只能看到很小的区域,并且需要好的建议。
当DPM应用于艺术作品时,可以很好地保持其AP。先前的工作理论认为DPM表现良好,因为它具有强大的对象形状和布局空间模型。尽管DPM的降级程度不如R-CNN,但它是从较低的AP开始的。
YOLO在VOC 2007上具有良好的性能,并且在应用于艺术品时,其AP的降级比其他方法要少。与DPM一样,YOLO对目标的大小和形状以及目标之间的关系以及目标通常出现的位置进行建模。艺术作品和自然图像在像素级别上有很大不同,但是在对象的大小和形状方面相似,因此YOLO仍可以预测良好的边界框和检测。
YOLO是一种快速,准确的物体检测器,非常适合计算机视觉应用。我们将YOLO连接到网络摄像头,并验证其保持实时性能,包括从相机中获取图像并显示检测结果的时间。
最终的系统是交互式的并且引人入胜。YOLO单独处理图像时,将其附加到网络摄像头后,其功能类似于跟踪系统,可以检测到物体移动和外观变化。该系统的演示和源代码可以在我们的项目网站上找到:http://pjreddie.com/yolo/。
图6:定性结果。YOLO运行样本作品和来自互联网的自然图像。尽管它确实认为一个人是一架飞机,但大多数情况下都是准确的。
我们介绍了YOLO,这是一个用于物体检测的统一模型。我们的模型易于构建且可以直接在完整图像上训练。
与基于分类器的方法不同,YOLO在直接与检测性能相对应的损失函数上进行训练,并且整个模型都在一起进行训练。
Fast YOLO是文献中最快的通用目标检测器,YOLO推动了实时目标检测的最新发展。YOLO还很好地推广到了新领域,使其成为依赖快速、强大的目标检测的应用程序的理想选择。