yolov1代码解读

前面已经对yolov1的原理做了一个了解,下面就来看一下yolov1的代码实现过程yolov1的代码倒是比Faster-Rcnn简单多了,但是一些逻辑顺序和Faster-Rcnn差不多● pascal_voc.py:对图片数据和XML数据进行解析和预处理;● yolo_net.py:搭建yolo v1网络,设置yolo v1的损失函数;● train.py 和test.py :一个用来训练模型,一个用来测试模型。1、pascal_voc.py这部分主要是解析xml文件,读取图片数据和对数据进行预
摘要由CSDN通过智能技术生成

yolov1论文解读
前面已经对yolov1的原理做了一个了解,下面就来看一下yolov1的代码实现过程

yolov1的代码倒是比Faster-Rcnn简单多了,但是一些逻辑顺序和Faster-Rcnn差不多
● pascal_voc.py:对图片数据和XML数据进行解析和预处理;
● yolo_net.py:搭建yolo v1网络,设置yolo v1的损失函数;
● train.py 和test.py :一个用来训练模型,一个用来测试模型。

1、pascal_voc.py

这部分主要是解析xml文件,读取图片数据和对数据进行预处理,主函数

def load_pascal_annotation(self, index):
    """
    Load image and bounding boxes info from XML file in the PASCAL VOC
    format.
    """

    imname = os.path.join(self.data_path, 'JPEGImages', index + '.jpg')
    im = cv2.imread(imname)
    h_ratio = 1.0 * self.image_size / im.shape[0]  # 448所占图片高度的比例
    w_ratio = 1.0 * self.image_size / im.shape[1]  # 448所占图片宽度的比例
    # im = cv2.resize(im, [self.image_size, self.image_size])

    label = np.zeros((self.cell_size, self.cell_size, 5+len(self.classes)))  # label的数据维度(7, 7, 25),一个ceil只负责预测一个类别
    filename = os.path.join(self.data_path, 'Annotations', index + '.xml')
    tree = ET.parse(filename)
    objs = tree.findall('object')

    for obj in objs:
        bbox = obj.find('bndbox')
        # Make pixel indexes 0-based
        x1 = max(min((float(bbox.find('xmin').text) - 1) * w_ratio, self.image_size - 1), 0)
        y1 = max(min((float(bbox.find('ymin').text) - 1) * h_ratio, self.image_size - 1), 0)
        x2 = max(min((float(bbox.find('xmax').text) - 1) * w_ratio, self.image_size - 1), 0)
        y2 = max(min((float(bbox.find('ymax').text) - 1) * h_ratio, self.image_size - 1), 0)
        cls_ind = self.class_to_ind[obj.find('name').text.lower().strip()]
        # 将(x1, y1, x2, y2)转化为(x_center, y_center, width, height)
        boxes = [(x2 + x1) / 2.0, (y2 + y1) / 2.0, x2 - x1, y2 - y1]
        
        # 查看object的中心点落在那个cell里,cell的索引从0开始
        x_ind = int(boxes[0] * self.cell_size / self.image_size)
        y_ind = int(boxes[1] * self.cell_size / self.image_size)
        # 设置标记,看这个ceil是否被访问过,1表示这个cell有object
        if label[y_ind, x_ind, 0] == 1:
            continue
        label[y_ind, x_ind, 0] = 1 
        label[y_ind, x_ind, 1:5] = boxes  
        label[y_ind, x_ind, 5 + cls_ind] = 1  

    return label, len(objs)

输出的label是一个维度为[7, 7, 25]的数组,这是真实数据的标签值,需要注意的是yolov1的网络输出是[7, 7, 30],所以在计算loss时会对label进行维度扩展(后面计算loss的代码中详解)。
label [7, 7, 25]的含义为:

# 查看object的中心点落在那个cell里,cell的索引从0开始
x_ind = int(boxes[0] * self.cell_size / self.image_size)
y_ind = int(boxes[1] * self.cell_size / self.image_size)
# 设置标记,看这个ceil是否被访问过,1表示这个cell有object
if label[y_ind, x_ind, 0] == 1:
    continue
label[y_ind, x_ind, 0] = 1 
label[y_ind, x_ind, 1:5] = boxes  
label[y_ind, x_ind, 5 + cls_ind] = 1

可看出:

label 维度[7, 7, 25]
[..., 0]值为01,1表示object的中心点落在这个cell里,0表示没有
[..., 1:5] ground_truth 标记框,格式为(x_center, y_center, width, height)
[..., 5:] 标记的类别,object的属于哪个类别,哪个类别对应位置为1,其他为0

举个栗子:
在这里插入图片描述
图中有三个物体,三个物体的中心分别落在7*7的格子中的(1,4),(2,3),(5,1),索引从0开始。
这张图片通过pascal_voc.py生成label是(7,7,25)的数组,其中label[1,4,0],label[2,3,0],label[5,1,0]处的值为1其余为0.(7,7,25)数组中深度(aixs=2)为(1,5)的部分存储着gt_boxes的坐标,所以label[1,4,1:5]、label[2,3,1:5]、label[5,1,1:5]存放着坐标,其余的label[:,:,1:5]全部为0。而(7,7,25)数组中深度(axis=2)为(5,25)的部分存储着gt_boxes的20分类的类别信息。

Q: 那如何判断object落在哪个cell里呢?
A:根据如下代码

x_ind = int(boxes[0] * self.cell_size / self.image_size)
y_ind = int(boxes[1] * self.cell_size / self.image_size)

假设 per = self.image_size / self.cell_size ,per是每个cell所占图片大小的比例,所以 boxes[0]/per 即 boxes[0] * self.cell_size / self.image_size 表示box的中心点落在第几个cell中。

2、yolo_net.py

yolo_net.py文件中主要包含三个部分
● 构建网络结构
● 计算iou
● 构建损失函数

构建网络结构

def build_network(self,
                  images,
                  num_outputs,
                  alpha,
                  keep_prob=0.5,
                  is_training=True,
                  scope='yolo'):
    with tf.variable_scope(scope):
        with slim.arg_scope(
            [slim.conv2d, slim.fully_connected],    # 卷积层+全连接层
            activation_fn=leaky_relu(alpha),        # 激活函数用leaky_relu
            weights_regularizer=slim.l2_regularizer(0.0005),   # L2正则项,防止过拟合
            weights_initializer=tf.truncated_normal_initializer(0.0, 0.01)   # 权值初始化
        ):
            net = tf.pad(
                images, np.array([[0, 0], [3, 3], [3, 3], [0, 0]]),
                name='pad_1')  # 进行填充,上、下、左、右
            net = slim.conv2d(
                net, 64, 7, 2, padding='VALID', scope='conv_2')
            net = slim.max_pool2d(net, 2, padding='SAME', scope='pool_3')
            net = slim.conv2d(net, 192, 3, scope='conv_4')
            net = slim.max_pool2d(net, 2, padding='SAME', scope='pool_5')
            net = slim.conv2d(net, 128, 1, scope='conv_6')
            net = slim.conv2d(net, 256, 3, scope='conv_7')
            net = slim.conv2d(net, 256, 1, scope='conv_8')
            net = slim.conv2d(net, 512, 3, scope='conv_9')
            net = slim.max_pool2d(net, 2, padding='SAME', scope='pool_10')
            net = slim.conv2d(net, 256, 1, scope
  • 9
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值