入门pytorch-Transformer
前言
虽然Transformer是2017年由Google推出,如果按照读论文只读近两年的思路看,那它无疑是过时的,但可惜的是,目前很多论文的核心依然是Transformer,或者由其进行改进的,故本文使用pytorch来搭建一下Transformer这个模型
全局分析
首先,我们要从整个模型架构入手,从大的层面看这块内容,然后再开始编写代码。欧克,这里默认大家掌握了一些基础知识,Transformer是由Google于2017年的Attention Is All You Need论文上所提出来的。如下图,则是论文中所提出的整个框架,可以很清晰的看出具体所使用的组件

总的来看,两个模块,编码器、解码器,特别有自编码器的思想(换句话说,Transformer借鉴了seq2sqe,而seq2sqe天然就是自编码器的思想),下面引用了论文当中的话.
-
Encoder: 编码器由 N = 6 N = 6 N=6 个相同层的堆叠组成。每一层有两个子层。第一个是多头自注意机制,第二个是一个简单的,位置全连接前馈网络。我们在两个子层中的每一个周围使用残差连接,随后进行层归一化。也就是说,每个子层的输出是 L a y e r N o r m ( x + S u b l a y e r ( x ) ) LayerNorm(x + Sublayer(x)) LayerNorm(x+Sublayer(x)),其中 S u b l a y e r ( x ) Sublayer(x) Sublayer(x) 是由子层本身实现的函数。为了促进这些剩余连接,模型中的所有子层以及嵌入层产生维度 d m o d e l = 512 d_{model} = 512 dmodel=512 的输出。
-
Decoder: 解码器也由 N = 6 N = 6 N=6 个相同层的堆栈组成。除了每个编码器层中的两个子层之外,解码器还插入第三子层,该第三子层对编码器堆栈的输出执行多头注意。与编码器类似,我们在每个子层周围使用残差连接,然后进行层归一化。我们还修改了解码器堆栈中的自注意子层,以防止位置注意到后续位置。该掩蔽与输出嵌入偏移一个位置的事实相结合,确保了位置i的预测可以仅依赖于小于 i i i 的位置处的已知输出。
好了,我们了解了整个大的框架,开始接触小的组件,由上图,我们可以进行拆分,其整个框架是由嵌入层、位置编码层、(掩码)多头注意力层、前馈神经网络层、残差连接+归一化层;接下来我们分别实现这些神经网络块(层),并将其堆叠在一起,其实就是Transformer了。
好了,接下来我们就开始编写代码吧
位置编码层
下面的就是位置编码。在这里打个比方,就比如机器翻译问题上,我们需要将一句话翻译成另一句话,即A --> B,那么A和B必然是长度随机的编码,这里输入的就是(想要翻译几句话,几个单词,每个单词的特征编码)
P E ( p o s , 2 i ) = s i n ( p o s / 1000 0 2 i / d m o d e l ) PE_{(pos,2i)} = sin(pos/10000^{2i/d_{model}}) PE(pos,2i)=sin(pos/100002i/dmodel)
P E ( p o s , 2 i + 1 ) = c o s ( p o s / 1000 0 2 i / d m o d e l ) PE_{(pos,2i+1)} = cos(pos/10000^{2i/d_{model}}) PE(pos,2i+1)=cos(pos/100002i/dmodel)
# 位置编码
class PositionalEncoding(nn.Module):'''num_hiddens: 神经元数量(嵌入维度数量)dropout: 神经元的丢弃概率max_len: 序列最大长度'''def __init__(self, num_hiddens, dropout, max_len=1000):super(PositionalEncoding, self).__init__()self.dropout = nn.Dropout(dropout)self.P = torch.zeros((1, max_len, num_hiddens))# 等差数列X = (torch.arange(max_len, dtype=torch.float32).reshape(-1, 1)/ torch.pow(10000, torch.arange(0, num_hiddens, 2, dtype=torch.float32) / num_hiddens))self.P[:, :, 0::2] = torch.sin(X)self.P[:, :, 1::2] = torch.cos(X)def forward(self, X): # X = (批次,序列长度,特征)X = X + self.P[:, :X.shape[1], :].to(X.device)return self.dropout(X)
残差连接+归一化层
欧克,接下来我们先来看一下简单理解的层。残差连接可以理解为防止梯度消失问题,以及加快收敛的一个有效的方法。而归一化就是防止梯度爆炸的问题
# 残差连接 + 归一化层
class AddNorm(nn.Module):'''normalized_shape: 形状大小dropout: 神经元的丢弃概率'''def __init__(self, normalized_shape, dropout):super(AddNorm, self).__init__()self.drop = nn.Dropout(dropout) # 丢弃层self.layer = nn.LayerNorm(normalized_shape) # 对输入的小批量应用层规范化def forward(self, X, Y):return self.layer(self.drop(Y) + X)
前馈神经网络层
这块也比较简单,就是两层的感知机而已。
F F N ( x ) = m a x ( 0 , x W 1 + b 1 ) W 2 + b 2 FFN(x) = max(0, xW_1 + b_1)W_2 + b_2 FFN(x)=max(0,xW1+b1)W2+b2
# 前馈神经网络
class PostionWiseFFN(nn.Module):'''num_input: 输入形状num_hiddens: 隐藏层形状num_ouput: 输出层形状'''def __init__(self, num_input, num_hiddens, num_ouput):super(PostionWiseFFN, self).__init__()self.liner1 = nn.Linear(num_input, num_hiddens) # 线性层1self.relu = nn.ReLU() # 激活函数self.liner2 = nn.Linear(num_hiddens, num_ouput) # 线性层2def forward(self, X):return self.liner2(self.relu(self.liner1(X)))
点积注意力机制

