Vision Transformer (ViT) 架构解析:从图像分块到全局注意力机制

## 1. 打破常规:为什么图像处理需要Transformer? 大家好,我是老张,在AI和硬件领域摸爬滚打了十几年。今天想和大家聊聊一个彻底改变了计算机视觉格局的模型——Vision Transformer,也就是我们常说的ViT。如果你对深度学习有点了解,肯定知道卷积神经网络(CNN)在过去十年里几乎是图像处理的“标配”,从人脸识别到自动驾驶,无处不在。但2020年,谷歌的一篇论文像一颗重磅炸弹,提出了一个大胆的想法:**能不能完全不用卷积,只用Transformer来处理图像?** 我刚开始接触这个想法时,第一反应也是“这能行吗?”。毕竟Transformer是为自然语言处理(NLP)设计的,它处理的是像句子那样一维的序列数据。而图像是二维的,有空间结构,像素之间还有复杂的局部关系。CNN的卷积核天生就是为了捕捉这种局部特征(比如边缘、纹理)而生的,它的“局部感受野”设计非常符合我们对图像处理的直觉。 但Transformer的核心——**自注意力机制**——有一个CNN难以比拟的绝活:**全局建模能力**。一个卷积核每次只能看到图像的一小块区域(比如3x3),要想知道图像左上角和右下角的关系,信息需要经过很多层卷积才能传递过去。而自注意力机制在理论上,从第一层开始,任何一个“元素”就能直接和图像上所有其他“元素”进行交互和计算关联性。 这就好比你要理解一整篇文章的意思。CNN的方式是,先让你认单词(局部特征),再组合成短语,再看句子,最后理解段落和全文。而Transformer的方式是,直接把所有单词摆在你面前,让你同时去分析每个单词和文章中所有其他单词的关系,立刻把握全文的核心思想和长距离的指代关系。后者在理解整体上下文和复杂依赖关系上,潜力巨大。 ViT的诞生,就是要把Transformer这种强大的全局理解能力,直接“嫁接”到图像上。它要回答的问题是:如果我们放弃CNN那些为图像量身定做的“先验知识”(比如平移不变性、局部性),完全让数据驱动,让模型自己从海量数据中学到图像的一切规律,结果会怎样?事实证明,当数据量足够大时,这个“暴力”但直接的方法,效果惊人。 ## 2. ViT的核心设计:把图像变成“句子” 那么,具体怎么把一张图片塞进为文本设计的Transformer里呢?这是ViT最精妙也最核心的一步。它的思路非常直观,可以概括为:**分块、拉平、视为词**。 ### 2.1 图像分块:从像素网格到视觉单词 想象一下,你有一张标准的224x224像素的彩色图片。如果直接把每个像素当作一个“词”,那序列长度就是224*224=50176,这对于计算注意力来说是不可承受之重(计算量随序列长度平方增长)。 ViT的做法很聪明:它不关心单个像素,而是把图像划分成一个个大小相等的**图像块**。论文里常用的设置是把图片切成16x16像素的小块。对于224x224的图,横竖各切14刀,就得到了14x14=196个图像块。 每个图像块的大小是16x16x3=768(16像素高,16像素宽,3个颜色通道)。现在,这196个图像块,就成了我们处理的基本单元。你可以把它们想象成196个“视觉单词”,每个“单词”包含了16x16区域内的所有视觉信息。 这一步在代码里通常用一个步长等于核大小的卷积层高效实现: ```python # 使用卷积层一步完成分块和线性投影 self.proj = nn.Conv2d(in_channels=3, out_channels=embed_dim, kernel_size=16, stride=16) # 输入 [B, 3, 224, 224] -> 输出 [B, 768, 14, 14] ``` 这个卷积核大小为16,步长也为16,意味着它不重叠地扫描整张图,每个16x16区域输出一个值(实际上是768维的向量),完美实现了分块操作。 ### 2.2 线性投影与位置编码:为Transformer准备输入 分块之后,每个图像块实际上是一个三维的小数组(16, 16, 3)。我们需要把它转换成一维的向量,才能输入Transformer。这个过程叫**线性投影**,其实就是用一个全连接层把768维的像素值映射到一个新的维度D(论文中D=768)。 现在,我们有了196个长度为768的向量。但Transformer本身没有位置概念,打乱这些向量的顺序,它计算出的结果是一样的。这对于图像来说显然是灾难性的——猫的鼻子长在眼睛上面还是下面,意义完全不同。因此,我们必须加入**位置编码**。 ViT采用了一种简单直接的可学习位置编码。我们初始化一个可训练的参数矩阵,形状是 `[197, 768]`(为什么是197?稍后解释),其中每一行代表一个位置(从0到196)的编码向量。在输入Transformer之前,把这个位置编码向量直接加到对应的图像块向量上: ```python # x 的形状是 [batch_size, 196, 768] # pos_embed 的形状是 [1, 197, 768],在batch维度广播 x = x + self.pos_embed[:, 1:, :] # 注意,位置0预留给了一个特殊token ``` 这个可学习的位置编码会在训练过程中,自己学会如何表征“上下左右”、“中心边缘”这些空间关系。我实测下来发现,学到的位置编码可视化后,确实能呈现出明显的二维空间结构,相邻位置编码相似,同行或同列的位置编码也有规律。 ### 2.3 Class Token:图像的“句子主旨” 在NLP的BERT模型里,有一个 `[CLS]` token,用于汇聚整个句子的信息,做分类任务。ViT借鉴了这个天才的设计,引入了一个**可学习的分类token**。 我们在序列的最前面,额外添加一个特殊的向量,称为 `cls_token`。现在,输入序列的长度从196变成了197。这个 `cls_token` 会和其他196个图像块token一起,经过所有Transformer层的处理。在最后一层,我们只取出这个 `cls_token` 对应的输出向量,把它送入一个轻量的分类头(通常是MLP),得到最终的图像分类结果。 你可以把这个 `cls_token` 理解为一个“提问者”或“汇总者”。它随着数据流经整个网络,通过自注意力机制不断地从所有图像块那里收集信息,最终它自己身上就凝聚了整张图片的全局语义。这个设计避免了我们需要从196个输出中选哪一个来做分类的尴尬,非常优雅。 ## 3. Transformer编码器:全局注意力的引擎 准备好输入序列后,就进入了ViT的主干——**Transformer编码器**。这部分和原始Transformer的编码器几乎一模一样,由多个相同的层堆叠而成(ViT-Base是12层)。每一层都包含两个核心子层:多头自注意力层和前馈神经网络层,并且每个子层都包裹着残差连接和层归一化。 ### 3.1 多头自注意力机制:让每个像素块“纵观全局” 这是Transformer的灵魂,也是ViT获得全局建模能力的来源。它的工作原理可以用一个“信息检索”的类比来理解。 对于序列中的每一个token(比如某个图像块),自注意力层会帮它做三件事: 1. **生成查询**:这个token想问:“我关心什么样的信息?” 2. **生成键**:序列里所有token(包括自己)都亮出自己的“身份标签”,说:“我这里有这样的信息。” 3. **生成值**:每个token准备好自己实际要提供的“内容信息”。 然后,计算这个token的“查询”与所有token的“键”的相似度(通过点积),得到一个注意力权重分布。这个权重决定了在汇总信息时,应该从每个token的“值”那里取多少。最后,用这个权重对所有token的“值”进行加权求和,就得到了该token新的表示。 **多头**机制,就是并行地做多组这样的操作(比如12个头),每组使用不同的投影矩阵,相当于从12个不同的角度或“语义子空间”去计算注意力。最后把12个结果拼接起来,再投影回原来的维度。这大大增强了模型的表达能力。 在ViT中,这意味着**从第一层开始,图像左上角的一个小块,就能直接关注到右下角的小块**,并建立联系。这对于识别“一只鸟的喙和它的脚属于同一个物体”这样的长距离依赖至关重要。而CNN需要很多层卷积,这种信息才能慢慢传递过去。 代码层面,核心计算非常紧凑: ```python # q, k, v 形状均为 [batch_size, num_heads, seq_len, head_dim] attn_weights = torch.matmul(q, k.transpose(-2, -1)) / math.sqrt(head_dim) # 计算相似度 attn_weights = F.softmax(attn_weights, dim=-1) # 归一化为权重 attn_output = torch.matmul(attn_weights, v) # 加权求和 ``` ### 3.2 前馈网络与层归一化:非线性变换与稳定训练 自注意力层输出后,会经过一个**前馈网络**。它通常是一个简单的两层MLP,中间有一个非线性激活函数(如GELU)。这个子层的作用是给每个token的表示增加非线性变换能力,进行特征混合和升维再降维。 这里有一个关键点:自注意力层是进行 **token与token之间** 的交互(混合空间信息),而前馈网络是进行 **每个token内部特征之间** 的交互(混合通道信息)。两者分工明确。 **残差连接**和**层归一化**是训练深层Transformer的关键技术。每个子层的输入和输出会相加(残差连接),这能有效缓解梯度消失,让网络可以堆得很深。层归一化则被应用在子层之前(Pre-Norm,这是ViT采用的方式,不同于原始Transformer的Post-Norm),它对每个样本的所有特征维度进行归一化,稳定了训练过程,让学习率可以设得更大,收敛更快。 我自己的经验是,在搭建ViT时,这些细节(Pre-Norm vs Post-Norm,GELU vs ReLU,初始化方式)对最终效果的影响非常显著,有时候调好一个细节,准确率能提升一两个点。 ## 4. ViT vs CNN:理念之争与实战差异 聊了这么多原理,大家最关心的肯定是:ViT和传统的CNN到底谁更强?在实际项目中该怎么选?我结合自己的实战经验,给大家做个对比分析。 | 特性 | 卷积神经网络 | Vision Transformer | | :--- | :--- | :--- | | **核心操作** | 卷积(局部滑动窗口) | 自注意力(全局交互) | | **归纳偏置** | 强:平移不变性、局部性 | 弱:几乎没有图像-specific的先验 | | **感受野** | 局部开始,随层数扩大 | **从第一层起就是全局** | | **数据需求** | 相对较少,在小数据集上也能学好 | **极度依赖大规模数据** | | **计算效率** | 高,局部计算,参数共享 | 序列长度平方级复杂度,对长序列慢 | | **可解释性** | 特征图可视化,相对直观 | 注意力图可视化,显示全局关联 | | **擅长任务** | 纹理、局部模式识别、实时检测 | 长距离依赖、全局上下文理解、大规模分类 | **CNN的优势在于它的“高效”和“数据友好”**。卷积的局部性和权重共享,让它用较少的参数和计算量就能提取有效的层次化特征。而且,它的归纳偏置非常符合图像的物理规律,所以即使在ImageNet这种“中等”规模的数据集上(120万张图),也能取得非常好的效果。在计算资源有限、数据量不大的场景下,CNN依然是首选。 **ViT的优势在于它的“强大”和“可扩展性”**。它几乎没有对图像结构做任何假设,所有空间关系都需要从数据中学。这既是缺点也是优点。缺点是需要海量数据(比如谷歌用的JFT-3亿数据集)来“喂饱”它,否则很容易过拟合,效果不如CNN。但一旦用超大数据集预训练好,它的表现往往能超越CNN,尤其是在需要理解图像全局结构的任务上。而且,模型越大,数据越多,ViT的性能提升似乎没有明显的天花板,显示出极好的可扩展性。 在实际项目中,我的选择策略是: - **如果任务类似ImageNet分类,数据量在百万级**:可以尝试ViT,但需要仔细调参和可能的数据增强。使用预训练模型进行微调是更稳妥的选择。 - **如果数据量只有几万甚至几千**:老老实实用CNN(如ResNet、EfficientNet)或者使用在ImageNet上预训练好的ViT进行微调。直接从头训练ViT大概率会翻车。 - **如果任务对全局上下文要求极高**:比如医学图像中分析整个器官的病变关联、卫星图像中分析地理要素的分布,即使数据量不大,也值得尝试用预训练的ViT,它的全局注意力机制可能带来惊喜。 - **如果对推理速度要求苛刻**:CNN或更轻量的混合模型(如MobileViT)仍是主流。 ## 5. 动手实践:从零理解ViT的代码实现 光说不练假把式。下面我带大家走一遍ViT关键模块的PyTorch实现代码,我会加上详细的注释,确保你能看懂每一行在做什么。 首先,是**图像分块嵌入模块**,它负责把图片变成序列: ```python import torch import torch.nn as nn class PatchEmbed(nn.Module): """ 将2D图像分割为Patches并做线性投影 """ def __init__(self, img_size=224, patch_size=16, in_chans=3, embed_dim=768): super().__init__() self.img_size = (img_size, img_size) self.patch_size = (patch_size, patch_size) # 计算patch数量: (224/16) * (224/16) = 14*14 = 196 self.num_patches = (img_size // patch_size) * (img_size // patch_size) # 核心:用一个大卷积核、大步长的卷积层同时完成分块和线性投影 # kernel_size=16, stride=16 意味着不重叠地取每个16x16区域 # 输入通道3,输出通道embed_dim(768) self.proj = nn.Conv2d(in_chans, embed_dim, kernel_size=patch_size, stride=patch_size) def forward(self, x): B, C, H, W = x.shape # 输入形状 [Batch, 3, 224, 224] # 确保输入尺寸正确 assert H == self.img_size[0] and W == self.img_size[1], f"输入尺寸({H},{W})与模型设定{self.img_size}不符" # 分块投影: [B, 3, 224, 224] -> [B, 768, 14, 14] # flatten(2): 将高和宽维度展平 -> [B, 768, 196] # transpose(1,2): 交换维度 -> [B, 196, 768] (序列长度196,特征维度768) x = self.proj(x).flatten(2).transpose(1, 2) return x ``` 接下来是ViT的**核心构建块**,即一个Transformer编码层: ```python class TransformerBlock(nn.Module): """ 一个完整的Transformer编码器层 """ def __init__(self, dim, num_heads, mlp_ratio=4., qkv_bias=False, drop_rate=0., attn_drop_rate=0.): super().__init__() # 第一层:层归一化 + 多头自注意力 + 残差 self.norm1 = nn.LayerNorm(dim) self.attn = MultiHeadAttention(dim, num_heads, qkv_bias, attn_drop_rate, drop_rate) # 第二层:层归一化 + 前馈网络(MLP) + 残差 self.norm2 = nn.LayerNorm(dim) mlp_hidden_dim = int(dim * mlp_ratio) self.mlp = Mlp(in_features=dim, hidden_features=mlp_hidden_dim, drop=drop_rate) # 随机深度丢弃(Stochastic Depth),一种正则化技术 self.drop_path = DropPath(drop_rate) if drop_rate > 0. else nn.Identity() def forward(self, x): # 注意Pre-Norm结构:先归一化,再进入子层 # 残差连接:x = x + 子层输出 x = x + self.drop_path(self.attn(self.norm1(x))) x = x + self.drop_path(self.mlp(self.norm2(x))) return x ``` 其中用到的**多头自注意力**实现如下: ```python class MultiHeadAttention(nn.Module): def __init__(self, dim, num_heads=8, qkv_bias=False, attn_drop=0., proj_drop=0.): super().__init__() self.num_heads = num_heads self.head_dim = dim // num_heads # 每个头的维度,如768/12=64 self.scale = self.head_dim ** -0.5 # 缩放因子,稳定softmax梯度 # 用一个线性层同时生成Q, K, V的投影矩阵 self.qkv = nn.Linear(dim, dim * 3, bias=qkv_bias) self.attn_drop = nn.Dropout(attn_drop) # 将多个头的输出合并回原维度 self.proj = nn.Linear(dim, dim) self.proj_drop = nn.Dropout(proj_drop) def forward(self, x): B, N, C = x.shape # [batch_size, 序列长度197, 特征维度768] # 生成QKV: [B, 197, 768] -> [B, 197, 768*3] -> 重塑并分头 qkv = self.qkv(x).reshape(B, N, 3, self.num_heads, self.head_dim).permute(2, 0, 3, 1, 4) q, k, v = qkv[0], qkv[1], qkv[2] # 每个形状: [B, num_heads, N, head_dim] # 计算注意力分数: Q * K^T / sqrt(d_k) attn = (q @ k.transpose(-2, -1)) * self.scale # [B, heads, N, N] attn = attn.softmax(dim=-1) # 在最后一个维度(N)上做softmax attn = self.attn_drop(attn) # 应用注意力权重到V上 x = (attn @ v).transpose(1, 2).reshape(B, N, C) # 合并多头 x = self.proj(x) x = self.proj_drop(x) return x ``` 最后,我们把所有部分组装成完整的**Vision Transformer模型**: ```python class VisionTransformer(nn.Module): def __init__(self, img_size=224, patch_size=16, in_chans=3, num_classes=1000, embed_dim=768, depth=12, num_heads=12): super().__init__() self.patch_embed = PatchEmbed(img_size, patch_size, in_chans, embed_dim) num_patches = self.patch_embed.num_patches # 可学习的分类token和位置编码 self.cls_token = nn.Parameter(torch.zeros(1, 1, embed_dim)) self.pos_embed = nn.Parameter(torch.zeros(1, num_patches + 1, embed_dim)) # +1 for cls_token # 堆叠Transformer层 self.blocks = nn.ModuleList([ TransformerBlock(dim=embed_dim, num_heads=num_heads) for _ in range(depth) ]) self.norm = nn.LayerNorm(embed_dim) # 分类头:通常就是一个线性层 self.head = nn.Linear(embed_dim, num_classes) # 初始化参数 nn.init.trunc_normal_(self.pos_embed, std=0.02) nn.init.trunc_normal_(self.cls_token, std=0.02) self.apply(self._init_weights) def _init_weights(self, m): if isinstance(m, nn.Linear): nn.init.trunc_normal_(m.weight, std=.02) if m.bias is not None: nn.init.constant_(m.bias, 0) def forward(self, x): B = x.shape[0] # 1. 分块嵌入 x = self.patch_embed(x) # [B, 196, 768] # 2. 添加cls token cls_tokens = self.cls_token.expand(B, -1, -1) # 从[1,1,768]扩展到[B,1,768] x = torch.cat((cls_tokens, x), dim=1) # [B, 197, 768] # 3. 添加位置编码 x = x + self.pos_embed # 4. 通过Transformer编码器 for blk in self.blocks: x = blk(x) # 5. 取cls token的输出做分类 x = self.norm(x) cls_output = x[:, 0] # 只取第一个token(cls_token)的输出 out = self.head(cls_output) return out ``` 你可以用几行代码实例化并测试这个模型: ```python model = VisionTransformer(img_size=224, patch_size=16, num_classes=10) dummy_input = torch.randn(4, 3, 224, 224) # 4张224x224的RGB图 output = model(dummy_input) print(output.shape) # 应该输出: torch.Size([4, 10]) ``` ## 6. 超越分类:ViT的进化与未来 ViT最初是为图像分类设计的,但它的影响力远不止于此。研究者们很快将这种“分块+Transformer”的思想拓展到了计算机视觉的各个角落,催生了一系列变体和改进。 **目标检测**:DETR是第一个用Transformer做端到端目标检测的框架,它去掉了传统的锚框和非极大值抑制,将检测视为一个集合预测问题。后续的Deformable DETR、Swin Transformer for Detection等,都在速度和精度上做了进一步优化。 **图像分割**:SETR、Segmenter等模型将ViT作为编码器,配合各种解码器结构,在语义分割任务上取得了媲美甚至超越CNN的成绩。ViT的全局上下文信息对于理解像素所属的物体类别非常有帮助。 **底层视觉任务**:甚至在图像超分辨率、去噪、风格迁移等任务中,也出现了基于Transformer的模型,它们能更好地建模图像的长程依赖,恢复出更连贯的纹理和结构。 当然,ViT也有其明显的**挑战**。最大的问题就是**计算复杂度**。自注意力的计算量与序列长度的平方成正比。当图像分辨率很高时(比如1024x1024),序列长度会爆炸式增长。为了解决这个问题,社区提出了许多聪明的方案: - **局部窗口注意力**:像Swin Transformer那样,将注意力计算限制在局部窗口内,再通过窗口移动来传递信息,将计算复杂度从平方降到了线性。 - **分层下采样结构**:同样在Swin中引入,像CNN一样构建特征金字塔,逐步减少序列长度,同时增加特征维度,兼顾效率和表达能力。 - **稀疏注意力**:只计算最重要的token对之间的注意力,比如根据键的相似度来筛选。 - **线性注意力**:通过核函数近似,将softmax注意力转化为线性计算。 在我个人看来,ViT的出现并不是要彻底取代CNN,而是为我们提供了另一种强大的工具。未来的趋势很可能是**融合**:吸收CNN在局部特征提取、平移等变性上的高效性,结合Transformer在全局建模上的强大能力。很多优秀的混合模型已经证明了这一点。 对于初学者,我的建议是,先扎实理解CNN,再深入学习Transformer和ViT。当你手里既有锤子又有螺丝刀时,面对不同的任务,你才能游刃有余地选择最合适的工具。ViT的代码实现虽然看起来比CNN复杂,但它的模块化程度很高,一旦理解了自注意力和分块嵌入这两个核心,整个架构就豁然开朗了。多动手写几遍代码,在小的数据集(比如CIFAR-10)上跑一跑,调整参数观察效果,是掌握它的最好方式。

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

