IoU就是就是我们说的交并比 Intersection over Union ,具体就是两个box的交集除以并集。

当我们计算我们的anchors 或者 proposals 与 ground truth bounding boxes 的损失的时候,就需要用到IoU。不同的IoU有不同的特性。

IoU loss:

IoU计算了最简单的情况:



IoU的损失函数公式:至于求loss为啥用1减去,是因为:iou越大 代表拟合效果越好,我们应让模型的loss越小。iou最大为1,也就是重合的情况。因此用1-IoU来代表loss。

\[Loss_{IoU}=1- IoU
\]

GIoU loss:

当两个anchor与gt box都不相交的时候,IoU的loss是一样大的,我们理论认为anchor距离gt box越近,loss应该越小,不应该一样大。这样GIoU就提出来了。GIoU通过计算两个box的最小闭包区域ac来计算loss。底色为红色的范围是Anchor2与Gt box的最小闭包区域,底色为黄色的范围是Anchor1与Gt box的最小闭包区域。明显Anchor2的最小闭包区域小,u代表并集,ac代表最小闭包区域,ac越大, \(L_{GIoU}\) 值越大。Anchor1的ac大,所以Anchor1的损失更高

\[L_{GIoU}=1- IoU+\frac{ac-u}{ac}
\]

DIoU loss:

黄色为proposal,蓝色为gt box。当propsals与gt box重叠时,我们认为下面的两种情况左边的效果好,因为它位于gt box中心。GIoU并不能解决这个问题,所以DIoU loss被提出来了,DIoU loss用,两个box中心点距离平方 除以 最小闭包区域对角线距离平方,来衡量预测的proposal是否位于gt box中心。

\[Loss_{DIoU}=1-(IoU+\frac{\rho^2 (b,b^{gt})}{c^2})
\]

CIoU loss:

当两个proposals都位于gt box中心时,我们还是认为坐标的效果比较好,因为左边的宽高比跟我们的gt box一致,所以CIoU loss在DIoU loss的基础上改进了宽高比。

\[Loss_{CIoU}=1-IoU+\frac{\rho^2 (b,b^{gt})}{c^2}+\alpha v
\]

v用来度量长宽比的相似性,\(\frac{4}{\pi^2}\)是作者感觉这个值取得的效果不错,就用了这个值。

\[v=\frac{4}{\pi^2}(arctan\frac{w^{gt}}{h^{gt}}-arctan\frac{w}{h}) ^2
\]

alpha是权重值,衡量ciou公式中第三项和第四项的权重,当IoU越大,alpha就越大,alpha大就优先考虑v; IoU越小时,alpha越小,alpha小优先考虑第三项,距离比。

\[\alpha=\frac{v}{(1-IoU)+v}
\]

Alpha-IoU loss:

Alpha-IoU loss主要是考虑IoU大于0.5的时候的梯度,因为在普通 \(L_{IoU}=1-IoU\) 中,IoU的梯度一直是-1。但是在Alpha-IoU loss中,当iou大于0.5的时候,loss的梯度是大于-1的,收敛的更快,在map0.7/map0.9有提升效果。

\[Loss_{\alpha-IoU}=1-IoU^{\alpha}
\]

\(\alpha>0\),当 \(\alpha=2,iou=0.6\) 时,\(L_{\alpha-IoU}\) 的梯度已经是-1.2了。训练时经验所得alpha取3比较好。

下面是常见的loss function的代码实现。

