Swin transformer 论文阅读记录 代码分析


该篇文章,是我解析 Swin transformer 论文原理(结合pytorch版本代码)所记,图片来源于源paper或其他相应博客。

代码也非原始代码,而是从代码里摘出来的片段,配上简单数据,以便理解。

当然,也可能因为设置数据不当,造成误解,请多指教。

刚写了一部分。先发布。希望多多指正。


在这里插入图片描述
Figure 1.
(a) The proposed Swin Transformer builds hierarchical feature maps by merging image patches (shown in gray) in deeper layers ,
and has linear computation complexity to input image size due to computation of self-attention only within each local window (shown in red).
It can thus serve as a general-purpose backbone for both image classification and dense recognition tasks.
(b) In contrast, previous vision Transformers produce feature maps of a single low resolution and have quadratic computation complexity to input image size due to computation of self attention globally.

模型结构图

在这里插入图片描述
Figure 3.
(a) The architecture of a Swin Transformer (Swin-T);
(b) two successive Swin Transformer Blocks (notation presented with Eq. (3)).
W-MSA and SW-MSA are multi-head self attention modules with regular and shifted windowing configurations, respectively.

Stage 1 – Patch Embedding

It first splits an input RGB image into non-overlapping patches by a patch splitting module, like ViT.

Each patch is treated as a “token” and its feature is set as a concatenation of the raw pixel RGB values.

In our implementation, we use a patch size of 4×4 and thus the feature dimension of each patch is 4×4×3 = 48.(channel–3)

A linear embedding layer is applied on this raw-valued feature to project it to an arbitrary dimension (denoted as C).
这个表述,linear embedding layer,我感觉不太准确,但是,后半部分比较准确,哈哈,将channel–3变成了96.

Several Transformer blocks with modified self-attention computation (Swin Transformer blocks) are applied on these patch tokens.

The Transformer blocks maintain the number of tokens (H/4 × W/4), and together with the linear embedding are referred to as “Stage 1”.

代码

以下代码来自于model.py:

class PatchEmbed(nn.Module):"""2D Image to Patch Embedding"""
"""
@ time : 2024/12/17
"""
import torch
from PIL import Image
from torchvision import transforms
import matplotlib.pyplot as plt
import torch.nn as nn
import torch.nn.functional as Fclass PatchEmbed(nn.Module):"""2D Image to Patch Embedding"""def __init__(self, patch_size=4, in_c=3, embed_dim=96, norm_layer=None):super().__init__()patch_size = (patch_size, patch_size)self.patch_size = patch_sizeself.in_chans = in_cself.embed_dim = embed_dimself.proj = nn.Conv2d(in_c, embed_dim, kernel_size=patch_size, stride=patch_size)self.norm = norm_layer(embed_dim) if norm_layer else nn.Identity()def forward(self, x):_, _, H, W = x.shape# padding# 如果输入图片的H,W不是patch_size的整数倍,需要进行paddingpad_input = (H % self.patch_size[0] != 0) or (W % self.patch_size[1] != 0)if pad_input:# to pad the last 3 dimensions,# (W_left,W_right, H_top,H_bottom, C_front,C_back)x = F.pad(x,(0, self.patch_size[1] - W % self.patch_size[1],0, self.patch_size[0] - H % self.patch_size[0],0, 0))# 下采样patch_size倍x = self.proj(x)_, _, H, W = x.shape# flatten: [B, C, H, W] -> [B, C, HW]# transpose: [B, C, HW] -> [B, HW, C]x = x.flatten(2).transpose(1, 2)x = self.norm(x)print(x.shape)# torch.Size([1, 3136, 96])# 224/4 * 224/4 = 3136return x, H, Wif __name__ == '__main__':img_path = "tulips.jpg"img = Image.open(img_path)plt.imshow(img)# [N, C, H, W]print(img.size)# (500,375)#img_size = 224data_transform = transforms.Compose([transforms.Resize(int(img_size * 1.14)),transforms.CenterCrop(img_size),transforms.ToTensor(),transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])])img = data_transform(img)print(img.shape)# torch.Size([3, 224, 224])# expand batch dimensionimg = torch.unsqueeze(img, dim=0)print(img.shape)# torch.Size([1, 3, 224, 224])# split image into non-overlapping patchespatch_embed = PatchEmbed(norm_layer=nn.LayerNorm)patch_embed(img)

