RT-DETR个人整理向理解

news2024/11/15 21:27:48

一、前言

在开始介绍RT-DETR这个网络之前,我们首先需要先了解DETR这个系列的网络与我们常提及的anchor-base以及anchor-free存在着何种差异。
首先我们先简单讨论一下anchor-base以及anchor-free两者的差异与共性:
1、两者差异:顾名思义,这两者一个显而易见的差别就是有无anchor,anchor-base是需要手工选取不同比例大小的anchor来得到proposals,而anchor-free则不需要。当然两者具体差异肯定不是这么几句话就能说的清的,这里不做详细讨论所以按下不表。
2、两者共性:两者虽然在获取proposals的原理方面存在不同,但是其最终还是存在了一个多对一的问题,也就是会对同一个目标产生多个proposal,也即最后两者最后都是需要通过阈值选取以及nms去过滤掉多余的预测框。此处可参考:Nms-Free时代
但是当问题涉及到了工业或者生活等其他领域落地问题上面的时候,无论是anchor-base还是anchor-free所面临的这中两套阈值问题(要先完成阈值筛选(Confidence threshold)和非极大值抑制(NMS)处理两个关键步骤)总是会对时效性产生很大的影响。

二、DETR系列网络的动机

在引言中,我们提到了无论是anchor-base还是anchor-free其实都存在着一个阈值问题,而这个阈值问题就决定了绕不开nms这个机制,nms这一机制的存在也就导致无法真正意义上去实现一个端到端的简易部署的网络模型,而DETR既不需要proposal也不需要anchor,而是直接利用Transformers这种能全局建模的能力,通过将目标检测视为一个集合预测问题。同时由于这种全局建模能力使得DETR系列网络不会输出那么多冗余的框。在此处个人水平有限害怕个人水平对读者的理解造成扭曲,因此在这就不对DETR做过多解释如果有兴趣的可以移步沐神的精讲视频:李沐DETR论文精读

而DETR系列网络究竟有多简洁,上述一小段文字自然无法很好的解释其简洁性,大家可以通过下面视频截图的50行代码看出DETR的简洁性。

在这里插入图片描述

三、RT-DETR网络

首先RT-DETR网络的检测动机其实非常明确,从这个命名也能看出来,其是想打造一个能实际用于工业界的DETR网络。但是对于DETR而言虽然其具备简单易用的特点,然而其实时性较差,在DETR的论文中的实验可以看到其FPS较之于Faster-RCNN更低(如下图所示),因此这是DETR的一个缺点。同时DETR还有另外一个缺点,就是其虽然借助于自注意机制带来的全局信息使得对于大目标检测效果表现较好,但是其对于小目标的检测效果相对而言较弱,当然在RT-DETR中也未解决这个问题,因此此处只提一下按下不表。

在这里插入图片描述
好了,既然目前已经知道DETR有一个实时性较差的缺点,那么接下来就应该对造成推理耗时高的原因进行一下分析,在RT-DETR中作者认为在Encoder部分作用在 S 5 S_5 S5(最顶层特征,即 C 5 C_5 C5只是换个表达方式),这样就可以大幅度减小计算量、提高计算速度,同时不会损伤模型性能,这样做的的原因是作者是基于一下两点考虑:

  1. 以往的DETR,如Deformable DETR是将多尺度的特征都拉平成拼接在其中,构成一个序列很长的向量,尽管这可以使得多尺度之间的特征进行充分的交互,但也会造成极大的计算量和计算耗时。RT-DETR认为这是当前的DETR计算速度慢的主要原因之一;
  2. RT-DETR认为相较于较浅 S 3 S_3 S3特征和 S 4 S_4 S4特征, S 5 S_5 S5特征拥有更深、更高级、更丰富的语义特征,这些语义特征是Transformer更加感兴趣的和需要的,对于区分不同物体的特征是更加有用的,而浅层特征因缺少较好的语义特征而起不到什么作用。

