首页
壁纸
留言板
友链
更多
统计归档
Search
1
TensorBoard:训练日志及网络结构可视化工具
12,596 阅读
2
主板开机跳线接线图【F_PANEL接线图】
7,456 阅读
3
Linux使用V2Ray 原生客户端
6,515 阅读
4
移动光猫获取超级密码&开启公网ipv6
5,470 阅读
5
NVIDIA 显卡限制功率
3,188 阅读
好物分享
实用教程
linux使用
wincmd
学习笔记
mysql
java学习
nginx
综合面试题
大数据
网络知识
linux
放码过来
python
javascript
java
opencv
蓝桥杯
leetcode
深度学习
开源模型
相关知识
数据集和工具
模型轻量化
语音识别
计算机视觉
杂七杂八
硬件科普
主机安全
嵌入式设备
其它
bug处理
登录
/
注册
Search
标签搜索
好物分享
学习笔记
linux
MySQL
nvidia
typero
内网穿透
webdav
vps
java
cudann
gcc
cuda
树莓派
CNN
图像去雾
ssh安全
nps
暗通道先验
阿里云
jupiter
累计撰写
358
篇文章
累计收到
72
条评论
首页
栏目
好物分享
实用教程
linux使用
wincmd
学习笔记
mysql
java学习
nginx
综合面试题
大数据
网络知识
linux
放码过来
python
javascript
java
opencv
蓝桥杯
leetcode
深度学习
开源模型
相关知识
数据集和工具
模型轻量化
语音识别
计算机视觉
杂七杂八
硬件科普
主机安全
嵌入式设备
其它
bug处理
页面
壁纸
留言板
友链
统计归档
搜索到
4
篇与
的结果
2022-04-13
YOLOv1论文复现
一.整理结构概览1.数据格式转换部分2.DataSet,DateLoader部分2.1 主模块2.2 DataSet辅助模块--boxs2yololabel将单个图片中yolo格式的所有box转为yolov1网络模型所需要的label3.YOLOv1网络部分4.YOLOv1损失函数部分二.对每部分逐一进行实现1.数据格式转换部分--VOC2YOLO.py模块封装import xmltodict import os from progressbar import * """ 将单个xml文件中的单个object转换为yolov1格式 """ def get_yolo_data(obj,img_width,img_height): # 获取voc格式的数据信息 name = obj['name'] xmin = float(obj['bndbox']['xmin']) xmax = float(obj['bndbox']['xmax']) ymin = float(obj['bndbox']['ymin']) ymax = float(obj['bndbox']['ymax']) # 计算对应的yolo格式的数据信息,并进行归一化处理 class_idx = class_names.index(name) x_lefttop = xmin / img_width y_lefttop = ymin / img_height box_width = (xmax - xmin) / img_width box_height = (ymax - ymin) / img_height # 组转YOLO格式的数据 yolo_data = "{} {} {} {} {}\n".format(class_idx,x_lefttop,y_lefttop,box_width,box_height) return yolo_data """ 逐一处理xml文件,转换为YOLO所需的格式 + input + voc_xml_dir:VOC数据集的所有xml文件存储的文件夹 + yolo_txt_dir:转化完成后的YOLOv1格式数据的存储文件夹 + class_names:涉及的所有的类别 + output + yolo_txt_dir文件夹下的文件中的对应每张图片的YOLO格式的数据 """ def VOC2YOLOv1(voc_xml_dir,yolo_txt_dir,class_names): #进度条支持 count = 0 #计数器 widgets = ['VOC2YOLO: ',Percentage(), ' ', Bar('#'),' ', Timer(),' ', ETA()] pbar = ProgressBar(widgets=widgets, maxval=len(os.listdir(xml_dir))).start() # 对xml文件进行逐一处理 for xml_file in os.listdir(xml_dir): # 路径组装 xml_file_path = os.path.join(xml_dir,xml_file) txt_file_path = os.path.join(txt_dir,xml_file[:-4]+".txt") yolo_data = "" # 读取xml文件 with open(xml_file_path) as f: xml_str = f.read() # 转为字典 xml_dic = xmltodict.parse(xml_str) # 获取图片的width、height img_width = float(xml_dic["annotation"]["size"]["width"]) img_height = float(xml_dic["annotation"]["size"]["height"]) # 获取xml文件中的所有object objects = xml_dic["annotation"]["object"] # 对所有的object进行逐一处理 if isinstance(objects,list): # xml文件中包含多个object for obj in objects: yolo_data += get_yolo_data(obj,img_width,img_height) else: # xml文件中包含1个object obj = objects yolo_data += get_yolo_data(obj,img_width,img_height) # 将图片对应的yolo格式的数据写入到对应的文件 with open(txt_file_path,'w') as f: f.write(yolo_data) #更新进度 count += 1 pbar.update(count) pbar.finish() # 释放进度条调用测试voc_xml_dir='../VOC2007/Annotations/' #原xml路径 yolo_txt_dir='../VOC2007/labels/' #转换后txt文件存放路径 # 所有待检测的labels class_names = ['aeroplane', 'cat', 'car', 'dog', 'chair', 'person', 'horse', 'bird', 'tvmonitor', 'bus', 'boat', 'diningtable', 'bicycle', 'bottle', 'sofa', 'pottedplant', 'motorbike', 'cow', 'train', 'sheep'] VOC2YOLOv1(voc_xml_dir,yolo_txt_dir,class_names)VOC2YOLO: 100% |##########################| Elapsed Time: 0:01:18 Time: 0:01:182.DataSet,DateLoader部分模块封装from torch.utils.data import Dataset,DataLoader from PIL import Image """ 构建YOLOv1的dataset,用于加载VOC数据集(已对其进行了YOLO格式转换) + input + mode:调用模式,train/val + DATASET_PATH:VOC数据集的根目录,已对其进行了YOLO格式转换 + yolo_input_size:训练和测试所用的图片大小,通常为448 """ class Dataset_VOC(Dataset): def __init__(self,mode = "train",DATASET_PATH = "../VOC2007/",yolo_input_size = 448): self.filenames = [] # 储存数据集的文件名称 # 获取数据集的文件夹列表 if mode == "train": with open(DATASET_PATH + "ImageSets/Main/train.txt", 'r') as f: # 调用包含训练集图像名称的txt文件 self.filenames = [x.strip() for x in f] elif mode =='val': with open(DATASET_PATH + "ImageSets/Main/val.txt", 'r') as f: # 调用包含训练集图像名称的txt文件 self.filenames = [x.strip() for x in f] # 图像文件所在的文件夹 self.img_dir = os.path.join(DATASET_PATH,"JPEGImages") # 图像对应的label文件(.txt文件)的文件夹 self.label_dir = os.path.join(DATASET_PATH,"labels") def boxs2yololabel(self,boxs): """ 将boxs数据转换为训练时方便计算Loss的数据形式(7,7,5*B+cls_num) 单个box数据格式:(cls,x_rela_width,y_rela_height,w_rela_width,h_rela_height) x_rela_width:相对width=1的x的取值 """ gridsize = 1.0/7 # 网格大小 # 初始化result,此处需要根据不同数据集的类别个数进行修改 label = np.zeros((7,7,30)) # 根据box的数据填充label for i in range(len(boxs)//5): # 计算当前box会位于哪个网格 gridx = int(boxs[i*5+1] // gridsize) # 当前bbox中心落在第gridx个网格,列 gridy = int(boxs[i*5+2] // gridsize) # 当前bbox中心落在第gridy个网格,行 # 计算box相对于网格的左上角的点的相对位置 # box中心坐标 - 网格左上角点的坐标)/网格大小 ==> box中心点的相对位置 x_offset = boxs[i*5+1] / gridsize - gridx y_offset = boxs[i*5+2] / gridsize - gridy # 将第gridy行,gridx列的网格设置为负责当前ground truth的预测,置信度和对应类别概率均置为1 label[gridy, gridx, 0:5] = np.array([x_offset, y_offset, boxs[i*5+3], boxs[i*5+4], 1]) label[gridy, gridx, 5:10] = np.array([x_offset, y_offset, boxs[i*5+3], boxs[i*5+4], 1]) label[gridy, gridx, 10+int(boxs[i*5])] = 1 return label def __len__(self): return len(self.filenames) def __getitem__(self, index): # 构建image部分 # 读取图片 img_path = os.path.join(self.img_dir,self.filenames[index]+".jpg") img = cv2.imread(img_path) # 计算padding值将图像padding为正方形 h,w = img.shape[0:2] padw,padh = 0,0 if h>w: padw = (h - w) // 2 img = np.pad(img,((0,0),(padw,padw),(0,0)),'constant',constant_values=0) elif w>h: padh = (w - h) // 2 img = np.pad(img,((padh,padh),(0,0),(0,0)), 'constant', constant_values=0) # 然后resize为yolo网络所需要的尺寸448x448 yolo_input_size = 448 # 输入YOLOv1网络的图像尺寸为448x448 img = cv2.resize(img,(yolo_input_size,yolo_input_size)) # 构建label部分 # 读取图像对应的box信息,按1维的方式储存,每5个元素表示一个bbox的(cls_id,x_lefttop,y_lefttop,w,h) label_path = os.path.join(self.label_dir,self.filenames[index]+".txt") with open(label_path) as f: boxs = f.read().split('\n') boxs = [x.split() for x in boxs] boxs = [float(x) for y in boxs for x in y] # 根据padding、图像增广等操作,将原始的box数据转换为修改后图像的box数据 for i in range(len(boxs)//5): if padw != 0: boxs[i*5+1] = (boxs[i*5+1] * w + padw) / h boxs[i*5+3] = (boxs[i*5+3] * w) / h elif padh != 0: boxs[i*5+2] = (boxs[i*5+2] * h + padh) / w boxs[i*5+4] = (boxs[i*5+4] * h) / w # boxs转为yololabel label = self.boxs2yololabel(boxs) # img,label转为tensor img = transforms.ToTensor()(img) label = transforms.ToTensor()(label) return img,label调用测试train_dataset = Dataset_VOC(mode="train") val_dataset = Dataset_VOC(mode="val") train_dataloader = DataLoader(train_dataset,batch_size=2,shuffle=True) val_dataloader = DataLoader(val_dataset,batch_size=2,shuffle=True) for i,(inputs,labels) in enumerate(train_dataloader): print(inputs.shape,labels.shape) break for i,(inputs,labels) in enumerate(val_dataloader): print(inputs.shape,labels.shape) breaktorch.Size([2, 3, 448, 448]) torch.Size([2, 30, 7, 7]) torch.Size([2, 3, 448, 448]) torch.Size([2, 30, 7, 7])3.YOLOv1网络部分网络结构模块封装import torch import torch.nn as nn class YOLOv1(nn.Module): def __init__(self): super(YOLOv1,self).__init__() self.feature = nn.Sequential( nn.Conv2d(in_channels=3,out_channels=64,kernel_size=7,stride=2,padding=3), nn.LeakyReLU(), nn.MaxPool2d(kernel_size=2,stride=2), nn.Conv2d(in_channels=64,out_channels=192,kernel_size=3,stride=1,padding=1), nn.LeakyReLU(), nn.MaxPool2d(kernel_size=2,stride=2), nn.Conv2d(in_channels=192,out_channels=128,kernel_size=1,stride=1,padding=0), nn.LeakyReLU(), nn.Conv2d(in_channels=128,out_channels=256,kernel_size=3,stride=1,padding=1), nn.LeakyReLU(), nn.Conv2d(in_channels=256,out_channels=256,kernel_size=1,stride=1,padding=0), nn.LeakyReLU(), nn.Conv2d(in_channels=256,out_channels=512,kernel_size=3,stride=1,padding=1), nn.LeakyReLU(), nn.MaxPool2d(kernel_size=2,stride=2), nn.Conv2d(in_channels=512,out_channels=256,kernel_size=1,stride=1,padding=0), nn.LeakyReLU(), nn.Conv2d(in_channels=256,out_channels=512,kernel_size=3,stride=1,padding=1), nn.LeakyReLU(), nn.Conv2d(in_channels=512,out_channels=256,kernel_size=1,stride=1,padding=0), nn.LeakyReLU(), nn.Conv2d(in_channels=256,out_channels=512,kernel_size=3,stride=1,padding=1), nn.LeakyReLU(), nn.Conv2d(in_channels=512,out_channels=256,kernel_size=1,stride=1,padding=0), nn.LeakyReLU(), nn.Conv2d(in_channels=256,out_channels=512,kernel_size=3,stride=1,padding=1), nn.LeakyReLU(), nn.Conv2d(in_channels=512,out_channels=256,kernel_size=1,stride=1,padding=0), nn.LeakyReLU(), nn.Conv2d(in_channels=256,out_channels=512,kernel_size=3,stride=1,padding=1), nn.Conv2d(in_channels=512,out_channels=512,kernel_size=1,stride=1,padding=0), nn.LeakyReLU(), nn.Conv2d(in_channels=512,out_channels=1024,kernel_size=3,stride=1,padding=1), nn.LeakyReLU(), nn.MaxPool2d(kernel_size=2,stride=2), nn.Conv2d(in_channels=1024,out_channels=512,kernel_size=1,stride=1,padding=0), nn.LeakyReLU(), nn.Conv2d(in_channels=512,out_channels=1024,kernel_size=3,stride=1,padding=1), nn.LeakyReLU(), nn.Conv2d(in_channels=1024,out_channels=512,kernel_size=1,stride=1,padding=0), nn.LeakyReLU(), nn.Conv2d(in_channels=512,out_channels=1024,kernel_size=3,stride=1,padding=1), nn.LeakyReLU(), nn.Conv2d(in_channels=1024,out_channels=1024,kernel_size=3,stride=1,padding=1), nn.LeakyReLU(), nn.Conv2d(in_channels=1024,out_channels=1024,kernel_size=3,stride=2,padding=1), nn.LeakyReLU(), nn.Conv2d(in_channels=1024,out_channels=1024,kernel_size=3,stride=1,padding=1), nn.LeakyReLU(), nn.Conv2d(in_channels=1024,out_channels=1024,kernel_size=3,stride=1,padding=1), nn.LeakyReLU(), ) self.classify = nn.Sequential( nn.Flatten(), nn.Linear(1024 * 7 * 7, 4096), nn.Dropout(0.5), nn.Linear(4096, 1470) #1470=7*7*30 ) def forward(self,x): x = self.feature(x) x = self.classify(x) return x调用测试yolov1 = YOLOv1() fake_input = torch.zeros((1,3,448,448)) print(fake_input.shape) output = yolov1(fake_input) print(output.shape)yolov1 = YOLOv1() fake_input = torch.zeros((1,3,448,448)) print(fake_input.shape) output = yolov1(fake_input) print(output.shape)4.YOLOv1损失函数部分损失函数详解模块封装""" + input + pred: (batch_size,30,7,7)的网络输出数据 + labels: (batch_size,30,7,7)的样本标签数据 + output + 当前批次样本的平均损失 """ """ + YOLOv1 的损失分为3部分 + 坐标预测损失 + 置信度预测损失 + 含object的box的confidence预测损失 + 不含object的box的confidence预测损失 + 类别预测损失 """ class YOLOv1_Loss(nn.Module): def __init__(self): super(YOLOv1_Loss,self).__init__() def convert_box_type(self,src_box): """ box格式转换 + input + src_box : [box_x_lefttop,box_y_lefttop,box_w,box_h] + output + dst_box : [box_x1,box_y1,box_x2,box_y2] """ x,y,w,h = tuple(src_box) x1,y1 = x,y x2,y2 = x+w,y+w return [x1,y1,x2,y2] def cal_iou(self,box1,box2): """ iou计算 """ # 求相交区域左上角的坐标和右下角的坐标 box_intersect_x1 = max(box1[0], box2[0]) box_intersect_y1 = max(box1[1], box2[1]) box_intersect_x2 = min(box1[2], box2[2]) box_intersect_y2 = min(box1[3], box2[3]) # 求二者相交的面积 area_intersect = (box_intersect_y2 - box_intersect_y1) * (box_intersect_x2 - box_intersect_x1) # 求box1,box2的面积 area_box1 = (box1[2] - box1[0]) * (box1[3] - box1[1]) area_box2 = (box2[2] - box2[0]) * (box2[3] - box2[1]) # 求二者相并的面积 area_union = area_box1 + area_box2 - area_intersect # 计算iou(交并比) iou = area_intersect / area_union return iou def forward(self,pred,target): batch_size = pred.shape[0] lambda_noobj = 0.5 # lambda_noobj参数 lambda_coord = 5 # lambda_coord参数 site_pred_loss = 0 # 坐标预测损失 obj_confidence_pred_loss = 0 # 含object的box的confidence预测损失 noobj_confidence_pred_loss = 0 #不含object的box的confidence预测损失 class_pred_loss = 0 # 类别预测损失 for batch_size_index in range(batch_size): # batchsize循环 for x_index in range(7): # x方向网格循环 for y_index in range(7): # y方向网格循环 # 获取单个网格的预测数据和真实数据 pred_data = pred[batch_size_index,:,x_index,y_index] # [x,y,w,h,confidence,x,y,w,h,confidence,cls*20] true_data = target[batch_size_index,:,x_index,y_index] #[x,y,w,h,confidence,x,y,w,h,confidence,cls*20] if true_data[4]==1:# 如果包含物体 # 解析预测数据和真实数据 pred_box_confidence_1 = pred_data[0:5] # [x,y,w,h,confidence1] pred_box_confidence_2 = pred_data[5:10] # [x,y,w,h,confidence2] true_box_confidence = true_data[0:5] # [x,y,w,h,confidence] # 获取两个预测box并计算与真实box的iou iou1 = self.cal_iou(self.convert_box_type(pred_box_confidence_1[0:4]),self.convert_box_type(true_box_confidence[0:4])) iou2 = self.cal_iou(self.convert_box_type(pred_box_confidence_2[0:4]),self.convert_box_type(true_box_confidence[0:4])) # 在两个box中选择iou大的box负责预测物体 if iou1 >= iou2: better_box_confidence,bad_box_confidence = pred_box_confidence_1,pred_box_confidence_2 better_iou,bad_iou = iou1,iou2 else: better_box_confidence,bad_box_confidence = pred_box_confidence_2,pred_box_confidence_1 better_iou,bad_iou = iou2,iou1 # 计算坐标预测损失 site_pred_loss += lambda_coord * torch.sum((better_box_confidence[0:2]- true_box_confidence[0:2])**2) # x,y的预测损失 site_pred_loss += lambda_coord * torch.sum((better_box_confidence[2:4].sqrt()-true_box_confidence[2:4].sqrt())**2) # w,h的预测损失 # 计算含object的box的confidence预测损失 obj_confidence_pred_loss += (better_box_confidence[4] - better_iou)**2 # iou比较小的bbox不负责预测物体,因此confidence loss算在noobj中 # 因此还需计算不含object的box的confidence预测损失 noobj_confidence_pred_loss += lambda_noobj * (bad_box_confidence[4] - bad_iou)**2 # 计算类别损失 class_pred_loss += torch.sum((pred_data[10:] - true_data[10:])**2) else: # 如果不包含物体,则只有置信度损失--noobj_confidence_pred_loss # [4,9]代表取两个预测框的confidence noobj_confidence_pred_loss += lambda_noobj * torch.sum(pred[batch_size_index,(4,9),x_index,y_index]**2) loss = site_pred_loss + obj_confidence_pred_loss + noobj_confidence_pred_loss + class_pred_loss return loss/batch_size调用测试loss = YOLOv1_Loss() label1 = torch.zeros([1,30,7,7]) label2 = torch.zeros([1,30,7,7]) print(label1.shape,label2.shape) print(loss(label1,label2)) loss = YOLOv1_Loss() label1 = torch.randn([8,30,7,7]) label2 = torch.randn([8,30,7,7]) print(label1.shape,label2.shape) print(loss(label1,label2))torch.Size([1, 30, 7, 7]) torch.Size([1, 30, 7, 7]) tensor(0.) torch.Size([8, 30, 7, 7]) torch.Size([8, 30, 7, 7]) tensor(46.7713)三.整体封装测试#TODO参考资料【YOLOv1论文翻译】:YOLO: 一体化的,实时的物体检测YOLOv1学习:(一)网络结构推导与实现YOLOv1学习:(二)损失函数理解和实现
2022年04月13日
791 阅读
0 评论
0 点赞
2021-02-03
【YOLOv1论文翻译】:YOLO: 一体化的,实时的物体检测
【YOLOv1论文翻译】:YOLO: 一体化的,实时的物体检测论文原文:You Only Look Once Unified, Real-Time Object Detection摘要 我们介绍一种新的物体检测方法YOLO。与先前的物体检测方法是重新设置分类器来执行检测不同,我们将物体检测方法看做一个回归问题,去预测空间分离的边界框和相关类别概率。单个神经网络从整个图片中一次性预测边界框和类别概率。由于整个检测流程是一个单一网络,所以可以进行端到端的直接对检测性能进行优化。 我们的这种单一网络结构体系速度非常快。我们的基本YOLO模型实时处理图像速度为每秒45帧。较小的YOLO模型版本,Fast YOLO可以实现每秒155帧的实时检测速度,同时实现mAP是其他物体检测网络的两倍左右。与当前最先进的物体检测方法相比,YOLO会出现较多的定位误差,但是从背景中检测出假阳性目标较少。最后,YOLO可以学习物体非常抽象的特征,所以在自然图像之外的其他检测领域比如艺术品的检测中,YOLO优于包括DPM和R-CNN在内的其他检测方法。1.介绍 人们只需瞥一眼图片就知道图片中有什么物体,物体的位置及它们之间的联系。人类的视觉系统是快速而准确的,使我们可以做很复杂的事,比如开车时不用刻意去思考。快速,准确的物体检测算法将允许计算机在没有专用传感器的情况下驾驶汽车,使辅助设备能够向人类用户传达实时场景信息,并释放通用,响应式机器人系统的潜力。 当前的检测系统重新利用分类器来执行检测。 为了检测物体,这些系统为该物体提供一个分类器,并在不同的位置评估它,并在测试图像中进行缩放。 像可变形零件模型(DPM)这样的系统使用滑动窗口方法,其中分类器在整个图像上以均匀间隔的位置运行[10]。 最近的方法比如R-CNN使用候选区域的方法,首先在图像中生成候选框,然后在候选框上运行分类器。分类之后,后续的操作是优化边界框、消除重复检测,最后根据图像中其他物体来重新定位边界框。这些复杂的流程很慢而且优化困难,因为每个组件都需要单独训练。 我们将物体检测系统,输入图像像素输出边界框坐标和类概率,重新设计为一个回归问题。使用我们的系统,只需运行一次就可以知道图像中有什么物体以及物体的位置。 YOLO非常简单:参考图片1,单个神经网络可以同时预测多个边界框和类概率 ,YOLO直接在整个图像上训练,并直接优化检测性能。这个统一的模型比传统的物体检测方法有几个优势。 第一,YOLO速度非常快。由于我们的检测是当做一个回归问题,不需要很复杂的流程。在测试的时候我们只需将一个新的图片输入网络来检测物体。在Titan X GPU上我们的基本网络检测速度可以实现45帧每秒,快速版本检测速度可以达到155帧每秒。这意味着我们可以以小于25毫秒的延迟处理流媒体视频。此外YOLO相比其他实时检测系统可以达到两倍的mAP,请参阅我们的项目网页http://pjreddie.com/yolo/.,上面有我们项目在网络摄像头上的实时运行演示。 第二,YOLO在预测时可以整体的检测图像。与基于滑动窗口和候选区域的方法不同,在训练和测试期间YOLO可以看到整个图像,所以它隐式的编码相关类的上下文信息及外观。Fast R-CNN是一种顶级的检测方法,由于它无法看到更大的上下文信息所以会从背景中检测出错误的物体,YOLO出现背景误差的概率是Fast R-CNN的一半。 第三,YOLO学习图像的抽象特征。当在自然图像上进行训练,并在艺术品上测试时,YOLO的效果大幅优于DPM和R-CNN等顶级检测方法。由于YOLO是高度抽象化的,所以在应用到新的领域或者有意外输入时不太会出现故障。 YOLO 在检测准确率上仍然大幅落后于最好的检测方法。虽然YOLO可以很快的识别出图像中的物体,但是在精准定位物体尤其是较小的物体位置上还需要更多的努力。我们在实验中正进一步测试如何平衡这些方面。 我们所有的训练和测试代码都是开源的,还提供一些预训练的模型可供下载。2.统一检测 我们将物体检测的单独组件集成到一个神经网络中。我们的网络使用整个图像的特征来预测每个边界框,网络还同时预测所有类的所有边界框,这也就意味着我们的网络全面的预测整个图像和图像中的所有的类。YOLO网络的设计保证能够实现端到端的训练和实时检测的速度,同时实现较高的检测平均精度。 我们的系统将输入图像划分成S × S个网格。如果一个物体的中心点在某个网格中,则这个网格负责检测这个物体。每个网格单元预测B个边界框以及每个边界框的confidence(置信度)。这些confidence反映了网络模型对该边界框是否含有物体的信心,以及边界框位置预测的准确度。 在形式上我们将confidence定义为 C = Pr(Object) ∗ IOU truth pred( Pr(Object)网格存在物体为1,不存在为0),如果网格中不包含物体则Pr(Object) = 0则confidence为0,包含物体Pr(Object) = 1则confidence等于预测边界框和真实边界框的IOU(交并比)。 每个边界框有5个预测值:x,y,w,h,confidence,(x,y)代表预测边界框的中心点坐标,w,h是边界框的宽度和高度,confidence是预测边界框和真实边界框的IOU。 每个网格预测C个条件类别概率, Pr(Class i |Object),这是网格中含有物体的条件下属于某个类别的概率,每个网格只预测一组条件类别概率,B个边界框公用。 测试时我们将条件类概率和confidence相乘,为我们提供了每个边界框在各个类别的得分值 ,这些得分值代表该类别物体出现在框中的概率和边界框与物体的拟合程度。 在PASCAL VOC数据集上评估YOLO,S = 7,B = 2,C = 20(因为PASCAL VOC数据集中有20个标记类) ,我们的最终预测结果是7 × 7 × 30张量。2.1设计 我们将模型以卷积神经网络来实现,在PASCAL VOC数据集上评估。网络的初始卷积层用来提取图像特征,全连接层用来预测类别概率和坐标。 我们的网络结构受到图像分类网络GoogLeNet[34]的启发,我们的网络包括24层卷积层和2层全连接层,不同于GoogLeNet使用的Inception块,我们使用和Lin等人【22】一样的结构,一个1×1卷积层后面跟一个3×3卷积层。完整的网络结构可以查看图片3。 为了加快检测速度我们还训练了一个快速的YOLO版本。Fast YOLO 使用较少的卷积层,9层而不是普通版的24层,和更小的卷积核。除了网络较小,Fast YOLO和YOLO训练和测试参数是一样的。我们的网络最终输出是7 × 7 × 30的预测张量。2.2训练 我们在ImageNet 1000类数据集上预训练我们的卷积层。预训练时我们使用图3中的前20为向量、一个平均池化层、一个全连接层。我们训练这个网络一周时间, 在ImageNet 2012数据集中获得了88%准确率排名位于前5名,与 Caffe上训练的模型中的GoogLeNet模型相当。我们使用 Darknet框架进行所有的训练和预测。 然后我们转化网络执行检测。Ren等人提出在预训练模型中加入卷积层和全连接层可以提高性能[29]。根据他们的想法,我们添加了随机初始化参数的4个卷积层和2个全连接层。检测任务需要细粒度的视觉信息,所以我们将网络输入的分辨率从224×224增加到448×448。 我们在最后一层输出类别概率和边界框坐标。我们通过图像的宽度和高度来标准化边界框的宽度和高度至0到1之间,我们将边界框x和y坐标参数化为相对特定网格的偏移量,使其值处于0到1之间。我们对最后一层使用线性激活函数,其他层使用以下激活函数。 我们使用平方和误差来优化模型。使用平方和误差较容易优化,但是不能完全符合我们最大化平均精度的目标。它将定位误差和分类误差同等对待是不太合理的,而且在图像中有很多网格不包含任何物体,将这些网格的置信度趋向于零时的梯度将会超过含有物体的网格的梯度,这会导致网络不稳定,从而使网络在训练初期就出现梯度爆炸。 为了弥补这一点,我们增加了边界框坐标预测损失的权重,并减少了不包含物体的边界框的置信度预测损失的权重。我们使用两个参数λcoord和λnoobj来完成这个。我们设置λcoord = 5和λnoobj =0 .5。 平方和误差计算损失时将大框和小框同等对待,同样的一个损失值对大框的影响小于对小框的影响。为了解决这个问题,我们计算损失时先对框的宽度和高度求根号再计算平方和。 YOLO为每个网格预测多个边界框。在训练时我们希望每个物体只有一个边界框负责检测这个物体。我们选择和真实物体位置IOU最大的边界框作为负责检测这个物体的边界框。这使得我们的边界框预测变量都负责预测特定物体。所以每个预测变量可以更好地预测边界框尺寸,纵横比或物体类别,从而改善整体召回率。 训练期间我们优化下图中的损失函数: 其中的$1^{obj}_{ij}$代表的是第i个网格中是否含有物体,以及第i个网格中的第j个边界框负责预测这个物体。 请注意,如果网格中含有物体,损失函数只需考虑分类损失(因此条件类概率在前面讲)。如果这个预测器负责预测真实边界框(和网格中的所有预测器都有最高的IOU),损失函数只考虑预测坐标损失。 我们在PASCAL VOC 2007和2012的训练和验证数据集上对网络进行了大约135个epochs的训练。当在VOC 2012上测试的时候,我们也包含了VOC 2007的测试数据用来训练。训练中我们的batch size为64,momentum为0.9,decay为0.0005。 我们的learning rate(学习率)计划如下:在第一个epoch中我们将learning rate慢慢的从0.001提高到0.01,如果我们从较高的学习率开始训练,由于不稳定的梯度会导致网络发散。我们以0.01训练75个epoch,再以0.001训练30个epoch,以0.0001训练30个epoch。 为了避免过拟合我们使用了dropout (神经元随机失效)层和数据增强的办法。在第一个连接层之后,速率为0.5的dropout层防止了层之间的联合性(dropout强迫一个神经单元,和随机挑选出来的其他神经单元共同工作,达到好的效果。消除减弱了神经元节点间的联合适应性,增强了泛化能力。)[18]。对于数据增强,我们引入达到原始图像大小20%的随机缩放和平移。我们还在HSV色彩空间中随机调整图像的曝光和饱和度达1.5倍。2.3前向传播 和训练时一样,在检测测试图像时只需网络执行一次预测。在PASCAL VOC上为每个图像预测98个边界框,每个边界框预测一个置信度得分。不像基于分类器的检测方法,YOLO因为只需运行一个网络,所以执行速度很快。 网格的设计在边界框预测中强制实现空间多样性。通常我们很清楚物体落入哪个网格中,并且模型为每个物体只预测一个边界框。但是,一些比较大的物体或者是在跨越多个网格边界的物体,可以被多个网格都很好的检测出来(即一个物体被多次检测出来造成多重检测问题)。可以使用NMS(非极大值抑制)来解决这种多重检测的问题。虽然NMS对YOLO性能的影响不像对R-CNN、DPM性能影响那么大,但也能提升2-3%的mAP值。2.4 YOLO的局限性 YOLO对边界框预测施加了强烈的空间约束,因为每个网格单元只预测两个框,并且只能有一个类。这种空间约束限制了模型能预测网格附近物体的数量。我们的模型在图像中出现的成群的小物体(比如鸟群)时将会出现物体间的竞争。 由于我们的模型从数据中学习如何预测边界框,因此它遇到新的数据或数据不寻常的高宽比或配置时将较难适应。因为我们的模型在输入图像中有多个下采样层,所以我们的模型是使用相对粗糙的特征来预测边界框。最后,我们在训练一个损失函数不断提高检测性能时,我们将小边框和大边框的损失同等对待。一个较小损失值对较大的边界框来说影响较小,但是对较小的边界框则意味着会极大地影响IOU。我们的误差主要来自检测定位误差。3.与其他检测系统对比 物体检测是计算机视觉领域的核心问题。检测流程通常是从输入图像中提取一组特征开始的(Haar [25], SIFT [23],HOG [4], convolutional features [6]) 。然后分类器[36, 21, 13, 10] 或定位器 [1, 32] 在特征空间中识别物体。这些分类器或定位器在整个图像上或在图像中某些区域子集上以滑动窗口方式运行[35,15,39]。我们将YOLO检测系统与几个顶级检测框架进行了比较,突出了主要的相似点和不同点。 Deformable Parts Model DPM 使用sliding window(滑动窗口)方法执行物体检测[10]。DPM使用不相交的管道来提取静态特征,对区域分类,预测高分边界框等。我们的系统用单个卷积神经网络取代了以上各个部分。网络是同时执行特征提取,边界框预测,非最大抑制和上下文推理这些操作。我们的网络不是静态的,而是在线训练和优化的。我们的网络是统一架构的比DPM速度更快更准确。 R-CNN R-CNN是使用region proposals(候选区域)的方式而不是滑动窗口的方式。Selective Search(选择性搜索)[35]生成候选的边界框,一个卷积网络提取特征,一个SVM给边界框评分,线性模型调整边界框,NMS消除重复检测。需要精确调整复杂的检测管道的每个阶段,这导致训练得到的系统运行缓慢,测试时每张图片耗时超过40s。 YOLO和R-CNN有一些相似之处。每个网格使用卷积特征预测候选框并对其评分。但是我们的系统对网格的预测施加空间限制,这一定程度上减少了重复检测问题。相比R-CNN提出约2000候选框,我们的YOLO提出较少的候选框只有98个。最后,我们整合了这些单独的组件,形成一个单一的同时优化的模型。 其他快速检测系统 Fast 和 Faster R-CNN 专注于通过共享计算和使用网络 候选区域取代选择性搜索来提高R-CNN的速度。虽然它们的速度和准确性都比R-CNN有所提高,但两者仍然达不到实时检测的要求。 许多工作集中在提高DPM速度上[31] [38] [5]。他们通过级联的方式加快HOG计算,并泛华到GPUs上。但是,DPM的实时速度只有30HZ。YOLO不是试图优化复杂的检测管道中的单个组件,而是完全抛出管道,并且设计的运行速度很快。单一类别的检测器比如人脸检测或者人员检测可以得到很好的优化,因为这些任务处理的特征变化较少。YOLO是一种通用的检测器,可以同时检测多种物体。 Deep MultiBox. 与R-CNN不同,Szegedy等人训练一个卷积网络而不是使用选择性搜索来预测感兴趣的区域。MultiBox还可以通过用单个类别预测替换置信预测来执行单个目标检测。但是MultiBox不能执行通用检测,因为它只是复杂管线中的一部分,还需要进一步的图像分类补丁。YOLO和MultiBox都使用卷积网络来预测图像中的边界框,但YOLO是一个完整的检测系统。 OverFeat Sermanet等人训练卷积神经网络以执行定位并使该定位器适于执行检测[32]。 OverFeat有效地执行滑动窗口检测,但它仍然是一个不相交的系统。OverFeat优化了定位,而不是检测性能。像DPM一样,定位器在进行预测时仅看到本地信息。OverFeat不能推测全局上下文,因此需要大量的后处理来产生相关检测。 MultiGrasp 我们的工作在设计方面类似于Redmon [27] 等人的抓取检测的工作。我们的网格预测边界框的方式是基于MultiGrasp为抓取检测的设计。但是抓取检测比物体检测要简单得多。MultiGrasp只需要从包含一个物体的图像中预测单个可抓取区域即可,它不必估计物体的大小,位置或边界或预测它的类,只需要找到适合抓取的区域。YOLO预测图像中多个类的多个对象的边界框和类概率。4.实验 首先我们在PASCAL VOC 2007上对比YOLO和其他实时检测系统。为了理解YOLO和多个R-CNN变体的区别,我们探讨了在VOC 2007上YOLO和Fast R-CNN(R-CNN系列变体中性能最高的版本[14])的损失。基于不同的错误文件,我们展示了YOLO可以重新调整Fast R-CNN的检测并且减少背景误报的错误,从而显著的提高性能。我们还展示了在VOC 2012上的测试性能,并和当前最先进的方法的mAP对比。最后,我们展示了在两个艺术品数据集上,YOLO比其他检测器更容易迁移到其他领域。4.1和其他实时系统对比 对象检测的许多研究工作都集中在快速制作标准检测管道上。 [5] [38] [31] [14] 17 。然而,只有Sadeghi等人,创造了一个实时检测系统(每秒30帧或更快)[31],我们将YOLO与他们在30Hz或100Hz下运行的DPM的GPU实现进行比较。而其他人的努力没有达到实时检测的要求。我们还比较了它们的相对mAP和速度,以检查物体检测系统的准确性和性能之间的权衡。 Fast YOLO是在PASCAL上最快的物体检测方法,而且据我们所知它也是目前最快的物体检测方法。它达到了52.7%的mAP,这比以前的实时检测系统的准确率高出一倍以上。YOLO在保持实时性能的同时将mAP提高到63.4%。 我们也用VGG-16来训练YOLO。这个模型比YOLO准确率更高但是速度降低很多。它与依赖于VGG-16的其他检测系统相比是更有效的,但由于它达不到实时系统速度要求,所以本文的其他部分将重点放在我们的这个更快的模型上。 最快的DPM可以在不牺牲太多mAP的情况下有效加速DPM,但仍然会将实时性能降低2倍[38]。与神经网络方法相比,它还受到DPM检测精度相对较低的限制。 R-CNN减去R用静态边界框提议取代选择性搜索[20]。虽然它的速度比R-CNN速度快得多,但是它还还达不到实时的要求, 而且因为没有很好的建议框所以精度很受影响。 快速R-CNN加速了R-CNN的分类阶段,但仍然依赖于选择性搜索,每个图像大约需要2秒才能生成建议边界框。所以虽然它的mAP很高,但是速度只有0.5 fps达不到实时速度要求。 目前的Fast R-CNN使用一个神经网络替代选择性搜索来生成建议边界框。比如:Szegedy等人。在我们的测试中,他们最精确的模型速度达到7 fps,而较小的,不太精确的模型以速度达到18 fps。VGG-16版本的Fast R-CNN比YOLO的mAP高10,但是速度比YOLO慢6倍。Zeiler-Fergus Faster R-CNN仅比YOLO慢2.5倍,但是精度还是不及YOLO。4.2. VOC 2007误差分析 为了进一步研究YOLO和最先进的检测器之间的差异,我们将详细分析在VOC 2007上的检测结果。我们将YOLO与Fast R-CNN进行比较,因为Fast R-CNN是P ASCAL上性能最高的检测器之一,它的检测是公开的。 我们使用Hoiem等人的方法和工具[19]。对于测试时的每个类别,我们查看该类别的前N个预测。 每个预测都是正确的,或者根据错误类型进行如下分类: 正确:正确类别 并且 IOU>.5 定位:正确类别 并且 .5>IOU>.1 相似:相似的类别 并且 IOU>.1 其他:类别错误 并且IOU>.1 背景:所有类别上IOU<.1 图4显示了所有20个类中平均每种错误类型的细分。YOLO努力的去准确定位物体。YOLO中的定位错误比其他所有类型错误之和还多。Fast R-CNN的定位错误更少但是背景错误更多,它最好的检测结果中有13.6%是假阳(本来不含有物体误报为有物体)。Fast R-CNN对背景的误报错误是YOLO的三倍。 4.3. Fast R-CNN和YOLO相结合 与Fast R-CNN相比,YOLO的背景误报错误要少得多。 通过使用YOLO减小Fast R-CNN的背景误报错误,我们可以显着提升性能。对于R-CNN预测的每个边界框,我们检查YOLO是否预测了一个类似的框。如果确实如此,我们会根据YOLO预测的概率和两个框之间的重叠来提高该预测得分。 最好的Fast R-CNN模型在VOC 2007测试集上获得了71.8%的mAP。当与YOLO结合使用时,其mAP增加了3.2%达到75.0%。 我们还尝试将最好的Fast R-CNN模型与其他几个版本的Fast R-CNN相结合。 这些结合使mAP小幅增加0.3%和0.6%之间,详见表2。 YOLO带来的性能提升不是模型集成的结果,因为集成不同版本的Fast R-CNN几乎没有什么性能提升。相反,正是因为YOLO在测试中犯了各种各样的错误,导致它能很有效地提升Fast R-CNN的性能。不幸的是因为我们是分别训练各个模型然后结合结果,所以系统没有从YOLO的快速性上受益,速度没有什么提高。但是,因为YOLO速度很快,所以相对单独的Fast R-CNN,结合YOLO之后不会增加多少计算时间。4.4 VOC 2012结果 在VOC 2012测试集中,YOLO的mAP分数为57.9%。这低于现有技术水平,更接近使用VGG-16的原始R-CNN,参见表3。与最接近的竞争对手相比,我们的系统在小物体检测时有物体间竞争。在瓶子,羊,电视/监视器等类别上,YOLO得分比R-CNN或Feature Edit低8-10%。然而,在其他类别如猫和火车上,YOLO实现了更高的性能。我们的Fast R-CNN + YOLO组合模型是性能最高的检测方法之一。 Fast R-CNN从与YOLO的组合中获得了2.3%的提升,使其在公共排行榜上提升了5位。4.5抽象性 艺术作品中的人物检测 用于对象检测的学术数据集是从同一分布中提取训练和测试数据。 在实际应用中,很难预测所有可能的用例,测试数据可能与系统之前的情况不同[3]。我们将YOLO与其他检测系统在毕加索数据集[12]和人物艺术数据集[3]上进行了比较,这两个数据集是用来测试艺术品中的人员检测。 图5展示了YOLO和其他系统的性能比较。作为参考,我们提供了只在VOC2007上训练的模型的人员检测AP。 Picasso模型在VOC 2012上训练,而People-Art 在VOC2010上训练。 R-CNN在VOC 2007上有较高的AP,但是在艺术品领域性能就急剧下降。R-CNN使用选择性搜索来调整自然图像的建议边界框。 R-CNN中的分类器步骤只能看到小区域,所以需要很好的建议边界框。 DPM在应用于艺术品时可以很好的保持它的AP。之前的工作认为DPM表现良好是因为它具有物体的形状和布局的空间模型。虽然DPM不会像R-CNN那样退化,但是它的起始AP比较低。5.实地场景的实时检测 YOLO是一款快速而准确的检测器,非常适合应用在计算机视觉领域。我们将YOLO连接到网络摄像头,并验证它是否保持实时性能,计算时间时包括从摄像头获取图像并显示检测结果的时间。由此生成的系统是交互式的。虽然YOLO可以单独处理图像,但是当它和网络摄像头连接起来时就像一个追踪系统,在物体运动或者变化的时候实时检测系统。系统演示和源代码可以在我们的项目网站上找到:http://pjreddie.com/yolo/。6:结论 我们介绍了一款一体化(端到端)的物体检测系统YOLO。我们的模型结构很简单,可以在整个图像上进行训练。与基于分类器的方法不同,YOLO针对与检测性能直接相关的损失函数来训练,而且整个模型是联合训练的。 Fast YOLO是目前文献中最快的通用物体检测系统,YOLO引领目前最先进的实时物体检测技术。YOLO还可以很好的迁移到新的领域,这使它成为需要快速高效的物体检测系统的应用的理想选择。致谢:本项工作得到了ONR N00014-13-1-0720,NSF IIS-1338054和艾伦杰出研究员奖的部分支持。参考文献[1] M. B. Blaschko and C. H. Lampert. Learning to localize ob- jects with structured output regression. In Computer Vision– ECCV 2008, pages 2–15. Springer, 2008. 4[2] L. Bourdev and J. Malik. Poselets: Body part detectors trained using 3d human pose annotations. In International Conference on Computer Vision (ICCV), 2009. 8[3] H. Cai, Q. Wu, T. Corradi, and P. Hall. The cross- depiction problem: Computer vision algorithms for recog- nising objects in artwork and in photographs. arXiv preprint arXiv:1505.00110, 2015. 7[4] N. Dalal and B. Triggs. Histograms of oriented gradients for human detection. In Computer Vision and Pattern Recogni- tion, 2005. CVPR 2005. IEEE Computer Society Conference on, volume 1, pages 886–893. IEEE, 2005. 4, 8[5] T. Dean, M. Ruzon, M. Segal, J. Shlens, S. Vijaya- narasimhan, J. Yagnik, et al. Fast, accurate detection of 100,000 object classes on a single machine. In Computer Vision and Pattern Recognition (CVPR), 2013 IEEE Confer- ence on, pages 1814–1821. IEEE, 2013. 5[6] J. Donahue, Y. Jia, O. Vinyals, J. Hoffman, N. Zhang, E. Tzeng, and T. Darrell. Decaf: A deep convolutional acti- vation feature for generic visual recognition. arXiv preprint arXiv:1310.1531, 2013. 4[7] J. Dong, Q. Chen, S. Yan, and A. Yuille. Towards unified object detection and semantic segmentation. In Computer Vision–ECCV 2014, pages 299–314. Springer, 2014. 7[8] D. Erhan, C. Szegedy, A. Toshev, and D. Anguelov. Scalable object detection using deep neural networks. In Computer Vision and Pattern Recognition (CVPR), 2014 IEEE Confer- ence on, pages 2155–2162. IEEE, 2014. 5, 6[9] M. Everingham, S. M. A. Eslami, L. Van Gool, C. K. I. Williams, J. Winn, and A. Zisserman. The pascal visual ob- ject classeschallenge: A retrospective. International Journal of Computer Vision, 111(1):98–136, Jan. 2015. 2[10] P.F.Felzenszwalb, R.B.Girshick, D.McAllester, andD.Ra- manan. Object detection with discriminatively trained part based models. IEEE Transactions on Pattern Analysis and Machine Intelligence, 32(9):1627–1645, 2010. 1, 4[11] S. Gidaris and N. Komodakis. Object detection via a multi- region & semantic segmentation-aware CNN model. CoRR, abs/1505.01749, 2015. 7[12] S. Ginosar, D. Haas, T. Brown, and J. Malik. Detecting peo- pleincubistart. InComputerVision-ECCV2014Workshops, pages 101–116. Springer, 2014. 7[13] R. Girshick, J. Donahue, T. Darrell, and J. Malik. Rich fea- ture hierarchies for accurate object detection and semantic segmentation. In Computer Vision and Pattern Recognition (CVPR), 2014 IEEE Conference on, pages 580–587. IEEE, 2014. 1, 4, 7[14] R. B. Girshick. Fast R-CNN. CoRR, abs/1504.08083, 2015. 2, 5, 6, 7[15] S. Gould, T. Gao, and D. Koller. Region-based segmenta- tion and object detection. In Advances in neural information processing systems, pages 655–663, 2009. 4[16] B. Hariharan, P. Arbeláez, R. Girshick, and J. Malik. Simul- taneous detection and segmentation. In Computer Vision– ECCV 2014, pages 297–312. Springer, 2014. 7[17] K.He, X.Zhang, S.Ren, andJ.Sun. Spatialpyramidpooling in deep convolutional networks for visual recognition. arXiv preprint arXiv:1406.4729, 2014. 5[18] G. E. Hinton, N. Srivastava, A. Krizhevsky, I. Sutskever, and R. R. Salakhutdinov. Improving neural networks by pre- venting co-adaptation of feature detectors. arXiv preprint arXiv:1207.0580, 2012. 4[19] D.Hoiem, Y.Chodpathumwan, andQ.Dai. Diagnosingerror in object detectors. In Computer Vision–ECCV 2012, pages 340–353. Springer, 2012. 6[20] K. Lenc and A. Vedaldi. R-cnn minus r. arXiv preprint arXiv:1506.06981, 2015. 5, 6[21] R. Lienhart and J. Maydt. An extended set of haar-like fea- tures for rapid object detection. In Image Processing. 2002. Proceedings. 2002 International Conference on, volume 1, pages I–900. IEEE, 2002. 4[22] M. Lin, Q. Chen, and S. Yan. Network in network. CoRR, abs/1312.4400, 2013. 2[23] D. G. Lowe. Object recognition from local scale-invariant features. In Computer vision, 1999. The proceedings of the seventh IEEE international conference on, volume 2, pages 1150–1157. Ieee, 1999. 4[24] D. Mishkin. Models accuracy on imagenet 2012 val. https://github.com/BVLC/caffe/wiki/ Models-accuracy-on-ImageNet-2012-val. Ac- cessed: 2015-10-2. 3[25] C. P. Papageorgiou, M. Oren, and T. Poggio. A general framework for object detection. In Computer vision, 1998. sixth international conference on, pages 555–562. IEEE, 1998. 4[26] J. Redmon. Darknet: Open source neural networks in c. http://pjreddie.com/darknet/, 2013–2016. 3[27] J.RedmonandA.Angelova. Real-timegraspdetectionusing convolutional neural networks. CoRR, abs/1412.3128, 2014. 5[28] S. Ren, K. He, R. Girshick, and J. Sun. Faster r-cnn: To- wards real-time object detection with region proposal net- works. arXiv preprint arXiv:1506.01497, 2015. 5, 6, 7[29] S. Ren, K. He, R. B. Girshick, X. Zhang, and J. Sun. Object detection networks on convolutional feature maps. CoRR, abs/1504.06066, 2015. 3, 7[30] O. Russakovsky, J. Deng, H. Su, J. Krause, S. Satheesh, S. Ma, Z. Huang, A. Karpathy, A. Khosla, M. Bernstein, A. C. Berg, and L. Fei-Fei. ImageNet Large Scale Visual Recognition Challenge. International Journal of Computer Vision (IJCV), 2015. 3[31] M. A. Sadeghi and D. Forsyth. 30hz object detection with dpm v5. In Computer Vision–ECCV 2014, pages 65–79. Springer, 2014. 5, 6[32] P. Sermanet, D. Eigen, X. Zhang, M. Mathieu, R. Fergus, and Y. LeCun. Overfeat: Integrated recognition, localiza- tion and detection using convolutional networks. CoRR, abs/1312.6229, 2013. 4, 5[33] Z.ShenandX.Xue. Domoredropoutsinpool5featuremaps for better object detection. arXiv preprint arXiv:1409.6911, 2014. 7[34] C. Szegedy, W. Liu, Y. Jia, P. Sermanet, S. Reed, D. Anguelov, D. Erhan, V. Vanhoucke, and A. Rabinovich. Going deeper with convolutions. CoRR, abs/1409.4842, 2014. 2[35] J. R. Uijlings, K. E. van de Sande, T. Gevers, and A. W. Smeulders. Selective search for object recognition. Inter- national journal of computer vision, 104(2):154–171, 2013. 4[36] P. Viola and M. Jones. Robust real-time object detection. International Journal of Computer Vision, 4:34–47, 2001. 4[37] P. Viola and M. J. Jones. Robust real-time face detection. International journal of computer vision, 57(2):137–154, 2004. 5[38] J. Yan, Z. Lei, L. Wen, and S. Z. Li. The fastest deformable part model for object detection. In Computer Vision and Pat- tern Recognition (CVPR), 2014 IEEE Conference on, pages 2497–2504. IEEE, 2014. 5, 6[39] C. L. Zitnick and P. Dollár. Edge boxes: Locating object pro- posals from edges. In Computer Vision–ECCV 2014, pages 391–405. Springer, 2014. 4参考资料YOLOv1论文翻译:https://blog.csdn.net/woduoxiangfeiya/article/details/80866155
2021年02月03日
732 阅读
0 评论
0 点赞
2021-01-12
YOLOv1学习:(二)损失函数理解和实现
YOLOv1学习:(二)损失函数理解和实现损失函数形式损失函数理解1预测框的中心点(x, y) 造成的损失(即对损失函数有贡献)是图中的第一行。其中$||_{ij}^{obj}$为控制函数,在标签中包含物体的那些格点处,该值为1;若格点不含有物体,该值为 0。也就是只对那些有真实物体所属的格点进行损失计算,若该格点不包含物体则不进行此项损失计算,因此预测数值不对此项损失函数造成影响(因为这个预测数值根本不带入此项损失函数计算)。预测框的高度(w, h)造成的损失(即对损失函数有贡献)是图中的第二行。其中 $||_{ij}^{obj}$为控制函数,含义与预测中心一样。1、2项就是边框回归。第三行与第四行,都是预测框的置信度C。当该格点不含有物体时,该置信度的标签为0;若含有物体时,该置信度的标签为预测框与真实物体框的IOU数值(IOU计算公式为:两个框交集的面积除以并集的面积)。其中第三行函数的$||_{ij}^{obj}$依然为控制函数,在标签中包含物体的那些格点处,该值为1;若格点不含有物体,该值为 0。也就是只对那些有真实物体所属的格点进行损失计算,若该格点不包含物体则不进行此项损失计算,因此预测数值不对此项损失函数造成影响(因为这个预测数值根本不带入此项损失函数计算)。第四行的$||_{ij}^{obj}$也控制函数,只是含义与第三项的相反,在标签中不含物体的那些格点处,该值为1;若格点含有物体,该值为 0。也就是只对那些没有真实物体所属的格点进行损失计算,若该格点包含物体(包含物体置信度损失已经在第三项计算了)则不进行此项损失计算,因此预测数值不对此项损失函数造成影响(因为这个预测数值根本不带入此项损失函数计算)。第五行为物体类别概率P,对应的类别位置,该标签数值为1,其余位置为0,与分类网络相同。其中此项$||_{ij}^{obj}$也为控制函数,在标签中包含物体的那些格点处,该值为1;若格点不含有物体,该值为 0。也就是只对那些有真实物体所属的格点进行物体类别损失计算,若该格点不包含物体则不进行此项损失计算,因此预测数值不对此项损失函数造成影响(因为这个预测数值根本不带入此项损失函数计算)。此时再来看${\lambda}_{coord}$ 与${\lambda}_{noobj}$ ,Yolo面临的物体检测问题,是一个典型的类别数目不均衡的问题。其中49个格点,含有物体的格点往往只有3、4个,其余全是不含有物体的格点。此时如果不采取点措施,那么物体检测的mAP不会太高,因为模型更倾向于不含有物体的格点。因此${\lambda}_{coord}$ 与 ${\lambda}_{noobj}$的作用,就是让含有物体的格点,在损失函数中的权重更大,让模型更加“重视”含有物体的格点所造成的损失。在论文中, ${\lambda}_{coord}$ 与 ${\lambda}_{noobj}$ 的取值分别为5与0.5。损失函数理解2-损失函数分为三个部分$$ ||_{ij}^{obj}表示cell中是否含有真实物体的中心,含有则1,否则取0 $$① 坐标误差为什么宽和高要带根号???对不同大小的bbox预测中,相比于大bbox预测偏一点,小box预测偏一点更不能忍受。作者用了一个比较取巧的办法,就是将box的width和height取平方根代替原本的height和width(主要为了平衡小目标检测预测的偏移)② IOU误差这里的$\hat{C_i}$分别表示 1 和 0 $,C_i=Pr(Object)*IOU_{pred}^{truth}$③ 分类误差这个很容易理解(激活函数的输出)。损失函数代码实现实现""" + input + pred: (batch_size,30,7,7)的网络输出数据 + labels: (batch_size,30,7,7)的样本标签数据 + output + 当前批次样本的平均损失 """ """ + YOLOv1 的损失分为3部分 + 坐标预测损失 + 置信度预测损失 + 含object的box的confidence预测损失 + 不含object的box的confidence预测损失 + 类别预测损失 """ class Loss_YOLOv1(nn.Module): def __init__(self,batch_size=1): super(Loss_YOLOv1,self).__init__() self.batch_size = batch_size """ box格式转换 + input + src_box : [box_x_lefttop,box_y_lefttop,box_w,box_h] + output + dst_box : [box_x1,box_y1,box_x2,box_y2] """ def convert_box_type(self,src_box): x,y,w,h = tuple(src_box) x1,y1 = x,y x2,y2 = x+w,y+w return [x1,y1,x2,y2] """ iou计算 """ def cal_iou(self,box1,box2): # 求相交区域左上角的坐标和右下角的坐标 box_intersect_x1 = max(box1[0], box2[0]) box_intersect_y1 = max(box1[1], box2[1]) box_intersect_x2 = min(box1[2], box2[2]) box_intersect_y2 = min(box1[3], box2[3]) # 求二者相交的面积 area_intersect = (box_intersect_y2 - box_intersect_y1) * (box_intersect_x2 - box_intersect_x1) # 求box1,box2的面积 area_box1 = (box1[2] - box1[0]) * (box1[3] - box1[1]) area_box2 = (box2[2] - box2[0]) * (box2[3] - box2[1]) # 求二者相并的面积 area_union = area_box1 + area_box2 - area_intersect # 计算iou(交并比) iou = area_intersect / area_union return iou def forward(self,pred,target): lambda_noobj = 0.5 # lambda_noobj参数 lambda_coord = 5 # lambda_coord参数 site_pred_loss = 0 # 坐标预测损失 obj_confidence_pred_loss = 0 # 含object的box的confidence预测损失 noobj_confidence_pred_loss = 0 #不含object的box的confidence预测损失 class_pred_loss = 0 # 类别预测损失 for batch_size_index in range(self.batch_size): # batchsize循环 for x_index in range(7): # x方向网格循环 for y_index in range(7): # y方向网格循环 # 获取单个网格的预测数据和真实数据 pred_data = pred[batch_size_index,:,x_index,y_index] # [x,y,w,h,confidence,x,y,w,h,confidence,cls*20] true_data = target[batch_size_index,:,x_index,y_index] #[x,y,w,h,confidence,x,y,w,h,confidence,cls*20] if true_data[4]==1:# 如果包含物体 # 解析预测数据和真实数据 pred_box_confidence_1 = pred_data[0:5] # [x,y,w,h,confidence1] pred_box_confidence_2 = pred_data[5:10] # [x,y,w,h,confidence2] true_box_confidence = true_data[0:5] # [x,y,w,h,confidence] # 获取两个预测box并计算与真实box的iou iou1 = self.cal_iou(self.convert_box_type(pred_box_confidence_1[0:4]),self.convert_box_type(true_box_confidence[0:4])) iou2 = self.cal_iou(self.convert_box_type(pred_box_confidence_2[0:4]),self.convert_box_type(true_box_confidence[0:4])) # 在两个box中选择iou大的box负责预测物体 if iou1 >= iou2: better_box_confidence,bad_box_confidence = pred_box_confidence_1,pred_box_confidence_2 better_iou,bad_iou = iou1,iou2 else: better_box_confidence,bad_box_confidence = pred_box_confidence_2,pred_box_confidence_1 better_iou,bad_iou = iou2,iou1 # 计算坐标预测损失 site_pred_loss += lambda_coord * torch.sum((better_box_confidence[0:2]- true_box_confidence[0:2])**2) # x,y的预测损失 site_pred_loss += lambda_coord * torch.sum((better_box_confidence[2:4].sqrt()-true_box_confidence[2:4].sqrt())**2) # w,h的预测损失 # 计算含object的box的confidence预测损失 obj_confidence_pred_loss += (better_box_confidence[4] - better_iou)**2 # iou比较小的bbox不负责预测物体,因此confidence loss算在noobj中 # 因此还需计算不含object的box的confidence预测损失 noobj_confidence_pred_loss += lambda_noobj * (bad_box_confidence[4] - bad_iou)**2 # 计算类别损失 class_pred_loss += torch.sum((pred_data[10:] - true_data[10:])**2) else: # 如果不包含物体,则只有置信度损失--noobj_confidence_pred_loss # [4,9]代表取两个预测框的confidence noobj_confidence_pred_loss += lambda_noobj * torch.sum(pred[batch_size_index,(4,9),x_index,y_index]**2) loss = site_pred_loss + obj_confidence_pred_loss + noobj_confidence_pred_loss + class_pred_loss return loss/self.batch_size调用测试label1 = torch.rand([1,30,7,7]) label2 = torch.rand([1,30,7,7]) print(label1.shape,label2.shape) print(loss(label1,label2))torch.Size([1, 30, 7, 7]) torch.Size([1, 30, 7, 7]) tensor(14.6910)参考资料YOLO V1损失函数理解:http://www.likecs.com/show-65912.htmlYOLOv1算法理解:https://www.cnblogs.com/ywheunji/p/10808989.html【目标检测系列】yolov1的损失函数详解(结合pytorch代码):https://blog.csdn.net/gbz3300255/article/details/109179751yolo-yolo v1损失函数理解:https://blog.csdn.net/qq_38236744/article/details/106724596
2021年01月12日
1,380 阅读
0 评论
0 点赞
2021-01-12
YOLOv1学习:(一)网络结构推导与实现
YOLOv1学习:(一)网络结构推导与实现原论文网络结构知乎看到的网络结构分析(见参考资料1)二次网络结构分析7*7*30输出解释实际操作如图所示,分为7*7个小格子,每个格子预测两个bounding box。如果一个目标的中心落入一个网格单元中,该网格单元负责检测 该目标。对每一个切割的小单元格预测(置信度,边界框的位置),每个bounding box需要4个数值来表示其位置,(Center_x,Center_y,width,height),即(bounding box的中心点的x坐标,y坐标,bounding box的宽度,高度)置信度定义为该区域内是否包含物体的概率,打标签的时候,正样本(与真实物体有最大IOU的边框设为正样本)置信度真值为1,负样本为0.还要得到分类的概率结果;20个分类每个类别的概率。7*7*30中的30=(20类概率+2*5(置信度,边框位置))Pytorch实现网络结构基本骨架import torch import torch.nn as nn feature = nn.Sequential( nn.Conv2d(in_channels=3,out_channels=64,kernel_size=7,stride=2,padding=3), nn.MaxPool2d(kernel_size=2,stride=2), nn.Conv2d(in_channels=64,out_channels=192,kernel_size=3,stride=1,padding=1), nn.MaxPool2d(kernel_size=2,stride=2), nn.Conv2d(in_channels=192,out_channels=128,kernel_size=1,stride=1,padding=0), nn.Conv2d(in_channels=128,out_channels=256,kernel_size=3,stride=1,padding=1), nn.Conv2d(in_channels=256,out_channels=256,kernel_size=1,stride=1,padding=0), nn.Conv2d(in_channels=256,out_channels=512,kernel_size=3,stride=1,padding=1), nn.MaxPool2d(kernel_size=2,stride=2), nn.Conv2d(in_channels=512,out_channels=256,kernel_size=1,stride=1,padding=0), nn.Conv2d(in_channels=256,out_channels=512,kernel_size=3,stride=1,padding=1), nn.Conv2d(in_channels=512,out_channels=256,kernel_size=1,stride=1,padding=0), nn.Conv2d(in_channels=256,out_channels=512,kernel_size=3,stride=1,padding=1), nn.Conv2d(in_channels=512,out_channels=256,kernel_size=1,stride=1,padding=0), nn.Conv2d(in_channels=256,out_channels=512,kernel_size=3,stride=1,padding=1), nn.Conv2d(in_channels=512,out_channels=256,kernel_size=1,stride=1,padding=0), nn.Conv2d(in_channels=256,out_channels=512,kernel_size=3,stride=1,padding=1), nn.Conv2d(in_channels=512,out_channels=512,kernel_size=1,stride=1,padding=0), nn.Conv2d(in_channels=512,out_channels=1024,kernel_size=3,stride=1,padding=1), nn.MaxPool2d(kernel_size=2,stride=2), nn.Conv2d(in_channels=1024,out_channels=512,kernel_size=1,stride=1,padding=0), nn.Conv2d(in_channels=512,out_channels=1024,kernel_size=3,stride=1,padding=1), nn.Conv2d(in_channels=1024,out_channels=512,kernel_size=1,stride=1,padding=0), nn.Conv2d(in_channels=512,out_channels=1024,kernel_size=3,stride=1,padding=1), nn.Conv2d(in_channels=1024,out_channels=1024,kernel_size=3,stride=1,padding=1), nn.Conv2d(in_channels=1024,out_channels=1024,kernel_size=3,stride=2,padding=1), nn.Conv2d(in_channels=1024,out_channels=1024,kernel_size=3,stride=1,padding=1), nn.Conv2d(in_channels=1024,out_channels=1024,kernel_size=3,stride=1,padding=1), ) classify = nn.Sequential( nn.Flatten(), nn.Linear(1024 * 7 * 7, 4096), nn.Linear(4096, 1470) #1470=7*7*30 ) yolov1 = nn.Sequential( feature, classify )基本骨架-结构打印Sequential( (0): Sequential( (0): Conv2d(3, 64, kernel_size=(7, 7), stride=(2, 2), padding=(3, 3)) (1): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False) (2): Conv2d(64, 192, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (3): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False) (4): Conv2d(192, 128, kernel_size=(1, 1), stride=(1, 1)) (5): Conv2d(128, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (6): Conv2d(256, 256, kernel_size=(1, 1), stride=(1, 1)) (7): Conv2d(256, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (8): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False) (9): Conv2d(512, 256, kernel_size=(1, 1), stride=(1, 1)) (10): Conv2d(256, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (11): Conv2d(512, 256, kernel_size=(1, 1), stride=(1, 1)) (12): Conv2d(256, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (13): Conv2d(512, 256, kernel_size=(1, 1), stride=(1, 1)) (14): Conv2d(256, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (15): Conv2d(512, 256, kernel_size=(1, 1), stride=(1, 1)) (16): Conv2d(256, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (17): Conv2d(512, 512, kernel_size=(1, 1), stride=(1, 1)) (18): Conv2d(512, 1024, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (19): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False) (20): Conv2d(1024, 512, kernel_size=(1, 1), stride=(1, 1)) (21): Conv2d(512, 1024, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (22): Conv2d(1024, 512, kernel_size=(1, 1), stride=(1, 1)) (23): Conv2d(512, 1024, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (24): Conv2d(1024, 1024, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (25): Conv2d(1024, 1024, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1)) (26): Conv2d(1024, 1024, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (27): Conv2d(1024, 1024, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) ) (1): Sequential( (0): Flatten() (1): Linear(in_features=50176, out_features=4096, bias=True) (2): Linear(in_features=4096, out_features=1470, bias=True) ) )加入损失函数和Dropoutimport torch import torch.nn as nn feature = nn.Sequential( nn.Conv2d(in_channels=3,out_channels=64,kernel_size=7,stride=2,padding=3), nn.LeakyReLU(), nn.MaxPool2d(kernel_size=2,stride=2), nn.Conv2d(in_channels=64,out_channels=192,kernel_size=3,stride=1,padding=1), nn.LeakyReLU(), nn.MaxPool2d(kernel_size=2,stride=2), nn.Conv2d(in_channels=192,out_channels=128,kernel_size=1,stride=1,padding=0), nn.LeakyReLU(), nn.Conv2d(in_channels=128,out_channels=256,kernel_size=3,stride=1,padding=1), nn.LeakyReLU(), nn.Conv2d(in_channels=256,out_channels=256,kernel_size=1,stride=1,padding=0), nn.LeakyReLU(), nn.Conv2d(in_channels=256,out_channels=512,kernel_size=3,stride=1,padding=1), nn.LeakyReLU(), nn.MaxPool2d(kernel_size=2,stride=2), nn.Conv2d(in_channels=512,out_channels=256,kernel_size=1,stride=1,padding=0), nn.LeakyReLU(), nn.Conv2d(in_channels=256,out_channels=512,kernel_size=3,stride=1,padding=1), nn.LeakyReLU(), nn.Conv2d(in_channels=512,out_channels=256,kernel_size=1,stride=1,padding=0), nn.LeakyReLU(), nn.Conv2d(in_channels=256,out_channels=512,kernel_size=3,stride=1,padding=1), nn.LeakyReLU(), nn.Conv2d(in_channels=512,out_channels=256,kernel_size=1,stride=1,padding=0), nn.LeakyReLU(), nn.Conv2d(in_channels=256,out_channels=512,kernel_size=3,stride=1,padding=1), nn.LeakyReLU(), nn.Conv2d(in_channels=512,out_channels=256,kernel_size=1,stride=1,padding=0), nn.LeakyReLU(), nn.Conv2d(in_channels=256,out_channels=512,kernel_size=3,stride=1,padding=1), nn.Conv2d(in_channels=512,out_channels=512,kernel_size=1,stride=1,padding=0), nn.LeakyReLU(), nn.Conv2d(in_channels=512,out_channels=1024,kernel_size=3,stride=1,padding=1), nn.LeakyReLU(), nn.MaxPool2d(kernel_size=2,stride=2), nn.Conv2d(in_channels=1024,out_channels=512,kernel_size=1,stride=1,padding=0), nn.LeakyReLU(), nn.Conv2d(in_channels=512,out_channels=1024,kernel_size=3,stride=1,padding=1), nn.LeakyReLU(), nn.Conv2d(in_channels=1024,out_channels=512,kernel_size=1,stride=1,padding=0), nn.LeakyReLU(), nn.Conv2d(in_channels=512,out_channels=1024,kernel_size=3,stride=1,padding=1), nn.LeakyReLU(), nn.Conv2d(in_channels=1024,out_channels=1024,kernel_size=3,stride=1,padding=1), nn.LeakyReLU(), nn.Conv2d(in_channels=1024,out_channels=1024,kernel_size=3,stride=2,padding=1), nn.LeakyReLU(), nn.Conv2d(in_channels=1024,out_channels=1024,kernel_size=3,stride=1,padding=1), nn.LeakyReLU(), nn.Conv2d(in_channels=1024,out_channels=1024,kernel_size=3,stride=1,padding=1), nn.LeakyReLU(), ) classify = nn.Sequential( nn.Flatten(), nn.Linear(1024 * 7 * 7, 4096), nn.Dropout(0.5), nn.Linear(4096, 1470) #1470=7*7*30 ) yolov1 = nn.Sequential( feature, classify ) print(yolov1)参考资料YOLO V1 网络结构分析:https://zhuanlan.zhihu.com/p/220062200?utm_source=wechat_sessionYOLOv1算法理解:https://www.cnblogs.com/ywheunji/p/10808989.html
2021年01月12日
641 阅读
0 评论
0 点赞