Stage 2 – 3.2. Shifted Window based Self-Attention

Shifted window partitioning in successive blocks

The window-based self-attention module lacks connections across windows, which limits its modeling power.

To introduce cross-window connections while maintaining the efficient computation of non-overlapping windows,
we propose a shifted window partitioning approach which alternates between two partitioning configurations in consecutive Swin Transformer blocks.
为了在保持非重叠窗口高效计算的同时引入跨窗口连接,我们提出了一种移位窗口划分方法,该方法在连续的Swin Transformer块中交替使用两种不同的划分配置。

在这里插入图片描述
Figure 2.
In layer l (left), a regular window partitioning scheme is adopted, and self-attention is computed within each window.
In the next layer l + 1 (right), the window partitioning is shifted, resulting in new windows.
The self-attention computation in the new windows crosses the boundaries of the previous windows in layer l, providing connections among them.
在新窗口中进行的自注意力计算跨越了第l层中先前窗口的边界,从而在它们之间建立了连接。

Efficient batch computation for shifted configuration

An issue with shifted window partitioning is that it will result in more windows, and some of the windows will be smaller than M×M.

Here, we propose a more efficient batch computation approach by cyclic-shifting toward the top-left direction(向左上方向循环移动), as illustrated in Figure 4.

这里的 more efficient,是说相对于直观方法 padding—mask来说:

A naive solution is to pad the smaller windows to a size of M×M and mask out the padded values when computing attention.


在这里插入图片描述
Figure 4. Illustration of an efficient batch computation approach for self-attention in shifted window partitioning.


After this shift, a batched window may be composed of several sub-windows that are not adjacent in the feature map, so a masking mechanism is employed to limit self-attention computation to within each sub-window.
在此转换之后,批处理窗口可能由特征图中不相邻的几个子窗口组成,因此采用掩蔽机制将自注意力计算限制在每个子窗口内。

With the cyclic-shift, the number of batched windows remains the same as that of regular window partitioning, and thus is also efficient.
通过循环移位,批处理窗口的数量与常规窗口分区的数量保持不变,因此也是高效的。


上图和叙述,并不太直观,找了相关资料,一起分析:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
移动完成之后,4是一个单独区域,5、3为一组,7、1为一组,8、6、2、0为一组。

但,5、3本身是两个图像的边缘,混在一起计算不是乱了吗?一起计算也没问题,ViT也是全局计算的。

但,Swin-Transformer为了防止这个问题,在代码中使用了masked MSA,这样就能够通过设置蒙板来隔绝不同区域的信息了。

源码中具体的方法就是将不计算的位置元素减去100。

这里需要注意的是,在窗口数据进行滑动完之后,需要将数据还原回去,即挪回到原来的位置上。

代码

以下代码来自于model.py:

def window_partition(x, window_size: int):"""将feature map按照window_size划分成一个个没有重叠的window主要思路是将feature转成 (num_windows*B, window_size*window_size, C)的shape,把需要self-attn计算的window排列到第0维,一次并行的qkv就可以了Args:x: (B, H, W, C)window_size (int): window size(M)Returns:windows: (num_windows*B, window_size, window_size, C)"""B, H, W, C = x.shape# B,224,224,C# B,56,56,Cx = x.view(B, H // window_size, window_size, W // window_size, window_size, C)# B,32,7,32,7,C# B,8,7,8,7,C# permute:# [B, H//Mh, Mh,    W//Mw, Mw, C] -># [B, H//Mh, W//Mh, Mw,    Mw, C]# B,32,32,7,7,C# B,8,8,7,7,C# view:# [B, H//Mh, W//Mw, Mh, Mw, C] -># [B*num_windows,   Mh, Mw, C]# B*1024,7,7,C# B*64,7,7,C# 32*32 = 1024# 224 / 7 = 32windows = x.permute(0, 1, 3, 2, 4, 5).contiguous().view(-1, window_size, window_size, C)return windows