Python内容推荐

基于Vision Transformer的图像去雾算法研究与实现python源码+使用说明.zip

基于Vision Transformer的图像去雾算法研究与实现python源码+使用说明.zip

Vision Transformer (ViT) 是Transformer在计算机视觉领域的变体,它将图像分割为一系列的像素块(tokens),然后通过多层自注意力机制来处理这些tokens,以学习图像的全局上下文信息。在图像去雾任务中,ViT可能...

深度学习大作业Python基于VIT实现CAFIR10分类项目源代码+详细文档

深度学习大作业Python基于VIT实现CAFIR10分类项目源代码+详细文档

Transformer通过自注意力机制处理输入序列,VIT将图像视为一系列的“patch”,并将这些patch转换为固定长度的向量,然后通过多层Transformer进行处理,实现全局信息的捕获和理解。 接下来,我们来看CAFIR10数据集。...

基于CNN-LSTM的滚动轴承故障诊断Python实现与预训练模型

基于CNN-LSTM的滚动轴承故障诊断Python实现与预训练模型

本项研究聚焦于人工智能课程中设定的第二个设计题目——轴承故障诊断。滚动轴承的基本构造可参考其机械结构示意。该类轴承的局部性损伤可能出现在外环、内环、滚动体或保持架等部件中。当轴承运转时,若滚动体撞击外环或内环的局部损伤点,或滚动体自身的损伤与内、外环接触,将会激起轴承系统与信号传感器之间的高频共振。因此,通过采集并分析轴承的振动信号,可实现对上述各类损伤的精确辨识。 此研究中考虑了三类典型的轴承故障模式,分别为外环故障、内环故障以及滚动体故障。结合轴承所具有的三类不同直径尺寸,经过组合,共构成九种不同的故障类型。本课题所设定的具体工作条件为:负载为3马力,旋转速度接近每分钟1730转。在这个工况下,涵盖了全部上述九种故障类别。 资源来源于网络分享,仅用于学习交流使用,请勿用于商业,如有侵权请联系我删除!

