Transformer架构详细解读(教程向)

news2026/4/3 1:36:51
说明本文内容多来自尚硅谷自然语言处理课程讲义图文并茂有图有公式内容质量很高在此表示感谢一、问题背景在大模型奠基之作Transformer出来之前传统的序列建模都是以RNNLSTM和GRU网络为主。这些网络虽然在一定程度上解决了自然语义序列信息建模困难的问题但是其局限性也十分明显每一个时间步的输出完全依赖于上一个时间步的隐藏状态这导致了这些网络无法对于长序列进行建模如果输入序列过长在隐藏状态的层层传递中最早的一个隐藏状态信息就可能丢失。尽管LSTM网络引入了遗忘门这一模块但是也无法彻底解决该问题此外RNN结构中梯度消失和梯度爆炸问题也十分棘手。Transformer架构的诞生从根本上完全摒弃了循环神经网路建模的思路使用Attention机制直接进行序列建模并通过一系列细节处理让模型近乎完美成为当下大模型的基石。二、模型整体结构模型整体上采取了编码器-解码器架构每个结构内采取Attention机制完整建模整个序列从而使模型有了并行处理序列的能力。整体模型架构如下编码器由两个子层组成分别是多头注意力子层和前馈神经网络子层FFN层解码器由三个子层组成分别是掩码mask自注意力子层、编码器解码器注意力子层和前馈神经网络子层FFN。编码器和解码器各N原始论文中6次堆叠形成整个架构。三、编码器详解3.1 多头自注意力子层自注意力机制Self-Attention是 Transformer 编码器的核心结构之一它的作用是在序列内部建立各位置之间的依赖关系使模型能够为每个位置生成融合全局信息的表示。之所以被称为“自”注意力是因为模型在计算每个位置的表示时所参考的信息全部来自同一个输入序列本身而不是来自另一个序列。3.1.1 自注意力计算过程自注意力机制的第一步是将输入序列中的每个位置表示映射为三个不同的向量分别是查询Query、键Key和值Value。这些向量的作用如下Query表示当前词的用于发起注意力匹配的向量Key表示序列中每个位置的内容标识用于与 Query 进行匹配Value表示该位置携带的信息用于加权汇总得到新的表示。自注意力的核心思想是每个位置用自身的 Query 向量与整个序列中所有位置的 Key 向量进行相关性计算从而得到注意力权重并据此对对应的 Value 向量加权汇总形成新的表示。其中Wq,Wk,Wv均为可学习的参数矩阵。完成 Query、Key、Value 向量的生成后模型会使用每个位置的 Query 向量与所有位置的 Key 向量进行相关性评分。具体计算公式如下其中dk是key向量的维度用于缩放点积的幅度。这个分数越大表示第 i 个位置越应该关注第 j 个位置的信息。对于整个序列可以通过矩阵运算一次性计算乘K矩阵转置即可所有位置之间的评分。在得到每个位置与所有位置之间的相关性评分后模型会使用 softmax 函数进行归一化确保每个位置对所有位置的关注程度之和为 1从而形成一个有效的加权分布。这里需要注意的是对于整个序列模型要做的是对之前得到的注意力评分矩阵的每一行进行softmax归一化。最后模型会根据注意力权重对所有位置的 Value 向量进行加权求和得到每个位置融合全局信息后的新表示。3.1.2 多头自注意力计算既然有了自注意力为什么又要弄一个多头自注意力这是因为自然语义中具有高度的复杂性例如“那只动物没有过马路因为它太累了”这一句话中包含了很多的逻辑关系“它”指代“那只动物”属于跨句的代指关系“因为”连接前后两个分句体现语义上的因果逻辑“过马路”构成动词短语属于固定的动宾结构。如果仅仅依靠Q,K,V向量计算序列中的上下文信息这是不够的要准确理解这类句子模型需要同时识别并建模多种层次和类型的依赖关系。但这些信息很难通过单一视角或一套注意力机制完整捕捉。为此Transformer 引入了多头注意力机制Multi-Head Attention。其核心思想是通过多组独立的 Query、Key、Value 投影让不同注意力头分别专注于不同的语义关系最后将各头的输出拼接融合。分别计算出各个头的自注意力然后使用cat多个输出矩阵按维度拼接再乘以Wo得到最终多头注意力的输出。3.2 前馈神经网络子层前馈神经网络Feed-Forward Network简称 FFN是 Transformer 编码器中每个子层的重要组成部分紧接在多头注意力子层之后。它通过对每个位置的表示进行逐位置、非线性的特征变换进一步提升模型对复杂语义的建模能力。一个标准的 FFN 子层包含两个线性变换和一个非线性激活函数中间通常使用 ReLU激活。其计算公式如下3.3 残差和归一化连接在 Transformer 的每个编码器层中每个子层包括自注意力子层和前馈神经网络子层其输出都要经过残差连接Residual Connection和层归一化Layer Normalization处理。这两者是深层神经网络中常用的结构用于缓解模型训练中的梯度消失、收敛困难等问题对于Transformer能够堆叠多层至关重要。残差连接大家比较熟悉就不多做介绍了。每个子层在残差连接之后都会进行层归一化Layer Normalization简称 LayerNorm。它的主要作用是规范输入序列中每个token的特征分布某个token的表示可能在不同维度上有较大数值差异提升模型训练的稳定性。该操作会将每个token的向量调整为均值为 0、方差为 1 的规范分布计算公式如下首先计算该向量在所有特征维度上的平均值然后计算向量各维度的标准差然后将每个特征值转换为均值为 0、方差为 1 的标准正态分布最后进行缩放和平移让模型可以学习在归一化后的基础上进行适当的调整保证归一化不会限制模型的表示能力四、位置编码Transformer 模型完全摒弃了 RNN 结构意味着它不再按顺序处理序列而是可以并行处理所有位置的信息。尽管这带来了显著的计算效率提升却也引发了一个问题Transformer 无法像 RNN 那样天然地捕捉词语之间的顺序关系。换句话说在没有额外机制的情况下Transformer 无法区分“猫吃鱼”和“鱼吃猫”这类语序不同但词汇相同的句子。为了解决这一问题Transformer 引入了一个关键机制——位置编码Positional Encoding。该机制为每个词引入一个表示其位置信息的向量并将其与对应的词向量相加作为模型输入的一部分。这样一来模型在处理每个词时既能获取词义信息也能感知其在句子中的位置从而具备对基本语序的理解能力。我们最容易想到的位置编码方法就是绝对位置编码使用绝对位置编号来表示每个词的位置例如第一个词用 0第二个词用 1依此类推...但是这样会造成严重的问题越靠后的 token 位置编码就越大若直接与词向量相加会造成数值倾斜让模型更关注位置而忽视词义。为缓解这一问题可以考虑将位置编号归一化为[0, 1]区间例如用pos/T表示位置其中T是句子长度。这种方式虽然使数值范围更平稳但也引入了一个严重的问题相同位置的词在不同长度句子中的位置编码不再一致。为了解决上述问题Transformer 使用了一种基于正弦sin和余弦cos函数的位置编码方式具体定义如下pos是当前词在序列中的位置i用于表示位置编码向量的维度索引2i表示偶数维2i1表示奇数维dmodel是词向量的维度大小。序列中的每个位置 pos 对应一个长度为dmodel的位置编码向量。该向量的偶数维度通过正弦函数生成奇数维度通过余弦函数生成如下图所示Transformer提出的这种编码方式不依赖任何可学习参数数值稳定并具备以下优势所有值都在[−1,1]范围内数值稳定编码方式固定、可预计算无需训练相同位置的编码在不同句子中保持一致编码之间具有数学规律便于模型在注意力机制中感知词语之间的相对位置关系。基于此当下大模型对于位置编码做了不同程度的改进最流行就是旋转位置编码RoPE。五、解码器详解Transformer 解码器的主要功能是根据编码器的输出逐步生成目标序列中的每一个词。其生成方式采用自回归机制autoregressive每一步的输入由此前已生成的所有词组成模型将输出一个与当前输入长度相同的序列表示。我们只取最后一个位置的输出作为当前步的预测结果。这一过程会不断重复直到生成特殊的结束标记 eos表示序列生成完成。5.1 掩码自注意力子层主要用于建模当前位置与前文词之间的依赖关系。为了在训练时模拟逐词生成的过程引入遮盖机制Mask限制每个位置只能关注它前面的词。由于 Transformer 不具备像 RNN 那样的隐藏状态传递机制无法在序列生成过程中保留上下文信息因此在生成每一个词时必须将此前已生成的所有词作为输入通过自注意力机制重新建模上下文关系以预测下一个词。此外从结构上看Transformer 编解码器都具有一个典型特性输入多少个词就输出多少个表示。需要注意的是在推理阶段我们只使用解码器最后一个位置的输出作为当前步的预测结果如果训练阶段也完全按照推理流程进行就必须将每个目标序列拆分成多个训练样本每个样本输入一段前文只预测一个词。这种方式虽然逻辑合理但训练效率极低完全无法利用 Transformer 并行计算的优势。为提升效率Transformer 采用了并行训练策略一次性输入完整目标序列同时预测每个位置的词。如下图所示但如果不加限制这种方式会让模型在预测每个位置时“看到”后面的词即提前访问未来信息破坏生成任务的因果结构。为解决这个问题解码器在自注意力机制中引入了遮盖机制Mask。该机制会在计算注意力时阻止模型访问当前位置之后的词只允许它依赖自身及前文的信息。这样即使在并行训练时模型也只能像逐词生成一样“看见”它应该看到的内容从而保持训练与推理阶段的一致性。如下图所示Mask 机制的实现非常简单只需将注意力得分矩阵中当前位置对其后续位置的评分设置为−∞如下图所示这样一来前面词与后文信息的注意力信息就会被负无穷遮住在经过 softmax 运算后这些位置的权重会趋近于 0。最终在加权求和时来自未来位置的信息几乎不会参与计算从而实现了“当前词只能看到它前面的词”的约束。十分巧妙5.2 编码器-解码器注意力子层该子层的主要作用是建模当前解码位置与源语言序列中各位置之间的依赖关系帮助模型在生成目标词时有效地参考输入内容相当于Seq2Seq模型中的注意力机制。编码器-解码器注意力的核心机制与前面讲过的自注意力机制完全一致区别仅在于Query 来自解码器当前的输入表示即当前生成状态Key和Value 来自编码器的输出表示即整个源序列的上下文。也就是说当前生成位置使用自己的Query去“询问”编码器输出中的哪些位置最相关。注意力机制会根据 Query 与所有 Key 的相似度为每个源位置分配一个权重然后用这些权重对 Value 进行加权求和得到当前生成词所需的上下文信息。这里Q,K,V不同源也就不是“自”注意力了。六、模型训练与推理Transformer 的训练与推理都基于自回归生成机制Autoregressive Generation模型逐步生成目标序列中的每一个词。然而在实现方式上训练与推理存在明显区别。6.1 模型训练训练时Transformer 将目标序列整体输入解码器并在每个位置同时进行预测。为防止模型“看到”后面的词破坏因果顺序解码器在自注意力机子层中引入了 遮盖机制Mask限制每个位置只能关注它前面的词。这种机制让模型在结构上模拟逐词生成但在实现上能充分利用并行计算大幅提升训练效率。6.2 模型推理推理时每一步都要重新输入整个已生成序列模型需要基于全量前文重新计算注意力分布决定下一个词的输出。整个过程必须顺序执行无法并行。推理阶段模型每一步都要重新输入当前已生成的全部词通过自注意力机制建模上下文关系预测下一个词。模型会基于完整前文重新计算注意力分布生成当前步的输出。由于每一步的输入依赖前一步结果整个过程必须顺序执行无法并行。每步输出的是一个词的概率分布最终生成结果也可使用不同的解码策略如贪心搜索、束搜索等。七、代码实现哈佛版本链接https://nlp.seas.harvard.edu/annotated-transformer/哈佛大学团队基于Pytorch实现了Transformer结构的完整代码为开源社区与学术研究做出了贡献。1、导入包import os from os.path import exists import torch import torch.nn as nn from torch.nn.functional import log_softmax, pad import math import copy import time from torch.optim.lr_scheduler import LambdaLR import pandas as pd import altair as alt from torchtext.data.functional import to_map_style_dataset from torch.utils.data import DataLoader from torchtext.vocab import build_vocab_from_iterator import torchtext.datasets as datasets import spacy import GPUtil import warnings from torch.utils.data.distributed import DistributedSampler import torch.distributed as dist import torch.multiprocessing as mp from torch.nn.parallel import DistributedDataParallel as DDP2、注意力计算def attention(query, key, value, maskNone, dropoutNone): Compute Scaled Dot Product Attention d_k query.size(-1) scores torch.matmul(query, key.transpose(-2, -1)) / math.sqrt(d_k) if mask is not None: scores scores.masked_fill(mask 0, -1e9) p_attn scores.softmax(dim-1) if dropout is not None: p_attn dropout(p_attn) return torch.matmul(p_attn, value), p_attnd_k取Q矩阵的最后一个维度也就是词向量维度一般来说是512。这里softmax是对最后一个维度做也就是前面提到的对每一行做归一化。3、多头注意力计算class MultiHeadedAttention(nn.Module): def __init__(self, h, d_model, dropout0.1): Take in model size and number of heads. super(MultiHeadedAttention, self).__init__() assert d_model % h 0 # We assume d_v always equals d_k self.d_k d_model // h self.h h self.linears clones(nn.Linear(d_model, d_model), 4) self.attn None self.dropout nn.Dropout(pdropout) def forward(self, query, key, value, maskNone): Implements Figure 2 if mask is not None: # Same mask applied to all h heads. mask mask.unsqueeze(1) nbatches query.size(0) # 1) Do all the linear projections in batch from d_model h x d_k query, key, value [ lin(x).view(nbatches, -1, self.h, self.d_k).transpose(1, 2) for lin, x in zip(self.linears, (query, key, value)) ] # 2) Apply attention on all the projected vectors in batch. x, self.attn attention( query, key, value, maskmask, dropoutself.dropout ) # 3) Concat using a view and apply a final linear. x ( x.transpose(1, 2) .contiguous() .view(nbatches, -1, self.h * self.d_k) ) del query del key del value return self.linears[-1](x)头数h为8要求d_model%h0将 512 维拆分为 8 个 64 维的头Q,K,V矩阵形状为[batch_size,seq_len,d_model]view操作后变成[batch_size,seq_len,h,d_k]→transpose(1,2)后[batch_size,h,seq_len,d_k]。这里cat拼接使用的是view先transpose(1,2)回到[batch, seq_len, h, d_k]再view拼接为[batch, seq_len, d_model]。contiguous()的作用是PyTorch 中 transpose 后内存不连续需用该函数确保 view 正常执行。4、前馈神经网络class PositionwiseFeedForward(nn.Module): Implements FFN equation. def __init__(self, d_model, d_ff, dropout0.1): super(PositionwiseFeedForward, self).__init__() self.w_1 nn.Linear(d_model, d_ff) self.w_2 nn.Linear(d_ff, d_model) self.dropout nn.Dropout(dropout) def forward(self, x): return self.w_2(self.dropout(self.w_1(x).relu()))5、位置编码首先是词向量嵌入Embeddingclass Embeddings(nn.Module): def __init__(self, d_model, vocab): super(Embeddings, self).__init__() self.lut nn.Embedding(vocab, d_model) self.d_model d_model def forward(self, x): return self.lut(x) * math.sqrt(self.d_model)然后是位置编码class PositionalEncoding(nn.Module): Implement the PE function. def __init__(self, d_model, dropout, max_len5000): super(PositionalEncoding, self).__init__() self.dropout nn.Dropout(pdropout) # Compute the positional encodings once in log space. pe torch.zeros(max_len, d_model) position torch.arange(0, max_len).unsqueeze(1) div_term torch.exp( torch.arange(0, d_model, 2) * -(math.log(10000.0) / d_model) ) pe[:, 0::2] torch.sin(position * div_term) pe[:, 1::2] torch.cos(position * div_term) pe pe.unsqueeze(0) self.register_buffer(pe, pe) def forward(self, x): x x self.pe[:, : x.size(1)].requires_grad_(False) return self.dropout(x)max_len5000预计算最多 5000 个位置的编码覆盖大部分序列长度register_buffer(pe, pe)将 pe 注册为 “缓冲区”不会被优化器更新位置编码是固定的不训练requires_grad_(False)明确禁用梯度计算节省内存前向传播词嵌入x 位置编码pe再经过 Dropout。6、掩码def subsequent_mask(size): Mask out subsequent positions. attn_shape (1, size, size) subsequent_mask torch.triu(torch.ones(attn_shape), diagonal1).type( torch.uint8 ) return subsequent_mask 0输入形状[1, seq_len, seq_len]torch.triu构造上三角矩阵diagonal1表示对角线以上为1最后返回转换为布尔掩码True1表示可见False0表示屏蔽。7、架构层编码器class Encoder(nn.Module): Core encoder is a stack of N layers def __init__(self, layer, N): super(Encoder, self).__init__() self.layers clones(layer, N) self.norm LayerNorm(layer.size) def forward(self, x, mask): Pass the input (and mask) through each layer in turn. for layer in self.layers: x layer(x, mask) return self.norm(x)class EncoderLayer(nn.Module): Encoder is made up of self-attn and feed forward (defined below) def __init__(self, size, self_attn, feed_forward, dropout): super(EncoderLayer, self).__init__() self.self_attn self_attn self.feed_forward feed_forward self.sublayer clones(SublayerConnection(size, dropout), 2) self.size size def forward(self, x, mask): Follow Figure 1 (left) for connections. x self.sublayer[0](x, lambda x: self.self_attn(x, x, x, mask)) return self.sublayer[1](x, self.feed_forward)layer单个 EncoderLayer 实例N堆叠层数论文中 N6所有层共享同一个掩码src_mask用于屏蔽 padding token最终输出前做层归一化进一步稳定输出分布lambda x: self.self_attn(x,x,x,mask)将自注意力层封装为 “单参数函数”适配 SublayerConnection 的sublayer参数要求。解码器class Decoder(nn.Module): Generic N layer decoder with masking. def __init__(self, layer, N): super(Decoder, self).__init__() self.layers clones(layer, N) self.norm LayerNorm(layer.size) def forward(self, x, memory, src_mask, tgt_mask): for layer in self.layers: x layer(x, memory, src_mask, tgt_mask) return self.norm(x)class DecoderLayer(nn.Module): Decoder is made of self-attn, src-attn, and feed forward (defined below) def __init__(self, size, self_attn, src_attn, feed_forward, dropout): super(DecoderLayer, self).__init__() self.size size self.self_attn self_attn self.src_attn src_attn self.feed_forward feed_forward self.sublayer clones(SublayerConnection(size, dropout), 3) def forward(self, x, memory, src_mask, tgt_mask): Follow Figure 1 (right) for connections. m memory x self.sublayer[0](x, lambda x: self.self_attn(x, x, x, tgt_mask)) x self.sublayer[1](x, lambda x: self.src_attn(x, m, m, src_mask)) return self.sublayer[2](x, self.feed_forward)memory编码器的输出源序列的编码结果src_mask源序列的掩码屏蔽 paddingtgt_mask目标序列的掩码屏蔽 padding 未来 token。编码器-解码器结构class EncoderDecoder(nn.Module): 标准的编码器-解码器架构是Transformer的基础 def __init__(self, encoder, decoder, src_embed, tgt_embed, generator): super(EncoderDecoder, self).__init__() self.encoder encoder # 编码器实例 self.decoder decoder # 解码器实例 self.src_embed src_embed # 源序列嵌入层词嵌入位置编码 self.tgt_embed tgt_embed # 目标序列嵌入层 self.generator generator # 输出层线性softmax def forward(self, src, tgt, src_mask, tgt_mask): 接收并处理经过掩码的源序列和目标序列 return self.decode(self.encode(src, src_mask), src_mask, tgt, tgt_mask) def encode(self, src, src_mask): # 编码源序列嵌入 编码器前向传播 return self.encoder(self.src_embed(src), src_mask) def decode(self, memory, src_mask, tgt, tgt_mask): # 解码目标序列嵌入 解码器前向传播依赖编码器输出memory return self.decoder(self.tgt_embed(tgt), memory, src_mask, tgt_mask)初始化参数encoder/decoder编码器 / 解码器的核心实例src_embed/tgt_embed源 / 目标序列的嵌入层词嵌入 位置编码generator最终输出层将解码器输出映射到目标词汇表。forward逻辑先通过encode得到源序列的编码结果memory再通过decode将memory和目标序列结合输出解码器结果src_mask/tgt_mask掩码屏蔽 padding / 未来 token。层归一化class LayerNorm(nn.Module): Construct a layernorm module (See citation for details). def __init__(self, features, eps1e-6): super(LayerNorm, self).__init__() self.a_2 nn.Parameter(torch.ones(features)) self.b_2 nn.Parameter(torch.zeros(features)) self.eps eps def forward(self, x): mean x.mean(-1, keepdimTrue) std x.std(-1, keepdimTrue) return self.a_2 * (x - mean) / (std self.eps) self.b_2残差连接class SublayerConnection(nn.Module): A residual connection followed by a layer norm. Note for code simplicity the norm is first as opposed to last. def __init__(self, size, dropout): super(SublayerConnection, self).__init__() self.norm LayerNorm(size) self.dropout nn.Dropout(dropout) def forward(self, x, sublayer): Apply residual connection to any sublayer with the same size. return x self.dropout(sublayer(self.norm(x)))8、一些工具函数克隆N层def clones(module, N): Produce N identical layers. return nn.ModuleList([copy.deepcopy(module) for _ in range(N)])class Generator(nn.Module): Define standard linear softmax generation step. def __init__(self, d_model, vocab): super(Generator, self).__init__() self.proj nn.Linear(d_model, vocab) def forward(self, x): return log_softmax(self.proj(x), dim-1)9、搭建模型def make_model( src_vocab, tgt_vocab, N6, d_model512, d_ff2048, h8, dropout0.1 ): Helper: Construct a model from hyperparameters. c copy.deepcopy attn MultiHeadedAttention(h, d_model) ff PositionwiseFeedForward(d_model, d_ff, dropout) position PositionalEncoding(d_model, dropout) model EncoderDecoder( Encoder(EncoderLayer(d_model, c(attn), c(ff), dropout), N), Decoder(DecoderLayer(d_model, c(attn), c(attn), c(ff), dropout), N), nn.Sequential(Embeddings(d_model, src_vocab), c(position)), nn.Sequential(Embeddings(d_model, tgt_vocab), c(position)), Generator(d_model, tgt_vocab), ) # This was important from their code. # Initialize parameters with Glorot / fan_avg. for p in model.parameters(): if p.dim() 1: nn.init.xavier_uniform_(p) return modelcopy.deepcopy每个层 / 组件都深拷贝确保参数独立比如编码器和解码器的注意力层不共享参数参数初始化xavier_uniform_Glorot 初始化适用于线性层使输入 / 输出的方差一致缓解梯度消失。

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

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

