深度学习模型试跑(四):yolov4

一.模型解读

这个现在太火了,蹭个热度写一下!###待完成的项目

官方代码

我这回打算详细分析一下,具体是根据这个tf版来写,因为这个项目还复现了trt版本!

需要weight的可以到我百度云里面下载:提取码:hwht

二.darknet 功能说明/yolov4.cfg网络结构

[net]
# Testing #测试模式
#batch=1
#subdivisions=1
# Training#训练模式 每次前向图片的数目=batch/subdivisions
batch=64###批大小.一个epoch要训练完训练集中的所有样本,样本总数记为num_train;故此可以确定迭代次数iteration=num_train/batch.
subdivisions=16
★★★ 在Darknet中,batch和sub是结合使用的,例如这儿的batch=64,sub=16表示训练的过程中将一次性加载64张图片进内存,然后分16次完成前向传播,意思是每次64/16=4张,前向传播的循环过程中累加loss求平均,待64张图片都完成前向传播后,再一次性后传更新参数
★★★ 调参经验:sub一般设置16(custom里面设置为16),不能太大或太小,且为8的倍数,其实也没啥硬性规定,看着舒服就好 batch的值可以根据显存占用情况动态调整,一次性加减sub大小即可,通常情况下batch越大越好,还需注意一点,在测试的时候batch和sub都设置为1,避免发生神秘错误!

width=608			### input图像的宽
height=608			### input图像的高
channels=3			### input图像的通道数 3为RGB彩色图片,1为灰度图,4为RGBA图,A通道表示透明度

### 以上三个参数为输入图像的参数信息width和height,越小对小目标效果越好
### 对应的是输入图像的分辨率,从而影响precision,只可以设置成32的倍数


momentum=0.949### 冲量。DeepLearning1中最优化方法中的动量参数,这个值影响着梯度下降 到最优值得速度,冲量的建议配置为0.9
decay=0.0005### 权重衰减正则项,防止过拟合;等效于给误差函数添加一个惩罚项,常用的惩罚项是所有权重的平方乘以一个衰减常量之和

### 在每次迭代中,会基于角度、饱和度、曝光、色调产生新的训练图片
angle=0###数据增强参数,单位为度angle=5,就是生成新图片的时候随机旋转-5~5度
saturation = 1.5### 饱和度
exposure = 1.5### 曝光变化大小
hue=.1### 色调变化范围


learning_rate=0.00261### 初始学习率。训练发散的话可以降低学习率。学习遇到瓶颈,loss不变的话也可以减低学习率                          
★★★ 学习率调整一定不要太死,实际训练过程中根据loss的变化和其他指标动态调整,手动ctrl+c结束此次训练后,修改学习率,再加载刚才保存的模型继续训练即可完成手动调参,调整的依据是根据训练日志来,如果loss波动太大,说明学习率过大,适当减小,变为1/51/10均可,如果loss几乎不变,可能网络已经收敛或者陷入了局部极小,此时可以适当增大学习率,注意每次调整学习率后一定要训练久一点,调参是个细活慢慢琢磨
★★ 一点小说明:实际学习率与GPU的个数有关,例如你的学习率设置为0.001,如果你有4块GPU,那真实学习率为0.001/4

burn_in=1000### 在迭代次数小于burn_in时,其学习率的更新有一种方式,大于burn_in时,才采用policy的更新方式
max_batches = 500500### 最大迭代次数。训练达到max_batches后停止学习,修改为类别数量*2000
policy=steps### 学习策略,一般都是step这种步进式;还有constant, steps, exp, poly, step, sig, RANDOM,constant等方式
steps=400000,450000### steps和scale是设置学习率的变化,比如迭代到0.8*max_batches =400000次时,学习率衰减十倍,0.9*max_batches =450000次迭代时,学习率又会在前一个学习率的基础上衰减十倍
scales=.1,.1###意思就是在0-400000次iteration期间learning rate为原始0.1,0.000261;在400000-500000次iteration期间learning rate为当前值的0.1倍,为0.0000261.随着iteration增加,降低学习率可以使模型更有效的学习,也就是更好的降低train loss
#cutmix=1###cutmix相当于cutout+mixup的结合.mixup相当于是全图融合,cutout仅仅对图片进行增强,不改变label,而cutmix则是采用了cutout的局部融合思想,并且采用了mixup的混合label策略
mosaic=1###Yolov4论文提出的,属于cutmix的扩展,cutmix是两张图混合,而马赛克增强是4张图混合,好处非常明显是一张图相当于4张图,等价于batch增加了,可以显著减少训练需要的batch size大小