import torch
import math
import torch.nn.functional as F
# 放到编辑器里收缩每个方法,直接看main函数,然后再对应loss去看。
################################# 分类损失 ########################################
def BCE_loss(proposals, gt_boxes):
# 对所求概率进行 clamp ,不然当某一概率过小时,进行 log ,会让 loss 变为 nan
proposals = proposals.clamp(min=0.0001, max=1.0)
diff = gt_boxes * torch.log(proposals) + (1 - gt_boxes) * (torch.log(1 - proposals))
loss = -torch.mean(diff)
return loss def CE_loss(proposals, gt_boxes_classid):
loss = 0
# 对所求概率进行 clamp ,不然当某一概率过小时,进行 log ,会让 loss 变为 nan
proposals = proposals.clamp(min=0.0001, max=1.0) # method1:
for i in range(proposals.shape[0]):
fenzi = torch.exp(proposals[i][gt_boxes_classid[i]]) # proposals中对应真实类别的置信度
fenmu = torch.sum(torch.exp(proposals[i])) # 所有类别的置信度
loss += -torch.log(fenzi / fenmu)
# method2:
# for i in range(proposals.shape[0]):
# first=-proposals[i][gt_boxes_classid[i]]
# second=torch.log(torch.sum(torch.exp(proposals[i])))
# loss+=first+second return loss / proposals.shape[0] ################################# 位置损失 ########################################
def L1_loss(proposals, gt_boxes):
# 优点:鲁棒性好,因为梯度各个地方都为1,所以对异常值不是那么敏感。
# 缺点:不稳定解,达不到最优解,也就是函数最低点。
# 也叫MAE,平均绝对误差,预测值和真实值之间距离的平均值
diff = torch.abs(gt_boxes - proposals)
loss = torch.mean(diff)
return loss def L2_loss(proposals, gt_boxes):
# 优点:稳定解,能够达到最优解,也就是函数最低点。
# 缺点:鲁棒性差,对异常值敏感,容易形成梯度爆炸。
# 也叫MSE,均方误差。预测值和真实值之差的平方的平均值。
diff = torch.pow(gt_boxes - proposals, 2)
loss = torch.mean(diff)
return loss def Smooth_l1_loss(proposals, gt_boxes):
diff = torch.abs(gt_boxes - proposals)
diff = torch.where(diff < 1, 0.5 * diff * diff, diff - 0.5)
loss = torch.mean(diff)
return loss def IoU_loss(boxa, boxb):
"""
boxa/boxb:Tensor [x1,y1,x2,y2], x2,y2保证大于x1,y1
loss = 1 - iou
"""
inter_x1, inter_y1 = torch.maximum(boxa[:, 0], boxb[:, 0]), torch.maximum(boxa[:, 1], boxb[:, 1])
inter_x2, inter_y2 = torch.minimum(boxa[:, 2], boxb[:, 2]), torch.minimum(boxa[:, 3], boxb[:, 3])
inter_h = torch.maximum(torch.tensor([0]), inter_y2 - inter_y1)
inter_w = torch.maximum(torch.tensor([0]), inter_x2 - inter_x1)
inter_area = inter_w * inter_h
union_area = ((boxa[:, 3] - boxa[:, 1]) * (boxa[:, 2] - boxa[:, 0])) + \
((boxb[:, 3] - boxb[:, 1]) * (boxb[:, 2] - boxb[:, 0])) - inter_area + 1e-8 # + 1e-8 防止除零
iou = inter_area / union_area
iou_loss = 1 - iou
return iou_loss def GIoU_loss(boxa, boxb):
"""
# 为了解决当两个bbox不相交时,距离远的和距离近的损失值一样大。我们认为距离近的损失应该小一点。
# 注意:划分anchor是否是正样本的时候,anchor与label不一定相交,这样giou能够起到积极的作用
# 当用正样本计算与label的iou损失时,这时候正样本与label都是相交的情况,这时候GIoU不一定起到积极的作用。
giou = iou-(|ac-u|)/|ac| ac最小闭包区域,u并集
loss = 1 - giou
"""
inter_x1, inter_y1 = torch.maximum(boxa[:, 0], boxb[:, 0]), torch.maximum(boxa[:, 1], boxb[:, 1])
inter_x2, inter_y2 = torch.minimum(boxa[:, 2], boxb[:, 2]), torch.minimum(boxa[:, 3], boxb[:, 3])
inter_h = torch.maximum(torch.tensor([0]), inter_y2 - inter_y1)
inter_w = torch.maximum(torch.tensor([0]), inter_x2 - inter_x1)
inter_area = inter_w * inter_h
union_area = ((boxa[:, 3] - boxa[:, 1]) * (boxa[:, 2] - boxa[:, 0])) + \
((boxb[:, 3] - boxb[:, 1]) * (boxb[:, 2] - boxb[:, 0])) - inter_area + 1e-8 # + 1e-8 防止除零 # 求最小闭包区域的x1,y1,x2,y2,h,w,area
ac_x1, ac_y1 = torch.minimum(boxa[:, 0], boxb[:, 0]), torch.minimum(boxa[:, 1], boxb[:, 1])
ac_x2, ac_y2 = torch.maximum(boxa[:, 2], boxb[:, 2]), torch.maximum(boxa[:, 3], boxb[:, 3])
ac_w = ac_x2 - ac_x1
ac_h = ac_y2 - ac_y1
ac_area = ac_w * ac_h giou = (inter_area / union_area) - (torch.abs(ac_area - union_area) / ac_area)
giou_loss = 1 - giou
return giou_loss def DIoU_loss(boxa, boxb):
"""
# 当boxes与真实box重合时,一个在中间重合,一个在边缘重合,我们认为在中间重合的是比较好的,
# 所以提出计算两个box中心点的距离,因为预测小目标的中心点box与真实值box本来距离就很小,
# 所以再除以一个最小闭包区域对角线长度,来平衡小目标和大目标的diou。都用平方不开根号减少计算量和精度损失。
diou=iou-两个box中心点距离平方/最小闭包区域对角线距离平方
loss=1-diou
"""
# 求交集
inter_x1, inter_y1 = torch.maximum(boxa[:, 0], boxb[:, 0]), torch.maximum(boxa[:, 1], boxb[:, 1])
inter_x2, inter_y2 = torch.minimum(boxa[:, 2], boxb[:, 2]), torch.minimum(boxa[:, 3], boxb[:, 3])
inter_h = torch.maximum(torch.tensor([0]), inter_y2 - inter_y1)
inter_w = torch.maximum(torch.tensor([0]), inter_x2 - inter_x1)
inter_area = inter_w * inter_h # 求并集
union_area = ((boxa[:, 3] - boxa[:, 1]) * (boxa[:, 2] - boxa[:, 0])) + \
((boxb[:, 3] - boxb[:, 1]) * (boxb[:, 2] - boxb[:, 0])) - inter_area + 1e-8 # + 1e-8 防止除零 # 求最小闭包区域的x1,y1,x2,y2
ac_x1, ac_y1 = torch.minimum(boxa[:, 0], boxb[:, 0]), torch.minimum(boxa[:, 1], boxb[:, 1])
ac_x2, ac_y2 = torch.maximum(boxa[:, 2], boxb[:, 2]), torch.maximum(boxa[:, 3], boxb[:, 3]) # 把两个bbox的x1,y1,x2,y2转换成ctr_x,ctr_y
boxa_ctrx, boxa_ctry = boxa[:, 0] + (boxa[:, 2] - boxa[:, 0]) / 2, boxa[:, 1] + (boxa[:, 3] - boxa[:, 1]) / 2
boxb_ctrx, boxb_ctry = boxb[:, 0] + (boxb[:, 2] - boxb[:, 0]) / 2, boxb[:, 1] + (boxb[:, 3] - boxb[:, 1]) / 2 # 求两个box中心点距离平方length_box_ctr,最小闭包区域对角线距离平方length_ac,以及diou
length_box_ctr = (boxb_ctrx - boxa_ctrx) * (boxb_ctrx - boxa_ctrx) + \
(boxb_ctry - boxa_ctry) * (boxb_ctry - boxa_ctry)
length_ac = (ac_x2 - ac_x1) * (ac_x2 - ac_x1) + (ac_y2 - ac_y1) * (ac_y2 - ac_y1)
# 求平方,相乘是最快的
iou = inter_area / (union_area + 1e-8)
diou = iou - length_box_ctr / length_ac
diou_loss = 1 - diou
return diou_loss def CIoU_loss(boxa, boxb):
"""
# 当boxes与真实box重合时,且都在在中心点重合时,一个长宽比接近真实box,一个差异很大
# 我们认为长宽比接近的是比较好的,损失应该是比较小的。所以ciou增加了对box长宽比的考虑
ciou=iou+两个box中心点距离平方/最小闭包区域对角线距离平方+alpha*v
loss=1-iou+两个box中心点距离平方/最小闭包区域对角线距离平方+alpha*v
注意loss跟上边不一样,这里不是1-ciou
v用来度量长宽比的相似性,4/(pi *pi)*(arctan(boxa_w/boxa_h)-arctan(boxb_w/boxb_h))^2
alpha是权重值,衡量ciou公式中第二项和第三项的权重,
alpha大优先考虑v,alpha小优先考虑第二项距离比,alpha = v / ((1 - iou) + v)。
"""
# 求交集
inter_x1, inter_y1 = torch.maximum(boxa[:, 0], boxb[:, 0]), torch.maximum(boxa[:, 1], boxb[:, 1])
inter_x2, inter_y2 = torch.minimum(boxa[:, 2], boxb[:, 2]), torch.minimum(boxa[:, 3], boxb[:, 3])
inter_h = torch.maximum(torch.tensor([0]), inter_y2 - inter_y1)
inter_w = torch.maximum(torch.tensor([0]), inter_x2 - inter_x1)
inter_area = inter_w * inter_h # 求并集
union_area = ((boxa[:, 3] - boxa[:, 1]) * (boxa[:, 2] - boxa[:, 0])) + \
((boxb[:, 3] - boxb[:, 1]) * (boxb[:, 2] - boxb[:, 0])) - inter_area + 1e-8 # + 1e-8 防止除零 # 求最小闭包区域的x1,y1,x2,y2
ac_x1, ac_y1 = torch.minimum(boxa[:, 0], boxb[:, 0]), torch.minimum(boxa[:, 1], boxb[:, 1])
ac_x2, ac_y2 = torch.maximum(boxa[:, 2], boxb[:, 2]), torch.maximum(boxa[:, 3], boxb[:, 3]) # 把两个bbox的x1,y1,x2,y2转换成ctr_x,ctr_y
boxa_ctrx, boxa_ctry = boxa[:, 0] + (boxa[:, 2] - boxa[:, 0]) / 2, boxa[:, 1] + (boxa[:, 3] - boxa[:, 1]) / 2
boxb_ctrx, boxb_ctry = boxb[:, 0] + (boxb[:, 2] - boxb[:, 0]) / 2, boxb[:, 1] + (boxb[:, 3] - boxb[:, 1]) / 2
boxa_w, boxa_h = boxa[:, 2] - boxa[:, 0], boxa[:, 3] - boxa[:, 1]
boxb_w, boxb_h = boxb[:, 2] - boxb[:, 0], boxb[:, 3] - boxb[:, 1] # 求两个box中心点距离平方length_box_ctr,最小闭包区域对角线距离平方length_ac
length_box_ctr = (boxb_ctrx - boxa_ctrx) * (boxb_ctrx - boxa_ctrx) + \
(boxb_ctry - boxa_ctry) * (boxb_ctry - boxa_ctry)
length_ac = (ac_x2 - ac_x1) * (ac_x2 - ac_x1) + (ac_y2 - ac_y1) * (ac_y2 - ac_y1) v = (4 / (math.pi * math.pi)) * (torch.atan(boxa_w / boxa_h) - torch.atan(boxb_w / boxb_h)) \
* (torch.atan(boxa_w / boxa_h) - torch.atan(boxb_w / boxb_h))
iou = inter_area / (union_area + 1e-8)
alpha = v / ((1 - iou) + v)
# ciou = iou - length_box_ctr / length_ac - alpha * v
ciou_loss = 1 - iou + length_box_ctr / length_ac + alpha * v
return ciou_loss def AlphaIoU_loss(boxa, boxb, alpha):
"""
# 除了alpha-iou,还有alpha-giou, alpha-diou, alpha-ciou,这里就不写了。
# alpha-iou的优点是,例如alpha取2,当iou大于0.5的时候,loss的梯度是大于1的,
# 相比iou的loss一直等于-1,收敛的更快,map0.7/map0.9有提升效果。
loss = 1 - iou^alpha alpha>0,取3效果比较好
"""
inter_x1, inter_y1 = torch.maximum(boxa[:, 0], boxb[:, 0]), torch.maximum(boxa[:, 1], boxb[:, 1])
inter_x2, inter_y2 = torch.minimum(boxa[:, 2], boxb[:, 2]), torch.minimum(boxa[:, 3], boxb[:, 3])
inter_h = torch.maximum(torch.tensor([0]), inter_y2 - inter_y1)
inter_w = torch.maximum(torch.tensor([0]), inter_x2 - inter_x1)
inter_area = inter_w * inter_h
union_area = ((boxa[:, 3] - boxa[:, 1]) * (boxa[:, 2] - boxa[:, 0])) + \
((boxb[:, 3] - boxb[:, 1]) * (boxb[:, 2] - boxb[:, 0])) - inter_area + 1e-8 # + 1e-8 防止除零
iou = inter_area / union_area alpha_iou = torch.pow(iou, alpha)
alpha_iou_loss = 1 - alpha_iou
return alpha_iou_loss if __name__ == '__main__':
# 定义一些输入的tensor
proposals = torch.tensor([0., 0., 2., 2.], dtype=torch.float32)
gt_boxes = torch.tensor([1., 1., 5., 5.], dtype=torch.float32) # 专门用于bce loss的输入
bce_prop = torch.tensor([0.2, 0.7, 0.99, 0.5], dtype=torch.float32)
bce_gt = torch.tensor([0, 1, 0, 1], dtype=torch.float32) # 专门用于ce loss的输入,4个边界框,每个边界框对应2个类别的置信度
ce_prop = torch.randn([4, 2], dtype=torch.float32)
ce_prop = F.softmax(ce_prop, dim=1) # 对每个bbox的置信度进行softmax
# 4个边界框的真实类别id
ce_gt_boxes_classid = torch.randint(0, 2, [4], dtype=torch.int64) # 专门用于iou loss的输入
iou_proposals = torch.tensor([[0, 0, 2, 2], [0, 0, 2, 2]])
iou_gt_boxes = torch.tensor([[1, 1, 3, 3], [1, 1, 2, 4]]) ########################################### our methods #############################################
# 分类损失:
bce_loss = BCE_loss(bce_prop, bce_gt)
ce_loss = CE_loss(ce_prop, ce_gt_boxes_classid) # 位置损失:
l1_loss = L1_loss(proposals, gt_boxes) # 也叫MAE
l2_loss = L2_loss(proposals, gt_boxes) # 也叫MSE
smooth_l1_loss = Smooth_l1_loss(proposals, gt_boxes)
iou_loss = IoU_loss(iou_proposals, iou_gt_boxes)
giou_loss = GIoU_loss(iou_proposals, iou_gt_boxes)
diou_loss = DIoU_loss(iou_proposals, iou_gt_boxes)
ciou_loss = CIoU_loss(iou_proposals, iou_gt_boxes) # proposals和gt_boxes宽高比一样,所以ciou等于diou
alphaiou1_loss = AlphaIoU_loss(iou_proposals, iou_gt_boxes, alpha=1)
alphaiou3_loss = AlphaIoU_loss(iou_proposals, iou_gt_boxes, alpha=3) ########################################### official methods #############################################
# 分类损失:
bce_loss_ = F.binary_cross_entropy(bce_prop, bce_gt)
ce_loss_ = F.cross_entropy(ce_prop, ce_gt_boxes_classid) # 位置损失:
l1_loss_ = F.l1_loss(proposals, gt_boxes) # 也叫MAE
l2_loss_ = F.mse_loss(proposals, gt_boxes) # 也叫MSE
smooth_l1_loss_ = F.smooth_l1_loss(proposals, gt_boxes) # 输出结果对比一下:
print("bce:",bce_loss)
print("bce_:",bce_loss_)
print("ce:",ce_loss)
print("ce_:",ce_loss_)
print("l1_loss:",l1_loss)
print("l1_loss_:",l1_loss_)
print("l2_loss:",l2_loss)
print("l2_loss_:",l2_loss_)
print("smooth_l1_loss:",smooth_l1_loss)
print("smooth_l1_loss_:",smooth_l1_loss_) # 自己计算一下,看写的iou loss函数对不对,下面是手动计算的结果:
# 下面我把并集中1e-8省略了,所以会有略微差距。下面手动计算的是[0, 0, 2, 2]与[1, 1, 3, 3]的各种iou loss
# box1 area=4, box2 area=4,inter area=1, union area=7, ac area=9, iou=1/7
print("iou loss:",iou_loss)
print("iou loss:", 1 - 1 / 7)
print("giou loss:",giou_loss)
print("giou loss:", 1 - (1 / 7 - (9 - 7) / 9))
print("diou loss:",diou_loss)
print("diou loss:", 1 - (1 / 7 - (1 * 1) / (3 * 3)))
print("ciou loss:",ciou_loss)
v = 4 / (math.pi * math.pi) * ((math.atan(2 / 2) - math.atan(2 / 2)) * (math.atan(2 / 2) - math.atan(2 / 2)))
print("ciou loss:", 1 - 1 / 7 + (1 * 1) / (3 * 3) + v / ((1 - 1 / 7) + v) * v)
print("alpha1 iou loss:",alphaiou1_loss)
print("alpha1 iou loss:", 1 - 1 / 7)
print("alpha3 iou loss:",alphaiou3_loss)
print("alpha3 iou loss:1", 1 - math.pow((1 / 7), 3))