相关文章

SpringBoot-17-MyBatis动态SQL标签之常用标签

文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…

wordpress后台更新后 前端没变化的解决方法

使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…

网络编程(Modbus进阶)

思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…

UE5 学习系列(二)用户操作界面及介绍

这篇博客是 UE5 学习系列博客的第二篇,在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下: 【Note】:如果你已经完成安装等操作,可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作,重…

IDEA运行Tomcat出现乱码问题解决汇总

最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…

利用最小二乘法找圆心和半径

#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式

一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明&#xff1a;假设每台服务器已…

XML Group端口详解

在XML数据映射过程中&#xff0c;经常需要对数据进行分组聚合操作。例如&#xff0c;当处理包含多个物料明细的XML文件时&#xff0c;可能需要将相同物料号的明细归为一组&#xff0c;或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码&#xff0c;增加了开…

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造&#xff0c;完美适配AGV和无人叉车。同时&#xff0c;集成以太网与语音合成技术&#xff0c;为各类高级系统&#xff08;如MES、调度系统、库位管理、立库等&#xff09;提供高效便捷的语音交互体验。 L…

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型

摘要 拍照搜题系统采用“三层管道&#xff08;多模态 OCR → 语义检索 → 答案渲染&#xff09;、两级检索&#xff08;倒排 BM25 向量 HNSW&#xff09;并以大语言模型兜底”的整体框架&#xff1a; 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后&#xff0c;分别用…