于个人而言感觉这个观点很类似YOLOF的观点,在YOLOF中也是直接使用顶层的特征层,有感兴趣的可以去看看YOLOF这篇文章。

而为了验证这个观点,作者的团队设计了若干对照组实验,实验如下图所示:
在这里插入图片描述
对于对照组(a),其结构就是DINO-R50,但移除了DINO-R50中的多尺度encoder,直接将 S 3 S_3 S3 S 4 S_4 S4 S 5 S_5 S5拼接在一起,交给后续的网络去处理,得到最终的输出。注意,这里的拼接是先将二维的 H × W H×W H×W拉平成 H W HW HW然后再去拼接: H 1 W 1 + H 2 W 2 + H 3 W 3 H_1W_1+H_2W_2+H_3W_3 H1W1+H2W2+H3W3

对于对照组(b),作者团队在(a)基础上,加入了单尺度的Transformer Encoder(SSE),仅包含一层Encoder层,分别处理三个尺度的输出,注意,三个尺度共享一个SSE,而不是为每一个尺度都设计一个独立的SSE。通过这一共享的操作,三个尺度的信息是可以实现一定程度的信息交互。最后将处理结果拼接在一起,交给后续的网络去处理,得到最终的输出。

对于对照组©,作者团队使用多尺度的Transformer Encoder(MSE),大概是Deformable DETR所采用的那一类MSE结构。将三个尺度的特征拼接在一起后,交由MSE来做处理,使得三个尺度的特征同时完成“尺度内”和“跨尺度”的信息交互和融合,最后将处理结果,交给后续的网络去处理,得到最终的输出。

对于对照组(d),作者团队则先用共享的SSE分别处理每个尺度的特征,然后再使用PAN-like的特征金字塔网络去融合三个尺度的特征,最后将融合后的多尺度特征拼接在一起,交给后续的网络去处理,得到最终的输出。

对于对照组(e),作者团队则使用一个SSE只处理 S 5 S_5 S5特征,即所谓的AIFI模块,随后再使用CCFM模块去完成跨尺度的特征融合,最后将融合后的多尺度特征拼接在一起,交给后续的网络去处理,得到最终的输出。

在这里插入图片描述
最终,对比结果如上方的图所示,我们简单地来分析一下这组对比试验说明了什么样的结论。

  • 首先,A即对照组(a)取得到了43.0 AP的结果,注意,A的设置是不包含Encoder的,即没有自注意力机制,在Backbone之后直接接Decoder去做处理,从而获得输出结果,可想而知,A的性能应该是最差的,这也是后续实验的Baseline;
  • 随后,在A的基础上,B引入了共享的SSE去处理每个尺度的特征,使得性能从43.0提升至44.9,表明使用共享的SSE是可以提升性能的。从研究的角度来说,对于B,应该再做一个额外的实验,即使用三个独立的SSE分别去处理每个尺度的特征,以此来论证“共享SSE”的必要性。当然,我们可以感性地认识到共享SSE会更好,但从理性的严谨层面来讲,补上这一对比试验还是有必要的。简而言之,B证明了加入Encoder会更好;
  • 相较于B,C则是使用MSE,即使用MSE来同步完成“尺度内”和“跨尺度”的特征融合(应该和Deformable DETR的多尺度Encoder做法相似),这一做法可以让不同尺度的特征之间得到更好的交互和融合,可预见地会提升了AP指标,其实验结果也意料内地证明了这一点:AP指标从43.0提升至45.6,要高于B的44.9,这表明MSE的做法是有效的,即“尺度内”和“跨尺度”的特征融合是必要的。但是,从速度的角度来看,MSE拖慢了推理速度,Latency从7.2增加值13.3 ms,要高于B组的11.1 ms;
  • 随后是对照组D,不同于C,D是相当于解耦了C中的MSE:先使用共享的SSE分别去处理每个尺度的特征,完成“尺度内”的信息交互,然后再用一个PAN风格的跨尺度融合网络去融合不同尺度之间的特征,完成“跨尺度”的信息融合。这种做法可以有效地避免MSE中因输入的序列过长而导致的计算量增加的问题。相较于C,D的这种解耦的做法不仅仅使得Latency从13.3 ms降低至12.2 ms,性能也从45.6 AP提升至46.4 AP,这表明MSE的做法并不是最优的,先处理“尺度内”,再完成“跨尺度”,性能会更好;
  • 随后是对照组D,不同于C,D是相当于解耦了C中的MSE:先使用共享的SSE分别去处理每个尺度的特征,完成“尺度内”的信息交互,然后再用一个PAN风格的跨尺度融合网络去融合不同尺度之间的特征,完成“跨尺度”的信息融合。这种做法可以有效地避免MSE中因输入的序列过长而导致的计算量增加的问题。相较于C,D的这种解耦的做法不仅仅使得Latency从13.3 ms降低至12.2 ms,性能也从45.6 AP提升至46.4 AP,这表明MSE的做法并不是最优的,先处理“尺度内”,再完成“跨尺度”,性能会更好;
  • 最后就是对照组E,在DS5的基础上,E重构了跨尺度特征融合模块,构建了新的CCFM模块,由于论文里没给出CSF模块的细节,所以CCFM模块究竟调整了哪里也是无法获知的,但就CCFM本身来看,大体上也是一个PAN-like的结构。在换上了CCFM后,性能从46.8进一步地提升至47.9。