分析:将 [B, C, 56, 56] 最后变成了[64B, C, 7, 7],原先的 B*C 张 56*56 的特征图,最后变成了 B*64*C张7*7的特征;

即,我们有64B个样本,每个样本包含C个7x7的通道。

注意,window_size–M–7,是每个window的大小,7*7,不是7*7个window,我刚开始混淆了这一点。


class BasicLayer(nn.Module):# A basic Swin Transformer layer for one stage.def __init__(self, dim, depth, num_heads, window_size,mlp_ratio=4., qkv_bias=True, drop=0., attn_drop=0.,drop_path=0., norm_layer=nn.LayerNorm, downsample=None, use_checkpoint=False):super().__init__()self.dim = dimself.depth = depthself.window_size = window_sizeself.use_checkpoint = use_checkpointself.shift_size = window_size // 2# 7//2 = 3# build blocksself.blocks = nn.ModuleList([SwinTransformerBlock(dim=dim,num_heads=num_heads,window_size=window_size,shift_size=0 if (i % 2 == 0) else self.shift_size,mlp_ratio=mlp_ratio,qkv_bias=qkv_bias,drop=drop,attn_drop=attn_drop,drop_path=drop_path[i] if isinstance(drop_path, list) else drop_path,norm_layer=norm_layer)for i in range(depth)])...# depth: 2, 2, 6, 2# 即,第一层,depth=2, 有两个SwinTransformerBlock,shift_size分别为:0,3# 即,第二层,depth=2, 有两个SwinTransformerBlock,shift_size分别为:0,3# 即,第三层,depth=6, 有两个SwinTransformerBlock,shift_size分别为:#	0,3,0,3,0,3# 即,第四层,depth=2, 有两个SwinTransformerBlock,shift_size分别为:0,3def create_mask(self, x, H, W):# calculate attention mask for SW-MSA
import numpy as np
import torchH = 7
W = 7
window_size = 7
shift_size = 3Hp = int(np.ceil(H / window_size)) * window_size
Wp = int(np.ceil(W / window_size)) * window_size# 拥有和feature map一样的通道排列顺序,方便后续window_partition
img_mask = torch.zeros((1, Hp, Wp, 1))
# [1, Hp, Wp, 1]
print(img_mask, '\n')h_slices = (slice(0, -window_size),slice(-window_size, -shift_size),slice(-shift_size, None)
)
print(h_slices, '\n')
# (slice(0, -7, None), slice(-7, -3, None), slice(-3, None, None))w_slices = (slice(0, -window_size),slice(-window_size, -shift_size),slice(-shift_size, None)
)
print(w_slices, '\n')
# (slice(0, -7, None), slice(-7, -3, None), slice(-3, None, None))cnt = 0
for h in h_slices:for w in w_slices:img_mask[:, h, w, :] = cntcnt += 1print(img_mask)

在这里插入图片描述

import torchimg_mask = torch.rand((2, 3))
print(img_mask)
'''
tensor([[0.7410, 0.6020, 0.5195],[0.9214, 0.2777, 0.8418]])
'''
attn_mask = img_mask.unsqueeze(1) - img_mask.unsqueeze(2)
print(attn_mask)
'''
tensor([[[ 0.0000, -0.1390, -0.2215],[ 0.1390,  0.0000, -0.0825],[ 0.2215,  0.0825,  0.0000]],[[ 0.0000, -0.6437, -0.0796],[ 0.6437,  0.0000,  0.5642],[ 0.0796, -0.5642,  0.0000]]])
'''print(img_mask.unsqueeze(1))
'''
tensor([[[0.7410, 0.6020, 0.5195]],[[0.9214, 0.2777, 0.8418]]])
'''
print(img_mask.unsqueeze(2))
'''
tensor([[[0.7410],[0.6020],[0.5195]],[[0.9214],[0.2777],[0.8418]]])
'''

