当前位置: 首页 > news >正文

【YOLO系列】YOLOv3代码详解(四):模型脚本model.py

前言

        以下内容仅为个人在学习人工智能中所记录的笔记,先将目标识别算法yolo系列的整理出来分享给大家,供大家学习参考。

        本文仅对YOLOV3代码中关键部分进行了注释,未掌握基础代码的铁汁可以自己百度一下。

        若文中内容有误,希望大家批评指正。


资料下载

        YOLOV3论文下载地址:YOLOv3:An Incremental Improvement

回顾

        YOLO V1:【YOLO系列】YOLO V1论文思想详解

        YOLO V2:【YOLO系列】YOLO V2论文思想详解

        YOLO V3:【YOLO系列】 YOLOv3论文思想详解

项目地址

        YOLOV3 keras版本:下载地址

        YOLOV3 Tensorflow版本:下载地址

        YOLOV3 Pytorch版本:下载地址

Gitee仓库

        YOLOV3 各版本:yolov3各版本


YOLO V3代码详解

        YOLO V3代码详解(一):【YOLO系列】YOLOv3代码详解(一):主脚本yolo_video.py

        YOLO V3代码详解(二):【YOLO系列】YOLOv3代码详解(二):检测脚本yolo.py

        YOLO V3代码详解(三):【YOLO系列】YOLOv3代码详解(三):训练脚本train.py


        本文主要基于keras版本进行讲解

        话不多说,直接上代码


一、代码详解

1、定义卷积神经网络函数

@wraps(Conv2D)
def DarknetConv2D(*args, **kwargs):"""Wrapper to set Darknet parameters for Convolution2D."""# 定义一个darknet_conv_kwargs字典,传递“kernel_regularizer”、“padding”参数darknet_conv_kwargs = {'kernel_regularizer': l2(5e-4)}# 如果输入的kwargs中定义了strides为(2,2),则padding模式为valid,否则为same模式darknet_conv_kwargs['padding'] = 'valid' if kwargs.get('strides') == (2, 2) else 'same'# 将输入的kwargs值更新到darknet_conv_kwargs字典中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字典no_bias_kwargs = {'use_bias': False}# 将传递里面的kwargs值更新到no_bias_kwargs字典中no_bias_kwargs.update(kwargs)# 返回一个组合函数,由DarknetConv2D、BN、LeakyRelu组成,LeakyRelu的alpha值为0.1,这意味着当输入值小于 0 时,输出为 0.1 倍的输入值;当输入值大于等于 0 时,输出为输入值本身。return compose(# 定义一个Conv2D层DarknetConv2D(*args, **no_bias_kwargs),BatchNormalization(),LeakyReLU(alpha=0.1))

2、定义残差结构块函数

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# 进行零填充# 第一个元组(1, 0)指定了垂直方向(或高度方向)的填充。1表示在顶部填充1行零,0表示在底部不填充。# 第二个元组(1, 0)指定了水平方向(或宽度方向)的填充。1表示在左侧填充1列零,0表示在右侧不填充。x = ZeroPadding2D(((1, 0), (1, 0)))(x)# 创建一个DarknetConv2D_BN_Leaky卷积层,其中包括卷积层(filters=num_filters, kernel_size=(3, 3),strides=(2, 2),padding="same")、归一化层BN、激活函数层LeakyRule# 这里strides=(2, 2),代替了池化的作用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

3、定义darknet_body()函数

def darknet_body(x):'''Darknent body having 52 Convolution2D layers'''# 创建一个DarknetConv2D_BN_Leaky卷积层,其中包括卷积层(filters=32, kernel_size=(3, 3),strides=(1, 1),padding="same")、归一化层BN、激活函数层LeakyRulex = DarknetConv2D_BN_Leaky(32, (3, 3))(x)# 残差结构,(输入,filter数量, 残差block数量)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

4、定义最后输出层的神经网络函数

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

5、定义输出倒数三个特征图函数

def yolo_body(inputs, num_anchors, num_classes):"""Create YOLO_V3 model CNN body in Keras."""darknet = Model(inputs, darknet_body(inputs))# 输出三个特征图# 输出层的最后计算,包括6个Conv2D_BN_Leaky层和1个Conv2D_linear层x, y1 = make_last_layers(darknet.output, 512, num_anchors * (num_classes + 5))# 最后一层输出层进行Conv2D_BN_Leaky层与上采样操作后,与第152层的输出拼接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))# 倒数第二层输出层进行Conv2D_BN_Leaky层与上采样操作后,与第92层的输出拼接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])

6、定义tiny model的输出特征图函数