综上,这组对比试验证明了两件事:1) Transformer的Encoder部分只需要处理high-level特征,既能大幅度削减计算量、提升计算速度,同时也不会损伤到性能,甚至还有所提升;2) 对于多尺度特征的交互和融合,我们仍可以采用CNN架构常用的PAN网络来搭建,只需要一些细节上的调整即可。

另外,我们仔细来看一下这个对照组(e),注意,根据论文给出的结果和源代码,所谓的CCFM其实还是PaFPN,如下方的图10所示,其中的Fusion模块就是一个CSPBlock风格的模块。
在这里插入图片描述
为了看得更仔细一些,我们来看一下官方源码,如下方的Python代码所示。依据论文的设定,HybridEncoder包含AIFI和CCFM两大模块,其中AIFI就是Transformer的Encoder部分,而CCFM其实就是常见的PaFPN结构:首先用若干层1x1卷积将所有的特征的通道数都映射至同一数目,如256,随后再进行top-down和bottom-up两部分的特征融合。

# https://github.com/PaddlePaddle/PaddleDetection/blob/develop/ppdet/modeling/transformers/hybrid_encoder.py

class HybridEncoder(nn.Layer):
    __shared__ = ['depth_mult', 'act', 'trt', 'eval_size']
    __inject__ = ['encoder_layer']

    def __init__(self,
                 in_channels=[512, 1024, 2048],
                 feat_strides=[8, 16, 32],
                 hidden_dim=256,
                 use_encoder_idx=[2],
                 num_encoder_layers=1,
                 encoder_layer='TransformerLayer',
                 pe_temperature=10000,
                 expansion=1.0,
                 depth_mult=1.0,
                 act='silu',
                 trt=False,
                 eval_size=None):
        super(HybridEncoder, self).__init__()
        self.in_channels = in_channels
        self.feat_strides = feat_strides
        self.hidden_dim = hidden_dim
        self.use_encoder_idx = use_encoder_idx
        self.num_encoder_layers = num_encoder_layers
        self.pe_temperature = pe_temperature
        self.eval_size = eval_size

        # channel projection
        self.input_proj = nn.LayerList()
        for in_channel in in_channels:
            self.input_proj.append(
                nn.Sequential(
                    nn.Conv2D(in_channel, hidden_dim, kernel_size=1, bias_attr=False),
                    nn.BatchNorm2D(
                        hidden_dim,
                        weight_attr=ParamAttr(regularizer=L2Decay(0.0)),
                        bias_attr=ParamAttr(regularizer=L2Decay(0.0)))))
        # encoder transformer
        self.encoder = nn.LayerList([
            TransformerEncoder(encoder_layer, num_encoder_layers)
            for _ in range(len(use_encoder_idx))
        ])

        act = get_act_fn(
            act, trt=trt) if act is None or isinstance(act, str, dict)) else act
        # top-down fpn
        self.lateral_convs = nn.LayerList()
        self.fpn_blocks = nn.LayerList()
        for idx in range(len(in_channels) - 1, 0, -1):
            self.lateral_convs.append(
                BaseConv(hidden_dim, hidden_dim, 1, 1, act=act))
            self.fpn_blocks.append(
                CSPRepLayer(
                    hidden_dim * 2,
                    hidden_dim,
                    round(3 * depth_mult),
                    act=act,
                    expansion=expansion))

        # bottom-up pan
        self.downsample_convs = nn.LayerList()
        self.pan_blocks = nn.LayerList()
        for idx in range(len(in_channels) - 1):
            self.downsample_convs.append(
                BaseConv(hidden_dim, hidden_dim, 3, stride=2, act=act))
            self.pan_blocks.append(
                CSPRepLayer(
                    hidden_dim * 2,
                    hidden_dim,
                    round(3 * depth_mult),
                    act=act,
                    expansion=expansion))

    def forward(self, feats, for_mot=False):
        assert len(feats) == len(self.in_channels)
        # get projection features
        proj_feats = [self.input_proj[i](feat) for i, feat in enumerate(feats)]
        # encoder
        if self.num_encoder_layers > 0:
            for i, enc_ind in enumerate(self.use_encoder_idx):
                h, w = proj_feats[enc_ind].shape[2:]
                # flatten [B, C, H, W] to [B, HxW, C]
                src_flatten = proj_feats[enc_ind].flatten(2).transpose(
                    [0, 2, 1])
                if self.training or self.eval_size is None:
                    pos_embed = self.build_2d_sincos_position_embedding(
                        w, h, self.hidden_dim, self.pe_temperature)
                else:
                    pos_embed = getattr(self, f'pos_embed{enc_ind}', None)
                memory = self.encoder[i](src_flatten, pos_embed=pos_embed)
                proj_feats[enc_ind] = memory.transpose([0, 2, 1]).reshape(
                    [-1, self.hidden_dim, h, w])

        # top-down fpn
        inner_outs = [proj_feats[-1]]
        for idx in range(len(self.in_channels) - 1, 0, -1):
            feat_heigh = inner_outs[0]
            feat_low = proj_feats[idx - 1]
            feat_heigh = self.lateral_convs[len(self.in_channels) - 1 - idx](
                feat_heigh)
            inner_outs[0] = feat_heigh

            upsample_feat = F.interpolate(
                feat_heigh, scale_factor=2., mode="nearest")
            inner_out = self.fpn_blocks[len(self.in_channels) - 1 - idx](
                paddle.concat(
                    [upsample_feat, feat_low], axis=1))
            inner_outs.insert(0, inner_out)

        # bottom-up pan
        outs = [inner_outs[0]]
        for idx in range(len(self.in_channels) - 1):
            feat_low = outs[-1]
            feat_height = inner_outs[idx + 1]
            downsample_feat = self.downsample_convs[idx](feat_low)
            out = self.pan_blocks[idx](paddle.concat(
                [downsample_feat, feat_height], axis=1))
            outs.append(out)

        return outs

