DL之Yolov3:基于深度学习Yolov3算法实现视频目标检测之对《我要打篮球》视频段进行实时目标检测(二)

简介: DL之Yolov3:基于深度学习Yolov3算法实现视频目标检测之对《我要打篮球》视频段进行实时目标检测

2、model.py文件


     上边网络模型的代码定义,比如DarknetConv2D、DarknetConv2D_BN_Leaky、resblock_body、darknet_body、make_last_layers、yolo_body、yolo_head、yolo_eval等函数,其中preprocess_true_boxes()函数找出人工标定框GT框,通过计算候选框和GT框的IOU,才会找出best_abchor。

      可以参考网络模型图去理解。详见DL之Yolov3:基于深度学习Yolov3算法实现视频目标检测之对《我要打篮球》视频段进行实时目标检测 的model.py文件。


image.png"""YOLO_v3 Model Defined in Keras."""

from functools import wraps

import numpy as np

import tensorflow as tf

from keras import backend as K

from keras.layers import Conv2D, Add, ZeroPadding2D, UpSampling2D, Concatenate, MaxPooling2D

from keras.layers.advanced_activations import LeakyReLU

from keras.layers.normalization import BatchNormalization

from keras.models import Model

from keras.regularizers import l2

from yolo3.utils import compose

@wraps(Conv2D)

def DarknetConv2D(*args, **kwargs):

   """Wrapper to set Darknet parameters for Convolution2D."""

   darknet_conv_kwargs = {'kernel_regularizer': l2(5e-4)}

   darknet_conv_kwargs['padding'] = 'valid' if kwargs.get('strides')==(2,2) else 'same'

   darknet_conv_kwargs.update(kwargs)

   return Conv2D(*args, **darknet_conv_kwargs)

def DarknetConv2D_BN_Leaky(*args, **kwargs):

   """Darknet Convolution2D followed by BatchNormalization and LeakyReLU."""

   no_bias_kwargs = {'use_bias': False}

   no_bias_kwargs.update(kwargs)

   return compose(

       DarknetConv2D(*args, **no_bias_kwargs),

       BatchNormalization(),

       LeakyReLU(alpha=0.1))