这里给出点积注意力机制的公式
A t t e n t i o n ( Q , K , V ) = s o f t m a x ( Q K T d ) V Attention(Q,K,V) = softmax(\frac{QK^T}{\sqrt{d}})V Attention(Q,K,V)=softmax(dQKT)V
其中Q为查询矩阵,K键矩阵,V值矩阵,它们的维度是 ( n , d k ) (n,d_k) (n,dk), ( m , d k ) (m,d_k) (m,dk), ( m , d v ) (m,d_v) (m,dv),m是键值对的数量, d k d_k dk是键矩阵和查询矩阵的特征维度, d v d_v dv是值矩阵的特征维度。而除于 d \sqrt{d} d是为了避免梯度消失问题
class DotProductAttention(nn.Module):'''dropout: 神经元的丢弃概率'''def __init__(self, dropout):super(DotProductAttention, self).__init__()self.dropout = nn.Dropout(dropout)def sequence_mask(self, X, valid_lens, value=0): # 根据valid_lens生成掩码'''X: (批量, 最大序列长度, 特征)valid_lens: 有效长度value: 填充数据'''maxlen = X.size(1)mask = torch.arange((maxlen), dtype=torch.float32,device=X.device)[None, :] < valid_lens[:, None]X[~mask] = valuereturn Xdef masked_softmax(self, X, valid_lens):if valid_lens is None:return nn.functional.softmax(X, dim=-1)else:shape = X.shapeif valid_lens.dim == 1:valid_lens = valid_lens.repeat_interleave(valid_lens, shape[1])else:valid_lens = valid_lens.reshape(-1)X = self.sequence_mask(X, valid_lens)return nn.functional.softmax(X.reshape(shape), dim=-1)def forward(self, Q, K, V, valid_lens=None):d = Q.shape[-1]scores = torch.bmm(Q, K.transpose(1, 2)) / math.sqrt(d) # 点积获取注意力分数self.attention_weights = self.masked_softmax(scores, valid_lens) # 获取注意力权重return torch.bmm(self.dropout(self.attention_weights), V) # 注意力权重 * 值V
到这里,我们由此便可以提出自注意力机制,而自注意力机制对上面做出了一个很简单的改变,就是 Q = K = V Q = K = V Q=K=V,换句话说Q、K、V同源
多头注意力
所谓多头注意力机制,就是有多个自注意力机制并行,然后将输出进行拼接送到线性层进一步整合
M u l t i H e a d ( Q , K , V ) = C o n c a t ( h e a d 1 , . . . , h e a d h ) W O w h e r e h e a d i = A t t e n t i o n ( Q W i Q , K W i K , V W i V ) MultiHead(Q,K,V) = Concat(head_1,...,head_h)W^O\\ where \ head_i = Attention(QW_i^Q,KW_i^K,VW_i^V) MultiHead(Q,K,V)=Concat(head1,...,headh)WOwhere headi=Attention(QWiQ,KWiK,VWiV)
# 多头注意力
class MultiHeadAttention(nn.Module):'''key_size: K值形状大小query_size: Q值形状大小value_size: V值形状大小num_hiddens: 隐藏层神经元数量num_heads: 头数dropout: 神经元的丢弃概率bias: 是否学习加性偏差,默认不学习'''def __init__(self, key_size, query_size, value_size, num_hiddens,num_heads, dropout, bias=False):super(MultiHeadAttention, self).__init__()assert num_hiddens % num_heads == 0self.num_heads = num_headsself.attention = DotProductAttention(dropout) # 这里使用到了点积注意力机制self.W_q = nn.Linear(query_size, num_hiddens, bias=bias) # Q矩阵权重self.W_k = nn.Linear(key_size, num_hiddens, bias=bias) # K矩阵权重self.W_v = nn.Linear(value_size, num_hiddens, bias=bias) # V矩阵权重self.W_o = nn.Linear(num_heads, num_hiddens, bias=bias) # 输出线性层def forward(self, Q, K, V, valid_lens): # valid_lens 有效长度Q = transpose_qkv(self.W_q(Q), self.num_heads)K = transpose_qkv(self.W_k(K), self.num_heads)V = transpose_qkv(self.W_v(V), self.num_heads)if valid_lens is not None:valid_lens = torch.repeat_interleave(valid_lens, repeats=self.num_heads, dim=0)output = self.attention(Q, K, V, valid_lens)output_concat = transpose_output(output, self.num_heads)return self.W_o(output_concat)
这里我们通过transpose_qkv和transpose_output函数来将数据进行改造,以此来进行并行操作
def transpose_qkv(X, num_heads):"""为了多注意力头的并行计算而变换形状"""# 输入X的形状:(batch_size,查询或者“键-值”对的个数,num_hiddens)# 输出X的形状:(batch_size,查询或者“键-值”对的个数,num_heads,num_hiddens/num_heads)X = X.reshape(X.shape[0], X.shape[1], num_heads, -1)X = X.permute(0, 2, 1, 3)return X.reshape(-1, X.shape[2], X.shape[3])
def transpose_output(X, num_heads):"""逆转transpose_qkv函数的操作"""X = X.reshape(-1, num_heads, X.shape[1], X.shape[2])X = X.permute(0, 2, 1, 3)return X.reshape(X.shape[0], X.shape[1], -1)
编码器
如下则是编码器的代码
class EncoderBlock(nn.Module):'''K_size, Q_size, V_size: 键值对和查询的大小num_hiddens: 中间隐藏层神经元num_heads: 头数norm_shape: 残差连接+归一化层的输入形状num_input: FFN的输入形状ffn_num_hiddens: FFN隐藏层神经元dropout: 神经元的丢弃概率'''def __init__(self, K_size, Q_size, V_size, num_hiddens, num_heads,norm_shape, num_input, ffn_num_hiddens, dropout, bias=False):super(EncoderBlock, self).__init__()self.attention = MultiHeadAttention(K_size, Q_size, V_size, num_hiddens, num_heads, dropout, bias) # 多头注意力机制 self.addnorm1 = AddNorm(norm_shape, dropout) # 归一化+残差连接self.ffn = PostionWiseFFN(num_input, ffn_num_hiddens, num_hiddens) # 前馈神经网络self.addnorm2 = AddNorm(norm_shape, dropout) # 归一化+残差连接def forward(self, X, valid_lens):Y = self.addnorm1(X, self.attention(X, X, X, valid_lens))return self.addnorm2(Y, self.ffn(Y))
接下来我们需要将位置编码层、嵌入层、残差连接+归一化层、前馈神经网络、编码器等封装起来
class TransformerEncoder(nn.Module):'''vocab_size: 词典大小K_size, Q_size, V_size: 键值对和查询的大小num_hiddens: 中间隐藏层神经元num_heads: 头数norm_shape: 残差连接+归一化层的输入形状num_input: FFN的输入形状ffn_num_hiddens: FFN隐藏层神经元num_layers: 编码器的层数dropout: 神经元的丢弃概率'''def __init__(self, vocab_size, K_size, Q_size, V_size, num_hiddens, num_heads,norm_shape, num_input, ffn_num_hiddens, num_layers, dropout, bias=False):super(TransformerEncoder, self).__init__()self.num_hiddens = num_hiddens# num_embeddings: 嵌入词典的大小 embedding_dim: 每个嵌入向量的尺寸self.embedding = nn.Embedding(num_embeddings=vocab_size, embedding_dim=num_hiddens) # 嵌入层self.pos_encoding = PositionalEncoding(num_hiddens, dropout) # 位置编码层self.blks = nn.Sequential()for i in range(num_layers):self.blks.add_module("block" + str(i),EncoderBlock(K_size, Q_size, V_size, num_hiddens, num_heads, norm_shape, num_input, ffn_num_hiddens, dropout, bias))def forward(self, X, valid_lens):# 输入 X (句子个数,单词个数)# 输出 ret (句子个数,单词个数,单词特征)X = self.pos_encoding(self.embedding(X) * math.sqrt(self.num_hiddens))self.attention_weights = [None] * len(self.blks)for i, blk in enumerate(self.blks):X = blk(X, valid_lens)self.attention_weights[i] = blk.attention.attention.attention_weightsreturn X
解码器
class DecodeBlock(nn.Module):'''K_size, Q_size, V_size: 键值对和查询的大小num_hiddens: 中间隐藏层神经元num_heads: 头数norm_shape: 残差连接+归一化层的输入形状num_input: FFN的输入形状ffn_num_hiddens: FFN隐藏层神经元dropout: 神经元的丢弃概率i:'''def __init__(self, K_size, Q_size, V_size, num_hiddens, num_heads,norm_shape, num_input, ffn_num_hiddens, dropout, i):super(DecodeBlock, self).__init__()self.i = iself.attention1 = MultiHeadAttention(K_size, Q_size, V_size, num_hiddens, num_heads, dropout) # 多头注意力机制self.addnorm1 = AddNorm(norm_shape, dropout)self.attention2 = MultiHeadAttention(K_size, Q_size, V_size, num_hiddens, num_heads, dropout) # 多头注意力机制self.addnorm2 = AddNorm(norm_shape, dropout)self.ffn = PostionWiseFFN(num_input, ffn_num_hiddens, num_hiddens)self.addnorm3 = AddNorm(norm_shape, dropout)def forward(self, X, state):# state [编码器输入,编码器有效长度,中间状态用于记录]enc_outputs, enc_valid_lens = state[0], state[1]if state[2][self.i] is None:K = Xelse:K = torch.cat((state[2][self.i], X), axis=1)state[2][self.i] = Kif self.training:batch_size, num_steps, _ = X.shapedec_valid_lens = torch.arange(1, batch_size + 1, device=X.device)else:dec_valid_lens = NoneX2 = self.attention1(X, K, K, dec_valid_lens)Y = self.addnorm1(X, X2)Y2 = self.attention2(Y, enc_outputs, enc_outputs, enc_valid_lens)Z = self.addnorm2(Y, Y2)return self.addnorm3(Z, self.ffn(Z)), state
封装
class TransformerDecoder(nn.Module):'''vocab_size: 词典大小K_size, Q_size, V_size: 键值对和查询的大小num_hiddens: 中间隐藏层神经元num_heads: 头数norm_shape: 残差连接+归一化层的输入形状num_input: FFN的输入形状ffn_num_hiddens: FFN隐藏层神经元num_layers: 编码器的层数dropout: 神经元的丢弃概率'''def __init__(self, vocab_size, K_size, Q_size, V_size, num_hiddens, num_heads,norm_shape, num_input, ffn_num_hiddens, num_layers, dropout):super(TransformerDecoder, self).__init__()self.num_hiddens = num_hiddensself.num_layers = num_layersself.embedding = nn.Embedding(num_embeddings=vocab_size, embedding_dim=num_hiddens)self.pos_encoding = PositionalEncoding(num_hiddens, dropout)self.blks = nn.Sequential()for i in range(num_layers):self.blks.add_module("block" + str(i),DecodeBlock(K_size, Q_size, V_size, num_hiddens, num_heads, norm_shape, num_input, ffn_num_hiddens, dropout, i))self.linear = nn.Linear(num_hiddens, vocab_size)def init_state(self, enc_outputs, enc_valid_lens):return [enc_outputs, enc_valid_lens, [None] * self.num_layers]def forward(self, X, state):X = self.pos_encoding(self.embedding(X) * math.sqrt(self.num_hiddens))self._attention_weights = [[None] * len(self.blks) for _ in range(2)]for i, blk in enumerate(self.blks):X, state = blk(X, state)self._attention_weights[0][i] = blk.attention1.attention.attention_weightsself._attention_weights[1][i] = blk.attention2.attention.attention_weightsreturn self.linear(X), self._attention_weights@propertydef attention_weights(self):return self._attention_weights
Transformer
最后整合一下
class EncoderDecoder(nn.Module):"""编码器-解码器架构的基类"""def __init__(self, encoder, decoder, **kwargs):super(EncoderDecoder, self).__init__(**kwargs)self.encoder = encoderself.decoder = decoderdef forward(self, enc_X, dec_X, *args):enc_outputs = self.encoder(enc_X, *args)dec_state = self.decoder.init_state(enc_outputs, *args)return self.decoder(dec_X, dec_state)
Transformer以三种不同的方式使用多头注意力:(引自论文)
- 在 “encoder-decoder attention” 层中,查询 Q Q Q来自先前的解码器层,并且存储器键 K K K和值 V V V来自编码器的输出。这使得解码器中的每个位置都能处理输入序列中的所有位置。这模拟了序列到序列模型中的典型编码器-解码器注意机制。
- 编码器包含自我注意层。在自关注层中,所有的键、值和查询都来自同一个地方,在这种情况下,是编码器中前一层的输出。编码器中的每个位置都可以处理编码器的前一层中的所有位置。
- 类似地,解码器中的自关注层允许解码器中的每个位置关注解码器中的直到并且包括该位置的所有位置。我们需要防止解码器中的冗余信息流,以保持自回归特性。我们通过屏蔽(设置为 − ∞ -\infty −∞) s o f t m a x softmax softmax 输入中对应于非法连接的所有值来实现这一点。
最后,大家再来回顾一下Transformer模型整体架构

