YOLOv8改进 | 2023 | AKConv轻量级架构下的高效检测(可变核卷积)

一、本文介绍

本文给大家带来的改进内容是AKConv(可变核卷积)是一种创新的卷积神经网络操作,它旨在解决标准卷积操作中的固有缺陷(采样形状是固定的),AKConv的核心思想在于它为卷积核提供了任意数量的参数和任意采样形状,能够使用任意数量的参数(如1, 2, 3, 4, 5, 6, 7等)来提取特征,这在标准卷积和可变形卷积中并未实现​​。AKConv能够根据硬件环境,使卷积参数的数量呈线性增减(非常适用于轻量化模型的读者)本文通过先介绍AKConv的基本网络结构和原理让大家对该卷积有一个大概的了解,然后教大家如何将该卷积添加到自己的网络结构中

(同时我修改了AKConv官方版本在训练到最后一个轮次报错和版本警告的问题RuntimeError: CUDA error: device-side assert triggered)

适用检测目标:所有的目标检测均有一定的提点(既轻量又提点)

推荐指数:⭐⭐⭐⭐⭐

专栏回顾YOLOv8改进系列专栏——本专栏持续复习各种顶会内容——科研必备    

训练结果对比图->  

因为资源有限我发的文章都要做对比实验所以本次实验我只用了一百张图片检测的是火灾训练了一百个epoch,该结果只能展示出该机制有效,但是并不能产生决定性结果,因为具体的效果还要看你的数据集和实验环境所影响

大家可以看出mAP(50)从0.288提高到了0.333(值得一提的是该卷积的GFLOPs降低了0.1左右适合轻量化的读者) 

目录

一、本文介绍

二、AKConv网络结构讲解

2.1 AKConv的主要思想和改进

2.1.1 灵活的卷积核设计

2.1.2 初始采样坐标算法

2.1.3 适应性采样位置调整

2.1.4 线性增减卷积参数的数量

三、AKConv的代码

3.1 AKConv的核心代码

四、手把手教你添加AKConv

4.1 AKConv的添加教程

4.2 AKConv的yaml文件和训练截图

4.2.1 AKConv的yaml文件

4.2.2 AKConv的训练过程截图 

五、AKConv可添加的位置

5.1 推荐AKConv可添加的位置 

5.2 图示AKConv可添加的位置 

六、本文总结


二、AKConv网络结构讲解

论文地址:官方论文地址

代码地址:官方代码地址


2.1 AKConv的主要思想和改进

AKConv的主要思想:AKConv(可变核卷积)主要提供一种灵活的卷积机制,允许卷积核具有任意数量的参数和采样形状。这种方法突破了传统卷积局限于固定局部窗口和固定采样形状的限制,从而使得卷积操作能够更加精准地适应不同数据集和不同位置的目标。

AKConv的改进点:

  1. 灵活的卷积核设计:AKConv允许卷积核具有任意数量的参数,这使得其可以根据实际需求调整大小和形状,从而更有效地适应目标的变化。

  2. 初始采样坐标算法:针对不同大小的卷积核,AKConv提出了一种新的算法来生成初始采样坐标,这进一步增强了其在处理各种尺寸目标时的灵活性。

  3. 适应性采样位置调整:为适应目标的不同变化,AKConv通过获得的偏移量调整不规则卷积核的采样位置,从而提高了特征提取的准确性。

  4. 减少模型参数和计算开销:AKConv支持线性增减卷积参数的数量,有助于在硬件环境中优化性能,尤其适合于轻量级模型的应用。

个人总结:总的来说,AKConv通过其创新的可变核卷积设计,为卷积神经网络带来了显著的性能提升。其能够根据不同的数据集和目标灵活调整卷积核的大小和形状,从而实现更高效的特征提取。

 图片展示了AKConv结构的详细示意图,并附上我个人的过程理解:

1. 输入:输入图像具有维度(C, H, W),其中C是通道数,H和W分别是图像的高度和宽度。
2. 初始采样形状:这一步是AKConv特有的,它给出了卷积核的初始采样形状。
3. 卷积操作:使用Conv2d对输入图像执行卷积操作。
4. 偏移:通过学习得到的偏移量来调整初始采样形状。这一步是AKConv的关键,允许卷积核形状动态调整以适应图像的特征。
5. 重采样:根据调整后的采样形状对特征图进行重采样。
6. 输出管道:重采样后的特征图经过重塑、再次卷积、标准化,最后通过激活函数SiLU输出最终结果。

底部的三行展示了采样坐标的变化:

  • 原始坐标:显示了卷积核在没有任何偏移的情况下的初始采样位置。
  • 偏移:展示了学习到的偏移量,这些偏移量将应用于原始坐标。
  • 修改后的坐标:应用偏移后的采样坐标。

总结:官方这个图说明了AKConv如何为任意大小的卷积分配初始采样坐标,并通过可学习的偏移调整采样形状。与原始采样形状相比,每个位置的采样形状都通过重采样进行了改变,这使得AKConv可以根据图像内容动态调整其操作,为卷积网络提供了前所未有的灵活性和适应性。


2.1.1 灵活的卷积核设计

AKConv中的灵活卷积核设计是一种创新的机制,旨在使卷积网络更加适应性和有效率。以下是其主要原理和机制的总结:

主要原理

  1. 任意参数数量:传统的卷积核通常具有固定的尺寸和形状,例如3x3或5x5的方形网格。而AKConv的核心原理是允许卷积核具有任意数量的参数。这意味着卷积核不再局限于标准的方形网格,而是可以根据图像特征和任务需求,采用更多样化和灵活的形状(如下图所示,任意参数数量)

  2. 自适应采样形状:在处理不同的图像和目标时,AKConv的卷积核能够自动调整其采样形状。这是通过引入一种新的坐标生成算法实现的,该算法能够为不同大小和形状的卷积核生成初始采样坐标(如下图所示,自适应采样形状)

工作机制

  1. 初始坐标生成:AKConv首先通过其坐标生成算法确定卷积核的初始采样位置。这些位置不再是固定不变的,而是可以根据图像中的特征和目标动态变化。

  2. 采样位置调整:为了更好地适应图像中目标的大小和形状变化,AKConv会根据目标的特点调整卷积核的采样位置。这种调整是通过添加偏移量来实现的,使得卷积操作更加灵活和适应性强。

个人总结:通过这种灵活的设计,AKConv能够有效地适应各种大小和形状的目标,提高了特征提取的准确性和效率。它在标准卷积核基础上引入了更多的灵活性和自适应性,从而使得卷积神经网络在处理复杂和多样化的图像数据时更为高效。这种灵活的卷积核设计不仅提升了模型的性能,还为减少模型参数和计算开销提供了可能,特别是在轻量级模型的应用中显示出其优势。


2.1.2 初始采样坐标算法

AKConv中的初始采样坐标算法是其核心特征之一,这个算法为AKConv的灵活性和适应性提供了基础。以下是该算法的主要原理和机制的概述:

主要原理

  1. 针对多样化尺寸的适应性:传统卷积操作通常使用固定尺寸的卷积核,这限制了其在处理不同尺寸和形状目标时的效果。AKConv的初始采样坐标算法旨在解决这一问题,通过允许卷积核适应不同大小的目标,增强其灵活性和有效性。

  2. 动态采样坐标生成:该算法能够根据目标的尺寸和形状动态生成卷积核的初始采样坐标。这种动态生成方式使卷积核能够更精确地覆盖和处理图像中的不同区域,从而提高特征提取的精度。