[convolutional]### 一层卷积层的配置说明
batch_normalize=1### 是否做BN:卷积层之后,激活层之前。BN层将数据归一化后,能够有效解决梯度消失与梯度爆炸问题
filters=32### 输出多少个特征图
size=3### 卷积核的尺寸
stride=1### 做卷积运算的步长
pad=1### 如果pad为0,padding由 padding参数指定。如果pad为1,padding大小为size/2
activation=mish###mish激活函数,为什么Mish表现这么好?
以上无边界(即正值可以达到任何高度)避免了由于封顶而导致的饱和。理论上对负值的轻微允许会有更好的梯度流,而不是像ReLU中那样的硬零边界。最后,可能也是最重要的,目前的想法是,平滑的激活函数允许更好的信息深入神经网络,得到更好的准确性和泛化。

# Downsample
[convolutional] ###下采样层的配置说明   
batch_normalize=1
filters=64
size=3
stride=2###卷积核尺寸为3*3,配合padding且步长为2时,feature map变为原来的一半大小
pad=1
activation=mish


[route]
layers = -2###route layer层主要是把对应的层连接在一起;当layers只有一个值,代表route layer输出的是router layer - 2那一层layer的feature map;当layers有2个值时,代表route layer的输出为route layer -1和第route layer -1 layer的feature map在深度方向(z方向)连接起来

[shortcut]###把两个c h w都相同的两个层相加成一个相同c h w的层
from=-3###与前面的多少次进行融合,-3表示前面第三层
activation=linear###层次激活函数

[upsample]###通过双线性插值法将N*N的feature map变为(stride*N) * (stride*N)的feature map.模仿特征金字塔,生成多尺度feature map.加强小目标检测效果
stride=2







### SPP ######SPP层,内部采用不同大小的kernel size和stride实现不同感受野特征输出,然后route即可


[maxpool]
stride=1
size=5

[route]
layers=-2

[maxpool]
stride=1
size=9

[route]
layers=-4

[maxpool]
stride=1
size=13

[route]
layers=-1,-3,-5,-6
### End SPP ###    ......

[convolutional]
batch_normalize=1
filters=512
size=1
stride=1
pad=1
activation=leaky
即上一层的特征图输入是13x13x512,然后三个分支分别是stride=1,kernel size为5,9,13,然后三个图拼接,得到13x13x2048的图,然后接一个1x1卷积,得到13x13x512的特征图,然后进行后续操作
    ......
[convolutional]###YOLO层前面一层卷积层配置说明
size=1
stride=1
pad=1
filters=255##filters=num.(预测框个数)*(classes+5),5的意义是4个坐标加一个置信率,论文中的tx,ty,tw,th,c,classes为类别数,COCO为80,num表示YOLO中每个cell预测的框的个数,YOLOV4中为3,3*(80+5)=255.自己使用时,此处的值一定要根据自己的数据集进行更改,例如你识别4个类,则:filters=3*(4+5)=27,三个fileters都需要修改,切记#
activation=linear###线性激活,也就是没用激活函数,原样输出

[yolo]###YOLO层配置说明
mask = 0,1,2###使用anchor的索引,0,1,2表示使用下面定义的anchors中的前三个anchor
anchors = 12, 16, 19, 36, 40, 28, 36, 75, 76, 55, 72, 146, 142, 110, 192, 243, 459, 401
classes=80###类别数目,对应上面的filters
num=9###每个grid cell总共预测几个box,和anchors的数量一致。当想要使用更多anchors时需要调大num(3*3)
jitter=.3###通过抖动增加噪声来抑制过拟合
ignore_thresh = .7### 参与计算的IOU阈值大小.当预测的检测框与ground true的IOU大于ignore_thresh的时候,参与loss的计算,否则,检测框的不参与损失计算目的是控制参与loss计算的检测框的规模,当ignore_thresh过于大,接近于1的时候,那么参与检测框回归loss的个数就会比较少,同时也容易造成过拟合;而如果ignore_thresh设置的过于小,那么参与计算的会数量规模就会很大。同时也容易在进行检测框回归的时候造成欠拟合
★ 参数设置:一般选取0.5-0.7之间的一个值,之前的计算基础都是小尺度(13*13)用的是0.7,(26*26)用的是0.5。这次先将0.5更改为0.7
random=1### random为1时会启用Multi-Scale Training,随机使用不同尺寸的图片进行训练,如果为0,每次训练大小与输入大小一致;是否随机确定最后的预测框,显存小可设置成0
truth_thresh = 1###
scale_x_y = 1.2
iou_thresh=0.213### 选定一个IOU阈值
cls_normalizer=1.0###class和confidence的权重参数,默认值1
iou_normalizer=0.07###box-iou的权重参数
iou_loss=ciou###x,y,w,h由mse损失函数换位box的ciou-loss,confidence和class用mse
nms_kind=greedynms###非极大值抑制(局部最大搜索),
beta_nms=0.6###需要设置权重阈值