而对于其中解码器的decoder部分使用的是"DINO Head"的decoder部分,也即使用了DINO的一个“去噪思想”(具体我未了解过,有感兴趣的可以自行了解)。但是看官方源码可知在推理阶段的时候,RT-DETR的decoder部分与DETR并无区别,由于我只关注推理阶段因此关于"去噪思想"这部分各位可以详细看看DINO以及官方源码自行了解。

 class RTDETRTransformer(nn.Layer):
    __shared__ = ['num_classes', 'hidden_dim', 'eval_size']

    def __init__(self,
                 num_classes=80,
                 hidden_dim=256,
                 num_queries=300,
                 position_embed_type='sine',
                 backbone_feat_channels=[512, 1024, 2048],
                 feat_strides=[8, 16, 32],
                 num_levels=3,
                 num_decoder_points=4,
                 nhead=8,
                 num_decoder_layers=6,
                 dim_feedforward=1024,
                 dropout=0.,
                 activation="relu",
                 num_denoising=100,
                 label_noise_ratio=0.5,
                 box_noise_scale=1.0,
                 learnt_init_query=True,
                 query_pos_head_inv_sig=False,
                 eval_size=None,
                 eval_idx=-1,
                 eps=1e-2):
        super(RTDETRTransformer, self).__init__()
        assert position_embed_type in ['sine', 'learned'], \
            f'ValueError: position_embed_type not supported {position_embed_type}!'
        assert len(backbone_feat_channels) <= num_levels
        assert len(feat_strides) == len(backbone_feat_channels)
        for _ in range(num_levels - len(feat_strides)):
            feat_strides.append(feat_strides[-1] * 2)

        self.hidden_dim = hidden_dim
        self.nhead = nhead
        self.feat_strides = feat_strides
        self.num_levels = num_levels
        self.num_classes = num_classes
        self.num_queries = num_queries
        self.eps = eps
        self.num_decoder_layers = num_decoder_layers
        self.eval_size = eval_size

        # backbone feature projection
        self._build_input_proj_layer(backbone_feat_channels)

        # Transformer module
        decoder_layer = TransformerDecoderLayer(
            hidden_dim, nhead, dim_feedforward, dropout, activation, num_levels,
            num_decoder_points)
        self.decoder = TransformerDecoder(hidden_dim, decoder_layer,
                                          num_decoder_layers, eval_idx)

        # denoising part
        self.denoising_class_embed = nn.Embedding(
            num_classes,
            hidden_dim,
            weight_attr=ParamAttr(initializer=nn.initializer.Normal()))
        self.num_denoising = num_denoising
        self.label_noise_ratio = label_noise_ratio
        self.box_noise_scale = box_noise_scale

        # decoder embedding
        self.learnt_init_query = learnt_init_query
        if learnt_init_query:
            self.tgt_embed = nn.Embedding(num_queries, hidden_dim)
        self.query_pos_head = MLP(4, 2 * hidden_dim, hidden_dim, num_layers=2)
        self.query_pos_head_inv_sig = query_pos_head_inv_sig

        # encoder head
        self.enc_output = nn.Sequential(
            nn.Linear(hidden_dim, hidden_dim),
            nn.LayerNorm(
                hidden_dim,
                weight_attr=ParamAttr(regularizer=L2Decay(0.0)),
                bias_attr=ParamAttr(regularizer=L2Decay(0.0))))
        self.enc_score_head = nn.Linear(hidden_dim, num_classes)
        self.enc_bbox_head = MLP(hidden_dim, hidden_dim, 4, num_layers=3)

        # decoder head
        self.dec_score_head = nn.LayerList([
            nn.Linear(hidden_dim, num_classes)
            for _ in range(num_decoder_layers)
        ])
        self.dec_bbox_head = nn.LayerList([
            MLP(hidden_dim, hidden_dim, 4, num_layers=3)
            for _ in range(num_decoder_layers)
        ])

        self._reset_parameters()

    def forward(self, feats, pad_mask=None, gt_meta=None, is_teacher=False):
        # input projection and embedding
        (memory, spatial_shapes,
         level_start_index) = self._get_encoder_input(feats)

        # prepare denoising training
        if self.training:
            denoising_class, denoising_bbox_unact, attn_mask, dn_meta = \
                get_contrastive_denoising_training_group(gt_meta,
                                            self.num_classes,
                                            self.num_queries,
                                            self.denoising_class_embed.weight,
                                            self.num_denoising,
                                            self.label_noise_ratio,
                                            self.box_noise_scale)
        else:
            denoising_class, denoising_bbox_unact, attn_mask, dn_meta = None, None, None, None

        target, init_ref_points_unact, enc_topk_bboxes, enc_topk_logits = \
            self._get_decoder_input(
            memory, spatial_shapes, denoising_class, denoising_bbox_unact,is_teacher)

        # decoder
        out_bboxes, out_logits = self.decoder(
            target,
            init_ref_points_unact,
            memory,
            spatial_shapes,
            level_start_index,
            self.dec_bbox_head,
            self.dec_score_head,
            self.query_pos_head,
            attn_mask=attn_mask,
            memory_mask=None,
            query_pos_head_inv_sig=self.query_pos_head_inv_sig)
        return (out_bboxes, out_logits, enc_topk_bboxes, enc_topk_logits,
                dn_meta)