上面那个代码,需要根据下面这个代码对应着走,shift_size–torch.roll()

class SwinTransformerBlock(nn.Module):# Swin Transformer Block....def forward(self, x, attn_mask):H, W = self.H, self.WB, L, C = x.shapeassert L == H * W, "input feature has wrong size"shortcut = xx = self.norm1(x)x = x.view(B, H, W, C)# pad feature maps to multiples of window size# 把feature map给pad到window size的整数倍pad_l = pad_t = 0pad_r = (self.window_size - W % self.window_size) % self.window_sizepad_b = (self.window_size - H % self.window_size) % self.window_size# 注意F.pad的顺序,刚好是反着来的, 例如:# x.shape = (b, h, w, c)# x = F.pad(x, (1, 1, 2, 2, 3, 3))# x.shape = (b, h+6, w+4, c+2)# 源码可能有误,修改成下面的# x = F.pad(x, (0, 0, pad_l, pad_r, pad_t, pad_b))x = F.pad(x, (0, 0, pad_t, pad_b, pad_l, pad_r))_, Hp, Wp, _ = x.shape# cyclic shiftif self.shift_size > 0:# paper中,滑动的size是窗口大小的/2(向下取整)# torch.roll以H,W的维度为例子,负值往左上移动,正值往右下移动。# 溢出的值在对角方向出现。即循环移动。shifted_x = torch.roll(x, shifts=(-self.shift_size, -self.shift_size), dims=(1, 2))else:shifted_x = xattn_mask = None# partition windowsx_windows = window_partition(shifted_x, self.window_size)  # [nW*B, Mh, Mw, C]x_windows = x_windows.view(-1, self.window_size * self.window_size, C) # [nW*B, Mh*Mw, C]# W-MSA/SW-MSAattn_windows = self.attn(x_windows, mask=attn_mask)  # [nW*B, Mh*Mw, C]...

其中,torch.roll()方法简易示例如下:

import torchx = torch.randn(1, 4, 4, 3)
print(x, '\n')shifted_x = torch.roll(x, shifts=(-3, -3), dims=(1, 2))
print(shifted_x, '\n')

为了方便理解,我更换了维度:

import torchx = torch.randn(1, 3, 7, 7)
print(x, '\n')shifted_x = torch.roll(x, shifts=(-3, -3), dims=(2, 3))
print(shifted_x, '\n')

在这里插入图片描述

Relative position bias


Relative Position Bias通过给自注意力机制的输出加上一个与token相对位置相关的偏置项,从而增强了模型对局部和全局信息的捕捉能力。

实现方式:

1、构建相对位置索引:

  • 首先,需要确定一个 window size ,并在该窗口内计算token之间的相对位置。
  • 通过构建相对位置索引表(relative position index table),可以方便地查询任意两个token之间的相对位置。

2、可学习的偏置表:

  • 初始化一个与相对位置索引表大小相同的可学习参数表(relative position bias table),这些参数在训练过程中会被优化。
  • 根据相对位置索引,从偏置表中查询对应的偏置值,并将其加到自注意力机制的输出上。

3、计算过程:

  • 在自注意力机制的计算中,通常会将 Q、K 和 V 进行矩阵乘法运算,得到注意力得分。
  • 然后,将 Relative Position Bias 加到注意力得分上,再进行 softmax 运算,最后与 V 相乘得到最终的输出。

代码