def tiny_yolo_body(inputs, num_anchors, num_classes):"""在keras架构上创建一个tiny YOLOV3模型,由8个CNN层+6个池化层+上采样层(CNN+upsampling)+2个输出(2个CNN+2个Conv)构成,总共20层"""# 生成一个卷积组合x1,输入为inputs,由5个DarknetConv2D_BN_Leaky与4个池化层构成x1 = compose(# 创建一个DarknetConv2D_BN_Leaky卷积层,其中包括卷积层(filters=16, kernel_size=(3, 3),strides=(1, 1),padding="same")、归一化层BN、激活函数层LeakyRuleDarknetConv2D_BN_Leaky(16, (3, 3)),# 池化层,池化框尺寸为(2,2),步长为(2,2),表示特征图缩小4倍,即宽和高各缩小2倍;padding模式为same,'same'表示在输入特征图的边缘填充0,使得经过池化后,输出特征图的大小与输入特征图一致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,输入为x1,由3个DarknetConv2D_BN_Leaky与2个池化层构成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)# 生成一个预测层,输入为x2,由1个DarknetConv2D_BN_Leaky与1个卷积层构成,输出一个N*N*Anchor个数*(类别数量+5)的tensory1 = compose(DarknetConv2D_BN_Leaky(512, (3, 3)),DarknetConv2D(num_anchors * (num_classes + 5), (1, 1)))(x2)# 生成一个卷积组合x2,输入为x2,由1个DarknetConv2D_BN_Leaky与1个上采样层构成x2 = compose(DarknetConv2D_BN_Leaky(128, (1, 1)),UpSampling2D(2))(x2)# 将经过上采样的x2与x1拼接在一起,再1个DarknetConv2D_BN_Leaky层与1个卷积层,输出一个N*N*Anchor个数*(类别数量+5)的tensory2 = compose(Concatenate(),DarknetConv2D_BN_Leaky(256, (3, 3)),DarknetConv2D(num_anchors * (num_classes + 5), (1, 1)))([x2, x1])return Model(inputs, [y1, y2])

7、计算bbox坐标、置信度与类别概率

def yolo_head(feats, anchors, num_classes, input_shape, calc_loss=False):"""Convert final layer features to bounding box parameters.预测box的坐标,置信度与分类"""num_anchors = len(anchors)# 生成一个tensor,形状为(batch, height, width, num_anchors, box_params).anchors_tensor = K.reshape(K.constant(anchors), [1, 1, 1, num_anchors, 2])# 获取输出层的height, width的维度grid_shape = K.shape(feats)[1:3]# 绘制x、y坐标,y-height, x-width# K.arange(0, stop=grid_shape[0]) 表示生成一个0-(grid_shape[0]-1)的张量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, 5 + num_classes])# 这一步对应论文中Bounding box Prediction.同时做了归一化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_whreturn box_xy, box_wh, box_confidence, box_class_probs

8、修正bbox坐标

def yolo_correct_boxes(box_xy, box_wh, input_shape, image_shape):"""Get corrected boxes修正box的坐标将得到的特征图与原图相比,求出偏移量,修正box的坐标"""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))# 新生成一个以(input_shape / image_shape)中最小比例的尺寸图片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的坐标box_yx = (box_yx - offset) * scalebox_hw *= scalebox_mins = box_yx - (box_hw / 2.)box_maxes = box_yx + (box_hw / 2.)boxes = K.concatenate([box_mins[..., 0:1],  # y_minbox_mins[..., 1:2],  # x_minbox_maxes[..., 0:1],  # y_maxbox_maxes[..., 1:2]  # x_max])# Scale boxes back to original image shape.# 反归一化,求得box在输入图片的实际坐标值boxes *= K.concatenate([image_shape, image_shape])return boxes

9、预测box的坐标(x, y, w, h),置信度与分类(用于预测)

def yolo_boxes_and_scores(feats, anchors, num_classes, input_shape, image_shape):"""Process Conv layer outputfeats: 输出层,shape=(m,N,N,3,5+80)anchors: 输出层对应的Anchornum_classes:类别的数量input_shape: 特征图放大32倍的尺寸image_shape:输入图片的大小"""# 预测box的坐标(x, y, w, h),置信度与分类box_xy, box_wh, box_confidence, box_class_probs = yolo_head(feats,anchors, num_classes, input_shape)# 修正每个特征图中box的坐标boxes = yolo_correct_boxes(box_xy, box_wh, input_shape, image_shape)boxes = K.reshape(boxes, [-1, 4])# 计算每个box的置信度box_scores = box_confidence * box_class_probsbox_scores = K.reshape(box_scores, [-1, num_classes])return boxes, box_scores