同样在RT-DETR中提及的IoU-aware Query Selection其实在推理阶段也不存在,其是在训练期间约束检测器对高 IoU 的特征产生高分类分数,对低 IoU 的特征产生低分类分数。因此若只关注推理阶段的读者,这部分也可无需关注,而关于IoU-aware Query Selection此部分其实是在assignment阶段和计算loss的阶段,classification的标签都换成了 “IoU软标签”

在这里插入图片描述

所谓的“IoU软标签”,就是指将预测框与GT之间的IoU作为类别预测的标签。熟悉YOLO工作的读者一定对此不会陌生,其本质就是已经被广泛验证了的IoU-aware。在最近的诸多工作里,比如RTMDet、DAMO-YOLO等工作中,都有引入这一理念,去对齐类别和回归的差异。之所以这么做,是因为按照以往的one-hot方式,完全有可能出现“当定位还不够准确的时候,类别就已经先学好了”的“未对齐”的情况,毕竟类别的标签非0即1。但如果将IoU作为类别的标签,那么类别的学习就要受到回归的调制,只有当回归学得也足够好的时候,类别才会学得足够好,否则,类别不会过快地先学得比回归好,因此后者显式地制约着前者。

四、总结

最后先看一下论文在实验部分给出的对比表格,如下方的图所示:
在这里插入图片描述
由于在这里我考虑的是RT-DETR的实时性、GFLOPS以及相应的检测性能,因此我只关注其与YOLO系列的对比,而在YOLO系列中目前使用较多的是YOLOV5以及PPYOLOE网络。而RT-DETR与这两个网络对应的L与X对比能看到其FPS是V5的一倍,同样也比PP高出十来FPS,而算力开销也是与两者接近,检测性能同样高出了这两者几个点。同时RT-DETR这个网络也继承了DETR网络只要支持CNN与Transformer就能使用以及其推理阶段简洁性的特点。不难看出在未来DETR系列的网络应能全面铺开,而且其网络的简洁性对于实际部署工作也是有利的。