三.试跑效果

测试环境:

机器 : Dell T5820服务器
GPU: Nvidia P4000
cuda: 10.1
cudnn: 7.5
关键库: 深度学习模型试跑(四):yolov4_第1张图片

测试单张图片

python detect.py --weights ./data/yolov4.weights --framework tf --size 608 --image ./data/kite.jpg

转换为tensorrt文件

python save_model.py --weights ./data/yolov4.weights --output ./checkpoints/yolov4.tf --input_size 416 --model yolov4
python convert_trt.py --weights ./checkpoints/yolov4.tf --quantize_mode float16 --output ./checkpoints/yolov4-trt-fp16-416

使用trt推理,大概在25fps左右

python benchmarks.py --framework trt --weights ./checkpoints/yolov4-trt-fp16-416/

上述推理是将一张图片遍历1000次,然后计算出每次的推理时间,本人改写了一下 benchmarks.py,但是在 改

img_raw = tf.image.decode_image(open(FLAGS.image, 'rb').read(), channels=3)

这处时,不知到tf如何解码视屏,于是在加载每一帧时我都存为一张图片,有朋友知道如何优化这部分麻烦请告知我.

import numpy as np
import tensorflow as tf
import time
import cv2
from core.yolov4 import YOLOv4, YOLOv3_tiny, YOLOv3, decode
from absl import app, flags, logging
from absl.flags import FLAGS
from tensorflow.python.saved_model import tag_constants
from core import utils
from core.config import cfg
from tensorflow.compat.v1 import ConfigProto
from tensorflow.compat.v1 import InteractiveSession

flags.DEFINE_boolean('tiny', False, 'yolo or yolo-tiny')
flags.DEFINE_string('framework', 'tf', '(tf, tflite, trt')
flags.DEFINE_string('model', 'yolov4', 'yolov3 or yolov4')
flags.DEFINE_string('weights', './data/yolov4.weights', 'path to weights file')
flags.DEFINE_string('image', './data/Skate.mp4', 'path to input image')
flags.DEFINE_integer('size', 416, 'resize images to')