def resblock_body(x, num_filters, num_blocks):

   '''A series of resblocks starting with a downsampling Convolution2D'''

   # Darknet uses left and top padding instead of 'same' mode

   x = ZeroPadding2D(((1,0),(1,0)))(x)

   x = DarknetConv2D_BN_Leaky(num_filters, (3,3), strides=(2,2))(x)

   for i in range(num_blocks):

       y = compose(

               DarknetConv2D_BN_Leaky(num_filters//2, (1,1)),

               DarknetConv2D_BN_Leaky(num_filters, (3,3)))(x)

       x = Add()([x,y])

   return x

def darknet_body(x):

   '''Darknent body having 52 Convolution2D layers'''

   x = DarknetConv2D_BN_Leaky(32, (3,3))(x)

   x = resblock_body(x, 64, 1)

   x = resblock_body(x, 128, 2)

   x = resblock_body(x, 256, 8)

   x = resblock_body(x, 512, 8)

   x = resblock_body(x, 1024, 4)

   return x

def make_last_layers(x, num_filters, out_filters):

   '''6 Conv2D_BN_Leaky layers followed by a Conv2D_linear layer'''

   x = compose(

           DarknetConv2D_BN_Leaky(num_filters, (1,1)),

           DarknetConv2D_BN_Leaky(num_filters*2, (3,3)),

           DarknetConv2D_BN_Leaky(num_filters, (1,1)),

           DarknetConv2D_BN_Leaky(num_filters*2, (3,3)),

           DarknetConv2D_BN_Leaky(num_filters, (1,1)))(x)

   y = compose(

           DarknetConv2D_BN_Leaky(num_filters*2, (3,3)),

           DarknetConv2D(out_filters, (1,1)))(x)

   return x, y

def yolo_body(inputs, num_anchors, num_classes):

   """Create YOLO_V3 model CNN body in Keras."""

   darknet = Model(inputs, darknet_body(inputs))

   x, y1 = make_last_layers(darknet.output, 512, num_anchors*(num_classes+5))

   x = compose(

           DarknetConv2D_BN_Leaky(256, (1,1)),

           UpSampling2D(2))(x)

   x = Concatenate()([x,darknet.layers[152].output])

   x, y2 = make_last_layers(x, 256, num_anchors*(num_classes+5))

   x = compose(

           DarknetConv2D_BN_Leaky(128, (1,1)),

           UpSampling2D(2))(x)

   x = Concatenate()([x,darknet.layers[92].output])

   x, y3 = make_last_layers(x, 128, num_anchors*(num_classes+5))

   return Model(inputs, [y1,y2,y3])

def tiny_yolo_body(inputs, num_anchors, num_classes):

   '''Create Tiny YOLO_v3 model CNN body in keras.'''

   x1 = compose(

           DarknetConv2D_BN_Leaky(16, (3,3)),

           MaxPooling2D(pool_size=(2,2), strides=(2,2), padding='same'),

           DarknetConv2D_BN_Leaky(32, (3,3)),

           MaxPooling2D(pool_size=(2,2), strides=(2,2), padding='same'),

           DarknetConv2D_BN_Leaky(64, (3,3)),

           MaxPooling2D(pool_size=(2,2), strides=(2,2), padding='same'),

           DarknetConv2D_BN_Leaky(128, (3,3)),

           MaxPooling2D(pool_size=(2,2), strides=(2,2), padding='same'),

           DarknetConv2D_BN_Leaky(256, (3,3)))(inputs)

   x2 = compose(

           MaxPooling2D(pool_size=(2,2), strides=(2,2), padding='same'),

           DarknetConv2D_BN_Leaky(512, (3,3)),

           MaxPooling2D(pool_size=(2,2), strides=(1,1), padding='same'),

           DarknetConv2D_BN_Leaky(1024, (3,3)),

           DarknetConv2D_BN_Leaky(256, (1,1)))(x1)

   y1 = compose(

           DarknetConv2D_BN_Leaky(512, (3,3)),

           DarknetConv2D(num_anchors*(num_classes+5), (1,1)))(x2)

   x2 = compose(

           DarknetConv2D_BN_Leaky(128, (1,1)),

           UpSampling2D(2))(x2)

   y2 = compose(

           Concatenate(),

           DarknetConv2D_BN_Leaky(256, (3,3)),

           DarknetConv2D(num_anchors*(num_classes+5), (1,1)))([x2,x1])

   return Model(inputs, [y1,y2])

def yolo_head(feats, anchors, num_classes, input_shape, calc_loss=False):

   """Convert final layer features to bounding box parameters."""

   num_anchors = len(anchors)

   # Reshape to batch, height, width, num_anchors, box_params.

   anchors_tensor = K.reshape(K.constant(anchors), [1, 1, 1, num_anchors, 2])

   grid_shape = K.shape(feats)[1:3] # height, width

   grid_y = K.tile(K.reshape(K.arange(0, stop=grid_shape[0]), [-1, 1, 1, 1]),

       [1, grid_shape[1], 1, 1])

   grid_x = K.tile(K.reshape(K.arange(0, stop=grid_shape[1]), [1, -1, 1, 1]),

       [grid_shape[0], 1, 1, 1])

   grid = K.concatenate([grid_x, grid_y])

   grid = K.cast(grid, K.dtype(feats))

   feats = K.reshape(

       feats, [-1, grid_shape[0], grid_shape[1], num_anchors, num_classes + 5])

   # Adjust preditions to each spatial grid point and anchor size.

   box_xy = (K.sigmoid(feats[..., :2]) + grid) / K.cast(grid_shape[::-1], K.dtype(feats))

   box_wh = K.exp(feats[..., 2:4]) * anchors_tensor / K.cast(input_shape[::-1], K.dtype(feats))

   box_confidence = K.sigmoid(feats[..., 4:5])

   box_class_probs = K.sigmoid(feats[..., 5:])

   if calc_loss == True:

       return grid, feats, box_xy, box_wh

   return box_xy, box_wh, box_confidence, box_class_probs

def yolo_correct_boxes(box_xy, box_wh, input_shape, image_shape):

   '''Get corrected boxes'''

   box_yx = box_xy[..., ::-1]

   box_hw = box_wh[..., ::-1]

   input_shape = K.cast(input_shape, K.dtype(box_yx))

   image_shape = K.cast(image_shape, K.dtype(box_yx))

   new_shape = K.round(image_shape * K.min(input_shape/image_shape))

   offset = (input_shape-new_shape)/2./input_shape

   scale = input_shape/new_shape

   box_yx = (box_yx - offset) * scale

   box_hw *= scale

   box_mins = box_yx - (box_hw / 2.)

   box_maxes = box_yx + (box_hw / 2.)

   boxes =  K.concatenate([

       box_mins[..., 0:1],  # y_min

       box_mins[..., 1:2],  # x_min

       box_maxes[..., 0:1],  # y_max

       box_maxes[..., 1:2]  # x_max

   ])

   # Scale boxes back to original image shape.

   boxes *= K.concatenate([image_shape, image_shape])

   return boxes

def yolo_boxes_and_scores(feats, anchors, num_classes, input_shape, image_shape):

   '''Process Conv layer output'''

   box_xy, box_wh, box_confidence, box_class_probs = yolo_head(feats,

       anchors, num_classes, input_shape)

   boxes = yolo_correct_boxes(box_xy, box_wh, input_shape, image_shape)

   boxes = K.reshape(boxes, [-1, 4])

   box_scores = box_confidence * box_class_probs

   box_scores = K.reshape(box_scores, [-1, num_classes])

   return boxes, box_scores

def yolo_eval(yolo_outputs,

             anchors,

             num_classes,

             image_shape,

             max_boxes=20,

             score_threshold=.6,

             iou_threshold=.5):

   """Evaluate YOLO model on given input and return filtered boxes."""

   num_layers = len(yolo_outputs)

   anchor_mask = [[6,7,8], [3,4,5], [0,1,2]] if num_layers==3 else [[3,4,5], [1,2,3]] # default setting

   input_shape = K.shape(yolo_outputs[0])[1:3] * 32

   boxes = []

   box_scores = []

   for l in range(num_layers):

       _boxes, _box_scores = yolo_boxes_and_scores(yolo_outputs[l],

           anchors[anchor_mask[l]], num_classes, input_shape, image_shape)

       boxes.append(_boxes)

       box_scores.append(_box_scores)

   boxes = K.concatenate(boxes, axis=0)

   box_scores = K.concatenate(box_scores, axis=0)

   mask = box_scores >= score_threshold

   max_boxes_tensor = K.constant(max_boxes, dtype='int32')

   boxes_ = []

   scores_ = []

   classes_ = []

   for c in range(num_classes):

       # TODO: use keras backend instead of tf.

       class_boxes = tf.boolean_mask(boxes, mask[:, c])

       class_box_scores = tf.boolean_mask(box_scores[:, c], mask[:, c])

       nms_index = tf.image.non_max_suppression(

           class_boxes, class_box_scores, max_boxes_tensor, iou_threshold=iou_threshold)

       class_boxes = K.gather(class_boxes, nms_index)

       class_box_scores = K.gather(class_box_scores, nms_index)

       classes = K.ones_like(class_box_scores, 'int32') * c

       boxes_.append(class_boxes)

       scores_.append(class_box_scores)

       classes_.append(classes)

   boxes_ = K.concatenate(boxes_, axis=0)

   scores_ = K.concatenate(scores_, axis=0)

   classes_ = K.concatenate(classes_, axis=0)

   return boxes_, scores_, classes_

def preprocess_true_boxes(true_boxes, input_shape, anchors, num_classes):

   '''Preprocess true boxes to training input format

   Parameters

   ----------

   true_boxes: array, shape=(m, T, 5)

       Absolute x_min, y_min, x_max, y_max, class_id relative to input_shape.

   input_shape: array-like, hw, multiples of 32

   anchors: array, shape=(N, 2), wh

   num_classes: integer

   Returns

   -------

   y_true: list of array, shape like yolo_outputs, xywh are reletive value

   '''

   assert (true_boxes[..., 4]<num_classes).all(), 'class id must be less than num_classes'

   num_layers = len(anchors)//3 # default setting

   anchor_mask = [[6,7,8], [3,4,5], [0,1,2]] if num_layers==3 else [[3,4,5], [1,2,3]]

   true_boxes = np.array(true_boxes, dtype='float32')

   input_shape = np.array(input_shape, dtype='int32')

   boxes_xy = (true_boxes[..., 0:2] + true_boxes[..., 2:4]) // 2

   boxes_wh = true_boxes[..., 2:4] - true_boxes[..., 0:2]

   true_boxes[..., 0:2] = boxes_xy/input_shape[::-1]

   true_boxes[..., 2:4] = boxes_wh/input_shape[::-1]

   m = true_boxes.shape[0]

   grid_shapes = [input_shape//{0:32, 1:16, 2:8}[l] for l in range(num_layers)]

   y_true = [np.zeros((m,grid_shapes[l][0],grid_shapes[l][1],len(anchor_mask[l]),5+num_classes),

       dtype='float32') for l in range(num_layers)]

   # Expand dim to apply broadcasting.

   anchors = np.expand_dims(anchors, 0)

   anchor_maxes = anchors / 2.

   anchor_mins = -anchor_maxes

   valid_mask = boxes_wh[..., 0]>0

   for b in range(m):

       # Discard zero rows.

       wh = boxes_wh[b, valid_mask[b]]

       if len(wh)==0: continue

       # Expand dim to apply broadcasting.

       wh = np.expand_dims(wh, -2)

       box_maxes = wh / 2.

       box_mins = -box_maxes

       intersect_mins = np.maximum(box_mins, anchor_mins)

       intersect_maxes = np.minimum(box_maxes, anchor_maxes)

       intersect_wh = np.maximum(intersect_maxes - intersect_mins, 0.)

       intersect_area = intersect_wh[..., 0] * intersect_wh[..., 1]

       box_area = wh[..., 0] * wh[..., 1]

       anchor_area = anchors[..., 0] * anchors[..., 1]

       iou = intersect_area / (box_area + anchor_area - intersect_area)

       # Find best anchor for each true box

       best_anchor = np.argmax(iou, axis=-1)

       for t, n in enumerate(best_anchor):

           for l in range(num_layers):

               if n in anchor_mask[l]:

                   i = np.floor(true_boxes[b,t,0]*grid_shapes[l][1]).astype('int32')

                   j = np.floor(true_boxes[b,t,1]*grid_shapes[l][0]).astype('int32')

                   k = anchor_mask[l].index(n)

                   c = true_boxes[b,t, 4].astype('int32')

                   y_true[l][b, j, i, k, 0:4] = true_boxes[b,t, 0:4]

                   y_true[l][b, j, i, k, 4] = 1

                   y_true[l][b, j, i, k, 5+c] = 1

   return y_true

def box_iou(b1, b2):

   '''Return iou tensor

   Parameters

   ----------

   b1: tensor, shape=(i1,...,iN, 4), xywh

   b2: tensor, shape=(j, 4), xywh

   Returns

   -------

   iou: tensor, shape=(i1,...,iN, j)

   '''

   # Expand dim to apply broadcasting.

   b1 = K.expand_dims(b1, -2)

   b1_xy = b1[..., :2]

   b1_wh = b1[..., 2:4]

   b1_wh_half = b1_wh/2.

   b1_mins = b1_xy - b1_wh_half

   b1_maxes = b1_xy + b1_wh_half

   # Expand dim to apply broadcasting.

   b2 = K.expand_dims(b2, 0)

   b2_xy = b2[..., :2]

   b2_wh = b2[..., 2:4]

   b2_wh_half = b2_wh/2.

   b2_mins = b2_xy - b2_wh_half

   b2_maxes = b2_xy + b2_wh_half

   intersect_mins = K.maximum(b1_mins, b2_mins)

   intersect_maxes = K.minimum(b1_maxes, b2_maxes)

   intersect_wh = K.maximum(intersect_maxes - intersect_mins, 0.)

   intersect_area = intersect_wh[..., 0] * intersect_wh[..., 1]

   b1_area = b1_wh[..., 0] * b1_wh[..., 1]

   b2_area = b2_wh[..., 0] * b2_wh[..., 1]

   iou = intersect_area / (b1_area + b2_area - intersect_area)

   return iou

def yolo_loss(args, anchors, num_classes, ignore_thresh=.5, print_loss=False):

   '''Return yolo_loss tensor

   Parameters

   ----------

   yolo_outputs: list of tensor, the output of yolo_body or tiny_yolo_body

   y_true: list of array, the output of preprocess_true_boxes

   anchors: array, shape=(N, 2), wh

   num_classes: integer

   ignore_thresh: float, the iou threshold whether to ignore object confidence loss

   Returns

   -------

   loss: tensor, shape=(1,)

   '''

   num_layers = len(anchors)//3 # default setting

   yolo_outputs = args[:num_layers]

   y_true = args[num_layers:]

   anchor_mask = [[6,7,8], [3,4,5], [0,1,2]] if num_layers==3 else [[3,4,5], [1,2,3]]

   input_shape = K.cast(K.shape(yolo_outputs[0])[1:3] * 32, K.dtype(y_true[0]))

   grid_shapes = [K.cast(K.shape(yolo_outputs[l])[1:3], K.dtype(y_true[0])) for l in range(num_layers)]

   loss = 0

   m = K.shape(yolo_outputs[0])[0] # batch size, tensor

   mf = K.cast(m, K.dtype(yolo_outputs[0]))

   for l in range(num_layers):

       object_mask = y_true[l][..., 4:5]

       true_class_probs = y_true[l][..., 5:]

       grid, raw_pred, pred_xy, pred_wh = yolo_head(yolo_outputs[l],

            anchors[anchor_mask[l]], num_classes, input_shape, calc_loss=True)

       pred_box = K.concatenate([pred_xy, pred_wh])

       # Darknet raw box to calculate loss.

       raw_true_xy = y_true[l][..., :2]*grid_shapes[l][::-1] - grid

       raw_true_wh = K.log(y_true[l][..., 2:4] / anchors[anchor_mask[l]] * input_shape[::-1])

       raw_true_wh = K.switch(object_mask, raw_true_wh, K.zeros_like(raw_true_wh)) # avoid log(0)=-inf

       box_loss_scale = 2 - y_true[l][...,2:3]*y_true[l][...,3:4]

       # Find ignore mask, iterate over each of batch.

       ignore_mask = tf.TensorArray(K.dtype(y_true[0]), size=1, dynamic_size=True)

       object_mask_bool = K.cast(object_mask, 'bool')

       def loop_body(b, ignore_mask):

           true_box = tf.boolean_mask(y_true[l][b,...,0:4], object_mask_bool[b,...,0])

           iou = box_iou(pred_box[b], true_box)

           best_iou = K.max(iou, axis=-1)

           ignore_mask = ignore_mask.write(b, K.cast(best_iou<ignore_thresh, K.dtype(true_box)))

           return b+1, ignore_mask

       _, ignore_mask = K.control_flow_ops.while_loop(lambda b,*args: b<m, loop_body, [0, ignore_mask])

       ignore_mask = ignore_mask.stack()

       ignore_mask = K.expand_dims(ignore_mask, -1)

       # K.binary_crossentropy is helpful to avoid exp overflow.

       xy_loss = object_mask * box_loss_scale * K.binary_crossentropy(raw_true_xy, raw_pred[...,0:2], from_logits=True)

       wh_loss = object_mask * box_loss_scale * 0.5 * K.square(raw_true_wh-raw_pred[...,2:4])

       confidence_loss = object_mask * K.binary_crossentropy(object_mask, raw_pred[...,4:5], from_logits=True)+ \

           (1-object_mask) * K.binary_crossentropy(object_mask, raw_pred[...,4:5], from_logits=True) * ignore_mask

       class_loss = object_mask * K.binary_crossentropy(true_class_probs, raw_pred[...,5:], from_logits=True)

       xy_loss = K.sum(xy_loss) / mf

       wh_loss = K.sum(wh_loss) / mf

       confidence_loss = K.sum(confidence_loss) / mf

       class_loss = K.sum(class_loss) / mf

       loss += xy_loss + wh_loss + confidence_loss + class_loss

       if print_loss:

           loss = tf.Print(loss, [loss, xy_loss, wh_loss, confidence_loss, class_loss, K.sum(ignore_mask)], message='loss: ')

   return loss


相关文章
|
22天前
|
算法 数据可视化
【视频】Copula算法原理和R语言股市收益率相依性可视化分析-3
【视频】Copula算法原理和R语言股市收益率相依性可视化分析
|
21天前
|
算法 数据可视化
【视频】Copula算法原理和R语言股市收益率相依性可视化分析(下)
【视频】Copula算法原理和R语言股市收益率相依性可视化分析
|
6天前
|
机器学习/深度学习 算法 调度
深度学习|改进两阶段鲁棒优化算法i-ccg
深度学习|改进两阶段鲁棒优化算法i-ccg
|
1天前
|
算法 计算机视觉
基于高斯混合模型的视频背景提取和人员跟踪算法matlab仿真
该内容是关于使用MATLAB2013B实现基于高斯混合模型(GMM)的视频背景提取和人员跟踪算法。算法通过GMM建立背景模型,新帧与模型比较,提取前景并进行人员跟踪。文章附有程序代码示例,展示从读取视频到结果显示的流程。最后,结果保存在Result.mat文件中。
|
6天前
|
算法
视频讲解|基于多目标粒子群算法的配电网储能选址定容
视频讲解|基于多目标粒子群算法的配电网储能选址定容
|
6天前
|
机器学习/深度学习 自然语言处理 算法
深度学习算法简介(二)
深度学习算法简介(二)
|
6天前
|
机器学习/深度学习 自然语言处理 算法
深度学习算法简介(一)
深度学习算法简介(一)
|
15天前
|
机器学习/深度学习 算法 数据挖掘
【视频】支持向量机算法原理和Python用户流失数据挖掘SVM实例(下)
【视频】支持向量机算法原理和Python用户流失数据挖掘SVM实例(下)
|
15天前
|
机器学习/深度学习 算法 搜索推荐
【视频】支持向量机算法原理和Python用户流失数据挖掘SVM实例(上)
【视频】支持向量机算法原理和Python用户流失数据挖掘SVM实例
|
16天前
|
机器学习/深度学习 存储 编解码
利用深度学习优化视频压缩算法
【4月更文挑战第28天】随着数字媒体时代的到来,视频数据量急剧增加,有效的视频压缩技术变得尤为重要。本文探讨了一种基于深度学习的视频压缩框架,旨在提高压缩效率同时保持较高的视频质量。通过使用卷积神经网络(CNN)对视频帧进行特征提取,并结合先进的编码技术,本研究提出了一种新的率失真优化算法。实验结果表明,该算法在多个标准测试序列上相比传统方法能显著降低比特率,同时维持了良好的视觉质量。