总而言之,在未来完完全全可以在实时的DETR网络方面好好期待一把。因此于此处记录一下阅读这篇文章以及DETR的读后感。受限于个人能力其中纰漏肯定还有不少,欢迎各位大力指出,共同成长。

参考链接:
《目标检测》-第33章-浅析RT-DETR
超越YOLOv8,飞桨推出精度最高的实时检测器RT-DETR!
PaddlePaddle
DETR 论文精读
Nms-Free时代

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

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

相关文章

《TCP/IP网络编程》阅读笔记--域名及网络地址

目录 1--域名系统 2--域名与 IP 地址的转换 2-1--利用域名来获取 IP 地址 2-2--利用 IP 地址获取域名 3--代码实例 3-1--gethostbyname() 3-2--gethostbyaddr() 1--域名系统 域名系统&#xff08;Domain Name System&#xff0c;DNS&#xff09;是对 IP 地址和域名进行相…

三分钟,教你做出领导满意的可视化报表

数字化已然成为社会发展的共识&#xff0c;企业想要在未来的竞争中占据优势&#xff0c;获取不断发展的数字经济&#xff0c;就必须将数据看作企业的战略资源&#xff0c;利用数据可视化将数据转化为信息&#xff0c;促进企业发展。 数据可视化是什么 在早期数据分析领域&…