import torchcoords_h = torch.arange(7)
coords_w = torch.arange(7)a, b = torch.meshgrid([coords_h, coords_w], indexing="ij")coords = torch.stack(torch.meshgrid([coords_h, coords_w], indexing="ij"))coords_flatten = torch.flatten(coords, 1)
# [2, Mh*Mw]
# print(coords_flatten)
'''
tensor([
[0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3,3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6],
[0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2,3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6]
])
'''
# [2, Mh*Mw, 1] - [2, 1, Mh*Mw]
relative_coords = coords_flatten[:, :, None] - coords_flatten[:, None, :]
relative_coords = relative_coords.permute(1, 2, 0).contiguous()
# [Mh*Mw, Mh*Mw, 2]
'''
tensor([[[ 0,  0],[ 0, -1],[ 0, -2],...,[-6, -4],[-6, -5],[-6, -6]],[[ 0,  1],[ 0,  0],[ 0, -1],...,[-6, -3],[-6, -4],[-6, -5]],[[ 0,  2],[ 0,  1],[ 0,  0],...,[-6, -2],[-6, -3],[-6, -4]],...,[[ 6,  4],[ 6,  3],[ 6,  2],...,[ 0,  0],[ 0, -1],[ 0, -2]],[[ 6,  5],[ 6,  4],[ 6,  3],...,[ 0,  1],[ 0,  0],[ 0, -1]],[[ 6,  6],[ 6,  5],[ 6,  4],...,[ 0,  2],[ 0,  1],[ 0,  0]]])
'''
relative_coords[:, :, 0] += 6
# shift to start from 0relative_coords[:, :, 1] += 6
relative_coords[:, :, 0] *= 13relative_position_index = relative_coords.sum(-1)
print(relative_position_index.shape)
# torch.Size([49, 49])# print(relative_position_index)
'''
tensor([[ 84,  83,  82,  ...,   2,   1,   0],[ 85,  84,  83,  ...,   3,   2,   1],[ 86,  85,  84,  ...,   4,   3,   2],...,[166, 165, 164,  ...,  84,  83,  82],[167, 166, 165,  ...,  85,  84,  83],[168, 167, 166,  ...,  86,  85,  84]])
'''

其中,

relative_coords = coords_flatten[:, :, None] - coords_flatten[:, None, :] 

这行代码是用来计算一个二维坐标点集 coords_flatten 中所有点对之间的相对坐标(或位移)。

未对行列加乘操作之前的矩阵,relative_coords 是一个形状为 (N, N, 2) 的数组,其中 relative_coords[i, j, :] 表示从点 i 到点 j 的相对坐标(或位移)。

在这里插入图片描述

结合其他博客的分析:

如图,假设我们现在有一个window-size=2的feature map;
这里面如果用绝对位置来表示位置索引;
然后如果用相对位置表示,就会有4个情况,但分别都是以自己为(0, 0)计算其他token的相对位置。
分别把4个相对位置展开,得到4x4的矩阵,如最下的矩阵所示。
在这里插入图片描述
请注意这里说的都是位置索引,并不是最后的位置编码。因为后面我们会根据相对位置索引去取对应位置的参数。取出来的值才是相对位置编码。
源码中,作者还将二维索引给转成了一维索引。如果直接将行列相加,就变成一维了。但这样(0, 1)和(1, 0)得到的结果都是1,这样肯定不行。来看看源码的做法怎么做的:
首先,所有行、列都加上M-1,其次将所有的行索引乘上2M-1
最后行索引和列索引相加,保证了相对位置关系,也不会出现0+1 = 1+0 的现象了。
在这里插入图片描述

刚刚也说了,之前计算的是相对位置索引,并不是实际位置偏执参数。

真正使用到的数值需要从relative position bias table,这个表的长度是等于(2M-1)X(2M-1)的。在代码中它是一个可学习参数。
在这里插入图片描述

import torch
from torch import nnwindow_size = (7, 7)
num_heads = 3relative_position_bias_table = nn.Parameter(torch.zeros((2 * window_size[0] - 1) * (2 * window_size[1] - 1), num_heads)
)
print(relative_position_bias_table)
......
nn.init.trunc_normal_(self.relative_position_bias_table, std=.02)

Stage 3 – patch merging layers

To produce a hierarchical representation, the number of tokens is reduced by patch merging layers as the network gets deeper.

The first patch merging layer concatenates the features of each group of 2×2 neighboring patches, and applies a linear layer on the 4C-dimensional concatenated features.
首个补丁合并层将每组2×2相邻补丁的特征进行拼接,并在拼接后的4C维特征上应用一个线性层。

This reduces the number of tokens by a multiple of 2×2=4(2 ×downsampling of resolution), and the output dimension is set to 2C.