输出结果:

bce: tensor(1.4695)
bce_: tensor(1.4695)
ce: tensor(0.9038)
ce_: tensor(0.9038)
l1_loss: tensor(2.)
l1_loss_: tensor(2.)
l2_loss: tensor(5.)
l2_loss_: tensor(5.)
smooth_l1_loss: tensor(1.5000)
smooth_l1_loss_: tensor(1.5000)
iou loss: tensor([0.8571, 0.8333])
iou loss: 0.8571428571428572
giou loss: tensor([1.0794, 1.0833])
giou loss: 1.0793650793650793
diou loss: tensor([0.9683, 0.9583])
diou loss: 0.9682539682539683
ciou loss: tensor([0.9683, 0.9666])
ciou loss: 0.9682539682539684
alpha1 iou loss: tensor([0.8571, 0.8333])
alpha1 iou loss: 0.8571428571428572
alpha3 iou loss: tensor([0.9971, 0.9954])
alpha3 iou loss:1 0.9970845481049563

一文读懂IoU,GIoU, DIoU, CIoU, Alpha-IoU (代码非常优雅)的更多相关文章

  1. 一文读懂HTTP/2及HTTP/3特性

    摘要: 学习 HTTP/2 与 HTTP/3. 前言 HTTP/2 相比于 HTTP/1,可以说是大幅度提高了网页的性能,只需要升级到该协议就可以减少很多之前需要做的性能优化工作,当然兼容问题以及如何 ...

  2. 一文读懂AI简史:当年各国烧钱许下的愿,有些至今仍未实现

    一文读懂AI简史:当年各国烧钱许下的愿,有些至今仍未实现 导读:近日,马云.马化腾.李彦宏等互联网大佬纷纷亮相2018世界人工智能大会,并登台演讲.关于人工智能的现状与未来,他们提出了各自的观点,也引 ...

  3. 一文读懂高性能网络编程中的I/O模型

    1.前言 随着互联网的发展,面对海量用户高并发业务,传统的阻塞式的服务端架构模式已经无能为力.本文(和下篇<高性能网络编程(六):一文读懂高性能网络编程中的线程模型>)旨在为大家提供有用的 ...

  4. 从HTTP/0.9到HTTP/2:一文读懂HTTP协议的历史演变和设计思路

    本文原作者阮一峰,作者博客:ruanyifeng.com. 1.引言 HTTP 协议是最重要的互联网基础协议之一,它从最初的仅为浏览网页的目的进化到现在,已经是短连接通信的事实工业标准,最新版本 HT ...

  5. 一文读懂 深度强化学习算法 A3C (Actor-Critic Algorithm)

    一文读懂 深度强化学习算法 A3C (Actor-Critic Algorithm) 2017-12-25  16:29:19   对于 A3C 算法感觉自己总是一知半解,现将其梳理一下,记录在此,也 ...

  6. [转帖]MerkleDAG全面解析 一文读懂什么是默克尔有向无环图

    MerkleDAG全面解析 一文读懂什么是默克尔有向无环图 2018-08-16 15:58区块链/技术 MerkleDAG作为IPFS的核心数据结构,它融合了Merkle Tree和DAG的优点,今 ...

  7. [转帖]一文读懂 HTTP/2

    一文读懂 HTTP/2 http://support.upyun.com/hc/kb/article/1048799/ 又小拍 • 发表于:2017年05月18日 15:34:45 • 更新于:201 ...

  8. [转帖]从HTTP/0.9到HTTP/2:一文读懂HTTP协议的历史演变和设计思路

    从HTTP/0.9到HTTP/2:一文读懂HTTP协议的历史演变和设计思路   http://www.52im.net/thread-1709-1-2.html     本文原作者阮一峰,作者博客:r ...

  9. 一文读懂HDMI和VGA接口针脚定义

    一文读懂HDMI和VGA接口针脚定义 摘自:http://www.elecfans.com/yuanqijian/jiekou/20180423666604.html   HDMI概述 HDMI是高清 ...

  10. 即时通讯新手入门:一文读懂什么是Nginx?它能否实现IM的负载均衡?

    本文引用了“蔷薇Nina”的“Nginx 相关介绍(Nginx是什么?能干嘛?)”一文部分内容,感谢作者的无私分享. 1.引言   Nginx(及其衍生产品)是目前被大量使用的服务端反向代理和负载均衡 ...