业务安全情报第22期 | 不法分子为何盗刷企业短信?

目录 手机短信的重要性 手机短信接口被攻击的危害 社交App短信遭遇疯狂盗刷 社交App该如何防控威胁 规则上的防护措施 技术上的防护措施 近期监测发现&#xff0c;某知名社交平台遭遇黑灰产大规模注册账号&#xff0c;账号短信接口被疯狂盗用。不仅影响正常用户操作&…

TSINGSEE青犀AI视频分析/边缘计算/AI算法·人脸识别功能——多场景高效运用

旭帆科技AI智能分析网关可提供海量算法供应&#xff0c;涵盖目标监测、分析、抓拍、动作分析、AI识别等&#xff0c;可应用于各行各业的视觉场景中。同时针对小众化场景可快速定制AI算法&#xff0c;主动适配大厂近百款芯片&#xff0c;打通云/边/端灵活部署&#xff0c;算法一…

Stable Diffusion — ControlNet 超详细讲解

Stable Diffusion — ControlNet 超详细讲解 ControlNet 最近非常火&#x1f525;&#xff01;ControlNet 和 Stable Diffusion 的结合使 Stable Diffusion 能够接受指导图像生成过程的条件输入&#xff0c;从而增强了 Stable Diffusion 的性能。今天为大家深入剖析 ControlNe…

华为数通方向HCIP-DataCom H12-821题库(单选题:321-340)

第321题 BGP的Open报文是用于建立对等体连接的,以下哪一项不属于Open报文中携带的参数信息? A、发送者的Router ID B、AS号 C、BGP版本号 D、TCP端口号 答案:D 解析:以下是BGP的Open报文: 第322题 在建立BGP对等体的过程中,OpenSent状态表明BGP等待的Open报文 并对收…

合宙Air724UG LuatOS-Air LVGL API控件-微调框 (Spinbox)

微调框 (Spinbox) 微调框用于数值调整&#xff0c;有时候我们希望获取一个用户输入的数值&#xff0c;但是又不希望弹出键盘&#xff0c;可以使用微调框。 示例代码 -- 回调函数 function spinbox_increment_event_cb(obj, event)if event lvgl.EVENT_SHORT_CLICKED thenlvg…

RetroArch 接入两个同款手柄只能识别到一个导致无法双打的问题

测试平台 设备:StationPC M3 RetroArch: 1.1.5(当前官方最新) 手柄:北通蝙蝠BD2F(XBOX360键位) 问题说明 RetroArch插入两个同款手柄/摇杆时只能识别到一个&#xff0c;此时两个手柄都是可以控制模拟器&#xff0c;但是进入游戏也都是p1&#xff0c;无法实现双打 解决办法 …

【Redis】Bitmap 使用及应用场景

前言&#xff1a;bitmap 占用空间小&#xff0c;查询效率高&#xff0c;在一些场景中使用 bitmap 是一个很好的选择。 一、bitmap 相关命令 SETBIT - 设置指定位置的比特值&#xff0c;可以设为 1 或 0 例如 SETBIT key 10 1&#xff0c;将在 key 对应的 bitmap 中第10位设置为…

数据结构——二叉树线索化遍历(前中后序遍历)

二叉树线索化 线索化概念&#xff1a; 为什么要转换为线索化 二叉树线索化是一种将普通二叉树转换为具有特殊线索&#xff08;指向前驱和后继节点&#xff09;的二叉树的过程。这种线索化的目的是为了提高对二叉树的遍历效率&#xff0c;特别是在不使用递归或栈的情况下进行遍历…

io和进程day03(文件IO、文件属性函数、目录相关函数)

今日任务 代码 #include <stdio.h> #include <string.h> #include <stdlib.h> #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> #include <sys/types.h> #include <pwd.h> #include <dirent.h> #in…