10、评估函数()

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.yolo_outputs:输出层,shape=(m,N,N,3,5+80)anchors:Anchor Boxnum_classes:类别的数量image_shape:输入图像的尺寸max_boxes:box的最大数量score_threshold:预测分数的阈值iou_threshold:IOU的阈值"""# 将Anchor Box与输出层对应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# 将特征图尺寸放大32倍input_shape = K.shape(yolo_outputs[0])[1:3] * 32boxes = []box_scores = []for l in range(num_layers):# 计算输出的box与分值_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_thresholdmax_boxes_tensor = K.constant(max_boxes, dtype='int32')boxes_ = []scores_ = []classes_ = []for c in range(num_classes):# TODO: use keras backend instead of tf.# 将box_scores >= score_threshold的box,box score取出来class_boxes = tf.boolean_mask(boxes, mask[:, c])class_box_scores = tf.boolean_mask(box_scores[:, c], mask[:, c])# 非极大值抑制,去除IOU>iou_threshold的框nms_index = tf.image.non_max_suppression(class_boxes, class_box_scores, max_boxes_tensor, iou_threshold=iou_threshold)# 将剩下的class_boxes、class_box_scores、class取出来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') * cboxes_.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_

11、对GT框进行预处理

def preprocess_true_boxes(true_boxes, input_shape, anchors, num_classes):'''Preprocess true boxes to training input formatParameters----------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 32anchors: array, shape=(N, 2), whnum_classes: integerReturns-------y_true: list of array, shape like yolo_outputs, xywh are reletive value'''# 首先判断GT框中的class_id是否超过了类别的总数assert (true_boxes[..., 4] < num_classes).all(), 'class id must be less than num_classes'# 判断Anchor Box是否能分为3组,并指定每一组中Anchor Box的索引值# 这里对应原文中 作者选择了9种不同Anchor Box来对3种不同的尺度进行预测# 特征图较大的用较小的Anchor([0, 1, 2])去预测,特征图较小的用较大的Anchor([6, 7, 8])去预测num_layers = len(anchors) // 3  # default settinganchor_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')# 计算GT框的中心点左边与宽、高,boxes_xy.shape=(m, T, 2)=boxes_wh.shapeboxes_xy = (true_boxes[..., 0:2] + true_boxes[..., 2:4]) // 2boxes_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]# 生成倒数三层输出层的特征图大小(13,13),(26,26),(52,52)grid_shapes = [input_shape // {0: 32, 1: 16, 2: 8}[l] for l in range(num_layers)]# 创建倒数三层输出层的y_true零数组(m,13,13,3,5+80),(m,26,26,3,5+80),(m,52,52,3,5+80)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.# 在anchor box数组中增加一维,shape=(1, N, 2)anchors = np.expand_dims(anchors, 0)anchor_maxes = anchors / 2.anchor_mins = -anchor_maxes# 要求所有维度的第一维元素要>0,返回的数组为(1,n)的bool值valid_mask = boxes_wh[..., 0] > 0for b in range(m):# Discard zero rows.# 判断wh是否为0,若为0则跳过该轮循环, wh.shape=(1, 2)wh = boxes_wh[b, valid_mask[b]]if len(wh) == 0: continue# Expand dim to apply broadcasting.# 在倒数第二维增加一维,wh.shape=(1, 1, 2)wh = np.expand_dims(wh, -2)box_maxes = wh / 2.box_mins = -box_maxesintersect_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# 获取与GT IOU最大的anchor box,记为best anchorbest_anchor = np.argmax(iou, axis=-1)# 将这个IOU最大的anchor box对应的GT的y_true记为1for 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] = 1y_true[l][b, j, i, k, 5 + c] = 1return y_true

12、IOU计算

def box_iou(b1, b2):'''Return iou tensorParameters----------b1: tensor, shape=(i1,...,iN, 4), xywhb2: tensor, shape=(j, 4), xywhReturns-------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_halfb1_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_halfb2_maxes = b2_xy + b2_wh_halfintersect_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

13、损失计算

def yolo_loss(args, anchors, num_classes, ignore_thresh=.5, print_loss=False):"""Return yolo_loss tensorParameters----------yolo_outputs: list of tensor, the output of yolo_body or tiny_yolo_bodyy_true: list of array, the output of preprocess_true_boxesanchors: array, shape=(N, 2), whnum_classes: integerignore_thresh: float, the iou threshold whether to ignore object confidence lossReturns-------loss: tensor, shape=(1,)"""# 这个默认将Anchor Box分为3组num_layers = len(anchors) // 3  # default setting# 将前num_layers层(不含num_layers层)定义为输出层,yolo_outputs中输出的张量为(batch_size, height, width, channels)yolo_outputs = args[:num_layers]# 将后num_layers层定义为y_true层y_true = args[num_layers:]# 判断Anchor Box是否能分为3组,并指定每一组中Anchor Box的索引值# 这里对应原文中 作者选择了9种不同Anchor Box来对3种不同的尺度进行预测# 特征图较大的用较小的Anchor([0, 1, 2])去预测,特征图较小的用较大的Anchor([6, 7, 8])去预测anchor_mask = [[6, 7, 8], [3, 4, 5], [0, 1, 2]] if num_layers == 3 else [[3, 4, 5], [1, 2, 3]]# K.cast()函数用于将一个值从一个类型转换为另一个类型# K.shape(yolo_outputs[0])[1:3]表示获取yolo_outputs[0]的第二维与第三维的形状,即(height, width)的形状# 然后再将(height, width)的形状放大32倍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# 获取batch sizem = K.shape(yolo_outputs[0])[0]mf = K.cast(m, K.dtype(yolo_outputs[0]))for l in range(num_layers):# [...]: 用于表示多个冒号,通常用于多维数组的索引,这里代表取第5维:是否为物体object_mask = y_true[l][..., 4:5]# 获取物体正确的分类true_class_probs = y_true[l][..., 5:]# 计算图像的每个像素点坐标grid,输出层raw_pred,shape=(m, N, N, 3, 5+80),预测box的坐标(x, y, w, h),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.# 计算坐标xy偏差raw_true_xy = y_true[l][..., :2] * grid_shapes[l][::-1] - grid# 计算wh的偏移量raw_true_wh = K.log(y_true[l][..., 2:4] / anchors[anchor_mask[l]] * input_shape[::-1])# 当object_mask是物体的时候,返回raw_true_wh,不是物体返回K.zeros_like(raw_true_wh)=0数组raw_true_wh = K.switch(object_mask, raw_true_wh, K.zeros_like(raw_true_wh))  # avoid log(0)=-infbox_loss_scale = 2 - y_true[l][..., 2:3] * y_true[l][..., 3:4]# Find ignore mask, iterate over each of batch.# 创建一个与y_true[0] 相同数据类型的动态数组,初始大小为 1。ignore_mask = tf.TensorArray(K.dtype(y_true[0]), size=1, dynamic_size=True)# 将object_mask数据类型转为boolobject_mask_bool = K.cast(object_mask, 'bool')# 计算某个bbox与ground truth的重合度是否超过某个阈值,超过则不计入损失计算def loop_body(b, ignore_mask):# 取出是物体的box坐标true_box = tf.boolean_mask(y_true[l][b, ..., 0:4], object_mask_bool[b, ..., 0])# 计算预测框与GT框的IOU值iou = box_iou(pred_box[b], true_box)# 输出best_iou < ignore_thresh判断的0,1值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_maskclass_loss = object_mask * K.binary_crossentropy(true_class_probs, raw_pred[..., 5:], from_logits=True)xy_loss = K.sum(xy_loss) / mfwh_loss = K.sum(wh_loss) / mfconfidence_loss = K.sum(confidence_loss) / mfclass_loss = K.sum(class_loss) / mfloss += xy_loss + wh_loss + confidence_loss + class_lossif print_loss:loss = tf.Print(loss, [loss, xy_loss, wh_loss, confidence_loss, class_loss, K.sum(ignore_mask)], message='loss: ')return loss

相关文章:

【YOLO系列】YOLOv3代码详解(四):模型脚本model.py

前言 以下内容仅为个人在学习人工智能中所记录的笔记&#xff0c;先将目标识别算法yolo系列的整理出来分享给大家&#xff0c;供大家学习参考。 本文仅对YOLOV3代码中关键部分进行了注释&#xff0c;未掌握基础代码的铁汁可以自己百度一下。 若文中内容有误&#xff0c;希望大家…...

Elasticsearch可视化平台Kibana [ES系列] - 第498篇

历史文章&#xff08;文章累计490&#xff09; 《国内最全的Spring Boot系列之一》 《国内最全的Spring Boot系列之二》 《国内最全的Spring Boot系列之三》 《国内最全的Spring Boot系列之四》 《国内最全的Spring Boot系列之五》 《国内最全的Spring Boot系列之六》 全…...

Python深度学习029:pytorch中常用的模块或方法

PyTorch是一个广泛使用的深度学习库,提供了许多用于构建和训练神经网络的模块和方法。下面是一些PyTorch中常用的模块和方法的简要介绍: PyTorch常用模块和方法 torch 用途:PyTorch的基础模块,提供了多种数学运算功能。常用方法: torch.tensor():创建张量torch.randn():…...

MongoDB创建和查询视图(二)

目录 基于$lookup创建关联查询视图 创建带有默认字符序的视图 字符序 创建视图 视图中的字符序 基于$lookup创建关联查询视图 基于$lookup命令&#xff0c;通过集合的关联查询&#xff0c;用户可以创建基于两个集合的视图并查询视图数据。应用在构建查询时&#xff0c;无需…...

【MYSQL】MYSQL 的学习教程(七)之 慢 SQL 优化思

1. 慢 SQL 优化思路 慢查询日志记录慢 SQLexplain 分析 SQL 的执行计划profile 分析执行耗时Optimizer Trace 分析详情确定问题并采用相应的措施 1. 慢查询日志记录慢 SQL 如何定位慢SQL呢&#xff1f; 我们可以通过 慢查询日志 来查看慢 SQL。 ①&#xff1a;开启慢查询日志…...

iOS - 真机调试的新经验

文章目录 获取真机 UDIDPlease reconnect the device.iOS 开发者模式Fetching debug symbols 很久没有在真机运行 iOS 测试了&#xff0c;今天帮忙调试&#xff0c;发现很多东西都变了&#xff0c;有些东西也生疏了&#xff0c;在这里记录下。 获取真机 UDID 创建Profile 需要…...

thinkphp6.0的workerman在PHP8.0下报错

一、我先升级了thinkphp6.0到最新版本&#xff1a; composer update topthink/framework二、结果提示我composer版本过低&#xff0c;需要升级到2&#xff0c;于是我又升级了composer composer self-update 三、我又升级了workerman: composer require topthink/think-work…...

SQL语句分类

关系分类 SQL区分为三类关系 表 在数据库中存储&#xff0c;可以对其进行增删改查 视图 通过计算定义的关系&#xff0c;并不在数据库中存储&#xff0c;只在需要的使用进行构造 临时表 在执行查询或更新时由SQL程序临时构造的&#xff0c;处理结束后就会删除 语言分类 数据查询…...

C# Onnx yolov8 pokemon detection

目录 效果 模型信息 项目 代码 下载 C# Onnx yolov8 pokemon detectio 效果 模型信息 Model Properties ------------------------- date&#xff1a;2023-12-25T17:55:44.583431 author&#xff1a;Ultralytics task&#xff1a;detect license&#xff1a;AGPL-3.0 h…...

Flink电商实时数仓(六)

交易域支付成功事务事实表 从topic_db业务数据中筛选支付成功的数据从dwd_trade_order_detail主题中读取订单事实数据、LookUp字典表关联三张表形成支付成功宽表写入 Kafka 支付成功主题 执行步骤 设置ttl&#xff0c;通过Interval join实现左右流的状态管理获取下单明细数据…...

本地部署Jellyfin影音服务器并实现远程访问内网影音库

文章目录 1. 前言2. Jellyfin服务网站搭建2.1. Jellyfin下载和安装2.2. Jellyfin网页测试 3.本地网页发布3.1 cpolar的安装和注册3.2 Cpolar云端设置3.3 Cpolar本地设置 4.公网访问测试5. 结语 1. 前言 随着移动智能设备的普及&#xff0c;各种各样的使用需求也被开发出来&…...

【React Native】第一个Android应用

第一个Android应用 环境TIP开发工具环境及版本要求建议官方建议 安装 Android Studio首次安装模板选择安装 Android SDK配置 ANDROID_HOME 环境变量把一些工具目录添加到环境变量 Path[可选参数] 指定版本或项目模板 运行使用 Android 模拟器编译并运行 React Native 应用修改项…...

解决IOS transform rotate后文字无法显示,backface-visibility导致@click事件失效

问题一&#xff1a;IOS transform rotate后文字无法显示 网上搜到可以用backface-visibility:hidden来解决&#xff0c;这样做文字是出来了&#xff0c;但是click事件无效了。 问题二&#xff1a;backface-visibility导致click事件失效 在Vue中使用backface-visibility和cli…...

Nature | 大型语言模型(LLM)能够产生和发现新知识吗?

大型语言模型&#xff08;LLM&#xff09;是基于大量数据进行预训练的超大型深度学习模型。底层转换器是一组神经网络&#xff0c;这些神经网络由具有自注意力功能的编码器和解码器组成。编码器和解码器从一系列文本中提取含义&#xff0c;并理解其中的单词和短语之间的关系。通…...

多维时序 | MATLAB实CNN-Mutilhead-Attention卷积神经网络融合多头注意力机制多变量时间序列预测

多维时序 | MATLAB实CNN-Mutilhead-Attention卷积神经网络融合多头注意力机制多变量时间序列预测 目录 多维时序 | MATLAB实CNN-Mutilhead-Attention卷积神经网络融合多头注意力机制多变量时间序列预测预测效果基本介绍模型描述程序设计参考资料 预测效果 基本介绍 多维时序 | …...

Nature 新研究发布,GPT 驱动的机器人化学家能够自行设计和进行实验,这对科研意味着什么?

文章目录 前言揭秘Coscientist不到四分钟&#xff0c;设计并改进了程序能力越大&#xff0c;责任越大 前言 有消息称&#xff0c;AI 大模型 “化学家” 登 Nature 能够自制阿司匹林、对乙酰氨基酚、布洛芬&#xff0c;甚至连复杂的钯催化交叉偶联反应&#xff0c;也能完成。 …...

Ai画板原理

在创建时画板可以选择数量和排列方式 也可以采用这个图片左上的画板工具&#xff0c;选择画板在其他地方画框即可生成&#xff0c;同时可以在属性框中可以修改尺寸大小 选择全部重新排列可以进行创建时的布局...

【hacker送书第11期】Python数据分析从入门到精通

探索数据世界&#xff0c;揭示未来趋势 《Python数据分析从入门到精通》是你掌握Python数据分析的理想选择。本书深入讲解核心工具如pandas、matplotlib和numpy&#xff0c;助您轻松处理和理解复杂数据。 通过matplotlib、seaborn和创新的pyecharts&#xff0c;本书呈现生动直…...

华为OD机试 - 精准核酸检测(Java JS Python C)

在线OJ刷题 题目详情 - 精准核酸检测 - Hydro 题目描述 为了达到新冠疫情精准防控的需要,为了避免全员核酸检测带来的浪费,需要精准圈定可能被感染的人群。 现在根据传染病流调以及大数据分析,得到了每个人之间在时间、空间上是否存在轨迹交叉。 现在给定一组确诊人员编…...

智能优化算法应用:基于材料生成算法3D无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于材料生成算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于材料生成算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.材料生成算法4.实验参数设定5.算法结果6.…...

【MySQL】:超详细MySQL完整安装和配置教程

&#x1f3a5; 屿小夏 &#xff1a; 个人主页 &#x1f525;个人专栏 &#xff1a; MySQL从入门到进阶 &#x1f304; 莫道桑榆晚&#xff0c;为霞尚满天&#xff01; 文章目录 &#x1f4d1;前言一. MySQL数据库1.1 版本1.2 下载1.3 安装1.4 客户端连接 &#x1f324;️全篇总…...

OpenAI亲授ChatGPT “屠龙术”!官方Prompt 工程指南来啦

应该如何形容 Prompt 工程呢&#xff1f;对于一个最开始使用 ChatGPT 的新人小白&#xff0c;面对据说参数量千亿万亿的庞然巨兽&#xff0c;Prompt 神秘的似乎像某种献祭&#xff1a;我扔进去几句话&#xff0c;等待聊天窗口后的“智慧生命”给我以神谕。 然而&#xff0c;上…...

最新ChatGPT商业运营网站程序源码,支持Midjourney绘画,GPT语音对话+DALL-E3文生图+文档对话总结

一、前言 SparkAi创作系统是基于ChatGPT进行开发的Ai智能问答系统和Midjourney绘画系统&#xff0c;支持OpenAI-GPT全模型国内AI全模型。本期针对源码系统整体测试下来非常完美&#xff0c;可以说SparkAi是目前国内一款的ChatGPT对接OpenAI软件系统。那么如何搭建部署AI创作Ch…...

经验 | IDEA常用快捷键

1、编辑&#xff08;Editing&#xff09; Ctrl Space 基本的代码完成&#xff08;类、方法、属性&#xff09; Ctrl Alt Space 快速导入任意类 Ctrl Shift Enter 语句完成 Ctrl P 参数信息&#xff08;在方法中调用参数&#xff09; Ctrl Q 快速查看文档 Shift F…...

spark中 write.csv时, 添加第一行的标题title

在 Spark 中使用 write.csv 写入 CSV 文件时&#xff0c;默认情况下是不会在文件中添加标题行的。但是&#xff0c;你可以通过设置 header 选项来控制是否包含标题行。 下面是一个示例&#xff1a; val data Seq((1, "John", 28),(2, "Alice", 22),(3, …...

HTML美化网页

使用CSS3美化的原因 用css美化页面文本,使页面漂亮、美观、吸引用户 可以更好的突出页面的主题内容,使用户第一眼可以看到页面主要内容 具有良好的用户体验 <span>标签 作用 能让某几个文字或者某个词语凸显出来 有效的传递页面信息用css美化页面文本&#xff0c;使页面漂…...

nn.LSTM个人记录

简介 nn.LSTM参数 torch.nn.lstm(input_size, "输入的嵌入向量维度&#xff0c;例如每个单词用50维向量表示&#xff0c;input_size就是50"hidden_size, "隐藏层节点数量,也是输出的嵌入向量维度"num_layers, "lstm 隐层的层数&#xff0c;默认…...

vr虚拟高压电器三维仿真展示更立体全面

VR工业虚拟仿真软件的应用价值主要体现在以下几个方面&#xff1a; 降低成本&#xff1a;通过VR技术进行产品设计和开发&#xff0c;可以在虚拟环境中进行&#xff0c;从而减少对物理样机的依赖&#xff0c;降低试错成本和时间。此外&#xff0c;利用VR技术构建的模拟场景使用方…...

轮廓平滑方法

目录 1. 形态学操作 2. 边缘平滑化 3. 轮廓近似 python 有回归线平滑 2D 轮廓 1. 形态学操作 利用形态学操作&#xff08;例如腐蚀、膨胀、开运算、闭运算等&#xff09;可以使分割边界更加平滑和连续。腐蚀可以消除小的不连续区域&#xff0c;膨胀可以填充空洞&#xff0…...

十大VSCODE 插件推荐2023

1、海鲸AI 插件链接&#xff1a;ChatGPT GPT-4 - 海鲸AI - Visual Studio Marketplace 包含了ChatGPT(3.5/4.0)等多个AI模型。可以实现代码优化&#xff0c;代码解读&#xff0c;代码bug修复等功能&#xff0c;反应迅捷&#xff0c;体验出色&#xff0c;是一个多功能的AI插件…...

HBase 集群搭建

文章目录 安装前准备兼容性官方网址 集群搭建搭建 Hadoop 集群搭建 Zookeeper 集群解压缩安装配置文件高可用配置分发 HBase 文件 服务的启停启动顺序停止顺序 验证进程查看 Web 端页面 安装前准备 兼容性 1&#xff09;与 Zookeeper 的兼容性问题&#xff0c;越新越好&#…...

大三了,C++还算可以从事什么岗位比较好?

大三了&#xff0c;C还算可以从事什么岗位比较好&#xff1f; 在开始前我有一些资料&#xff0c;是我根据自己从业十年经验&#xff0c;熬夜搞了几个通宵&#xff0c;精心整理了一份「c的资料从专业入门到高级教程工具包」&#xff0c;点个关注&#xff0c;全部无偿共享给大家…...

java 贪吃蛇游戏

前言 此实现较为简陋&#xff0c;如有错误请指正。 其次代码中的图片需要自行添加地址并修改。 主类 public class Main { public static void main(String[] args) { new myGame(); } } 1 2 3 4 5 游戏类 import javax.swing.*; import java.awt.eve…...

聊聊Java算法的时间复杂度

参考 o(1), o(n), o(logn), o(nlogn)_o&#xff08;1&#xff09;-CSDN博客算法时间复杂度的表示法O(n)、O(n)、O(1)、O(nlogn)等是什么意思&#xff1f;-CSDN博客 在描述算法复杂度时,经常用到o(1), o(n), o(logn), o(nlogn)来表示对应算法的时间复杂度, 这里进行归纳一下它…...

hive中array相关函数总结

目录 hive官方函数解释示例实战 hive官方函数解释 hive官网函数大全地址&#xff1a; hive官网函数大全地址 Return TypeNameDescriptionarrayarray(value1, value2, …)Creates an array with the given elements.booleanarray_contains(Array, value)Returns TRUE if the a…...

年终盘点文生图的狂飙之路,2023年文生图卷到什么程度了?

目录 前言发展1月2月3月4月5月6月7月9月10月11月12月 思考与总结参考文献 前言 说到文生图&#xff0c;可能有些人不清楚&#xff0c;但要说AI绘画&#xff0c;就有很多人直呼&#xff1a; 2022可以说是AI绘图大爆发的元年。 AI绘画模型可以分为扩散模型&#xff08;Diffusio…...

C++:list增删查改模拟实现

C:list增删查改模拟实现 前言一、list底层双链表验证、节点构造1.1 list底层数据结构1. 2 节点构造 二、迭代器封装实现&#xff08;重点、难点&#xff09;2.1 前置说明2.2 迭代器实现 三、list实现3.1 基本框架3.2 迭代器和const迭代器3.2 构造函数、析构函数、拷贝构造、赋值…...

基于阿里云服务网格流量泳道的全链路流量管理(二):宽松模式流量泳道

作者&#xff1a;尹航 在前文基于阿里云服务网格流量泳道的全链路流量管理&#xff08;一&#xff09;&#xff1a;严格模式流量泳道中&#xff0c;我们介绍了使用服务网格 ASM 的严格模式流量泳道进行全链路灰度管理的使用场景。该模式对于应用程序无任何要求&#xff0c;只需…...

ubuntu 18.04 共享屏幕

用于windows远程ubuntu 1. sudo apt install xrdp 2. 配置 sudo vim /etc/xrdp/startwm.sh 把最下面的test和exec两行注释掉&#xff0c;添加一行 gnome-session 3.安装dconf-editor : sudo apt-get install dconf-editor 关闭require encrytion org->gnome->desktop…...

第十三节TypeScript 元组

1、简介 我们知道数组中元素的数据类型一般都是相同的&#xff08;any[]类型的数组可以不同&#xff09;&#xff0c;如果存储的元素类型不同&#xff0c;则需要使用元组。 元组中允许存储不同类型的元素&#xff0c;元组可以作为参数传递给函数。2、创建元组的语法格式&#x…...

基于Java (spring-boot)的仓库管理系统

一、项目介绍 本系统的使用者一共有系统管理员、仓库管理员和普通用户这3种角色: 1.系统管理员&#xff1a;通过登录系统后&#xff0c;可以进行管理员和用户信息的管理、仓库和物品分类的管理&#xff0c;以及操作日志的查询&#xff0c;具有全面的系统管理权限。 2.仓库管理…...

SQL面试题挑战06:互相关注的人

目录 问题&#xff1a;SQL解答&#xff1a; 问题&#xff1a; 现在有一张relation表&#xff0c;里面只有两个字段&#xff1a;from_user和to_user&#xff0c;代表关注关系从from指向to&#xff0c;即from_user关注了to_user。现在要找出互相关注的所有人。 from_user to_…...

LSTM和GRU的区别

LSTM&#xff08;Long Short-Term Memory&#xff09;和GRU&#xff08;Gated Recurrent Unit&#xff09;都是循环神经网络&#xff08;RNN&#xff09;的变体&#xff0c;旨在解决传统RNN中的梯度消失和梯度爆炸的问题&#xff0c;使网络能够更好地处理长期依赖关系。 以下是…...

算法基础之数字三角形

数字三角形 核心思想&#xff1a;线性dp 集合的定义为 f[i][j] –> 到i j点的最大距离 从下往上传值 父节点f[i][j] max(f[i1][j] , f[i1][j1]) w[i][j] 初始化最后一层 f w #include <bits/stdc.h>using namespace std;const int N 510;int w[N][N],f[N][…...

蓝桥杯宝藏排序题目算法(冒泡、选择、插入)

冒泡排序: def bubble_sort(li): # 函数方式for i in range(len(li)-1):exchangeFalsefor j in range(len(li)-i-1):if li[j]>li[j1]:li[j],li[j1]li[j1],li[j]exchangeTrueif not exchange:return 选择排序: 从左往右找到最小的元素&#xff0c;放在起始位置…...

如何使用Docker部署Dashy并无公网ip远程访问管理界面

文章目录 简介1. 安装Dashy2. 安装cpolar3.配置公网访问地址4. 固定域名访问 简介 Dashy 是一个开源的自托管的导航页配置服务&#xff0c;具有易于使用的可视化编辑器、状态检查、小工具和主题等功能。你可以将自己常用的一些网站聚合起来放在一起&#xff0c;形成自己的导航…...

【接口测试】如何定位BUG的产生原因

我们从在日常功能测试过程中对UI的每一次操作说白了就是对一个或者多个接口的一次调用&#xff0c;接口的返回的内容(移动端一般为json)经过前端代码的处理最终展示在页面上。http接口是离我们最近的一层接口&#xff0c;web端和移动端所展示的数据就来自于这层&#xff0c;那么…...

JavaScript 中的短路求值(if语句简洁写法--逻辑运算符||和的高级用法)

在JavaScript中&#xff0c;Short-Circuit Evaluation&#xff08;短路求值&#xff09;是一种逻辑运算的行为&#xff0c;其中表达式的求值在达到不必要的部分时就提前终止&#xff08;所以短路一词非常贴切&#xff09;。这种行为可以通过逻辑运算符&#xff08;例如&&am…...

普本毕业,还有逆风翻盘的机会吗?

作为普通二本的本科生&#xff0c;从踏入大学开始&#xff0c;我一直在不断寻找自己感兴趣的行业和职业方向。 在这里&#xff0c;我想给大家分享一些我从校园走向工作整个学习和求职过程&#xff0c;以及其中的酸甜苦辣&#xff0c;希望这些经历可以给各位学弟学妹一些鼓励和…...

spark:RDD编程(Python版)

RDD运行原理 RDD设计背景 许多选代目前的MapReduce框架都是把中间结果写入到稳定存储 (比如磁盘)中带来了大量的数据复制、磁盘IO和序列化开销 RDD就是为了满足这种需求而出现的&#xff0c;它提供了一个抽象的数据架构&#xff0c;我们不必担心底层数据的分布式特性&#xf…...