Swin Transformer blocks are applied afterwards for feature transformation, with the resolution kept at H/8 × W/8.

同样,结合其他大神分析,图展示如下:

在这里插入图片描述

Related Work

Self-attention based backbone architectures

Instead of using sliding windows, we propose to shift windows between consecutive layers, which allows for a more efficient implementation in general hardware.

。。。。。

Cited link or paper name

  1. Swin Transformer: Hierarchical Vision Transformer using Shifted Windows.
  2. https://blog.csdn.net/weixin_42392454/article/details/141395092

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Vulnhub靶场Nginx解析漏洞复现

一.nginx_parsing 原理:这个解析漏洞其实是PHP CGI的漏洞,在PHP的配置⽂件中有⼀个关键的选项cgi.fix_pathinfo默认是开启的,当URL中有不存在的⽂件,PHP就会向前递归解析。在⼀个⽂件/xx.jpg后⾯加上/.php会将 /xx.jpg/xx.php 解…

P1305 新二叉树

题目: P1305 新二叉树 - 洛谷 | 计算机科学教育新生态 题目描述 输入一串二叉树,输出其前序遍历。 输入格式 第一行为二叉树的节点数 n。(1≤n≤26) 后面 n 行,每一个字母为节点,后两个字母分别为其左右儿子。特别地&#x…

jvm字节码中方法的结构

“-Xss”这一名称并没有一个特定的“为什么”来解释其命名,它更多是JVM(Java虚拟机)配置参数中的一个约定俗成的标识。在JVM中,有多个配置参数用于调整和优化Java应用程序的性能,这些参数通常以一个短横线“-”开头&am…

熟悉u8g2图形库C语言函数

前言: 前面我们已经成功移植了U8g2的图形库(0.96寸OLED):手把手移植U8g2图形库,这个文章主要熟悉u8g2图形库的常用C语言函数!需要移植的资料的可以关注一波评论区评论,我看到了就会给你发哦&am…

MobaXterm 连接不上VMware 的Ubuntu 虚拟机

想在window11的笔记本上通过VMWare安装Ubuntu操作系统,但是在两个桌面见来回切换,十分的麻烦,于是通过远程服务访问客户端软件MateXterm来访问虚拟机的Linux系统,但是从CSDN上搜到的教程都没有成功,于是,尝…

java中带缓存的输入/输出流

1、介绍 缓存时I/O的一种性能优化。缓存流为I/O流增加了内存缓存区。有了缓存区,使得在流上执行skip()、mark()、reset()方法都成为可能。 2、BufferedInputStream与BufferedOutputStream类 BufferedInputStream类可以对所有InputStream类进行带缓存区的包装以达…

国家认可的人工智能从业人员证书如何报考?

一、证书出台背景 为进一步贯彻落实中共中央印发《关于深化人才发展体制机制改革的意见》和国务院印发《关于“十四五”数字经济发展规划》等有关工作的部署要求,深入实施人才强国战略和创新驱动发展战略,加强全国数字化人才队伍建设,持续推…

基于Spring Boot的找律师系统

一、系统背景与意义 在现代社会,法律服务的需求日益增长,但传统寻找律师的方式往往存在信息不透明、选择困难等问题。基于Spring Boot的找律师系统旨在解决这些问题,通过线上平台,用户可以轻松搜索、比较和选择合适的律师&#x…

springboot460实习生管理系统设计和实现(论文+源码)_kaic

摘 要 现代经济快节奏发展以及不断完善升级的信息化技术,让传统数据信息的管理升级为软件存储,归纳,集中处理数据信息的管理方式。本实习生管理系统就是在这样的大环境下诞生,其可以帮助管理者在短时间内处理完毕庞大的数据信息&…

C#中方法参数传值和传引用的情况

对于引用类型 - 传类类型的具体值时 此时传的是引用 - 单纯传类类型 此时传的是个test引用的副本,在方法内修改的是这个副本的指向 传string,集合同理,只要是指向新对象,就是引用副本在指向 对于值类型 - 传普通值类型 …

游戏AI实现-寻路算法(A*)