随机推荐

  1. vetur volar 是否可以共用,vue2 vue3项目 如何同时开发?

    vetur volar 是否可以共用,vue2 vue3项目 如何同时开发? 先提问 以后再找答案 20220704 补答 vetur volar 不要一起装 vscode环境

  2. maven问题之Could not calculate build plan:

    问题描述: Could not calculate build plan: Failure to transfer org.apache.maven.plugins:maven-surefire-pl ...

  3. UE像素流送是什么?像素流推流原理介绍

    游戏开发者通常在运行游戏逻辑时会将游戏渲染到屏幕的同一台设备上来运行虚幻引擎应用,多人联网游戏可能会在应用程序的多个实例之间分发部分游戏逻辑,但每个单独的实例仍然会为自己的玩家在本地渲染游戏.即使是使 ...

  4. JS(DOM事件高级)

    一 注册事件(绑定事件) 1.1 注册事件概述 给元素添加事件,称为注册事件或者绑定事件.注册事件有两种方式:传统方式和方法监听注册方式 1.2 addEventListener 事件监听方式 eve ...

  5. Bootstrap前端开发框架

    一 Bootstrap 简介 Bootstrap 来自 Twitter(推特),是目前最受欢迎的前端框架.Bootstrap 是基于 HTML.CSS 和 JAVASCRIPT 的,它简洁灵活,使得 ...

  6. openApi generator总是生成类名为 defaultApi

    生成器可以开启 useTags 设置,开启之后会根据 api 文档中的 tags 生成前缀类名,因此,要不生成 defaultApi 需要以下操作: 1.openApi 文档中每个 url 必须要有 ...

  7. 学习笔记-Kafka消息队列

    官网地址:https://kafka.apache.org/ 一.认识kafka 1.认识kafka Apache Kafka是Apache软件基金会的开源的流处理平台,该平台提供了消息的订阅与发布的 ...

  8. KingbaseES 逻辑读与物理读

    oracle数据库中逻辑读,物理读 数据访问方式:数据库少不了和操作系统进行数据交互,表数据最好的方式是从数据库共享池中访问到,避免发生磁盘IO,当然如果共享池中没有访问到数据就难免发生磁盘IO. 物 ...

  9. KingbaseES 函数与存储过程内容加密

    说明: 数据库系统使用过程中,有些业务功能在特殊的安全级别情况下,需要对数据库中的函数和存储过程进行加密存储,以保证数据库函数和过程的代码安全性.KingbaseES 数据库,提供了DBMS_DDL扩 ...

  10. Finereport11 类Excel筛选

    微信公众号:次世代数据技术 关注可了解更多的教程.问题或建议,请公众号留言或联系本人; 微信号:weibw162 本教程视频讲解可以关注本人B站账号进行观看:weibw162 一.需求描述 在使用FI ...