【Axure高保真原型】引导弹窗

今天和大家中分享引导弹窗的原型模板&#xff0c;载入页面后&#xff0c;会显示引导弹窗&#xff0c;适用于引导用户使用页面&#xff0c;点击完成后&#xff0c;会显示下一个引导弹窗&#xff0c;直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…

接口测试中缓存处理策略

在接口测试中&#xff0c;缓存处理策略是一个关键环节&#xff0c;直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性&#xff0c;避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明&#xff1a; 一、缓存处理的核…

龙虎榜——20250610

上证指数放量收阴线&#xff0c;个股多数下跌&#xff0c;盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型&#xff0c;指数短线有调整的需求&#xff0c;大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的&#xff1a;御银股份、雄帝科技 驱动…

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析

1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具&#xff0c;该工具基于TUN接口实现其功能&#xff0c;利用反向TCP/TLS连接建立一条隐蔽的通信信道&#xff0c;支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式&#xff0c;适应复杂网…

铭豹扩展坞 USB转网口 突然无法识别解决方法

当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?

编辑&#xff1a;陈萍萍的公主一点人工一点智能 未来机器人的大脑&#xff1a;如何用神经网络模拟器实现更智能的决策&#xff1f;RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战&#xff0c;在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…

Linux应用开发之网络套接字编程(实例篇)

服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …

华为云AI开发平台ModelArts

华为云ModelArts&#xff1a;重塑AI开发流程的“智能引擎”与“创新加速器”&#xff01; 在人工智能浪潮席卷全球的2025年&#xff0c;企业拥抱AI的意愿空前高涨&#xff0c;但技术门槛高、流程复杂、资源投入巨大的现实&#xff0c;却让许多创新构想止步于实验室。数据科学家…

深度学习在微纳光子学中的应用

深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向&#xff1a; 逆向设计 通过神经网络快速预测微纳结构的光学响应&#xff0c;替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…