【管理运筹学】第 7 章 | 图与网络分析(3,最短路问题)

文章目录 引言三、最短路问题3.1 最短路问题定义3.2 Dijkstra 算法3.2.1 算法基本依据3.2.2 算法基本思想与步骤 3.3 逐次逼近算法&#xff08;Bellman-Ford 算法&#xff09;3.4 Floyd 算法 写在最后 引言 承接前文&#xff0c;我们来学习图论中另一个经典问题 —— 最短路问…

解决:使用MySQL Command Line Client时光标不显示的问题

项目场景&#xff1a; 在使用MySQL Command Line Client时&#xff0c;有时候光标会不显示出来&#xff0c;就像下面的图片显示一样。 问题描述&#xff1a; 光标会不显示出来。 解决方案&#xff1a;​​​​​​​ 1.首先将输入法切换到中文输入法&#xff0c;然后随便打出一…

(2023,Diffusion 稳健性 攻击)稳定扩散模型是不稳定的

Stable Diffusion is Unstable 公众号&#xff1a;EDPJ&#xff08;添加 VX&#xff1a;CV_EDPJ 进交流群获取资料&#xff09; 目录 0. 摘要 1. 简介 2. 相关工作 2.1 扩散模型 2.2 文本到图像模型的缺陷 3. 基础 4. 稳定扩散模型的缺陷 4.1 生成速度的变化 4.…

介绍PHP

PHP是一种流行的服务器端编程语言&#xff0c;用于开发Web应用程序。它是一种开源的编程语言&#xff0c;具有易学易用的语法和强大的功能。PHP支持在服务器上运行的动态网页和Web应用程序的快速开发。 PHP可以与HTML标记语言结合使用&#xff0c;从而能够生成动态的Web页面&a…

Java实践-物联网loT入门-MQTT传输协议

前言 MQTT是一个极其轻量级的发布/订阅消息传输协议,适用于网络带宽较低的场合. 它通过一个代理服务器&#xff08;broker&#xff09;&#xff0c;任何一个客户端&#xff08;client&#xff09;都可以订阅或者发布某个主题的消息&#xff0c;然后订阅了该主题的客户端则会收…

红米note5 拆金属外壳

红米note5 拆金属外壳 卡扣式 外壳 屏幕 先拿下来&#xff0c;sim卡的那个卡座。 贴边&#xff0c;到这个卡扣的地方&#xff0c;用工具翘一下&#xff0c;然后下一个卡扣的地方翘一下&#xff0c;然后慢慢的整个的拿下来。 别硬翘&#xff0c;小刀的刀尖&#xff0c;容易给…

jeesite自定义数据字典,自定义字典表,自带树选择数据源(保姆级图文教程)

文章目录 前言一、框架自带树字典表如何使用二、自定义表作为字典表1. 下拉选项使用自建表作为字典表。实际效果框架示例实际开发代码总结前言 项目开发中字典表如果不满足实际需求,比如使用自己的表作为字典,系统自带字典表树如何使用等问题进行总结记录。 一、框架自带树字…

端口扫描-安全体系-网络安全技术和协议

端口扫描-安全体系-网络安全技术和协议 端口扫描信息安全的保证体系和评估方法网络安全技术网络攻击和威胁(重要)网络安全协议 端口扫描 全TCP连接:三次握手 半打开式扫描:前两次握手 FIN扫描:不用建立TCP连接 第三方扫描: 拒绝服务攻击有: 同步包风暴ICMP攻击SNMP攻击 都是修改…

卡牌类游戏推荐,卡牌类三国手游排行榜

以下是小编要推荐给大家的关于卡牌类三国手游排行榜的内容。这里有来自各个历史阶段的名将和美女&#xff0c;让你体验最真实的三国战役。你可以将各种战略思维运用到其中&#xff0c;感受步步为营的喜悦&#xff0c;最终赢得战火纷飞的三国&#xff0c;如果想了解每个游戏的具…