def main(_argv):
    if FLAGS.tiny:
        STRIDES = np.array(cfg.YOLO.STRIDES_TINY)
        ANCHORS = utils.get_anchors(cfg.YOLO.ANCHORS_TINY, FLAGS.tiny)
    else:
        STRIDES = np.array(cfg.YOLO.STRIDES)
        if FLAGS.model == 'yolov4':
            ANCHORS = utils.get_anchors(cfg.YOLO.ANCHORS, FLAGS.tiny)
        else:
            ANCHORS = utils.get_anchors(cfg.YOLO.ANCHORS_V3, FLAGS.tiny)
    NUM_CLASS = len(utils.read_class_names(cfg.YOLO.CLASSES))
    XYSCALE = cfg.YOLO.XYSCALE

    config = ConfigProto()
    config.gpu_options.allow_growth = True
    session = InteractiveSession(config=config)
    input_size = FLAGS.size
    physical_devices = tf.config.experimental.list_physical_devices('GPU')
    if len(physical_devices) > 0:
        tf.config.experimental.set_memory_growth(physical_devices[0], True)
    if FLAGS.framework == 'tf':
        input_layer = tf.keras.layers.Input([input_size, input_size, 3])
        if FLAGS.tiny:
            feature_maps = YOLOv3_tiny(input_layer, NUM_CLASS)
            bbox_tensors = []
            for i, fm in enumerate(feature_maps):
                bbox_tensor = decode(fm, NUM_CLASS, i)
                bbox_tensors.append(bbox_tensor)
            model = tf.keras.Model(input_layer, bbox_tensors)
            utils.load_weights_tiny(model, FLAGS.weights)
        else:
            if FLAGS.model == 'yolov3':
                feature_maps = YOLOv3(input_layer, NUM_CLASS)
                bbox_tensors = []
                for i, fm in enumerate(feature_maps):
                    bbox_tensor = decode(fm, NUM_CLASS, i)
                    bbox_tensors.append(bbox_tensor)
                model = tf.keras.Model(input_layer, bbox_tensors)
                utils.load_weights_v3(model, FLAGS.weights)
            elif FLAGS.model == 'yolov4':
                feature_maps = YOLOv4(input_layer, NUM_CLASS)
                bbox_tensors = []
                for i, fm in enumerate(feature_maps):
                    bbox_tensor = decode(fm, NUM_CLASS, i)
                    bbox_tensors.append(bbox_tensor)
                model = tf.keras.Model(input_layer, bbox_tensors)
                utils.load_weights(model, FLAGS.weights)
    elif FLAGS.framework == 'trt':
        saved_model_loaded = tf.saved_model.load(FLAGS.weights, tags=[tag_constants.SERVING])
        signature_keys = list(saved_model_loaded.signatures.keys())
        print(signature_keys)
        infer = saved_model_loaded.signatures['serving_default']

    logging.info('weights loaded')

    @tf.function
    def run_model(x):
        return model(x)

    # Test the TensorFlow Lite model on random input data.
    sum = 0
    videoCapture = cv2.VideoCapture(FLAGS.image)
    while 1:
        ret, original_image = videoCapture.read()
        #original_image = cv2.imread(FLAGS.image)
        s_time = time.time()
        tem_path = './temp/'+str(s_time)+'.jpg'
        cv2.imwrite(tem_path,original_image)

        original_image = cv2.cvtColor(original_image, cv2.COLOR_BGR2RGB)
        original_image_size = original_image.shape[:2]
        image_data = utils.image_preporcess(np.copy(original_image), [FLAGS.size, FLAGS.size])
        image_data = image_data[np.newaxis, ...].astype(np.float32)
        #data_tensor = tf.convert_to_tensor(np_image)
        #kkzssm = open(FLAGS.image, 'rb').read()
        #print('kkzssm',type(kkzssm),np.shape(kkzssm))
        img_raw = tf.image.decode_image(open(tem_path, 'rb').read(), channels=3)

        img_raw = tf.expand_dims(img_raw, 0)
        img_raw = tf.image.resize(img_raw, (FLAGS.size, FLAGS.size))
        batched_input = tf.constant(image_data)
        prev_time = time.time()
        # pred_bbox = model.predict(image_data)
        if FLAGS.framework == 'tf':
            pred_bbox = []
            result = run_model(image_data)
            for value in result:
                value = value.numpy()
                pred_bbox.append(value)
            if FLAGS.model == 'yolov4':
                pred_bbox = utils.postprocess_bbbox(pred_bbox, ANCHORS, STRIDES, XYSCALE)
            else:
                pred_bbox = utils.postprocess_bbbox(pred_bbox, ANCHORS, STRIDES)
            bboxes = utils.postprocess_boxes(pred_bbox, original_image_size, input_size, 0.25)
            bboxes = utils.nms(bboxes, 0.213, method='nms')
        elif FLAGS.framework == 'trt':
            pred_bbox = []
            result = infer(batched_input)
            for key, value in result.items():
                value = value.numpy()
                pred_bbox.append(value)
            if FLAGS.model == 'yolov4':
                pred_bbox = utils.postprocess_bbbox(pred_bbox, ANCHORS, STRIDES, XYSCALE)
            else:
                pred_bbox = utils.postprocess_bbbox(pred_bbox, ANCHORS, STRIDES)
            bboxes = utils.postprocess_boxes(pred_bbox, original_image_size, input_size, 0.25)
            bboxes = utils.nms(bboxes, 0.213, method='nms')
        # pred_bbox = pred_bbox.numpy()

        curr_time = time.time()
        exec_time = curr_time - prev_time
        #if i == 0: continue
        sum += (1 / exec_time)
        info = "FPS: " + str(round((1 / exec_time), 1))
        print(info)
        if cv2.waitKey(100) & 0xff == ord('q'):
            break


if __name__ == '__main__':
    try:
        app.run(main)
    except SystemExit:
        pass

FPS大概都在24左右
深度学习模型试跑(四):yolov4_第2张图片

你可能感兴趣的:(yolov4,trt)