有效涨点,增强型 YOLOV8 与多尺度注意力特征融合,附代码,详细步骤

目录

摘要

结构图 

 原理

代码实现

添加ymal文件 

实验结果

可接论文指导----------> v jiabei-545

完整代码(失效+ -----------👆 )

执行程序流程


摘要

在本实验中,我们通过将双层路由注意(BRA)、广义特征金字塔网络(GFPN)和第四检测头结合到YOLOv8中,开发了一种新颖的BGF-YOLO架构。 BGF-YOLO 包含注意力机制,可以更多地关注重要特征,特征金字塔网络可以通过将高级语义特征与空间细节合并来丰富特征表示。此外,我们研究了不同的注意力机制和特征融合、检测头架构对检测准确性的影响。实验结果表明,与YOLOv8x相比,BGF-YOLO的mAP50增加了4.7%。

我们提出了一种称为 BGF-YOLO 的新模型,它通过结合双层路由注意(BRA)、广义 FPN(GFPN)和第四检测头来增强 YOLOv8 的检测性能。这项工作的贡献总结如下:

1、我们用基于GFPN的结构化特征融合网络重建了YOLOv8的原始颈部部分,以促进不同级别的有效特征融合。

2、我们利用 BRA 进行动态和稀疏注意力机制,以关注更显着的特征并减少特征冗余。

3、我们添加了第四个检测头来丰富锚框的尺度并优化检测的回归损失。

结构图 
 BGF-YOLO的架构基于YOLOv8,并结合了新的彩色模块Bi-level Routing Attention(BRA)和Cross Stage Partial DenseNet(CSP)。 Conv、C2f(快捷方式)、SPPF、Concat、Upsample 和 Detect 是原始 YOLOv8 架构中的现有模块。
 原理

广义FPN(GFPN)采用密集链接和皇后融合的结构来产生更好融合的特征,并使用concat操作而不是求和来执行特征融合以减少信息丢失。 AFPN在渐近过程中使用自适应空间融合,首先融合两个低级特征,然后融合更高级别的特征,最后融合顶级特征,以增强关键级别的重要性并减轻来自不同对象的矛盾信息的影响。

注意力机制最初是为了权衡特定特征相对于其他特征的重要性而提出的。在计算机视觉背景下,有五种注意力机制在提高目标检测性能方面具有巨大潜力:挤压和激励(SE)、CBAM、高效通道注意力(ECA)、CA、感受野注意力(RFA)和BRA。它们之间的区别在于SE和ECA属于通道注意力,RFA和BRA处理空间注意力,CBAM和CA促进通道和空间注意力。 SE 是通过显式建模卷积特征通道之间的相互依赖性来自适应地重新校准通道特征响应。 ECA仅捕获本地通道相互依赖性,而不依赖全局统计来减少计算需求。 RFA的优点是提供有效的注意力权重来实现卷积核参数共享。 BRA 是一种动态的、查询感知的稀疏注意力机制,它以内容感知的方式为每个查询启用最相关的键/值标记的一小部分。我们通过采用 BRA 注意模块改进了所提出的基于 GFPN 的特征融合结构,以实现有效的多级特征融合,同时避免跨特征图的冗余信息。动态稀疏注意力可以通过在整合不同尺度的特征图时应用每个通道的权重分布和空间位置来减少冗余特征信息并提高模型的检测精度。我们在特征融合过程中将BRA模块放置在Conv或Upsample模块后面,使模型在特征提取后只关注特定区域。为了进一步避免信息丢失,CSP 模块中的跳过连接使得底层特征图的知识能够在后续层中重用。 BRA 的目标是在更广泛的区域层面消除大多数不相关的键值对输入,只留下少数相关区域。以特征图作为输入,BRA 首先将其分割成各个区域,并通过线性变换导出查询、键和值。将查询和键的区域级关系输入到邻接矩阵中以构造有向图并查明特定键值对的关联。这实质上确定了每个指定区域应涉及哪些领域。最后,利用区域到区域路由索引矩阵在各个令牌之间执行多头自注意力。通过多头自注意力的双层路由优化,更多地关注特征图的ROI部分,从而提高模型检测的能力。