相关文章:
入门pytorch-Transformer
前言 虽然Transformer是2017年由Google推出,如果按照读论文只读近两年的思路看,那它无疑是过时的,但可惜的是,目前很多论文的核心依然是Transformer,或者由其进行改进的,故本文使用pytorch来搭建一下Trans…...
泛型编程--
auto自动推导数据类型 函数模板 定义和调用 函数模板具体化 函数模板通用版本之外的一个特殊版本 函数模板 具体化函数 ,它们的声明和定义都可以分开写。 声明 定义 函数模板写变量 模板参数缺省 类成员函数作为函数模板 类构造函数是函数模板 函数模板重载 函数模…...
【大语言模型】LangChain 核心模块介绍(Agents)
【大语言模型】LangChain 核心模块介绍(Agents) 一、简介二、Agents 的核心概念三、实战案例3.1、需求说明3.2、实现思路3.3、完整源码 一、简介 我们都知道四肢的绝大部分动作都是由大脑决定的,大脑通过中枢神经下发自己的操作指令…...
19C-RAC 环境mgmtca.trc.1过大
客户监控告警/u01使用率超过80%,通过一层层目录查看,发现是mgmtca.trc.1过大导致的告警 [rootgsdb1 ~]# du -sh /u01/app/grid/cfgtoollogs/mgmtca/mgmtca.trc.1 103G /u01/app/grid/cfgtoollogs/mgmtca/mgmtca.trc.1 查看MOS文档:Huge …...
基于Spring Boot的同城宠物照看系统的设计与实现
一、摘要 在快节奏的现代生活中,宠物已成为许多家庭不可或缺的一部分。然而,宠物照看服务的需求也随之增长。为了满足这一需求,我们设计并实现了一款同城宠物照看系统,该系统利用Java技术和MySQL数据库,为用户提供一个…...
爬虫学习案例5
爬取b站一个视频 罗翔老师某一个视频很刑 单个完整代码: 安装依赖库 pip install lxml requests import osimport requests import re from lxml import etree import json # 格式化展开输出 from pprint import pprint # 导入进程模块 import subprocess head…...
视频监控汇聚平台方案设计:Liveweb视频智能监管系统方案技术特点与应用
随着科技的发展,视频监控平台在各个领域的应用越来越广泛。然而,当前的视频监控平台仍存在一些问题,如视频质量不高、监控范围有限、智能化程度不够等。这些问题不仅影响了监控效果,也制约了视频监控平台的发展。 为了解决这些问…...
ansible自动化运维(三)jinja2模板roles角色管理
相关文章ansible自动化运维(一)简介及清单,模块-CSDN博客ansible自动化运维(二)playbook模式详解-CSDN博客ansible自动化运维(四)运维实战-CSDN博客 三.Ansible jinja2模板 Jinja2是Python的全功能模板引…...
队列+宽搜_429. N 叉树的层序遍历_二叉树最大宽度
429. N 叉树的层序遍历 定义一个队列q,将一层的节点入队,并记录节点个数。根据节点的个数,出队列,并将其孩子入队列。出完队列,队列当前剩余节点的个数就是下次出队列的次数。直到队列为空 /* // Definition for a Nod…...
Windows11安装及使用nvm
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 Windows11安装nvm 前言一、简介二、下载三、安装1、双击运行,同意协议,点击Next2、选择nvm安装路径,此路径也是环境变量NVM_HOME的路径&am…...
(一)机器学习 - 入门
数据集 数据集是一组数据的集合,这些数据可以是数值型、文本型、图形型等多种形式。数据集通常用于统计分析、机器学习、科学研究、商业智能等领域,以发现数据中的模式、趋势和关联性。 数据集的组成: 变量(Variables)…...
【解决】k8s使用kubeadm初始化集群失败问题整理
执行提示命令,查看报错信息 journalctl -xeu kubelet1、错误:running with swap on is no 报错 "command failed" err"failed to run Kubelet: running with swap on is no 解决: swap未禁用,需要禁用swap&…...
apache-dubbo
dubbo 文档地址 dubbo 官方文档地址 https://dubbo.apache.org/zh-cn/docs/user/references/api.html nacos 官方文档地址 https://nacos.io/zh-cn/docs/quick-start.html nacos下载地址 https://github.com/alibaba/nacos/releases/download/2.3.0/nacos-server-2.3.0.…...
ECharts柱状图-柱图2,附视频讲解与代码下载
引言: 在数据可视化的世界里,ECharts凭借其丰富的图表类型和强大的配置能力,成为了众多开发者的首选。今天,我将带大家一起实现一个柱状图图表,通过该图表我们可以直观地展示和分析数据。此外,我还将提供…...
【新人系列】Python 入门(十六):正则表达式
✍ 个人博客:https://blog.csdn.net/Newin2020?typeblog 📝 专栏地址:https://blog.csdn.net/newin2020/category_12801353.html 📣 专栏定位:为 0 基础刚入门 Python 的小伙伴提供详细的讲解,也欢迎大佬们…...
HTML综合
一.HTML的初始结构 <!DOCTYPE html> <html lang"en"><head><!-- 设置文本字符 --><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><!-- 设置网页…...
孚盟云 MailAjax.ashx SQL注入漏洞复现
0x01 产品简介 上海孚盟软件有限公司是一家外贸SaaS服务提供商,也是专业的外贸行业解决方案专业提供商。 全新的孚盟云产品,让用户可以用云模式实现信息化管理,让用户的异地办公更加流畅,大大降低中小企业在信息化上成本,用最小的投入享受大型企业级别的信息化服务,主要…...
解决“VMware虚拟机报Intel VT-x”错误
今天,在windows系统上,打开VMware WorkStation v15软件里的虚拟机,弹出"Intel VT-x处于禁用状态"错误,如图(1)所示: 图(1) 虚拟机报"Intel VT-x"错误 问题原因:当前电脑的BIOS没有开启…...
NiceGUI `ui.table` 基础
NiceGUI ui.table 基础 ui.table 是 NiceGUI 提供的一个组件,用于在页面上展示数据表格 基本概念 官方简介 A table based on Quasar’s QTable component. 参数参考rows:list of row objects; 行对象列表columns:list of column objects (defaults to the colu…...
分布式 Raft算法 总结
前言 相关系列 《分布式 & 目录》《分布式 & Raft算法 & 总结》《分布式 & Raft算法 & 问题》 参考文献 《Raft一致性算法论文译文》《深入剖析共识性算法 Raft》 简介 Raft 木筏是一种基于日志复制实现的分布式容错&一致性算法。在Raft算法…...
Python|GIF 解析与构建(5):手搓截屏和帧率控制
目录 Python|GIF 解析与构建(5):手搓截屏和帧率控制 一、引言 二、技术实现:手搓截屏模块 2.1 核心原理 2.2 代码解析:ScreenshotData类 2.2.1 截图函数:capture_screen 三、技术实现&…...
从深圳崛起的“机器之眼”:赴港乐动机器人的万亿赛道赶考路
进入2025年以来,尽管围绕人形机器人、具身智能等机器人赛道的质疑声不断,但全球市场热度依然高涨,入局者持续增加。 以国内市场为例,天眼查专业版数据显示,截至5月底,我国现存在业、存续状态的机器人相关企…...
Python如何给视频添加音频和字幕
在Python中,给视频添加音频和字幕可以使用电影文件处理库MoviePy和字幕处理库Subtitles。下面将详细介绍如何使用这些库来实现视频的音频和字幕添加,包括必要的代码示例和详细解释。 环境准备 在开始之前,需要安装以下Python库:…...
鱼香ros docker配置镜像报错:https://registry-1.docker.io/v2/
使用鱼香ros一件安装docker时的https://registry-1.docker.io/v2/问题 一键安装指令 wget http://fishros.com/install -O fishros && . fishros出现问题:docker pull 失败 网络不同,需要使用镜像源 按照如下步骤操作 sudo vi /etc/docker/dae…...
【碎碎念】宝可梦 Mesh GO : 基于MESH网络的口袋妖怪 宝可梦GO游戏自组网系统
目录 游戏说明《宝可梦 Mesh GO》 —— 局域宝可梦探索Pokmon GO 类游戏核心理念应用场景Mesh 特性 宝可梦玩法融合设计游戏构想要素1. 地图探索(基于物理空间 广播范围)2. 野生宝可梦生成与广播3. 对战系统4. 道具与通信5. 延伸玩法 安全性设计 技术选…...
鸿蒙DevEco Studio HarmonyOS 5跑酷小游戏实现指南
1. 项目概述 本跑酷小游戏基于鸿蒙HarmonyOS 5开发,使用DevEco Studio作为开发工具,采用Java语言实现,包含角色控制、障碍物生成和分数计算系统。 2. 项目结构 /src/main/java/com/example/runner/├── MainAbilitySlice.java // 主界…...
浪潮交换机配置track检测实现高速公路收费网络主备切换NQA
浪潮交换机track配置 项目背景高速网络拓扑网络情况分析通信线路收费网络路由 收费汇聚交换机相应配置收费汇聚track配置 项目背景 在实施省内一条高速公路时遇到的需求,本次涉及的主要是收费汇聚交换机的配置,浪潮网络设备在高速项目很少,通…...
排序算法总结(C++)
目录 一、稳定性二、排序算法选择、冒泡、插入排序归并排序随机快速排序堆排序基数排序计数排序 三、总结 一、稳定性 排序算法的稳定性是指:同样大小的样本 **(同样大小的数据)**在排序之后不会改变原始的相对次序。 稳定性对基础类型对象…...
逻辑回归暴力训练预测金融欺诈
简述 「使用逻辑回归暴力预测金融欺诈,并不断增加特征维度持续测试」的做法,体现了一种逐步建模与迭代验证的实验思路,在金融欺诈检测中非常有价值,本文作为一篇回顾性记录了早年间公司给某行做反欺诈预测用到的技术和思路。百度…...
【C++】纯虚函数类外可以写实现吗?
1. 答案 先说答案,可以。 2.代码测试 .h头文件 #include <iostream> #include <string>// 抽象基类 class AbstractBase { public:AbstractBase() default;virtual ~AbstractBase() default; // 默认析构函数public:virtual int PureVirtualFunct…...