工作机制

  1. 适应不同目标尺寸:对于每一个卷积操作,算法首先考虑目标的尺寸。基于这一信息,它生成一组初始坐标,这些坐标定义了卷积核将要采样的位置。

  2. 灵活的坐标调整:生成的初始坐标不是固定不变的,而是可以根据图像中的特征动态调整。这意味着卷积核可以根据图像内容的不同而改变其采样策略,从而更有效地提取特征。

个人总结:通过引入这种初始采样坐标算法,AKConv能够更灵活地处理各种尺寸的目标,无论是大尺寸还是小尺寸的目标,都能得到更准确的特征提取。


2.1.3 适应性采样位置调整

AKConv的适应性采样位置调整机制是其核心之一,该机制允许卷积核基于图像内容进行动态调整。这里是对这一机制的概述:

  1. 动态采样调整:传统的卷积网络使用固定形状的卷积核在图像上滑动来提取特征,这种方法忽略了图像中对象形状和尺寸的多样性。AKConv采用一种新颖的方法,它允许卷积核的形状和位置根据图像内容动态调整,更好地匹配和覆盖目标区域。

  2. 偏移量学习:在AKConv中,卷积核的位置可以通过学习到的偏移量来调整。在训练过程中,网络学习到对于特定图像和目标最有效的偏移量,以便在采样过程中自动调整卷积核的位置。

  3. 提高特征提取准确性:通过这种自适应调整,AKConv能够更准确地对齐并提取图像中的关键特征,特别是当目标的形状和大小在不同图像中有所变化时。

个人总结:AKConv的适应性采样位置调整为卷积网络提供了前所未有的灵活性和适应性,使其能够对各种不同形状和尺寸的目标实现更精确的特征提取。


2.1.4 线性增减卷积参数的数量

AKConv通过其独特的设计减少了模型参数和计算开销实现方式如下:

1. 线性参数调整:AKConv允许卷积核的参数数量根据需要进行线性调整。这与传统卷积网络中参数数量随着卷积核尺寸平方级增长的情况形成对比。通过支持参数数量的线性调整,AKConv能够根据任务需求和硬件能力灵活地增减模型的复杂度。

2. 优化性能:在硬件资源有限的环境中,AKConv能够通过减少不必要的参数来优化性能。这样不仅减轻了对存储和计算资源的需求,还有助于加快模型的训练和推理速度,同时降低能耗。

3. 轻量级模型设计:AKConv特别适合于轻量级模型的设计,这类模型需要在保持高性能的同时,尽可能地减少参数数量。AKConv的这一特性使其成为设计紧凑而高效模型的理想选择,特别是在移动设备、嵌入式系统和物联网设备等资源受限的平台上。

总结:AKConv通过支持卷积参数的线性增减,提供了一种在不牺牲性能的前提下,降低模型参数和计算开销的有效方法。这使得AKConv不仅在实现高精度的特征提取方面表现出色,而且在实际应用中具有显著的资源效率优势。


三、AKConv的代码

3.1 AKConv的核心代码

在AKConv的官方代码中有一个版本的警告我给进行了一定的处理解决了,该代码的使用方式我们看章节四进行使用。 

(同时我修改了AKConv官方版本在训练到最后一个轮次报错和版本警告的问题RuntimeError: CUDA error: device-side assert triggered)

import torch.nn as nn
import torch
from einops import rearrange
import math


