Wise-IoU 作者导读:基于动态非单调聚焦机制的边界框损失

news2024/12/22 20:11:55

论文地址:Wise-IoU: Bounding Box Regression Loss with Dynamic Focusing Mechanism

GitHub:https://github.com/Instinct323/wiou

摘要:目标检测作为计算机视觉的核心问题,其检测性能依赖于损失函数的设计。边界框损失函数作为目标检测损失函数的重要组成部分,其良好的定义将为目标检测模型带来显著的性能提升。近年来的研究大多假设训练数据中的示例有较高的质量,致力于强化边界框损失的拟合能力。但我们注意到目标检测训练集中含有低质量示例,如果一味地强化边界框对低质量示例的回归,显然会危害模型检测性能的提升。Focal-EIoU v1 被提出以解决这个问题,但由于其聚焦机制是静态的,并未充分挖掘非单调聚焦机制的潜能。基于这个观点,我们提出了动态非单调的聚焦机制,设计了 Wise-IoU (WIoU)。动态非单调聚焦机制使用“离群度”替代 IoU 对锚框进行质量评估,并提供了明智的梯度增益分配策略。该策略在降低高质量锚框的竞争力的同时,也减小了低质量示例产生的有害梯度。这使得 WIoU 可以聚焦于普通质量的锚框,并提高检测器的整体性能。将WIoU应用于最先进的单级检测器 YOLOv7 时,在 MS-COCO 数据集上的 AP-75 从 53.03% 提升到 54.50%

前言:因为我能使用的算力有限,所以做实验时只在 YOLOv7 上做了。而且因为完整的 MS-COCO 需要更大的参数量,训练一个模型需要 3 天时间,所以我只取了其中四分之一的数据进行训练 (28474 张训练图片)。虽然实验量相比其它工作是远远不足的,但这几天中文社区的反应让我感觉这篇文章还有救哈哈哈。为了支持广大计算机视觉研究者的工作,我决定来这里讲解一下理论部分和代码实战

CIoU、SIoU 的 v2 使用和 WIoU v2 一致的单调聚焦机制,v3 使用和 WIoU v3 一致的动态非单调聚焦机制,详见论文的消融实验

在计算速度上,WIoU 所增加的计算成本主要在于聚焦系数的计算、IoU 损失的均值统计。在实验条件相同时,WIoU 因为没有对纵横比进行计算反而有更快的速度,WIoU 的计算耗时为 CIoU 的 87.2%

在性能提升上,数据集的标注质量越差 (当然差到一定程度就不叫数据集了),WIoU 相对其它边界框损失的表现越好。比如说我在一个检测火焰的比赛里用的 WIoU (那时的初版还比较捞) 使 mAP 提升了 1.70% (相比 CIoU)

这篇博客没有像论文那么详细,大家有什么地方看不明白的欢迎在评论区提问,我会抽时间补上的 ~

现有工作

记锚框为 \vec{B}=[x\ y\ w\ h],目标框为 \vec{B_{gt}}=[x_{gt}\ y_{gt}\ w_{gt}\ h_{gt}]

IoU 用于度量目标检测任务中预测框与真实框的重叠程度,定义为:

\mathcal{L}_{IoU} = 1 - IoU = 1 - \frac{W_i H_i}{S_u}

同时,IoU 有一个致命的缺陷,可以在下面公式中观察到。当边界框之间没有重叠时 (W_i=0\ or\ H_i=0)\mathcal{L}_{IoU} 反向传播的梯度消失。这导致重叠区域的宽度 W_i 在训练时无法更新