A*(A-star)是一种图遍历和寻路算法,由于其完整性、最优性和最佳效率,它被用于计算机科学的许多领域。给定一个加权图、一个源节点和一个目标节点,该算法将找到从源到目标的最短路径(相对于给定的权重&#…

Autosar入门_架构(Architecture)

上一篇 | 返回主目录 | 下一篇 架构(Architecture) 1 Autosar架构分层概述2 MCAL3 ECU抽象层4 复杂设备驱动5 服务层6 RTE7 应用软件层1 Autosar架构分层概述 整体架构分为三层:应用软件(APP)、实时运行环境(RTE)、基础软件(BSW)以下架构对BSW进行了细化,主要包含四…

【计算机网络2】计算机网络的性能能指标

目录 一 、计算机网络的性能指标 二、具体介绍 1、速 率 2、带 宽 3、吞 吐 量 4、时 延 5、时延带宽积 6、往 返 时 延 7、信道利用率 一 、计算机网络的性能指标 计算机网络的性能指标就是从不同方面度量计算机网络的性能,有如下7个指标: 速…

Oracle 中间件 Webcenter Portal服务器环境搭建

环境信息 服务器基本信息 如下表,本次安装总共使用2台服务器,具体信息如下: Webcenter1服务器 归类 SOA服务器 Ip Address 172.xx.xx.xx.xx HostName wcc01.xxxxxx.com Alias wccprd01 Webcenter2服务器 归类 OSB服务器 Ip Addr…

【游戏设计原理】20 - 囚徒困境

一、分析与总结 1. 核心思想 囚徒困境是一种非零和博弈模型,揭示了理性自利个体在决策时的矛盾:在短期利益和长期合作之间往往存在冲突。 合作与背叛:博弈者可以选择合作(短期牺牲,换取长远收益)或背叛&…

线性代数期末总复习的点点滴滴(1)

一、可逆矩阵、行列式、秩的关系 1.行列式与可逆矩阵的关系 所以,不难看出矩阵可逆的充分必要条件是该矩阵的行列式不为0。 2.接着来看,满秩和矩阵行列式的关系 不难看出满秩和行列式不为0是等价的。 3.再来看,满秩和矩阵可逆的关系 说明了…

ubuntu22.04编译安装Opencv4.8.0+Opencv-contrib4.8.0教程

本章教程,主要记录在Ubuntu22.04版本系统上编译安装安装Opencv4.8.0+Opencv-contrib4.8.0的具体过程。 一、下载opencv和opencv-contrib包 wget https://github.com/opencv/opencv/archive/refs/tags/4.8.0.zip wget https://github.com/opencv/opencv_contrib/archive/refs/…

2024年12月陪玩系统-仿东郊到家约玩系统是一种新兴的线上预约线下社交、陪伴系统分享-优雅草央千澈-附带搭建教程

2024年12月陪玩系统-仿东郊到家约玩系统是一种新兴的线上预约线下社交、陪伴系统分享-优雅草央千澈-附带搭建教程 产品介绍 仿东郊到家约玩系统是一种新兴的线上预约,线下社交、陪伴、助娱、助攻、分享、解答、指导等服务模式,范围涉及电竞、运动、音乐…

算法学习(十六)—— 综合练习

目录 1863. 找出所有子集的异或总和再求和 47. 全排列 Ⅱ 17. 电话号码的字母组合 22. 括号生成 77. 组合 494. 目标和 39. 组合总和 784. 字母大小写全排列 526. 优美的排列 51. N皇后 36. 有效的数独 37. 解数独 79. 单词搜索 1219. 黄金矿工 980. 不同路径 Ⅲ…

「Mac畅玩鸿蒙与硬件45」UI互动应用篇22 - 评分统计工具

本篇将带你实现一个评分统计工具,用户可以对多个选项进行评分。应用会实时更新每个选项的评分结果,并统计平均分。这一功能适合用于问卷调查或评分统计的场景。 关键词 UI互动应用评分统计状态管理数据处理多目标评分 一、功能说明 评分统计工具允许用…