class AKConv(nn.Module):
    def __init__(self, inc, outc, num_param, stride=1, bias=None):
        super(AKConv, self).__init__()
        self.num_param = num_param
        self.stride = stride
        self.conv = nn.Sequential(nn.Conv2d(inc, outc, kernel_size=(num_param, 1), stride=(num_param, 1), bias=bias),
                                  nn.BatchNorm2d(outc),
                                  nn.SiLU())  # the conv adds the BN and SiLU to compare original Conv in YOLOv5.
        self.p_conv = nn.Conv2d(inc, 2 * num_param, kernel_size=3, padding=1, stride=stride)
        nn.init.constant_(self.p_conv.weight, 0)
        self.p_conv.register_full_backward_hook(self._set_lr)

    @staticmethod
    def _set_lr(module, grad_input, grad_output):
        grad_input = (grad_input[i] * 0.1 for i in range(len(grad_input)))
        grad_output = (grad_output[i] * 0.1 for i in range(len(grad_output)))

    def forward(self, x):
        # N is num_param.
        offset = self.p_conv(x)
        dtype = offset.data.type()
        N = offset.size(1) // 2
        # (b, 2N, h, w)
        p = self._get_p(offset, dtype)

        # (b, h, w, 2N)
        p = p.contiguous().permute(0, 2, 3, 1)
        q_lt = p.detach().floor()
        q_rb = q_lt + 1

        q_lt = torch.cat([torch.clamp(q_lt[..., :N], 0, x.size(2) - 1), torch.clamp(q_lt[..., N:], 0, x.size(3) - 1)],
                         dim=-1).long()
        q_rb = torch.cat([torch.clamp(q_rb[..., :N], 0, x.size(2) - 1), torch.clamp(q_rb[..., N:], 0, x.size(3) - 1)],
                         dim=-1).long()
        q_lb = torch.cat([q_lt[..., :N], q_rb[..., N:]], dim=-1)
        q_rt = torch.cat([q_rb[..., :N], q_lt[..., N:]], dim=-1)

        # clip p
        p = torch.cat([torch.clamp(p[..., :N], 0, x.size(2) - 1), torch.clamp(p[..., N:], 0, x.size(3) - 1)], dim=-1)

        # bilinear kernel (b, h, w, N)
        g_lt = (1 + (q_lt[..., :N].type_as(p) - p[..., :N])) * (1 + (q_lt[..., N:].type_as(p) - p[..., N:]))
        g_rb = (1 - (q_rb[..., :N].type_as(p) - p[..., :N])) * (1 - (q_rb[..., N:].type_as(p) - p[..., N:]))
        g_lb = (1 + (q_lb[..., :N].type_as(p) - p[..., :N])) * (1 - (q_lb[..., N:].type_as(p) - p[..., N:]))
        g_rt = (1 - (q_rt[..., :N].type_as(p) - p[..., :N])) * (1 + (q_rt[..., N:].type_as(p) - p[..., N:]))

        # resampling the features based on the modified coordinates.
        x_q_lt = self._get_x_q(x, q_lt, N)
        x_q_rb = self._get_x_q(x, q_rb, N)
        x_q_lb = self._get_x_q(x, q_lb, N)
        x_q_rt = self._get_x_q(x, q_rt, N)

        # bilinear
        x_offset = g_lt.unsqueeze(dim=1) * x_q_lt + \
                   g_rb.unsqueeze(dim=1) * x_q_rb + \
                   g_lb.unsqueeze(dim=1) * x_q_lb + \
                   g_rt.unsqueeze(dim=1) * x_q_rt

        x_offset = self._reshape_x_offset(x_offset, self.num_param)
        out = self.conv(x_offset)

        return out

    # generating the inital sampled shapes for the AKConv with different sizes.
    def _get_p_n(self, N, dtype):
        base_int = round(math.sqrt(self.num_param))
        row_number = self.num_param // base_int
        mod_number = self.num_param % base_int
        p_n_x, p_n_y = torch.meshgrid(
            torch.arange(0, row_number),
            torch.arange(0, base_int), indexing='xy')
        p_n_x = torch.flatten(p_n_x)
        p_n_y = torch.flatten(p_n_y)
        if mod_number > 0:
            mod_p_n_x, mod_p_n_y = torch.meshgrid(
                torch.arange(row_number, row_number + 1),
                torch.arange(0, mod_number),indexing='xy')

            mod_p_n_x = torch.flatten(mod_p_n_x)
            mod_p_n_y = torch.flatten(mod_p_n_y)
            p_n_x, p_n_y = torch.cat((p_n_x, mod_p_n_x)), torch.cat((p_n_y, mod_p_n_y))
        p_n = torch.cat([p_n_x, p_n_y], 0)
        p_n = p_n.view(1, 2 * N, 1, 1).type(dtype)
        return p_n

    # no zero-padding
    def _get_p_0(self, h, w, N, dtype):
        p_0_x, p_0_y = torch.meshgrid(
            torch.arange(0, h * self.stride, self.stride),
            torch.arange(0, w * self.stride, self.stride),indexing='xy')

        p_0_x = torch.flatten(p_0_x).view(1, 1, h, w).repeat(1, N, 1, 1)
        p_0_y = torch.flatten(p_0_y).view(1, 1, h, w).repeat(1, N, 1, 1)
        p_0 = torch.cat([p_0_x, p_0_y], 1).type(dtype)

        return p_0

    def _get_p(self, offset, dtype):
        N, h, w = offset.size(1) // 2, offset.size(2), offset.size(3)

        # (1, 2N, 1, 1)
        p_n = self._get_p_n(N, dtype)
        # (1, 2N, h, w)
        p_0 = self._get_p_0(h, w, N, dtype)
        p = p_0 + p_n + offset
        return p

    def _get_x_q(self, x, q, N):
        b, h, w, _ = q.size()
        padded_w = x.size(3)
        c = x.size(1)
        # (b, c, h*w)
        x = x.contiguous().view(b, c, -1)

        # (b, h, w, N)
        index = q[..., :N] * padded_w + q[..., N:]  # offset_x*w + offset_y
        # (b, c, h*w*N)

        index = index.contiguous().unsqueeze(dim=1).expand(-1, c, -1, -1, -1).contiguous().view(b, c, -1)

        # 根据实际情况调整
        index = index.clamp(min=0, max=x.shape[-1] - 1)

        x_offset = x.gather(dim=-1, index=index).contiguous().view(b, c, h, w, N)

        return x_offset

    #  Stacking resampled features in the row direction.
    @staticmethod
    def _reshape_x_offset(x_offset, num_param):
        b, c, h, w, n = x_offset.size()
        # using Conv3d
        # x_offset = x_offset.permute(0,1,4,2,3), then Conv3d(c,c_out, kernel_size =(num_param,1,1),stride=(num_param,1,1),bias= False)
        # using 1 × 1 Conv
        # x_offset = x_offset.permute(0,1,4,2,3), then, x_offset.view(b,c×num_param,h,w)  finally, Conv2d(c×num_param,c_out, kernel_size =1,stride=1,bias= False)
        # using the column conv as follow, then, Conv2d(inc, outc, kernel_size=(num_param, 1), stride=(num_param, 1), bias=bias)

        x_offset = rearrange(x_offset, 'b c h w n -> b c (h n) w')
        return x_offset