【计算机视觉】基于Transformer的ViT模型关键技术解析:图像分类与多模态融合应用系统设计

【计算机视觉】基于Transformer的ViT模型关键技术解析:图像分类与多模态融合应用系统设计

文章从传统CNN的局限性与Transformer在NLP中的成功切入,详细解析了ViT的核心原理,包括图像分块、序列化输入、自注意力机制的全局建模能力以及位置编码的重要性。随后,文章完整剖析了ViT从输入预处理、Transformer...

Vision Transformer(ViT)介绍、应用与安装教程

Vision Transformer(ViT)介绍、应用与安装教程

Vision Transformer(ViT)是一种基于Transformer模型的新型架构,首次在2020年由Google团队提出并应用于图像分类任务。其核心原理是将输入的图像划分为固定大小的图块,随后这些图块被展开成为序列输入给...

vit.zip视觉transformer代码

vit.zip视觉transformer代码

近年来,这种模型的影响力已跨越了NLP,逐渐渗透到计算机视觉(CV)领域,催生出一种名为视觉Transformer(ViT,Vision Transformer)的新颖架构。本文将基于提供的"vit.zip"压缩包,深入探讨ViT的核心概念、实现...

Vision Transformer系列参考论文

Vision Transformer系列参考论文

- 分块与位置编码:在VIT中,图像被切割成固定大小的patches,然后线性展开成一维向量,这些向量加上位置编码后输入到Transformer中,以保留图像的空间信息。 2. **Vision Transformer的发展** - ViT(Vision ...

OCR识别-基于ViT实现的将图像转换为LaTex公式代码-附项目源码-优质实用项目实战.zip

OCR识别-基于ViT实现的将图像转换为LaTex公式代码-附项目源码-优质实用项目实战.zip

2. Vision Transformer(ViT):ViT是深度学习模型的一种,它对输入图像进行分块处理,然后将这些块作为序列传递给Transformer架构。Transformer在自然语言处理领域表现出色,而ViT则将其成功扩展到了图像识别任务。...

CIFAR10上训练ViT[可运行源码]

CIFAR10上训练ViT[可运行源码]

此外,作者详细介绍了如何实现transforms块,这是Transformer架构的核心之一,包括多头注意力机制和多层感知机(MLP)的构建和使用。 文章的后半部分提供了完整的Vision Transformer模型代码,使得读者可以复现模型...

深度学习ViT解读[项目代码]

深度学习ViT解读[项目代码]

ViT模型的核心是将传统卷积神经网络中的卷积操作替换为Transformer中的自注意力机制,这样做能够更好地处理图像中的全局依赖关系。 在ViT模型中,首先对输入图像进行分块处理,将其划分为多个小块,这些小块将作为...

《AFR-Net: Attention-Driven Fingerprint Recognition Network》PPT

《AFR-Net: Attention-Driven Fingerprint Recognition Network》PPT

在对ViT进行改进以提升其在指纹识别领域的性能时,研究者们采取了以下措施:一是评估并引入基于注意力的架构,二是利用更大、更多样化的数据集进行训练和评估,三是结合基于注意力机制和基于卷积神经网络(CNN)的...

深度学习-ConvNeXt + ParC Net论文梳理-组会汇报PPT

深度学习-ConvNeXt + ParC Net论文梳理-组会汇报PPT

ViT通过其独特的分块和自注意力机制改变了网络架构设计的格局,而Swin Transformer和ResNet虽然具有相似的归纳偏置,但在训练方法和宏观/微观层次的架构设计上有所不同。ConvNeXt旨在探索Transformer的设计决策如何...

MAE论文精读笔记[代码]

MAE论文精读笔记[代码]

MAE(Masked Autoencoders Are Scalable Vision Learners)是一种基于视觉变换器(Vision Transformer, ViT)的自监督学习模型,其核心思想在于通过随机遮罩图像中的一部分块(patches),仅让模型处理未被遮罩的...

ESXI+ROS+LEDE软路由配置概述

ESXI+ROS+LEDE软路由配置概述

代码下载链接: https://pan.quark.cn/s/aeea50b2f179 一分钟在线编译定制专属固件: openwrt.ai openwrt 软路由固件 Acknowledgments OpenWrt Lean's OpenWrt ImmortalWrt unifreq ophub hanwckf P3TERX aparcar Actions

基于Java语言与MicrosoftGraphRESTfulAPI深度集成开发的跨全局Office365高效批量管理与自动化运维平台_支持A1_A3_A1P_E3_E5等多.zip

基于Java语言与MicrosoftGraphRESTfulAPI深度集成开发的跨全局Office365高效批量管理与自动化运维平台_支持A1_A3_A1P_E3_E5等多.zip

基于Java语言与MicrosoftGraphRESTfulAPI深度集成开发的跨全局Office365高效批量管理与自动化运维平台_支持A1_A3_A1P_E3_E5等多.zip

(共201页PPT)施工企业农民工安全知识培训.pptx

(共201页PPT)施工企业农民工安全知识培训.pptx

(共201页PPT)施工企业农民工安全知识培训.pptx

Navicat Premium manual.7z

Navicat Premium manual.7z

代码下载链接: https://pan.quark.cn/s/a4b39357ea24 Navicat Premium 中文版 当前版本 * 2019-12-17 12.1.28 原版下载地址 Navicat Premium 12.1.28 简体中文版.dmg 使用说明 现在原版并拖拽安装至应用程序目录 下载并执行 举个栗子

canal-1.1.5(deployer adapter)

canal-1.1.5(deployer adapter)

下载代码方式:https://pan.quark.cn/s/ec12e26dbf31 Canal是由阿里巴巴开源的一个数据库实时同步解决方案,它专注于MySQL数据的变更捕获并将其传输至其他系统,例如Elasticsearch、Hadoop、Kafka等,主要用于数据备份、数据分析或实时增量数据推送。本资源提供的版本为canal的1.1.5版本,尽管并非正式稳定版,但通常包含了最新的功能增强与性能优化。1. **Canal的核心架构** Canal的架构设计主要划分为三个主要部分:Server、Client以及Adapter。 - Server:Canal Server作为核心服务,负责监听并解析MySQL的binlog事件,随后将这些事件进行发布。 - Client:Canal Client扮演消费者的角色,订阅并处理Canal Server发布的binlog事件。 - Adapter:Canal Adapter充当连接Canal Server与目标系统的中介,它将Canal Server解析出的binlog事件转换为目标系统可识别的数据格式,从而实现数据同步。2. **部署Canal Deployer** Canal Deployer是Canal的部署管理工具,它负责管理多个Canal实例。部署Canal Deployer需要遵循以下步骤: - 安装Java环境:由于Canal是用Java开发的,因此需要确保系统已安装JDK。 - 下载Canal:可以从GitHub获取,或者直接获取这里的canal-1.1.5压缩文件。 - 配置Canal:编辑conf目录下的canal.properties文件,设置MySQL连接参数、Canal实例配置等。 - 启动C...

MySQL小版本升级方法

MySQL小版本升级方法

源码直接下载地址: https://pan.quark.cn/s/a4b39357ea24 遵循官方指南来执行Mysql小版本升级。倘若MYSQL系通过rpm包进行安装,那么在升级阶段必须更新所有安装时的rpm包。举例来说,倘若旧版mysql安装了server和client rpm包,那么在升级期间这两个包均需进行更新。MySQL的小版本升级是一项标准的维护工作,其目的是引入新功能、修正已知缺陷以及优化系统性能。在小版本升级过程中,必须遵循特定的流程,以确保升级过程顺利且不会造成数据丢失。以下是一份详尽的MySQL小版本升级指南:1. **确认安装配置**: 你需要明确MySQL是以何种方式安装的。在此场景中,假设是通过RPM包(Red Hat Package Manager)在Linux系统中安装的。这意味着升级流程将涉及更新所有的RPM包。2. **禁用InnoDB快速关闭特性**: 倘若你的MySQL实例运用InnoDB存储引擎,你应该在升级前禁用`innodb_fast_shutdown`特性。这有助于确保在关闭数据库时进行完整的InnoDB数据和事务清理,防止潜在的数据不一致问题。3. **稳妥地终止MySQL服务**: 在升级前,务必正确关闭MySQL服务,以避免任何未完成的操作或数据损坏。通常,可以通过`systemctl stop mysql`或`service mysql stop`命令来实现。4. **安装新版的RPM包**: 下载对应的新版MySQL RPM包,确保包括`client`、`shared`和`server`组件。这些组件分别用于提供客户端工具、共享库以及服务器程序。其他的RPM包如`debuginfo`、`devel`和`test...

51单片机大量源码-下载即用.zip

51单片机大量源码-下载即用.zip

源码直接下载地址: https://pan.quark.cn/s/a4b39357ea24 单片机C51学习-练习例程 ===================== 555定时器 AT24C02 DS1302实时时钟 DS18B20 LCD1602 LED灯 LED点阵 PCF8591 中断 串口通信 光敏热敏电阻 数码管 看门狗寄存器 空闲掉电模式 红外遥控 继电器 蜂鸣器 软件复位 锁存器 键盘 项目 LCD时钟 如果编码有问题,打开有乱码, 可以使用iconv指令. $ iconv -f gbk -t utf-8 hello.c > hello.utf-8.c

最新推荐最新推荐

recommend-type

学生成绩管理系统C++课程设计与实践

资源摘要信息:"学生成绩信息管理系统-C++(1).doc" 1. 系统需求分析与设计 在进行学生成绩信息管理系统开发前,首先需要进行系统需求分析,这是确定系统开发目标与范围的过程。需求分析应包括数据需求和功能需求两个方面。 - 数据需求分析: - 学生成绩信息:需要收集学生的姓名、学号、课程成绩等数据。 - 数据类型和长度:明确每个数据项的数据类型(如字符串、整型等)和长度,例如学号可能是字符串类型且长度为一定值。 - 描述:详细描述每个数据项的意义,以确保系统能够准确处理。 - 功能需求分析: - 列出功能列表:用户界面应提供清晰的操作指引,列出所有可用功能。 - 查询学生成绩:系统应能通过学号或姓名查询学生的成绩信息。 - 增加学生成绩信息:允许用户添加未保存的学生成绩信息。 - 删除学生成绩信息:能够通过学号或姓名删除已经保存的成绩信息。 - 修改学生成绩信息:通过学号或姓名修改已有的成绩记录。 - 退出程序:提供安全退出程序的选项,并确保所有修改都已保存。 2. 系统设计 系统设计阶段主要完成内存数据结构设计、数据文件设计、代码设计、输入输出设计、用户界面设计和处理过程设计。 - 内存数据结构设计: - 使用链表结构组织内存中的数据,便于动态增删查改操作。 - 数据文件设计: - 选择文本文件存储数据,便于查看和编辑。 - 代码设计: - 根据功能需求,编写相应的函数和模块。 - 输入输出设计: - 设计简洁明了的输入输出提示信息和操作流程。 - 用户界面设计: - 用户界面应为字符界面,方便在命令行环境下使用。 - 处理过程设计: - 设计数据处理流程,确保每个操作都有明确的处理逻辑。 3. 系统实现与测试 实现阶段需要根据设计阶段的成果编写程序代码,并进行系统测试。 - 程序编写: - 完成系统设计中所有功能的程序代码编写。 - 系统测试: - 设计测试用例,通过测试用例上机测试系统。 - 记录测试方法和测试结果,确保系统稳定可靠。 4. 设计报告撰写 最后,根据系统开发的各个阶段,撰写详细的设计报告。 - 系统描述:包括问题说明、数据需求和功能需求。 - 系统设计:详细记录内存数据结构设计、数据文件设计、代码设计、输入/输出设计、用户界面设计、处理过程设计。 - 系统测试:包括测试用例描述、测试方法和测试结果。 - 设计特点、不足、收获和体会:反思整个开发过程,总结经验和教训。 时间安排: - 第19周(7月12日至7月16日)完成项目。 - 7月9日8:00到计算机学院实验中心(三楼)提交程序和课程设计报告。 指导教师和系主任(或责任教师)需要在文档上签名确认。 系统需求分析: - 使用表格记录系统需求分析的结果,包括数据项、数据类型、数据长度和描述。 - 分析数据项如学生成绩信息、状态器、链表节点等,确定其属性和行为。 以上就是文档中提到的学生成绩信息管理系统开发的关键知识点。开发此类系统需要熟练掌握C++编程基础,了解面向对象的程序设计思想,以及熟悉文件操作和链表等数据结构的应用。此外,良好的软件开发流程意识、测试意识和文档撰写能力也是必不可少的。
recommend-type

别再手动拖拽了!用Lumerical脚本批量创建FDTD仿真结构(附完整代码)

# 告别低效建模:Lumerical脚本自动化实战指南 在光子学仿真领域,时间就是科研生命线。当同行还在GUI界面里反复点击菜单时,你已经用脚本批量生成了20组参数化结构——这不是未来场景,而是每位FDTD用户都应该掌握的基础生产力革命。本文将彻底改变你与Lumerical的交互方式,从手动拖拽的农耕时代,跃迁到自动化建模的工业文明。 ## 1. 为何脚本建模是必然选择 2019年Nature Photonics的一项研究显示,科研工作者在仿真工具上平均浪费37%的时间在重复性操作上。对于需要参数扫描的纳米光学结构设计,这个数字可能更高。手动创建10个不同尺寸的纳米柱阵列意味着: -
recommend-type

Java邮件解析任务中,如何安全高效地提取HTML邮件内容并避免硬编码、资源泄漏和类型转换异常?

<think>我们被要求优化一段Java代码,该代码用于处理邮件(特别是来自特定发件人的构建通知邮件)。代码的主要问题包括: 1. 重复获取邮件内容:在检查MIME类型后,多次调用`msg[i].getContent()`,这可能导致性能问题或流关闭异常。 2. 类型转换问题:直接将邮件内容转换为`Multipart`而不进行类型检查,可能引发`ClassCastException`。 3. 代码结构问题:逻辑嵌套过深,可读性差,且存在重复代码(如插入邮件详情的操作在两个地方都有)。 4. 硬编码和魔法值:例如在解析HTML表格时使用了硬编码的索引(如list3.get(10)),这容易因邮件
recommend-type

RH公司应收账款管理优化策略研究

资源摘要信息:"本文针对RH公司的应收账款管理问题进行了深入研究,并提出了改进策略。文章首先分析了应收账款在企业管理中的重要性,指出其对于提高企业竞争力、扩大销售和充分利用生产能力的作用。然后,以RH公司为例,探讨了公司应收账款管理的现状,并识别出合同管理、客户信用调查等方面的不足。在此基础上,文章提出了一系列改善措施,包括完善信用政策、改进业务流程、加强信用调查和提高账款回收力度。特别强调了建立专门的应收账款回收部门和流程的重要性,并建议在实际应用过程中进行持续优化。同时,文章也意识到企业面临复杂多变的内外部环境,因此提出的策略需要根据具体情况调整和优化。 针对财务管理领域的专业学生和从业者,本文提供了一个关于应收账款管理问题的案例研究,具有实际指导意义。文章还探讨了信用管理和征信体系在应收账款管理中的作用,强调了它们对于提升企业信用风险控制和市场竞争能力的重要性。通过对比国内外企业在应收账款管理上的差异,文章总结了适合中国企业实际环境的应收账款管理方法和策略。" 根据提供的文件内容,以下是详细的知识点: 1. 应收账款管理的重要性:应收账款作为企业的一项重要资产,其有效管理关系到企业的现金流、财务健康以及市场竞争力。不良的应收账款管理会导致资金链断裂、坏账损失增加等问题,严重影响企业的正常运营和长远发展。 2. 应收账款的信用风险:在信用交易日益频繁的商业环境中,企业必须对客户信用进行评估,以便采取合理的信用政策,降低信用风险。 3. 合同管理的薄弱环节:合同是应收账款管理的法律基础,严格的合同管理能够保障企业权益,减少因合同问题导致的应收账款风险。 4. 客户信用调查:了解客户的信用状况对于预测和控制应收账款风险至关重要。企业需要建立有效的客户信用调查机制,识别和筛选信用良好的客户。 5. 应收账款回收策略:企业应建立有效的账款回收机制,包括定期的账款跟进、逾期账款的催收等。同时,建立专门的应收账款回收部门可以提升回收效率。 6. 应收账款管理流程优化:通过改进企业内部管理流程,如简化审批流程、提高工作效率等措施,能够提升应收账款的管理效率。 7. 应收账款管理策略的调整和优化:由于企业的内外部环境复杂多变,因此制定的管理策略需要根据实际情况进行动态调整和持续优化。 8. 信用管理和征信体系的作用:建立和完善企业内部信用管理体系和征信体系,有助于企业更好地控制信用风险,并在市场竞争中占据有利地位。 9. 对比国内外应收账款管理实践:通过研究国内外企业在应收账款管理上的不同做法和经验,可以借鉴先进的管理理念和方法,提升国内企业的应收账款管理水平。 综上所述,本文深入探讨了应收账款管理的多个方面,为RH公司乃至其他同类型企业提供了应收账款管理的改进方向和策略,对于财务管理专业的教育和实践都具有重要的参考价值。
recommend-type

新手别慌!用BingPi-M2开发板带你5分钟搞懂Tina Linux SDK目录结构

# 新手别慌!用BingPi-M2开发板带你5分钟搞懂Tina Linux SDK目录结构 第一次拿到BingPi-M2开发板时,面对Tina Linux SDK里密密麻麻的文件夹,我完全不知道从哪下手。就像走进一个陌生的大仓库,每个货架上都堆满了工具和零件,却找不到操作手册。这种困惑持续了整整两天,直到我意识到——理解目录结构比死记硬背每个文件更重要。 ## 1. 为什么SDK目录结构如此重要 想象你正在组装一台复杂的模型飞机。如果所有零件都混在一个箱子里,你需要花大量时间寻找每个螺丝和面板。但如果有分门别类的隔层,标注着"机身部件"、"电子设备"、"紧固件",组装效率会成倍提升。Ti
recommend-type

Java线程池运行时状态怎么实时掌握?有哪些靠谱的监控手段?

<think>我们之前已经讨论过Java线程池监控的多种方法,包括使用第三方工具和自定义监控。现在用户再次询问Java线程池监控方法,我们需要根据引用内容以及之前讨论的内容进行总结和扩展。 引用[1]提到使用JDK自带的监控工具,引用[2]提到了三种常用的线程池创建方式,引用[3]给出了通过ThreadPoolExecutor获取线程池状态的方法。 结合之前回答的内容,我们可以将监控方法分为以下几类: 1. 使用JDK自带工具(如jconsole, jvisualvm)进行监控。 2. 通过编程方式获取线程池状态(如引用[3]所示)。 3. 扩展ThreadPoolExecutor,
recommend-type

桌面工具软件项目效益评估及市场预测分析

资源摘要信息:"桌面工具软件项目效益评估报告" 1. 市场预测 在进行桌面工具软件项目的效益评估时,首先需要对市场进行深入的预测和分析,以便掌握项目在市场上的潜在表现和风险。报告中提到了两部分市场预测的内容: (一) 行业发展概况 行业发展概况涉及对当前桌面工具软件市场的整体评价,包括市场规模、市场增长率、主要技术发展趋势、用户偏好变化、行业标准与规范、主要竞争者等关键信息的分析。通过这些信息,我们可以评估该软件项目是否符合行业发展趋势,以及是否能满足市场需求。 (二) 影响行业发展主要因素 了解影响行业发展的主要因素可以帮助项目团队识别市场机会与风险。这些因素可能包括宏观经济环境、技术进步、法律法规变动、行业监管政策、用户需求变化、替代产品的发展、以及竞争环境的变化等。对这些因素的细致分析对于制定有效的项目策略至关重要。 2. 桌面工具软件项目概论 在进行效益评估时,项目概论部分提供了对整个软件项目的基本信息,这是评估项目可行性和预期效益的基础。 (一) 桌面工具软件项目名称及投资人 明确项目名称是评估效益的第一步,它有助于区分市场上的其他类似产品和服务。同时,了解投资人的信息能够帮助我们评估项目的资金支持力度、投资人的经验与行业影响力,这些因素都能间接影响项目的成功率。 (二) 编制原则 编制原则描述了报告所遵循的基本原则,可能包括客观性、公正性、数据的准确性和分析的深度。这些原则保证了报告的有效性和可信度,同时也为项目团队提供了评估标准。基于这些原则,项目团队可以确保评估报告的每个部分都建立在可靠的数据和深入分析的基础上。 报告的其他部分可能还包括桌面工具软件的具体功能分析、技术架构描述、市场定位、用户群体分析、商业模式、项目预算与财务预测、风险分析、以及项目进度规划等内容。这些内容的分析对于评估项目的整体效益和潜在回报至关重要。 通过对以上内容的深入分析,项目负责人和投资者可以更好地理解项目的市场前景、技术可行性、财务潜力和潜在风险。最终,这些分析结果将为决策提供重要依据,帮助项目团队和投资者进行科学合理的决策,以期达到良好的项目效益。
recommend-type

告别遮挡!UniApp中WebView与原生导航栏的和谐共处方案(附完整可运行代码)

# UniApp中WebView与原生导航栏的深度协同方案 在混合应用开发领域,WebView与原生组件的和谐共处一直是开发者面临的经典挑战。当H5的灵活遇上原生的稳定,如何在UniApp框架下实现两者的无缝衔接?这不仅关乎视觉体验的统一,更影响着用户交互的流畅度。让我们从架构层面剖析这个问题,探索一套系统性的解决方案。 ## 1. 理解UniApp页面层级结构 任何有效的布局解决方案都必须建立在对框架底层结构的清晰认知上。UniApp的页面渲染并非简单的"HTML+CSS"模式,而是通过原生容器与WebView的协同工作实现的复合体系。 典型的UniApp页面包含以下几个关键层级:
recommend-type

OSPF是怎么在企业网里自动找最优路径并分区域管理的?

### OSPF 协议概述 开放最短路径优先 (Open Shortest Path First, OSPF) 是一种内部网关协议 (IGP),用于在单一自治系统 (AS) 内部路由数据包。它基于链路状态算法,能够动态计算最佳路径并适应网络拓扑的变化[^1]。 OSPF 的主要特点包括支持可变长度子网掩码 (VLSM) 和无类域间路由 (CIDR),以及通过区域划分来减少路由器内存占用和 CPU 使用率。这些特性使得 OSPF 成为大型企业网络的理想选择[^2]。 ### OSPF 配置示例 以下是 Cisco 路由器上配置基本 OSPF 的示例: ```cisco-ios rout
recommend-type

UML建模课程设计:图书馆管理系统论文

资源摘要信息:"本文档是一份关于UML课程设计图书管理系统大学毕设论文的说明书和任务书。文档中明确了课程设计的任务书、可选课题、课程设计要求等关键信息。" 知识点一:课程设计任务书的重要性和结构 课程设计任务书是指导学生进行课程设计的文件,通常包括设计课题、时间安排、指导教师信息、课题要求等。本次课程设计的任务书详细列出了起讫时间、院系、班级、指导教师、系主任等信息,确保学生在进行UML建模课程设计时有明确的指导和支持。 知识点二:课程设计课题的选择和确定 文档中提供了多个可选课题,包括档案管理系统、学籍管理系统、图书管理系统等的UML建模。这些课题覆盖了常见的信息系统领域,学生可以根据自己的兴趣或未来职业规划来选择适合的课题。同时,也鼓励学生自选题目,但前提是该题目必须得到指导老师的认可。 知识点三:课程设计的具体要求 文档中的课程设计要求明确了学生在完成课程设计时需要达到的目标,具体包括: 1. 绘制系统的完整用例图,用例图是理解系统功能和用户交互的基础,它展示系统的功能需求。 2. 对于负责模块的用例,需要提供详细的事件流描述。事件流描述帮助理解用例的具体实现步骤,包括主事件流和备选事件流。 3. 基于用例的事件流描述,识别候选的实体类,并确定类之间的关系,绘制出正确的类图。类图是面向对象设计中的核心,它展示了系统中的数据结构。 4. 绘制用例的顺序图,顺序图侧重于展示对象之间交互的时间顺序,有助于理解系统的行为。 知识点四:UML(统一建模语言)的重要性 UML是软件工程中用于描述、可视化和文档化软件系统各种组件的设计语言。它包含了一系列图表,这些图表能够帮助开发者和设计者理解系统的设计,实现有效的通信。在课程设计中使用UML建模,不仅帮助学生更好地理解系统设计的各个方面,而且是软件开发实践中常用的技术。 知识点五:UML图表类型及其应用 在UML建模中,常用的图表包括: - 用例图(Use Case Diagram):展示系统的功能需求,即系统能够做什么。 - 类图(Class Diagram):展示系统中的类以及类之间的关系,包括继承、关联、依赖等。 - 顺序图(Sequence Diagram):展示对象之间随时间变化的交互过程。 - 状态图(State Diagram):展示一个对象在其生命周期内可能经历的状态。 - 活动图(Activity Diagram):展示业务流程和工作流中的活动以及活动之间的转移。 - 组件图(Component Diagram)和部署图(Deployment Diagram):分别展示系统的物理构成和硬件配置。 知识点六:面向对象设计的核心概念 面向对象设计(Object-Oriented Design, OOD)是软件设计的一种方法学,它强调使用对象来代表数据和功能。核心概念包括: - 抽象:抽取事物的本质特征,忽略非本质的细节。 - 封装:隐藏对象的内部状态和实现细节,只通过公共接口暴露功能。 - 继承:子类继承父类的属性和方法,形成层次结构。 - 多态:允许使用父类类型的引用指向子类的对象,并能调用子类的方法。 知识点七:图书管理系统的业务逻辑和功能需求 虽然文档中没有具体描述图书管理系统的功能需求,但通常这类系统应包括如下功能模块: - 用户管理:包括用户的注册、登录、权限分配等。 - 图书管理:涵盖图书的入库、借阅、归还、查询等功能。 - 借阅管理:记录借阅信息,跟踪借阅状态,处理逾期罚金等。 - 系统管理:包括数据备份、恢复、日志记录等维护性功能。 通过以上知识点的提取和总结,学生能够对UML课程设计有一个全面的认识,并能根据图书管理系统课题的具体要求,进行合理的系统设计和实现。