代码实现
class CSPStage(nn.Module):
    def __init__(self,
                 ch_in,
                 ch_out,
                 n,
                 block_fn='BasicBlock_3x3_Reverse',
                 ch_hidden_ratio=1.0,
                 act='silu',
                 spp=False):
        super(CSPStage, self).__init__()

        split_ratio = 2
        ch_first = int(ch_out // split_ratio)
        ch_mid = int(ch_out - ch_first)
        self.conv1 = ConvBNAct(ch_in, ch_first, 1, act=act)
        self.conv2 = ConvBNAct(ch_in, ch_mid, 1, act=act)
        self.convs = nn.Sequential()

        next_ch_in = ch_mid
        for i in range(n):
            if block_fn == 'BasicBlock_3x3_Reverse':
                self.convs.add_module(
                    str(i),
                    BasicBlock_3x3_Reverse(next_ch_in,
                                           ch_hidden_ratio,
                                           ch_mid,
                                           act=act,
                                           shortcut=True))
            else:
                raise NotImplementedError
            if i == (n - 1) // 2 and spp:
                self.convs.add_module(
                    'spp', SPP(ch_mid * 4, ch_mid, 1, [5, 9, 13], act=act))
            next_ch_in = ch_mid
        self.conv3 = ConvBNAct(ch_mid * n + ch_first, ch_out, 1, act=act)

    def forward(self, x):
        y1 = self.conv1(x)
        y2 = self.conv2(x)

        mid_out = [y1]
        for conv in self.convs:
            y2 = conv(y2)
            mid_out.append(y2)
        y = torch.cat(mid_out, axis=1)
        y = self.conv3(y)
        return y
class BiLevelRoutingAttention(nn.Module):
    """
    n_win: number of windows in one side (so the actual number of windows is n_win*n_win)
    kv_per_win: for kv_downsample_mode='ada_xxxpool' only, number of key/values per window. Similar to n_win, the actual number is kv_per_win*kv_per_win.
    topk: topk for window filtering
    param_attention: 'qkvo'-linear for q,k,v and o, 'none': param free attention
    param_routing: extra linear for routing
    diff_routing: wether to set routing differentiable
    soft_routing: wether to multiply soft routing weights
    """
    def __init__(self, dim, n_win=7, num_heads=8, qk_dim=None, qk_scale=None,
                 kv_per_win=4, kv_downsample_ratio=4, kv_downsample_kernel=None, kv_downsample_mode='identity',
                 topk=4, param_attention="qkvo", param_routing=False, diff_routing=False, soft_routing=False, side_dwconv=3,
                 auto_pad=True):
        super().__init__()
        # local attention setting
        self.dim = dim
        self.n_win = n_win  # Wh, Ww
        self.num_heads = num_heads
        self.qk_dim = qk_dim or dim
        assert self.qk_dim % num_heads == 0 and self.dim % num_heads==0, 'qk_dim and dim must be divisible by num_heads!'
        self.scale = qk_scale or self.qk_dim ** -0.5


        ################side_dwconv (i.e. LCE in ShuntedTransformer)###########
        self.lepe = nn.Conv2d(dim, dim, kernel_size=side_dwconv, stride=1, padding=side_dwconv//2, groups=dim) if side_dwconv > 0 else \
            lambda x: torch.zeros_like(x)

        ################ global routing setting #################
        self.topk = topk
        self.param_routing = param_routing
        self.diff_routing = diff_routing
        self.soft_routing = soft_routing
        # router
        assert not (self.param_routing and not self.diff_routing) # cannot be with_param=True and diff_routing=False
        self.router = TopkRouting(qk_dim=self.qk_dim,
                                  qk_scale=self.scale,
                                  topk=self.topk,
                                  diff_routing=self.diff_routing,
                                  param_routing=self.param_routing)
        if self.soft_routing: # soft routing, always diffrentiable (if no detach)
            mul_weight = 'soft'
        elif self.diff_routing: # hard differentiable routing
            mul_weight = 'hard'
        else:  # hard non-differentiable routing
            mul_weight = 'none'
        self.kv_gather = KVGather(mul_weight=mul_weight)

        # qkv mapping (shared by both global routing and local attention)
        self.param_attention = param_attention
        if self.param_attention == 'qkvo':
            self.qkv = QKVLinear(self.dim, self.qk_dim)
            self.wo = nn.Linear(dim, dim)
        elif self.param_attention == 'qkv':
            self.qkv = QKVLinear(self.dim, self.qk_dim)
            self.wo = nn.Identity()
        else:
            raise ValueError(f'param_attention mode {self.param_attention} is not surpported!')

        self.kv_downsample_mode = kv_downsample_mode
        self.kv_per_win = kv_per_win
        self.kv_downsample_ratio = kv_downsample_ratio
        self.kv_downsample_kenel = kv_downsample_kernel
        if self.kv_downsample_mode == 'ada_avgpool':
            assert self.kv_per_win is not None
            self.kv_down = nn.AdaptiveAvgPool2d(self.kv_per_win)
        elif self.kv_downsample_mode == 'ada_maxpool':
            assert self.kv_per_win is not None
            self.kv_down = nn.AdaptiveMaxPool2d(self.kv_per_win)
        elif self.kv_downsample_mode == 'maxpool':
            assert self.kv_downsample_ratio is not None
            self.kv_down = nn.MaxPool2d(self.kv_downsample_ratio) if self.kv_downsample_ratio > 1 else nn.Identity()
        elif self.kv_downsample_mode == 'avgpool':
            assert self.kv_downsample_ratio is not None
            self.kv_down = nn.AvgPool2d(self.kv_downsample_ratio) if self.kv_downsample_ratio > 1 else nn.Identity()
        elif self.kv_downsample_mode == 'identity': # no kv downsampling
            self.kv_down = nn.Identity()
        elif self.kv_downsample_mode == 'fracpool':
            # assert self.kv_downsample_ratio is not None
            # assert self.kv_downsample_kenel is not None
            # TODO: fracpool
            # 1. kernel size should be input size dependent
            # 2. there is a random factor, need to avoid independent sampling for k and v
            raise NotImplementedError('fracpool policy is not implemented yet!')
        elif kv_downsample_mode == 'conv':
            # TODO: need to consider the case where k != v so that need two downsample modules
            raise NotImplementedError('conv policy is not implemented yet!')
        else:
            raise ValueError(f'kv_down_sample_mode {self.kv_downsaple_mode} is not surpported!')

        # softmax for local attention
        self.attn_act = nn.Softmax(dim=-1)

        self.auto_pad=auto_pad

    def forward(self, x, ret_attn_mask=False):
        """
        x: NHWC tensor

        Return:
            NHWC tensor
        """
        x = rearrange(x, "n c h w -> n h w c")
        # NOTE: use padding for semantic segmentation
        ###################################################
        if self.auto_pad:
            N, H_in, W_in, C = x.size()

            pad_l = pad_t = 0
            pad_r = (self.n_win - W_in % self.n_win) % self.n_win
            pad_b = (self.n_win - H_in % self.n_win) % self.n_win
            x = F.pad(x, (0, 0, # dim=-1
                          pad_l, pad_r, # dim=-2
                          pad_t, pad_b)) # dim=-3
            _, H, W, _ = x.size() # padded size
        else:
            N, H, W, C = x.size()
            assert H%self.n_win == 0 and W%self.n_win == 0 #
        ###################################################


        # patchify, (n, p^2, w, w, c), keep 2d window as we need 2d pooling to reduce kv size
        #print(x.shape,self.n_win)
        x = rearrange(x, "n (j h) (i w) c -> n (j i) h w c", j=self.n_win, i=self.n_win)
       # print(x.shape,self.n_win)
        #################qkv projection###################
        # q: (n, p^2, w, w, c_qk)
        # kv: (n, p^2, w, w, c_qk+c_v)
        # NOTE: separte kv if there were memory leak issue caused by gather
        q, kv = self.qkv(x)

        # pixel-wise qkv
        # q_pix: (n, p^2, w^2, c_qk)
        # kv_pix: (n, p^2, h_kv*w_kv, c_qk+c_v)
        q_pix = rearrange(q, 'n p2 h w c -> n p2 (h w) c')
        kv_pix = self.kv_down(rearrange(kv, 'n p2 h w c -> (n p2) c h w'))
        kv_pix = rearrange(kv_pix, '(n j i) c h w -> n (j i) (h w) c', j=self.n_win, i=self.n_win)

        q_win, k_win = q.mean([2, 3]), kv[..., 0:self.qk_dim].mean([2, 3]) # window-wise qk, (n, p^2, c_qk), (n, p^2, c_qk)

        ##################side_dwconv(lepe)##################
        # NOTE: call contiguous to avoid gradient warning when using ddp
        lepe = self.lepe(rearrange(kv[..., self.qk_dim:], 'n (j i) h w c -> n c (j h) (i w)', j=self.n_win, i=self.n_win).contiguous())
        lepe = rearrange(lepe, 'n c (j h) (i w) -> n (j h) (i w) c', j=self.n_win, i=self.n_win)

        ############ gather q dependent k/v #################

        r_weight, r_idx = self.router(q_win, k_win) # both are (n, p^2, topk) tensors

        kv_pix_sel = self.kv_gather(r_idx=r_idx, r_weight=r_weight, kv=kv_pix) #(n, p^2, topk, h_kv*w_kv, c_qk+c_v)
        k_pix_sel, v_pix_sel = kv_pix_sel.split([self.qk_dim, self.dim], dim=-1)
        # kv_pix_sel: (n, p^2, topk, h_kv*w_kv, c_qk)
        # v_pix_sel: (n, p^2, topk, h_kv*w_kv, c_v)

        ######### do attention as normal ####################
        k_pix_sel = rearrange(k_pix_sel, 'n p2 k w2 (m c) -> (n p2) m c (k w2)', m=self.num_heads) # flatten to BMLC, (n*p^2, m, topk*h_kv*w_kv, c_kq//m) transpose here?
        v_pix_sel = rearrange(v_pix_sel, 'n p2 k w2 (m c) -> (n p2) m (k w2) c', m=self.num_heads) # flatten to BMLC, (n*p^2, m, topk*h_kv*w_kv, c_v//m)
        q_pix = rearrange(q_pix, 'n p2 w2 (m c) -> (n p2) m w2 c', m=self.num_heads) # to BMLC tensor (n*p^2, m, w^2, c_qk//m)

        # param-free multihead attention
        attn_weight = (q_pix * self.scale) @ k_pix_sel # (n*p^2, m, w^2, c) @ (n*p^2, m, c, topk*h_kv*w_kv) -> (n*p^2, m, w^2, topk*h_kv*w_kv)
        attn_weight = self.attn_act(attn_weight)
        out = attn_weight @ v_pix_sel # (n*p^2, m, w^2, topk*h_kv*w_kv) @ (n*p^2, m, topk*h_kv*w_kv, c) -> (n*p^2, m, w^2, c)
        out = rearrange(out, '(n j i) m (h w) c -> n (j h) (i w) (m c)', j=self.n_win, i=self.n_win,
                        h=H//self.n_win, w=W//self.n_win)

        out = out + lepe
        # output linear
        out = self.wo(out)

        # NOTE: use padding for semantic segmentation
        # crop padded region
        if self.auto_pad and (pad_r > 0 or pad_b > 0):
            out = out[:, :H_in, :W_in, :].contiguous()

        if ret_attn_mask:
            return out, r_weight, r_idx, attn_weight
        else:
            return rearrange(out, "n h w c -> n c h w")
添加ymal文件 
# BGF-YOLO based on Ultralytics YOLOv8x 8.0.109 object detection model with same license, AGPL-3.0 license
# BGF object detection model with P3-P6 outputs.

# Parameters
nc: 1  # number of classes
scales: # model compound scaling constants, i.e. 'model=yolov8n.yaml' will call yolov8.yaml with scale 'n'
  # [depth, width, max_channels]
  n: [0.33, 0.25, 1024]  # YOLOv8n summary: 225 layers,  3157200 parameters,  3157184 gradients,   8.9 GFLOPs
  x: [1.00, 1.25, 512]   # YOLOv8x summary: 365 layers, 68229648 parameters, 68229632 gradients, 258.5 GFLOPs

# YOLOv8.0n backbone
backbone:
  # [from, repeats, module, args]
  - [-1, 1, Conv, [64, 3, 2]]  # 0-P1/2
  - [-1, 1, Conv, [128, 3, 2]]  # 1-P2/4
  - [-1, 3, C2f, [128, True]]
  - [-1, 1, Conv, [256, 3, 2]]  # 3-P3/8
  - [-1, 6, C2f, [256, True]]
  - [-1, 1, Conv, [512, 3, 2]]  # 5-P4/16
  - [-1, 6, C2f, [512, True]]
  - [-1, 1, Conv, [1024, 3, 2]]  # 7-P5/32
  - [-1, 3, C2f, [1024, True]]
  - [-1, 1, SPPF, [1024, 5]]  # 9

# YOLOv8.0n head
head:
  - [-1, 1, Conv, [512, 1, 1]]
  - [ 6, 1, Conv, [ 512, 3, 2 ] ]
  - [-1, 1, BiLevelRoutingAttention, [8 ]]
  - [ [ -1, 10 ], 1, Concat, [ 1 ] ]
  - [ -1, 3, CSPStage, [ 512 ] ] # 14      20*20

  - [ -1, 1, nn.Upsample, [ None, 2, 'nearest' ] ]
  - [4, 1, Conv, [256, 3, 2]]
  - [-1, 1, BiLevelRoutingAttention, [8 ]]
  - [ [ 15, -1, 6 ], 1, Concat, [ 1 ] ]
  - [-1, 3, CSPStage, [512]] # 19     40*40

  - [ -1, 1, nn.Upsample, [ None, 2, 'nearest' ] ]
  - [ -1, 1, BiLevelRoutingAttention, [ 8 ] ]
  - [ [ -1, 4 ], 1, Concat, [ 1 ] ]
  - [ -1, 3, CSPStage, [ 256 ] ]# 23   80*80

  - [ -1, 1, nn.Upsample, [ None, 2, 'nearest' ] ]
  - [ -1, 1, BiLevelRoutingAttention, [ 8 ] ]
  - [ [ -1, 2 ], 1, Concat, [ 1 ] ]
  - [ -1, 3, CSPStage, [ 128 ] ] # 27   160*160

  - [ -1, 1, Conv, [ 128, 3, 2 ] ]
  - [-1, 1, BiLevelRoutingAttention, [8 ]]
  - [ [ -1, 23  ], 1, Concat, [ 1 ] ]  # cat head P4
  - [ -1, 3, CSPStage, [ 256 ] ]  # 31     80*80

  - [ -1, 1, Conv, [ 256, 3, 2 ] ]
  - [ -1, 1, BiLevelRoutingAttention, [ 8 ] ]
  - [ [ -1, 19 ], 1, Concat, [ 1 ] ]  # cat head P4
  - [ -1, 3, CSPStage, [ 512 ] ]  # 35    40*40

  - [ 19, 1, Conv, [ 256, 3, 2 ] ] #   20*20
  - [ 35, 1, Conv, [ 256, 3, 2 ] ] #   20*20
  - [ [14, 36, -1 ], 1, Concat, [ 1 ] ]
  - [ -1, 3, CSPStage, [ 1024 ] ]  # 39    20*20


  - [ [ 27, 31, 35, 39 ], 1, Detect, [ nc ] ]  # Detect(P3, P4, P5, P6)

实验结果

通过优化 GFPN 特征融合结构、BRA 注意力机制以及在 BGF-YOLO 模型中添加检测头,YOLOv8 的目标检测能力得到了显着增强。这些修改能够实现不同级别和更丰富尺度的加权特征融合,并产生具有动态聚焦机制的高质量锚框。此外,BGF-YOLO 中提出的模块优于其他替代技术,对不同特征融合结构、注意力机制和回归损失。我们提出的 BGF-YOLO 成为检测数据集 上当前最先进的模型。 

可接论文指导----------> v jiabei-545
完整代码(失效+ -----------👆 )

链接: https://pan.baidu.com/s/1K5I13pJdsKvGyMub5c1HKw?pwd=zk88 提取码: zk88 

执行程序流程

pip install -r requirements.txt  # install

python yolo/bgf/detect/train.py 

现在就能顺利的执行了 

ok,快去试试你的实验有没有涨点!

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

[云原生] 二进制安装K8S(上)搭建单机matser、etcd集群和node节点

一、单机matser预部署设计 目前Kubernetes最新版本是v1.25,但大部分公司一般不会使用最新版本。 目前公司使用比较多的:老版本是v1.15,因为v1.16改变了很多API接口版本,国内目前使用比较多的是v1.18、v1.20。 组件部署&#xff…

Stable Diffusion 绘画入门教程(webui)-ControlNet(Inpaint)

上篇文章介绍了语义分割Tile/Blur,这篇文章介绍下Inpaint(重绘) Inpaint类似于图生图的局部重绘,但是Inpain效果要更好一点,和原图融合会更加融洽,下面是案例,可以看下效果(左侧原图…

“美元是吸血鬼”!“这资产”成为最强避风港,兑14个国家货币创下历史新高!

随着比特币站稳5万美元大关,比特币兑土耳其、阿根廷、埃及、巴基斯坦、尼日利亚、日本和黎巴嫩等14个国家货币已创下历史新高。在价格尚未达到峰值69000美元前,多国货币的贬值造就了这一盛况,比特币正成为强大的避风港。 这种情况突显了14个国…

解决若依的分页失效问题

解决若依的分页失效问题 我的迷茫和胆怯也一直都在,但我告诉自己,就算是万丈深渊,走下去,也是前程万里。——木心《素履之往》 首先,我们根据若依的文档来清楚几个问题: 前端采用基于bootstrap的轻量级表格…

OpenAI视频生成Sora技术简析

基本介绍 Sora是春节期间OpenAI发布的产品,主要是通过文字描述生成视频,通过大规模视频数据训练而成的生成模型,当前还没开放试用。官方发布的技术报告:https://openai.com/research/video-generation-models-as-world-simulators…

【Simulink系列】——动态系统仿真 之 混合系统

声明:本系列博客参考有关专业书籍,截图均为自己实操,仅供交流学习! 一、混合系统概述 由不同类型系统共同构成的系统称为混合系统!仿真时必须考虑连续信号和离散信号的采样匹配问题,一般使用变步长连续求…

Sora 提示词每日分享 | 中英文对照

每日分享一个 sora 创意视频提示词之《冲浪者在历史大厅的巨浪中展现技艺》 sora提示词视频 prompt: In an ornate, historical hall, a massive tidal wave peaks and begins to crash. Two surfers, seizing the moment, skillfully navigate the face of the wave. 提示词…

成都直播产业园进行时!发挥直播电商优势 赋能优势产业发展

在当今数字化的时代,直播电商已经成为一种新型的商业模式,为优势产业的发展带来了巨大的机遇。通过直播电商,优势产业能够更好地展示自身特色和优势,扩大渠道,提升品牌影响力,从而实现产业的升级和转型。天…

JAVA工程师面试专题-《Redis》篇

目录 一、基础 1、Redis 是什么 2、说一下你对redis的理解 3、Redis 为什么这么快? 4、项目中如何使用缓存? 5、为什么使用缓存? 6、Redis key 和value 可以存储最大值分别多是多少? 7、Redis和memcache有什么区别&#xf…

数字电路设计得力助手——《Design Compiler User Guide》

在当今数字化时代,电子设备和芯片的需求日益增长,这使得数字电路设计变得愈发重要。在数字电路设计过程中,使用先进的工具和技术是至关重要的。Synopsys公司的Design Compiler就是这样一款备受推崇的设计编译器软件,而其详尽的用户…

python(ch2)

可变长编码和不可变长编码 可变长编码是指不同字符使用不同数量的字节进行编码。例如,UTF-8 编码中,ASCII 字符使用 1 个字节编码,而其他语言的字符使用 2 个或更多字节编码。 不可变长编码是指所有字符都使用相同数量的字节进行编码。例如…

代码随想录01 移除元素

移除元素 1.暴力解法2.双指针法 1.暴力解法 暴力解法就是嵌套两次for循环,第一层for循环来寻找数组中的值等于val的, 第二层for循环是往前覆盖,将值等于val的删除. 2.双指针法 双指针法,分为快指针和慢指针 快指针的意义是新的数组中含有的值 慢指针的意义是新的数组中值所在的…

SAP MD81创建客户独立需求简介

正常我们用的最多的计划独立需求都是使用的是MD61 ,今天我们说下SAP的另外的一个标准功能客户独立需求MD81。虽然SAP给这个TCODE的描述是客户独立需求,但是实际是没有地方去关联对应的客户信息的。或者可以理解为是一个关联销售订单的一个计划独立需求。 1、MD81在SAP中的路…

Pyglet综合应用|推箱子游戏之关卡图片载入内存

目录 读取图片 分割图片 综合应用 本篇为之前写的博客《怎样使用Pyglet库给推箱子游戏画关卡地图》的续篇,内容上有相关性,需要阅读的请见链接: https://hannyang.blog.csdn.net/article/details/136209138 「推箱子」是一款风靡全球的益…

Python及Pydev调试程序传递参数方法的实践

在Python中,可以使用sys.argv来获取命令行参数。下面是一个示例的Python脚本,展示了如何通过命令行传递参数并打印输出: import sys# 判断是否有传入参数 if len(sys.argv) > 1:# 获取第二个参数(索引为1)param s…

spring面试题

文章目录 前言一、面试题1、springIOC是什么?2、springIOC产生的原因:背景3、spring 中Bean的生命周期:4、springAOP:5、Spring框架中的设计模式-太多了1、单例模式(Singleton Pattern):2、工厂…

如何在三维地球上快速拉白模以辅助建筑规划设计?

通过以下方法可以在三维地球上快速拉白模以辅助建筑规划设计。 方法/步骤 下载三维地图浏览器 http://www.geosaas.com/download/map3dbrowser.exe,安装完成后桌面上出现”三维地图浏览器“图标。 2、双击桌面图标打开”三维地图浏览器“ 3、点击“要素标绘”菜…

算法打卡day3|链表篇|Leetcode 203.移除链表元素、 707.设计链表 、 206.反转链表

链表基本概念 定义 链表是一种通过指针串联在一起的线性结构,每一个节点由两部分组成,一个是数据域一个是指针域(存放指向下一个节点的指针),最后一个节点的指针域指向null(空指针的意思)。其…

聚水潭和金蝶云星空接口打通对接实战

聚水潭和金蝶云星空接口打通对接实战 对接系统聚水潭 聚水潭成立于2014年,创始人兼CEO骆海东拥有近三十年传统及电商ERP的研发和实施部署经验。聚水潭创建之初,以电商SaaSERP切入市场,凭借出色的产品和服务,快速获得市场的肯定。随…

谷歌竞价:8个提升谷歌竞价排名营销推广展示方式

伴随着网络广告的高速发展,谷歌竞价排名变成企业品牌推广产品与服务的有效工具。怎样提高谷歌竞价排名推广展示率却是一个值得探究讨论的话题。下面我们就详细介绍8个方式来帮助你提高谷歌竞价排名推广展示率。 方法一:关键字科学研究和选择关键字在谷歌…