四、手把手教你添加AKConv

4.1 AKConv的添加教程

添加教程这里不再重复介绍、因为专栏内容有许多,添加过程又需要截特别图片会导致文章大家读者也不通顺如果你已经会添加注意力机制了,可以跳过本章节,如果你还不会,大家可以看我下面的文章,里面详细的介绍了拿到一个任意机制(C2f、Conv、Bottleneck、Loss、DetectHead)如何添加到你的网络结构中去。

这个卷积也可以放在C2f和Bottleneck中进行使用可以即插即用,个人觉得放在Bottleneck中效果比较好。

添加教程->YOLOv8改进 | 如何在网络结构中添加注意力机制、C2f、卷积、Neck、检测头


4.2 AKConv的yaml文件和训练截图

4.2.1 AKConv的yaml文件

下面的配置文件为我修改的AKConv的位置。

# Ultralytics YOLO 🚀, AGPL-3.0 license
# YOLOv8 object detection model with P3-P5 outputs. For Usage examples see https://docs.ultralytics.com/tasks/detect

# Parameters
nc: 80  # 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
  s: [0.33, 0.50, 1024]  # YOLOv8s summary: 225 layers, 11166560 parameters, 11166544 gradients,  28.8 GFLOPs
  m: [0.67, 0.75, 768]   # YOLOv8m summary: 295 layers, 25902640 parameters, 25902624 gradients,  79.3 GFLOPs
  l: [1.00, 1.00, 512]   # YOLOv8l summary: 365 layers, 43691520 parameters, 43691504 gradients, 165.7 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, AKConv, [128, 3, 2]]  # 1-P2/4
  - [-1, 3, C2f, [128, True]]
  - [-1, 1, AKConv, [256, 3, 2]]  # 3-P3/8
  - [-1, 6, C2f, [256, True]]
  - [-1, 1, AKConv, [512, 3, 2]]  # 5-P4/16
  - [-1, 6, C2f, [512, True]]
  - [-1, 1, AKConv, [1024, 3, 2]]  # 7-P5/32
  - [-1, 3, C2f, [1024, True]]
  - [-1, 1, SPPF, [1024, 5]]  # 9


