丰富的线上&线下活动,深入探索云世界
做任务,得社区积分和周边
最真实的开发者用云体验
让每位学生受益于普惠算力
让创作激发创新
资深技术专家手把手带教
遇见技术追梦人
技术交流,直击现场
海量开发者使用工具、手册,免费下载
极速、全面、稳定、安全的开源镜像
开发手册、白皮书、案例集等实战精华
为开发者定制的Chrome浏览器插件
YOLO框架(YouOnlyLookOnce)与RCNN系列算法不一样,是以不同的方式处理对象检测。它将整个图像放在一个实例中,并预测这些框的边界框坐标和及所属类别概率。使用YOLO算法最大优的点是速度极快,每秒可处理45帧,也能够理解一般的对象表示。
在本节中,将介绍YOLO用于检测给定图像中的对象的处理步骤。
整个过程是不是很清晰,下面逐一详细介绍。首先需要将标记数据传递给模型以进行训练。假设已将图像划分为大小为3X3的网格,且总共只有3个类别,分别是行人(c1)、汽车(c2)和摩托车(c3)。因此,对于每个单元格,标签y将是一个八维向量:
假设从上面的例子中选择第一个网格:
如前所述,bx、by、bh和bw是相对于正在处理的网格单元计算而言的。下面通过一个例子来说明这一点。以包含汽车的右边网格为例:
这里有一些思考的问题——如何判断预测的边界框是否是一个好结果(或一个坏结果)?单元格之间的交叉点,计算实际边界框和预测的边界框的并集交集。假设汽车的实际和预测边界框如下所示:
如果IoU大于0.5,就可以说预测足够好。0.5是在这里采取的任意阈值,也可以根据具体问题进行更改。阈值越大,预测就越准确。还有一种技术可以显着提高YOLO的效果——非极大值抑制。对象检测算法最常见的问题之一是,它不是一次仅检测出一次对象,而可能获得多次检测结果。假设:
以上就是非极大值抑制的全部内容,总结一下关于非极大值抑制算法的要点:
在上述内容中,每个网格只能识别一个对象。但是如果单个网格中有多个对象呢?这就行需要了解AnchorBoxes的概念。假设将下图按照3X3网格划分:
在本节中,首先介绍如何训练YOLO模型,然后是新的图像进行预测。
训练模型时,输入数据是由图像及其相应的y标签构成。样例如下:
对于每个网格,模型将预测·3X3X16·大小的输出。该预测中的16个值将与训练标签的格式相同。前8个值将对应于AnchorBoxes1,其中第一个值将是该网络中对象的概率,2-5的值将是该对象的边界框坐标,最后三个值表明对象属于哪个类。以此类推。最后,非极大值抑制方法将应用于预测框以获得每个对象的单个预测结果。以下是YOLO算法遵循的确切维度和步骤:
本节中用于实现YOLO的代码来自AndrewNG的[GitHub存储库],需要下载此[zip文件],其中包含运行此代码所需的预训练权重。首先定义一些函数,这些函数将用来选择高于某个阈值的边界框,并对其应用非极大值抑制。首先,导入所需的库:
importosimportmatplotlib.pyplotaspltfrommatplotlib.pyplotimportimshowimportscipy.ioimportscipy.miscimportnumpyasnpimportpandasaspdimportPILimporttensorflowastffromskimage.transformimportresizefromkerasimportbackendasKfromkeras.layersimportInput,Lambda,Conv2Dfromkeras.modelsimportload_model,Modelfromyolo_utilsimportread_classes,read_anchors,generate_colors,preprocess_image,draw_boxes,scale_boxesfromyad2k.models.keras_yoloimportyolo_head,yolo_boxes_to_corners,preprocess_true_boxes,yolo_loss,yolo_body%matplotlibinline然后,实现基于概率和阈值过滤边界框的函数:
defyolo_filter_boxes(box_confidence,boxes,box_class_probs,threshold=.6):box_scores=box_confidence*box_class_probsbox_classes=K.argmax(box_scores,-1)box_class_scores=K.max(box_scores,-1)filtering_mask=box_class_scores>thresholdscores=tf.boolean_mask(box_class_scores,filtering_mask)boxes=tf.boolean_mask(boxes,filtering_mask)classes=tf.boolean_mask(box_classes,filtering_mask)returnscores,boxes,classes之后,实现计算IoU的函数:
defiou(box1,box2):xi1=max(box1[0],box2[0])yi1=max(box1[1],box2[1])xi2=min(box1[2],box2[2])yi2=min(box1[3],box2[3])inter_area=(yi2-yi1)*(xi2-xi1)box1_area=(box1[3]-box1[1])*(box1[2]-box1[0])box2_area=(box2[3]-box2[1])*(box2[2]-box2[0])union_area=box1_area+box2_area-inter_areaiou=inter_area/union_areareturniou然后,实现非极大值抑制的函数:
defyolo_non_max_suppression(scores,boxes,classes,max_boxes=10,iou_threshold=0.5):max_boxes_tensor=K.variable(max_boxes,dtype='int32')K.get_session().run(tf.variables_initializer([max_boxes_tensor]))nms_indices=tf.image.non_max_suppression(boxes,scores,max_boxes,iou_threshold)scores=K.gather(scores,nms_indices)boxes=K.gather(boxes,nms_indices)classes=K.gather(classes,nms_indices)returnscores,boxes,classes随机初始化下大小为(19,19,5,85)的输出向量:
yolo_outputs=(tf.random_normal([19,19,5,1],mean=1,stddev=4,seed=1),tf.random_normal([19,19,5,2],mean=1,stddev=4,seed=1),tf.random_normal([19,19,5,2],mean=1,stddev=4,seed=1),tf.random_normal([19,19,5,80],mean=1,stddev=4,seed=1))最后,实现一个将CNN的输出作为输入并返回被抑制的边界框的函数:
defyolo_eval(yolo_outputs,image_shape=(720.,1280.),max_boxes=10,score_threshold=.6,iou_threshold=.5):box_confidence,box_xy,box_wh,box_class_probs=yolo_outputsboxes=yolo_boxes_to_corners(box_xy,box_wh)scores,boxes,classes=yolo_filter_boxes(box_confidence,boxes,box_class_probs,threshold=score_threshold)boxes=scale_boxes(boxes,image_shape)scores,boxes,classes=yolo_non_max_suppression(scores,boxes,classes,max_boxes,iou_threshold)returnscores,boxes,classes使用yolo_eval函数对之前创建的随机输出向量进行预测:
scores,boxes,classes=yolo_eval(yolo_outputs)withtf.Session()astest_b:print("scores[2]="+str(scores[2].eval()))print("boxes[2]="+str(boxes[2].eval()))print("classes[2]="+str(classes[2].eval()))
sess=K.get_session()class_names=read_classes("model_data/coco_classes.txt")anchors=read_anchors("model_data/yolo_anchors.txt")yolo_model=load_model("model_data/yolo.h5")在加载类别信息和预训练模型之后,使用上面定义的函数来获取·yolo_outputs·。
yolo_outputs=yolo_head(yolo_model.output,anchors,len(class_names))之后,定义一个函数来预测边界框并在图像上标记边界框:
defpredict(sess,image_file):image,image_data=preprocess_image("images/"+image_file,model_image_size=(608,608))out_scores,out_boxes,out_classes=sess.run([scores,boxes,classes],feed_dict={yolo_model.input:image_data,K.learning_phase():0})print('Found{}boxesfor{}'.format(len(out_boxes),image_file))#Generatecolorsfordrawingboundingboxes.colors=generate_colors(class_names)#Drawboundingboxesontheimagefiledraw_boxes(image,out_scores,out_boxes,out_classes,class_names,colors)#Savethepredictedboundingboxontheimageimage.save(os.path.join("out",image_file),quality=90)#Displaytheresultsinthenotebookoutput_image=scipy.misc.imread(os.path.join("out",image_file))plt.figure(figsize=(12,12))imshow(output_image)returnout_scores,out_boxes,out_classes接下来,将使用预测函数读取图像并进行预测:
img=plt.imread('images/img.jpg')image_shape=float(img.shape[0]),float(img.shape[1])scores,boxes,classes=yolo_eval(yolo_outputs,image_shape)最后,输出预测结果:
out_scores,out_boxes,out_classes=predict(sess,"img.jpg")