\frac{\partial \mathcal{L}_{IoU}}{\partial W_i} = \left\{\begin{matrix} -H_i\frac{IoU + 1}{S_u},W_i >0\\ 0,W_i = 0 \end{matrix}\right.

现有的工作考虑了许多与包围盒相关的几何因素并构造了惩罚项 \mathcal{R}_i 来解决这个问题,现有的边界框损失都是基于加法的损失,并遵循以下范式:

\mathcal{L}_i = \mathcal{L}_{IoU} + \mathcal{R}_i

Distance-IoU

DIoU 将惩罚项定义为中心点连接的归一化长度:

\mathcal{R}_{DIoU} = \frac{(x-x_{gt})^2 + (y-y_{gt})^2}{W^2_g + H^2_g}

同时为最小包围框的尺寸 W_g, H_g 提供了负梯度,这将使得 W_g, H_g 增大而阻碍预测框与目标框重叠:

\frac {\partial \mathcal{R}_{DIoU}} {\partial W_g} = -2W_g \frac{(x-x_{gt})^2 + (y-y_{gt})^2}{(W^2_g + H^2_g)^2} < 0

\frac {\partial \mathcal{R}_{DIoU}} {\partial H_g} = -2H_g \frac{(x-x_{gt})^2 + (y-y_{gt})^2}{(W^2_g + H^2_g)^2} < 0

但不可否认的是,距离度量的确是一个极其有效的解决方案,成为高效边界框损失的必要因子。EIoU 在此基础上加大了对距离度量的惩罚力度,其惩罚项定义为:

\mathcal{R}_{EIoU} = \mathcal{R}_{DIoU} + \frac{(x-x_{gt})^2}{W^2_g} + \frac{(y-y_{gt})^2}{H^2_g}

Complete-IoU

在 \mathcal{R}_{DIoU} 的基础上,CIoU 增加了对纵横比一致性的考虑:

\mathcal{R}_{CIoU} = \mathcal{R}_{DIoU} + \alpha v, \alpha = \frac{v}{\mathcal{L}_{IoU} + v}

其中的 v 描述了纵横比一致性:

v=\frac{4}{\pi^2} (\tan^{-1}\frac{w}{h} - \tan^{-1}\frac{w_{gt}}{h_{gt}}) ^2

\frac{\partial v}{\partial w} = \frac{8}{\pi^2} (\tan^{-1}\frac{w}{h} - \tan^{-1}\frac{w_{gt}}{h_{gt}}) ^2 \frac{h}{h^2+w^2}

\frac{\partial v}{\partial h} =- \frac{8}{\pi^2} (\tan^{-1}\frac{w}{h} - \tan^{-1}\frac{w_{gt}}{h_{gt}}) ^2 \frac{w}{h^2+w^2}

其中 v 反向传播的梯度满足 \frac{\partial v}{\partial h} = -\frac{w}{h} \frac{\partial v}{\partial w},也就是 v 不可能为预测框的宽高提供同号的梯度。在前文对 DIoU 的分析中可知 DIoU 会产生负梯度 \frac {\partial \mathcal{R}_{DIoU}} {\partial W_g},当这个负梯度与 \frac {\partial \mathcal{L}_{IoU}} {\partial W_g} 正好抵消时,会导致预测框无法优化。而 CIoU 对纵横比一致性的考虑将打破这种僵局

Scylla-IoU

Zhora Gevorgyan 证明了中心对齐的边界框会具有更快的收敛速度,以 angle cost、distance cost、shape cost 构造了 SIoU。其中 angle cost 描述了边界框中心连线与 x-y 轴的最小夹角:

\mathcal{\varLambda} = \sin(2\sin^{-1}\frac{\min(|x-x_{gt}|,|y-y_{gt}|)}{\sqrt{(x-x_{gt})^2 + (y-y_{gt})^2} + \epsilon})

distance cost 描述了两边界框的中心点在x轴和y轴上的归一化距离,其惩罚力度与 angle cost 正相关。distance cost 被定义为:

\Delta = \frac{1}{2}\sum_{t=w,h}(1 - e^{-\gamma \rho_{t}}),\gamma = 2 - \varLambda

\left\{\begin{matrix} \rho_x = (\frac{x - x_{gt}}{W_g})^2\\ \rho_y = (\frac{y - y_{gt}}{H_g})^2 \end{matrix}\right.

shape cost 描述了两边界框的形状差异,当两边界框的尺寸不一致时不为 0。shape cost 被定义为:

\Omega = \frac{1}{2}\sum_{t=w,h}(1 - e^{\omega_t})^{\theta},\theta = 4

\left\{\begin{matrix} \omega_w = \frac{|w-w_{gt}|}{\max(w,w_{gt})}\\ \omega_h = \frac{|h-h_{gt}|}{\max(h,h_{gt})} \end{matrix}\right.

\mathcal{R}_{SIoU} 与 \mathcal{R}_{CIoU} 类似,它们都由 distance cost 和 shape cost 组成:

\mathcal{R}_{SIoU} = \Delta + \Omega

本文方法

本文所涉及的聚焦机制有以下几种:

  • 静态:当边界框的 IoU 为某一指定值时有最高的梯度增益,如 Focal EIoU v1
  • 动态:享有最高梯度增益的边界框的条件处于动态变化中,如 WIoU v3
  • 单调:梯度增益随损失值的增加而单调增加,如 Focal loss
  • 非单调:梯度增益随损失值的增加呈非单调变化

WIoU v1 构造了基于注意力的边界框损失,WIoU v2 和 v3 则是在此基础上通过构造梯度增益 (聚焦系数) 的计算方法来附加聚焦机制

Wise-IoU v1

因为训练数据中难以避免地包含低质量示例,所以如距离、纵横比之类的几何度量都会加剧对低质量示例的惩罚从而使模型的泛化性能下降。好的损失函数应该在锚框与目标框较好地重合时削弱几何度量的惩罚,不过多地干预训练将使模型有更好的泛化能力。在此基础上,我们根据距离度量构建了距离注意力,得到了具有两层注意力机制的 WIoU v1:

  • \mathcal{R}_{WIoU} \in [1,e),这将显著放大普通质量锚框的 \mathcal{L}_{IoU}
  • \mathcal{L}_{IoU} \in [0,1],这将显著降低高质量锚框的 \mathcal{R}_{WIoU},并在锚框与目标框重合较好的情况下显著降低其对中心点距离的关注

\mathcal{L}_{WIoUv1} = \mathcal{R}_{WIoU} \mathcal{L}_{IoU}

\mathcal{R}_{WIoU} = \exp(\frac{(x-x_{gt})^2 + (y-y_{gt})^2}{(W^2_g + H^2_g)^*})

为了防止 \mathcal{R}_{WIoU} 产生阻碍收敛的梯度,将 W_g, H_g 从计算图 (上标 * 表示此操作) 中分离。因为它有效地消除了阻碍收敛的因素,所以我们没有引入新的度量指标,如纵横比

Wise-IoU v2

Focal Loss 设计了一种针对交叉熵的单调聚焦机制,有效降低了简单示例对损失值的贡献。这使得模型能够聚焦于困难示例,获得分类性能的提升。类似地,我们构造了 \mathcal{L}_{WIoUv1} 的单调聚焦系数 \mathcal{L}_{IoU}^{\gamma*}

\mathcal{L}_{WIoUv2} = \mathcal{L}_{IoU}^{\gamma *} \mathcal{L}_{WIoUv1}, \gamma > 0

在模型训练过程中,梯度增益 \mathcal{L}_{IoU}^{\gamma *} 随着 \mathcal{L}_{IoU} 的减小而减小,导致训练后期收敛速度较慢。因此,引入 \mathcal{L}_{IoU} 的均值作为归一化因子:

\mathcal{L}_{WIoUv2} = (\frac{\mathcal{L}_{IoU}^*}{\ \overline{\mathcal{L}_{IoU}}\ })^{\gamma} \mathcal{L}_{WIoUv1}

其中的 \overline{\mathcal{L}_{IoU}} 为动量为 m 的滑动平均值,动态更新归一化因子使梯度增益 r= (\frac{\mathcal{L}_{IoU}^*}{\ \overline{\mathcal{L}_{IoU}}\ })^{\gamma} 整体保持在较高水平,解决了训练后期收敛速度慢的问题

Wise-IoU v3

定义离群度以描述锚框的质量,其定义为:

\beta = \frac{\mathcal{L}_{IoU}^*}{\ \overline{\mathcal{L}_{IoU}}\ } \in [0, +\infty)

离群度小意味着锚框质量高,我们为其分配一个小的梯度增益,以便使边界框回归聚焦到普通质量的锚框上。对离群度较大的锚框分配较小的梯度增益,将有效防止低质量示例产生较大的有害梯度。我们利用 \beta 构造了一个非单调聚焦系数并将其应用于 WIoU v1:

\mathcal{L}_{WIoUv3}= r\mathcal{L}_{WIoUv1},\ r=\frac{\beta}{\delta \alpha^{\beta - \delta}}

其中,当 \beta = \delta 时,\delta 使得 r=1。当锚框的离群程度满足 \beta = C (C 为定值)时,锚框将获得最高的梯度增益。由于 \overline{\mathcal{L}_{IoU}} 是动态的,锚框的质量划分标准也是动态的,这使得 WIoU v3 在每一时刻都能做出最符合当前情况的梯度增益分配策略

为了防止低质量锚框在训练初期落后,我们初始化 \overline{\mathcal{L}_{IoU}}=1 使得 \mathcal{L}_{IoU}=1 的锚框具有最高的梯度增益。为了在训练的早期阶段保持这样的策略,需要设置一个小的动量 m 来延迟 \overline{\mathcal{L}_{IoU}} 接近真实值 \overline{\mathcal{L}_{IoU-real}} 的时间。对于 batch size 为 n 的训练,我们建议将动量设置为:

m = 1- \sqrt[tn]{0.5},\ tn > 7000

这种设置使得经过 t 轮训练后有 \overline{\mathcal{L}_{IoU}} = 0.5(1+\overline{\mathcal{L}_{IoU-real}})。在训练的中后期,WIoU v3 将小梯度增益分配给低质量的锚框以减少有害梯度。同时 WIoU v3 会聚焦于普通质量的锚框,提高模型的定位性能

核心代码

下面这个类可以计算现有的边界框损失 (IoU,GIoU,DIoU,CIoU,EIoU,SIoU,WIoU),核心的类变量有:

  • iou_mean:即 \overline{\mathcal{L}_{IoU}} 的滑动平均值,每次程序刚开始运行时初始化为 1。如果训练中断导致该值重置,需要将该值恢复为中断前的值,否则会导致性能增速下降
  • monotonus:其指示了边界框损失使用单调聚焦机制 (e.g., WIoU v2) 或是非单调聚焦机制 (e.g., WIoU v3),具体看该类的文档
  • momentum:遵循 m = 1- \sqrt[tn]{0.5},\ tn > 7000 的设置。当 m 足够小时,验证集的 IoU 基本不影响 \overline{\mathcal{L}_{IoU}} 的值,此时不需要使用 eval 和 train 函数指定训练模式;否则需要使用 eval 和 train 函数指定训练模式

此外,聚焦机制会对边界框损失的值进行缩放,具体通过实例方法 _scaled_loss 实现

import math

import torch


class IoU_Cal:
    ''' pred, target: x0,y0,x1,y1
        monotonous: {
            None: origin
            True: monotonic FM
            False: non-monotonic FM
        }
        momentum: The momentum of running mean'''
    iou_mean = 1.
    monotonous = False
    momentum = 1 - pow(0.5, exp=1 / 7000)
    _is_train = True

    def __init__(self, pred, target):
        self.pred, self.target = pred, target
        self._fget = {
            # x,y,w,h
            'pred_xy': lambda: (self.pred[..., :2] + self.pred[..., 2: 4]) / 2,
            'pred_wh': lambda: self.pred[..., 2: 4] - self.pred[..., :2],
            'target_xy': lambda: (self.target[..., :2] + self.target[..., 2: 4]) / 2,
            'target_wh': lambda: self.target[..., 2: 4] - self.target[..., :2],
            # x0,y0,x1,y1
            'min_coord': lambda: torch.minimum(self.pred[..., :4], self.target[..., :4]),
            'max_coord': lambda: torch.maximum(self.pred[..., :4], self.target[..., :4]),
            # The overlapping region
            'wh_inter': lambda: self.min_coord[..., 2: 4] - self.max_coord[..., :2],
            's_inter': lambda: torch.prod(torch.relu(self.wh_inter), dim=-1),
            # The area covered
            's_union': lambda: torch.prod(self.pred_wh, dim=-1) +
                               torch.prod(self.target_wh, dim=-1) - self.s_inter,
            # The smallest enclosing box
            'wh_box': lambda: self.max_coord[..., 2: 4] - self.min_coord[..., :2],
            's_box': lambda: torch.prod(self.wh_box, dim=-1),
            'l2_box': lambda: torch.square(self.wh_box).sum(dim=-1),
            # The central points' connection of the bounding boxes
            'd_center': lambda: self.pred_xy - self.target_xy,
            'l2_center': lambda: torch.square(self.d_center).sum(dim=-1),
            # IoU
            'iou': lambda: 1 - self.s_inter / self.s_union
        }
        self._update(self)

    def __setitem__(self, key, value):
        self._fget[key] = value

    def __getattr__(self, item):
        if callable(self._fget[item]):
            self._fget[item] = self._fget[item]()
        return self._fget[item]

    @classmethod
    def train(cls):
        cls._is_train = True

    @classmethod
    def eval(cls):
        cls._is_train = False

    @classmethod
    def _update(cls, self):
        if cls._is_train: cls.iou_mean = (1 - cls.momentum) * cls.iou_mean + \
                                         cls.momentum * self.iou.detach().mean().item()

    def _scaled_loss(self, loss, gamma=1.9, delta=3):
        if isinstance(self.monotonous, bool):
            if self.monotonous:
                loss *= (self.iou.detach() / self.iou_mean).sqrt()
            else:
                beta = self.iou.detach() / self.iou_mean
                alpha = delta * torch.pow(gamma, beta - delta)
                loss *= beta / alpha
        return loss

    @classmethod
    def IoU(cls, pred, target, self=None):
        self = self if self else cls(pred, target)
        return self.iou

    @classmethod
    def WIoU(cls, pred, target, self=None):
        self = self if self else cls(pred, target)
        dist = torch.exp(self.l2_center / self.l2_box.detach())
        return self._scaled_loss(dist * self.iou)

    @classmethod
    def EIoU(cls, pred, target, self=None):
        self = self if self else cls(pred, target)
        penalty = self.l2_center / self.l2_box.detach() \
                  + torch.square(self.d_center / self.wh_box.detach()).sum(dim=-1)
        return self._scaled_loss(self.iou + penalty)

    @classmethod
    def GIoU(cls, pred, target, self=None):
        self = self if self else cls(pred, target)
        return self._scaled_loss(self.iou + (self.s_box - self.s_union) / self.s_box)

    @classmethod
    def DIoU(cls, pred, target, self=None):
        self = self if self else cls(pred, target)
        return self._scaled_loss(self.iou + self.l2_center / self.l2_box)

    @classmethod
    def CIoU(cls, pred, target, eps=1e-4, self=None):
        self = self if self else cls(pred, target)
        v = 4 / math.pi ** 2 * \
            (torch.atan(self.pred_wh[..., 0] / (self.pred_wh[..., 1] + eps)) -
             torch.atan(self.target_wh[..., 0] / (self.target_wh[..., 1] + eps))) ** 2
        alpha = v / (self.iou + v)
        return self._scaled_loss(self.iou + self.l2_center / self.l2_box + alpha.detach() * v)

    @classmethod
    def SIoU(cls, pred, target, theta=4, self=None):
        self = self if self else cls(pred, target)
        # Angle Cost
        angle = torch.arcsin(torch.abs(self.d_center).min(dim=-1)[0] / (self.l2_center.sqrt() + 1e-4))
        angle = torch.sin(2 * angle) - 2
        # Dist Cost
        dist = angle[..., None] * torch.square(self.d_center / self.wh_box)
        dist = 2 - torch.exp(dist[..., 0]) - torch.exp(dist[..., 1])
        # Shape Cost
        d_shape = torch.abs(self.pred_wh - self.target_wh)
        big_shape = torch.maximum(self.pred_wh, self.target_wh)
        w_shape = 1 - torch.exp(- d_shape[..., 0] / big_shape[..., 0])
        h_shape = 1 - torch.exp(- d_shape[..., 1] / big_shape[..., 1])
        shape = w_shape ** theta + h_shape ** theta
        return self._scaled_loss(self.iou + (dist + shape) / 2)

在将 WIoU v3 引进 YOLOv7 时,先在 train_aux.py 中找到损失函数的位置。ComputeLossAuxOTA 是 train 的时候用的,找到其源代码并进行修改

因为 YOLOv7 对模型性能的比较主要利用 utils/metrics 里的 fitness 函数,与损失值无关。而 ComputeLoss 是在 eval 的时候用的,保证不出 bug 就行

在初始化函数动一下手脚,指定使用的损失函数

再修改 __call__ 函数 (修改的行已用书签标注出) 

再找到 bbox_iou 函数的所在位置,修改边界框损失的计算方法

这里因为形参、返回值都和原函数不同,所以要检查 ComputeLoss 中调用这个函数的地方,以防报错

def bbox_iou(box1, box2, type_, x1y1x2y2=True):
    # Returns the IoU of box1 to box2. box1 is 4, box2 is nx4
    box2 = box2.T

    # Get the coordinates of bounding boxes
    if x1y1x2y2:  # x1, y1, x2, y2 = box1
        b1_x1, b1_y1, b1_x2, b1_y2 = box1[0], box1[1], box1[2], box1[3]
        b2_x1, b2_y1, b2_x2, b2_y2 = box2[0], box2[1], box2[2], box2[3]
    else:  # transform from xywh to xyxy
        b1_x1, b1_x2 = box1[0] - box1[2] / 2, box1[0] + box1[2] / 2
        b1_y1, b1_y2 = box1[1] - box1[3] / 2, box1[1] + box1[3] / 2
        b2_x1, b2_x2 = box2[0] - box2[2] / 2, box2[0] + box2[2] / 2
        b2_y1, b2_y2 = box2[1] - box2[3] / 2, box2[1] + box2[3] / 2

    # 将边界框信息拼接
    b1 = torch.stack([b1_x1, b1_y1, b1_x2, b1_y2], dim=-1)
    b2 = torch.stack([b2_x1, b2_y1, b2_x2, b2_y2], dim=-1)

    self = IoU_Cal(b1, b2)
    loss = getattr(IoU_Cal, type_)(b1, b2, self=self)
    iou = 1 - self.iou

    return loss, iou

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/337576.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

153、【动态规划】leetcode ——416. 分割等和子集:滚动数组(C++版本)

题目描述 原题链接&#xff1a;1049. 最后一块石头的重量 II 解题思路 本题要找的是最小重量&#xff0c;我们可以将石头划分成两个集合&#xff0c;当两个集合的重量越接近时&#xff0c;相减后&#xff0c;可达到的装量就会是最小&#xff0c;此时本题的思路其实就类似于 4…

【光伏功率预测】基于EMD-PCA-LSTM的光伏功率预测模型(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

MSI_MSI-X中断之体验与使用

MSI_MSI-X中断之体验与使用 文章目录MSI_MSI-X中断之体验与使用1. 怎么发出MSI/MSI-X中断1.1 在RK3399上体验1.1.1 安装工具1.1.2 查看设备MSI-X信息1.1.3 验证MSI-X信息2. 怎么使用MSI/MSI-X3. MSI/MSI-X中断源码分析3.1 IRQ Domain创建流程3.1.1 GIC3.1.2 ITS3.1.3 PCI MSI3.…

【Flutter】【Unity】使用 Flutter + Unity 构建(AR 体验工具包)

使用 Flutter Unity 构建&#xff08;AR 体验工具包&#xff09;【翻译】 原文&#xff1a;https://medium.com/potato/building-with-flutter-unity-ar-experience-toolkit-6aaf17dbb725 由于屡获殊荣的独立动画工作室 Aardman 与讲故事的风险投资公司 Fictioneers&#x…

最大公约数:常用的四大算法求解最大公约数,分解质因数法、短除法、辗转相除法、更相减损法。

常用的四大算法求解最大公约数&#xff0c;分解质因数法、短除法、辗转相除法、更相减损法。 (本文获得CSDN质量评分【91】)【学习的细节是欢悦的历程】Python 官网&#xff1a;https://www.python.org/ Free&#xff1a;大咖免费“圣经”教程《 python 完全自学教程》&#x…

网络基础-虚拟化工具-网桥

系列文章目录 本系列文章主要是回顾和学习工作中常用的网络基础命令&#xff0c;在此记录以便于回顾。 该篇文章主要是讲解虚拟化的工具网桥相关的概念和常用命令 提示&#xff1a;写完文章后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录系…

C++之多态【详细总结】

前言 想必大家都知道面向对象的三大特征&#xff1a;封装&#xff0c;继承&#xff0c;多态。封装的本质是&#xff1a;对外暴露必要的接口&#xff0c;但内部的具体实现细节和部分的核心接口对外是不可见的&#xff0c;仅对外开放必要功能性接口。继承的本质是为了复用&#x…

MySQL(主从、半同步、组复制、MHA高可用)

文章目录一、MySQL源码编译以及初始化二、mysql主从复制、半同步MySQL组复制MySQL读写分离MHA高可用一、MySQL源码编译以及初始化 源码编译使用cmake&#xff0c;所以要提前安装cmake&#xff0c;完成之后make install即可 这里要创建mysql用户&#xff0c;以及用普通用户方式…

电子秤专用模拟数字(AD)转换器芯片HX711介绍

HX711简介HX711是一款专为高精度电子秤而设计的24 位A/D 转换器芯片。与同类型其它芯片相比&#xff0c;该芯片集成了包括稳压电源、片内时钟振荡器等其它同类型芯片所需要的外围电路&#xff0c;具有集成度高、响应速度快、抗干扰性强等优点。降低了电子秤的整机成本&#xff…

分享112个JS菜单导航,总有一款适合您

分享112个JS菜单导航&#xff0c;总有一款适合您 112个JS菜单导航下载链接&#xff1a;https://pan.baidu.com/s/1Dm73d2snbu15hZErJjTXxg?pwdfz1c 提取码&#xff1a;fz1c Python采集代码下载链接&#xff1a;https://wwgn.lanzoul.com/iKGwb0kye3wj base_url "h…

【游戏逆向】RPG游戏背包镶嵌系统分析

镶嵌系统是很多3D游戏都有的功能&#xff0c;玩家可以向镶嵌槽内附加宝石来提升装备的属性&#xff0c;这也直接提升了物品的价值。在一些扫拍卖和摆摊的外挂中经常利用这个属性来低价购入高价值装备。以这款游戏为例&#xff0c;我们来对装备上的镶嵌槽和镶嵌宝石进行分析。 …

Nacos,一款非常优秀的注册中心(附视频)

Nacos 核心源码精讲 - IT贱男 - 掘金小册全方位源码精讲&#xff0c;深度剖析 Nacos 注册中心和配置中心的核心思想。「Nacos 核心源码精讲」由IT贱男撰写&#xff0c;375人购买https://s.juejin.cn/ds/BuC3Vs9/ 先简单说两句 你好&#xff0c;很高兴你能够点开本小册&#x…

python 的 if 语句如何使用说明

文章目录1. 一个示例2. 条件测试2.1 检查是否相等2.2 检查是否相等时不考虑大小写2.3 检查是否不相等2.4 比较数字2.5 检查多个条件2.6 布尔表达式3. if 语句4. 使用 if 语句处理列表1. 一个示例 关于 if 条件语句的使用&#xff0c;我们来写一个示例进行说明&#xff1a; #写…

6.14 Rayleigh商

定义 矩阵在某个向量处的瑞利商Rayleigh quotient是这样定义的: ρ(x):xHAxxHx\rho(x) :\frac{x^HAx}{x^Hx} ρ(x):xHxxHAx​   这个怎么理解呢?上面是埃尔米特内积的表达式&#xff0c;下面是标准埃尔米特内积。但是矩阵不一定是对称阵&#xff0c;如果不是复数的话&#x…

ChatGPT 这个风口,普通人怎么抓住:比如APP集成ChatGPT,公众号集成ChatGPT...

文章目录1. 引出问题2. 简单介绍ChatGPT2.1 ChatGPT是什么2.2 如何使用ChatGPT3. 普通人利用ChatGPT 变现方式1. 引出问题 最近几天OpenAI发布的ChatGPT聊天机器人如日中天&#xff0c;连着上了各个平台的热搜榜。 很多平台也都已集成了ChatGPT&#xff0c;比如csdn的客户端A…

json-server使用

文章目录json-server使用简介安装json-server启动json-server操作创建数据库查询数据增加数据删除数据修改数据putpatch配置静态资源静态资源首页资源json-server使用 简介 github地址 安装json-server npm install -g json-server启动json-server json-server --watch db…

Linux系统位运算函数以及相应CPU ISA实现收录

以32位数据的二进制表示为例&#xff0c;习惯的写法是LSB在左&#xff0c;MSB在右&#xff0c;注意BIT序和大小端的字节序没有关系。Linux和BIT操作有关的接口在定义在头文件bitops.h中&#xff0c;bitops.h定义有两层&#xff0c;通用层和架构层&#xff0c;对应两个bitops.h&…

【重要】2023年上半年有三AI新课程规划出炉,讲师持续招募中!

2023年正式起航&#xff0c;想必大家都已经完全投入到了工作状态中&#xff0c;有三AI平台今年将在已有内容的基础上&#xff0c;继续进行新课程开发&#xff0c;本次我们来介绍今年上半年的课程计划&#xff0c;以及新讲师招募计划。2023年新上线课程我们平台的课程当前分为两…

【Python爬虫案例】批量采集网站壁纸,实现自动更换桌面壁纸

前言 美照天天换&#xff0c;才不会腻 不知道你们是不是这样&#xff0c;我的手机壁纸电脑壁纸&#xff0c;隔三岔五就喜欢换&#xff0c;看久了 我就腻了&#xff0c;索性就用python把这个网站的壁纸都采集下来&#xff0c;顺便再让电脑自动更换我的桌面壁纸 ~ 一篇文章教会…

【AI简报第20230210期】 ChatGPT爆火背后、为AIoT和边缘侧AI喂算力的RISC-V

1. ChatGPT爆火背后&#xff1a;AI芯片迎接算力新挑战原文:https://www.163.com/dy/article/HT7BHN3C05199NPP.htmlChatGPT的出圈走红为AIGC打开全新市场增量&#xff0c;催生了更高的算力需求。作为人工智能三大核心要素之一&#xff0c;算力也被誉为人工智能“发动机”。华泰…