# YOLOv8.0n head
head:
  - [-1, 1, nn.Upsample, [None, 2, 'nearest']]
  - [[-1, 6], 1, Concat, [1]]  # cat backbone P4
  - [-1, 3, C2f, [512]]  # 12

  - [-1, 1, nn.Upsample, [None, 2, 'nearest']]
  - [[-1, 4], 1, Concat, [1]]  # cat backbone P3
  - [-1, 3, C2f, [256]]  # 15 (P3/8-small)

  - [-1, 1, AKConv, [256, 3, 2]]
  - [[-1, 12], 1, Concat, [1]]  # cat head P4
  - [-1, 3, C2f, [512]]  # 18 (P4/16-medium)

  - [-1, 1, AKConv, [512, 3, 2]]
  - [[-1, 9], 1, Concat, [1]]  # cat head P5
  - [-1, 3, C2f, [1024]]  # 21 (P5/32-large)

  - [[15, 18, 21], 1, Detect, [nc]]  # Detect(P3, P4, P5)


4.2.2 AKConv的训练过程截图 

下面是添加了AKConv的训练截图。

(最近有人说我改的代码是没有发全的,我不知道这群人是怎么说出这种话的,希望大家如果用我的代码成功的可以在评论区支持一下,我也好发更多的改进毕竟免费给大家看。同时有问题皆可在评论区留言我看到都会回复) 

​​​


五、AKConv可添加的位置

5.1 推荐AKConv可添加的位置 

AKConv是一种即插即用的模块其可以添加的位置有很多,添加的位置不同效果也不同,所以我下面推荐几个添加的位,置大家可以进行参考,当然不一定要按照我推荐的地方添加。

  1. 残差连接中:在残差网络的残差连接中加入AKConv

  2. Neck部分:YOLOv8的Neck部分负责特征融合,这里添加修改后的AKConv可以帮助模型更有效地融合不同层次的特征。

  3. 检测头中的卷积:在最终的输出层前加入AKConv可以使模型在做出最终预测之前,更加集中注意力于最关键的特征。

文字大家可能看我描述不太懂,大家可以看下面的网络结构图中我进行了标注。


5.2 图示AKConv可添加的位置 

2949694815404620bdfb5875286c8e73.png​​​


六、本文总结

到此本文的正式分享内容就结束了,在这里给大家推荐我的YOLOv8改进有效涨点专栏,本专栏目前为新开的平均质量分98分,后期我会根据各种最新的前沿顶会进行论文复现,也会对一些老的改进机制进行补充,目前本专栏免费阅读(暂时,大家尽早关注不迷路~),如果大家觉得本文帮助到你了,订阅本专栏,关注后续更多的更新~

专栏回顾:YOLOv8改进系列专栏——本专栏持续复习各种顶会内容——科研必备

