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. hadoop 3.3.5伪分布式集群部署以及遇到的问题解决

    hadoop包下载 https://archive.apache.org/dist/hadoop/common/ 安装好jdk并配置环境变量 下载hadoop压缩包并放至 /data/hadoop目录 ...

  2. mysql视图详细笔记

    1 #视图 2 /* 3 含义:虚拟表,和普通表一样使用 4 mysql5.1版本出现的新特性,是通过表动态生成的数据 5 6 比如:舞蹈班和普通班级的对比 7 创建语法的关键字 是否实际占用物理空间 ...

  3. eclipse错误之Errors occurred during the build. Errors running builder 'JavaScript Validator' on project

    把JavaScript Validator去掉.去掉的方法是:选择一个项目--右键Properties--Builders(排第二)--点一下右侧会有四项--取消第一项"JavaScript ...

  4. Java Spring Redis 如何向Set中添加List?

    调用list.toArray方法将list转成数组,再使用add方法参数传入数组,即可批量添加. redisTemplate.opsForSet().add(key,collect.toArray(n ...

  5. AOSP中获取系统签名

    制作系统签名: 1.将AOSP源码路径下build\target\product\security\platform.pk8和platform.x509.pem复制出来放在同一目录下 2.执行命令 后 ...

  6. 关于linux系统版本的一个分类展现

    PS:要转载请注明出处,本人版权所有. PS: 这个只是基于<我自己>的理解, 如果和你的原则及想法相冲突,请谅解,勿喷. 前置说明   本文发布于 2014-07-06 22:58:35 ...

  7. 2024-03-16:用go语言,给你一个正整数数组 nums, 每一次操作中,你可以从 nums 中选择 任意 一个数并将它减小到 恰好 一半。 (注意,在后续操作中你可以对减半过的数继续执行操作)

    2024-03-16:用go语言,给你一个正整数数组 nums, 每一次操作中,你可以从 nums 中选择 任意 一个数并将它减小到 恰好 一半. (注意,在后续操作中你可以对减半过的数继续执行操作) ...

  8. 详解SSL证书系列(5)SSL证书为什么不能好多年签一次呢

    上一篇介绍了详解SSL证书系列(4)免费的SSL证书和收费的证书有什么区别,这一篇我们继续了解一下我们申请的SSL证书为什么不能好多年签一次呢,这样不是更省事吗? SSL证书最多只能签发一年,一年到期 ...

  9. c# WPF制作百度网盘资源搜索工具

    界面如下 1.搜索中 2.搜索成功 源码地址:https://github.com/BruceQiu1996/BaiduDiskSearcher 希望有用的学到的或者对此感兴趣的可以给一个star,谢 ...

  10. Java内存马2-Spring内存马

    Spring内存马 目录 Spring内存马 1.Spring&Spring MVC简介 2.环境搭建 3.Controller内存马 4.踩坑日记 5.Interceptor内存马 1.Sp ...