3d51a0611af1442f833362eaf18fbae2.gif

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

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

相关文章

最小化安装 Neokylin7.0 用于搭建 Hadoop 集群

文章目录 环境搭建背景虚拟机创建和环境配置安装过程注意事项虚拟机设置软件选择KOUMP系统分区网络和主机名打开以太网,并记录信息配置 IPv4修改主机名 创建用户 hadoop完全分布式搭建-CSDN博客 环境搭建背景 为什么不从hadoop100或者hadoop101开始,而是…

【Python表白系列】这个情人节送她一个漂浮的爱心吧(完整代码)

文章目录 漂浮的爱心环境需求完整代码详细分析系列文章 漂浮的爱心 环境需求 python3.11.4PyCharm Community Edition 2023.2.5pyinstaller6.2.0(可选,这个库用于打包,使程序没有python环境也可以运行,如果想发给好朋友的话需要这…

外包搞了6年,技术退步明显......

先说情况,大专毕业,18年通过校招进入湖南某软件公司,干了接近6年的功能测试,今年年初,感觉自己不能够在这样下去了,长时间呆在一个舒适的环境会让一个人堕落!而我已经在一个企业干了四年的功能测试&#xf…

对 Vision Transformers 及其基于 CNN-Transformer 的变体的综述

A survey of the Vision Transformers and its CNN-Transformer based Variants 摘要1、介绍2、vit的基本概念2.1 patch嵌入2.2 位置嵌入2.2.1 绝对位置嵌入(APE)2.2.2 相对位置嵌入(RPE)2.2.3卷积位置嵌入(CPE) 2.3 注意力机制2.3.1多头自我注意(MSA) 2.4 Transformer层2.4.1 …

【精选】VulnHub Shuriken-1 (超详细过程思路)

🍬 博主介绍👨‍🎓 博主介绍:大家好,我是 hacker-routing ,很高兴认识大家~ ✨主攻领域:【渗透领域】【应急响应】 【java】 【VulnHub靶场复现】【面试分析】 🎉点赞➕评论➕收藏 …

spring @Autowired 和 @Qualifier 配合使用实现按名称属性赋值源码

一、调用过程 1、QualifierAnnotationAutowireCandidateResolver.java用于解析注解候选类,在构造器中往qualifierTypes集合中添加注解类。 2、执行逻辑 (1)、接着上篇博客【Spring之Autowired 属性多实现和单实现源码解析 】AutowiredAnnot…

【话题】程序员养生指南(AI生成)

目录 程序猿可能出现的职业病有哪些? 如何预防和对付这些职业病? 一、颈椎病的预防 二、神经衰弱的调适 三、肩周炎的防护 四、视力下降的保护 五、饮食与运动的重要性 六、消化系统职业病的预防 程序员养生心得:呵护健康&#xff0c…

每天五分钟计算机视觉:经典的卷积神经网络之VGG-16模型

VGG-16 Vgg16是牛津大学VGG组提出来的,相比于AlexNet来说,AlexNet的一个改进是采用连续的几个4*3的卷积核来代替AlexNet中的较大的卷积核(11*11,5*5)。前面我们也说过了使用小卷积核是优于大的卷积核的,因为多层非线性层可以增加网络深度来保证学习到更加复杂的模式,而且代…

Vlan配置

需求 1 PC1和PC3所在接口为Access接口 PC2/4/5/6处于同一网段,其中pc2可以访问pc4/5/6 PC4可以访问pc5,但不能访问pc6 PC5不能访问PC6 2 PC1/3与PC2/4/5/6不再同一网段 3 所有PC通过DHCP获取IP地址,且PC1/3可以正常访问PC2/4/5/6 R1 [V200R00…

(下)11.24_苍穹外卖后端二刷day11day12笔记

其实后面已经没有什么好写的了,就随便写写 day11-5 . StringUtils.join 的用处是将datalist里面的元素一个个取出来,然后用“,” 拼接起来,形成一个字符串类型。 day11-6 LocalDateTime.of 的用处是获取date(因为…

算法通关村第六关—二叉树的层次遍历经典问题(白银)

二叉树的层次遍历经典问题 一、层次遍历简介 广度优先遍历又称层次遍历,过程如下:  层次遍历就是从根节点开始,先访问根节点下面一层全部元素,再访问之后的层次,图里就是从左到右一层一层的去遍历二叉树&#xff0c…

LangChain的函数,工具和代理(三):LangChain中轻松实现OpenAI函数调用

在我之前写的两篇博客中:OpenAI的函数调用,LangChain的表达式语言(LCEL)中介绍了如何利用openai的api来实现函数调用功能,以及在langchain中如何实现openai的函数调用功能,在这两篇博客中,我们都需要手动去创建一个结构比较复杂的函数描述变量…

leetCode 131.分割回文串 + 动态规划 + 回溯算法 + 优化 + 图解 + 笔记

我的往期文章: leetCode 647.回文子串 动态规划 优化空间 / 中心扩展法 双指针-CSDN博客https://blog.csdn.net/weixin_41987016/article/details/133883091?spm1001.2014.3001.5501leetCode 131.分割回文串 回溯算法 图解 笔记-CSDN博客https://blog.csdn.n…

杏色主题卧室书房一体装修,温馨舒适的不二之选!福州中宅装饰,福州装修

分享一间暖杏色系卧室装修案例,希望可以给你们一些启发! 01.配色:杏色;浅杏色;浅咖色;咖色;茶色 你是否想要一个宁静而优雅的居室,融合了卧室与书房的功能,提供既实用又…

java基础语法总结

导言: Java语言是一种面向对象的编程语言,具有简单、可移植、安全、高性能等特点。本篇文章主要对java的基础的语法进行一个简单的总结和概述。 目录 导言: 正文: 1. 数据类型与变量 2. 运算符与逻辑控制 3. 方法 4. 数组…

如何在C/C++中测量一个函数或者功能的运行时间(串行和并行,以及三种方法的实际情况对比)

本文算是一个比较完整的关于在 C/C 中测量一个函数或者功能的总结,最后会演示三种方法的对比。 最常用的clock() 最常用的测量方法是使用clock()来记录两个 CPU 时间点clock_t,然后做差。这个方法的好处在于非常简单易写,如下(第…

探究Kafka原理-4.API使用

👏作者简介:大家好,我是爱吃芝士的土豆倪,24届校招生Java选手,很高兴认识大家📕系列专栏:Spring源码、JUC源码、Kafka原理🔥如果感觉博主的文章还不错的话,请&#x1f44…

程序员成了teamleader

在职场中,你是否遇到过这样的领导或同事,他可能是自恋狂,自吹自擂自我标榜;可能是团队合作的绊脚石,对团队合作态度消极并频繁拖后腿;可能是抱怨专家,满满负能量;可能是完美主义者,对细节过度挑剔;可能是技术白痴,对技术一窍不通或总是犯低级错误;可能是抢功劳者,…

消息中间件介绍

概述 消息队列已经逐渐成为企业IT系统内部通信的核心手段。它具有低耦合、可靠投递、广播、流量控制、最终一致性等一系列功能,成为异步RPC的主要手段之一。当今市面上有很多主流的消息中间件,如ActiveMQ、RabbitMQ,Kafka,还有阿里…

【工具分享】| 阅读论文神器 使用技巧 AI润色 AI翻译

文章目录 1 使用技巧1.1 功能一 即时翻译1.2 功能二 文献跳转1.3 功能三 多设备阅读1.4 功能四 小组讨论笔记共享1.5 功能五 个人文献管理 2 其他功能 超级喜欢Readpaper这一款论文阅读软件,吹爆他哈哈 为什么? 当然是他可以解决我们传统阅读论文的种种…