Transformer架构和对照代码详解

1、英文架构图

下面图中展示了Transformer的英文架构,英文架构中的模块名称和具体代码一一对应,方便大家对照代码、理解和使用

2、编码器

2.1 编码器介绍

        从宏观⻆度来看,Transformer的编码器是由多个相同的层叠加⽽ 成的,每个层都有两个⼦层(⼦层表⽰为sublayer)。第⼀个⼦层是多头⾃注意⼒(multi-head self-attention) 汇聚;第⼆个⼦层是基于位置的前馈⽹络(positionwise feed-forward network)。

     具体来说,在计算编码器 的⾃注意⼒时,查询、键和值都来⾃前⼀个编码器层的输出。受 7.6节中残差⽹络的启发,每个⼦层都采⽤了残差连接(residual connection)。在Transformer中,对于序列中任何位置的任何输⼊x ∈ R d,都要求满 ⾜sublayer(x) ∈ R d,以便残差连接满⾜x + sublayer(x) ∈ R d。在残差连接的加法计算之后,紧接着应⽤层 规范化(layer normalization)。因此,输⼊序列对应的每个位置,Transformer编码器都将输出⼀个d维表⽰向量。

2.2 编码器中各模块的实现

2.2.1 Positionwise FNN实现(对照架构图中的Positionwise FNN组件)

        基于位置的前馈⽹络(Positionwise FNN)对序列中的所有位置的表⽰进⾏变换时使⽤的是同⼀个多层感知机(MLP),这就是称前馈⽹络是基于位置的(positionwise)的原因。在下⾯的实现中,输⼊X的形状(批量⼤⼩,时间步数或序列 ⻓度,隐单元数或特征维度)将被⼀个两层的感知机转换成形状为(批量⼤⼩,时间步数,ffn_num_outputs) 的输出张量。

代码:

#@save
class PositionWiseFFN(nn.Module):
"""基于位置的前馈⽹络"""
   def __init__(self, ffn_num_input, ffn_num_hiddens, ffn_num_outputs,**kwargs):
       super(PositionWiseFFN, self).__init__(**kwargs)
       self.dense1 = nn.Linear(ffn_num_input, ffn_num_hiddens)
       self.relu = nn.ReLU()
       self.dense2 = nn.Linear(ffn_num_hiddens, ffn_num_outputs)

   def forward(self, X):
       return self.dense2(self.relu(self.dense1(X)))

代码解释: 

这段代码是用PyTorch框架定义的一个类 PositionWiseFFN,它是一个基于位置的前馈神经网络(Position-wise Feed-Forward Network),通常用于Transformer架构中。此类实现了一个简单的两层全连接神经网络,每一层后接ReLU激活函数。

代码解释:

类定义:

class PositionWiseFFN(nn.Module):
    """基于位置的前馈⽹络"""
这里定义了一个名为 PositionWiseFFN 的类,该类继承自 PyTorch 中的 nn.Module 类,这是构建神经网络模块的基础类。

初始化方法 __init__:

def __init__(self, ffn_num_input, ffn_num_hiddens, ffn_num_outputs, **kwargs):
    super(PositionWiseFFN, self).__init__(**kwargs)
    self.dense1 = nn.Linear(ffn_num_input, ffn_num_hiddens)
    self.relu = nn.ReLU()
    self.dense2 = nn.Linear(ffn_num_hiddens, ffn_num_outputs)
初始化时,通过 super().__init__(**kwargs) 调用了父类 nn.Module 的初始化方法。
定义了两个线性层(全连接层):self.dense1 和 self.dense2。dense1 输入维度为 ffn_num_input,输出维度为 ffn_num_hiddens;dense2 输入维度与隐藏层输出维度相同,即 ffn_num_hiddens,输出维度为 ffn_num_outputs。
同时定义了一个ReLU激活函数 self.relu,在前馈过程中将被应用在线性层之间。

前向传播方法 forward:

def forward(self, X):
    return self.dense2(self.relu(self.dense1(X)))
在这个方法中,定义了输入数据 X 经过模型的处理流程。首先,X 通过第一个线性层 self.dense1 计算输出。
然后,对线性层的输出应用ReLU激活函数 self.relu 进行非线性变换。
最后,将ReLU激活后的结果送入第二个线性层 self.dense2 进行计算,得到最终的输出。
总结来说,这个类实现了 Transformer 中的一个基本单元——位置感知前馈神经网络,其结构为:输入 -> Linear -> ReLU -> Linear -> 输出。这个模块应用于每个位置上的输入特征上,独立地进行计算并增加非线性表达能力。

2.2.2 Add & norm组件的实现

       现在我们关注架构图中的加法和规范化(Add & norm)组件。正如在本节开头所述,这是由残差连接和紧随其后的层规范化组成的。两者都是构建有效的深度架构的关键。

       层规范化和批量规范化:后续将解释在⼀个⼩批量的样本内基于批量规范化对数据进⾏重新中⼼化和重新缩放的调整。层规范化和批量规范化的⽬标相同,但层规范化是基于特征维度进⾏规范化。尽管批量规范化在计算机视觉中被⼴泛 应⽤,但在⾃然语⾔处理任务中(输⼊通常是变⻓序列)批量规范化通常不如层规范化的效果好。 

现在可以使⽤残差连接和层规范化来实现AddNorm类。暂退法也被作为正则化⽅法使⽤。

代码:

class AddNorm(nn.Module):
"""残差连接后进⾏层规范化"""
      def __init__(self, normalized_shape, dropout, **kwargs):
          super(AddNorm, self).__init__(**kwargs)
          self.dropout = nn.Dropout(dropout)
          self.ln = nn.LayerNorm(normalized_shape)

      def forward(self, X, Y):
          return self.ln(self.dropout(Y) + X)

代码解释:

这段代码定义了一个名为 AddNorm 的类,该类继承自 PyTorch 中的 nn.Module 类。这个类在Transformer架构中实现了一个残差连接(Residual Connection)与层规范化(Layer Normalization)相结合的模块。

代码解释:

类定义:
python
class AddNorm(nn.Module):
    """残差连接后进行层规范化"""
这个类表示一个神经网络模块,其功能是在执行层规范化操作之前先进行残差连接。
初始化方法 __init__:
python
def __init__(self, normalized_shape, dropout, **kwargs):
    super(AddNorm, self).__init__(**kwargs)
    self.dropout = nn.Dropout(dropout)
    self.ln = nn.LayerNorm(normalized_shape)
初始化时,调用父类 nn.Module 的初始化方法。
定义了一个 dropout 层,使用了给定的 dropout 参数来控制随机失活的比例。
创建了一个 nn.LayerNorm 对象,用于对指定维度大小(normalized_shape)的数据进行层规范化处理。
前向传播方法 forward:
python
def forward(self, X, Y):
    return self.ln(self.dropout(Y) + X)
在 forward 方法中,模型接收两个输入变量 X 和 Y。
先将输入 Y 通过 dropout 层,以一定概率丢弃部分激活值,从而增加模型的泛化能力。
将经过 dropout 操作后的 Y 与原始输入 X 相加,实现残差连接,允许信息直接从上一层传递到下一层。
最后,将相加的结果送入 self.ln 即 Layer Normalization 层进行规范化处理,确保每一层的输出具有稳定的分布,有利于梯度传播和训练过程。
所以,整个 AddNorm 模块的作用是首先对输入 Y 进行可能的随机失活,然后将其与另一个输入 X 做残差连接,并对结果应用层规范化,这是Transformer模型中常见的结构之一。

2.2.3 Multi-head attention组件的实现

      在实践中,当给定相同的查询、键和值的集合时,我们希望模型可以基于相同的注意⼒机制学习到不同的⾏ 为,然后将不同的⾏为作为知识组合起来,捕获序列内各种范围的依赖关系(例如,短距离依赖和⻓距离依 赖关系)。因此,允许注意⼒机制组合使⽤查询、键和值的不同⼦空间表⽰(representation subspaces可能是有益的。

       为此,与其只使⽤单独⼀个注意⼒汇聚,我们可以⽤独⽴学习得到的h组不同的 线性投影(linear projections) 来变换查询、键和值。然后,这h组变换后的查询、键和值将并⾏地送到注意⼒汇聚中。最后,将这h个注意 ⼒汇聚的输出拼接在⼀起,并且通过另⼀个可以学习的线性投影进⾏变换,以产⽣最终输出。这种设计被称 为多头注意⼒(multihead attention)。对于h个注意⼒汇聚输出,每⼀个注意⼒汇聚都 被称作⼀个头(head)。下图 展⽰了使⽤全连接层来实现可学习的线性变换的多头注意⼒。

图 多头注意⼒:多个头连结后做线性变换 

      模型:     

\mathbf{h}_{i}=f\left (\mathbf{ W}_{i}^{\left (q \right )}\mathbf{q},\mathbf{ W}_{i}^{\left (k \right )}\mathbf{k},\mathbf{ W}_{i}^{\left (v \right )}\mathbf{v}\right )\in \mathbb{R}^{p_{v}}

\mathbf{H}=\mathbf{W}_{o}\begin{bmatrix} \mathbf{h}_{1} \\ \vdots \\ \mathbf{h}_{h} \end{bmatrix}\in \mathbb{R}^{p_{o}}

       在实现过程中通常选择缩放点积注意⼒作为每⼀个注意⼒头。为了避免计算代价和参数代价的⼤幅增⻓,我 们设定p_{q} = p_{k} = p_{v} = p_{o}/h。值得注意的是,如果将查询、键和值的线性变换的输出数量设置为p_{q}h = p_{k}h = p_{v}h = p_{o},则可以并⾏计算h个头。在下⾯的实现中,p_{o}是通过参数num_hiddens指定的。

     代码:

#@save
class MultiHeadAttention(nn.Module):
"""多头注意⼒"""
      def __init__(self, key_size, query_size, value_size, num_hiddens,
                   num_heads, dropout, bias=False, **kwargs):
          super(MultiHeadAttention, self).__init__(**kwargs)
          self.num_heads = num_heads
          self.attention = d2l.DotProductAttention(dropout)
          self.W_q = nn.Linear(query_size, num_hiddens, bias=bias)
          self.W_k = nn.Linear(key_size, num_hiddens, bias=bias)
          self.W_v = nn.Linear(value_size, num_hiddens, bias=bias)
          self.W_o = nn.Linear(num_hiddens, num_hiddens, bias=bias)

      def forward(self, queries, keys, values, valid_lens):
          # queries,keys,values的形状:
          # (batch_size,查询或者“键-值”对的个数,num_hiddens)
          # valid_lens 的形状:
          # (batch_size,)或(batch_size,查询的个数)
          # 经过变换后,输出的queries,keys,values 的形状:
          # (batch_size*num_heads,查询或者“键-值”对的个数,
          # num_hiddens/num_heads)
          queries = transpose_qkv(self.W_q(queries), self.num_heads)
          keys = transpose_qkv(self.W_k(keys), self.num_heads)
          values = transpose_qkv(self.W_v(values), self.num_heads)
          if valid_lens is not None:
          # 在轴0,将第⼀项(标量或者⽮量)复制num_heads次,
          # 然后如此复制第⼆项,然后诸如此类。
          valid_lens = torch.repeat_interleave(
          valid_lens, repeats=self.num_heads, dim=0)
          # output的形状:(batch_size*num_heads,查询的个数,
          # num_hiddens/num_heads)
          output = self.attention(queries, keys, values, valid_lens)
          # output_concat的形状:(batch_size,查询的个数,num_hiddens)
          output_concat = transpose_output(output, self.num_heads)
          return self.W_o(output_concat)

代码详细解释:

代码定义了一个名为MultiHeadAttention的类,它是实现Transformer中多头注意力机制的核心模块。这个类基于PyTorch框架构建,并且遵循了Dive into Deep Learning (d2l) 一书中的实现风格。以下是对代码逐段详细解释:

类定义与初始化:

继承自nn.Module,这是PyTorch中所有神经网络模块的基础类。

初始化函数__init__接收多个参数:

key_size, query_size, value_size: 分别是键、查询和值向量的维度。
num_hiddens: 每个注意力头内部的隐藏层维度(每个头的输入和输出维度)。
num_heads: 多头注意力的头数。
dropout: 注意力机制中的 dropout 率,用于防止过拟合。
bias: 可选布尔值,决定线性变换层是否使用偏置项。
定义内部属性:

self.num_heads:保存注意力头的数量。
self.attention:实例化一个d2l.DotProductAttention对象,这是一个点积注意力子模块,包含了缩放点积注意力计算以及可能的dropout操作。
self.W_q, self.W_k, self.W_v:分别对应三个线性层,将查询、键、值映射到隐藏层维度(即num_hiddens)。
self.W_o:最后一个线性层,将从多头注意力得到的结果转换回原始的num_hiddens维度。
forward方法:

输入包括queries, keys, values,它们通常是从编码器或解码器的不同位置获取的特征向量,形状为 (batch_size, query_or_key_value_pairs_num, num_hiddens);valid_lens 是序列的有效长度,对于变长序列做掩码处理时有用,其形状可以是 (batch_size,) 或 (batch_size, query_num)。

首先通过对应的线性层(self.W_q, self.W_k, self.W_v)将查询、键和值投影到新的空间,并通过transpose_qkv函数进行转置和重塑,使得形状变为 (batch_size*num_heads, query_or_key_value_pairs_num, num_hiddens/num_heads),这样就可以实现并行计算多个注意力头。

如果传入了有效长度valid_lens,则会对其进行复制以匹配多个注意力头的数量。

调用self.attention(点积注意力)来计算注意力得分并加权求和得到上下文向量,同时应用dropout和masking。

通过transpose_output函数对结果进行反向转置和重塑,合并来自所有注意力头的输出,恢复成单个注意力头的形状(batch_size, query_num, num_hiddens)。

最后,将整合后的注意力输出通过线性层self.W_o进一步映射到最终的输出维度。

总之,这段代码实现了多头注意力机制,它能够并行地执行多个注意力头的计算,并将各个头的输出融合在一起,从而增强了模型捕捉不同表示子空间中信息的能力。

2.3 编码器的整体实现

2.3.1 EncoderBlock

有了组成Transformer编码器的基础组件,现在可以先实现编码器中的⼀个层。下⾯EncoderBlock类包含 两个⼦层:多头⾃注意⼒和基于位置的前馈⽹络,这两个⼦层都使⽤了残差连接和紧随的层规范化。

代码:

class EncoderBlock(nn.Module):
"""Transformer编码器块"""
      def __init__(self, key_size, query_size, value_size, num_hiddens,
                   norm_shape, ffn_num_input, ffn_num_hiddens, num_heads,
                   dropout, use_bias=False, **kwargs):
          super(EncoderBlock, self).__init__(**kwargs)
          self.attention = d2l.MultiHeadAttention(
          key_size, query_size, value_size, num_hiddens, num_heads, dropout,use_bias)
          self.addnorm1 = AddNorm(norm_shape, dropout)
          self.ffn = PositionWiseFFN(ffn_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))

代码解释:

这段代码定义了一个名为EncoderBlock的类,它是Transformer模型中的编码器部分的基本组成单元,即一个编码块。这个类继承自PyTorch的nn.Module基类,并在初始化函数中构建了两个主要组成部分:多头注意力机制(Multi-Head Attention)和前馈神经网络(Position-wise Feed-Forward Network, FFN)。同时,该类还包含了两个用于添加残差连接(Add)与层归一化(Norm)的子模块。

初始化方法 __init__:

接收多个参数,如关键尺寸(key_size)、查询尺寸(query_size)、值尺寸(value_size)、隐藏层大小(num_hiddens)、层归一化的形状(norm_shape)、FFN输入维度(ffn_num_input)、FFN隐藏层维度(ffn_num_hiddens)、注意力头的数量(num_heads)、dropout率等。
定义内部属性:
attention: 使用d2l库中的MultiHeadAttention类创建一个多头注意力子模块,其参数由传入的关键、查询、值尺寸以及隐藏层大小、注意力头数量和dropout率确定。
addnorm1 和 addnorm2: 分别是两次残差连接后接层归一化的组合模块,这里使用的是自定义的AddNorm类,它包含加法操作(Add)和层归一化(Norm),并接收norm_shape和dropout作为参数。
ffn: 创建一个位置感知的前馈神经网络子模块,利用PositionWiseFFN类实现,其参数包括FFN的输入维度、隐藏层维度和输出维度(此处与隐藏层大小相同)。
正向传播方法 forward:

输入参数为X(编码器的输入序列)和valid_lens(有效序列长度)。
首先,将X传递给attention子模块计算多头注意力结果,并通过addnorm1模块进行残差连接和层归一化,得到中间表示Y。
最后,将经过注意力机制处理后的Y传递给ffn子模块进行前馈神经网络计算,再通过addnorm2模块进行第二次残差连接和层归一化,从而得到最终的编码块输出。
综上所述,EncoderBlock类实现了Transformer编码器的一个完整基本块,包括多头注意力机制和前馈神经网络结构,并结合了残差连接和层归一化来优化训练过程和提高模型性能。

 2.3.2 TransformerEncoder

       实现的Transformer编码器的代码中,堆叠了num_layers个EncoderBlock类的实例。由于这⾥使⽤的是 值范围在−1和1之间的固定位置编码,因此通过学习得到的输⼊的嵌⼊表⽰的值需要先乘以嵌⼊维度的平⽅ 根进⾏重新缩放,然后再与位置编码相加。

代码:

class TransformerEncoder(d2l.Encoder):
"""Transformer编码器"""
      def __init__(self, vocab_size, key_size, query_size, value_size,
                   num_hiddens, norm_shape, ffn_num_input, ffn_num_hiddens,
                   num_heads, num_layers, dropout, use_bias=False, **kwargs):
          super(TransformerEncoder, self).__init__(**kwargs)
          self.num_hiddens = num_hiddens
          self.embedding = nn.Embedding(vocab_size, num_hiddens)
          self.pos_encoding = d2l.PositionalEncoding(num_hiddens, dropout)
          self.blks = nn.Sequential()
          for i in range(num_layers):
          self.blks.add_module("block"+str(i),
          EncoderBlock(key_size, query_size, value_size, num_hiddens,
                       norm_shape, ffn_num_input, ffn_num_hiddens,
                       num_heads, dropout, use_bias))
      def forward(self, X, valid_lens, *args):
      # 因为位置编码值在-1和1之间,
      # 因此嵌⼊值乘以嵌⼊维度的平⽅根进⾏缩放,
      # 然后再与位置编码相加。
          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_weights
          return X

代码解释: 

这段代码定义了一个名为TransformerEncoder的类,它是基于深度学习框架实现的一个Transformer模型的编码器部分。这个类继承自d2l库中的Encoder基类,并在初始化和前向传播过程中实现了以下功能:

初始化方法 __init__:

接收一系列参数,包括词汇表大小(vocab_size)、关键尺寸(key_size)、查询尺寸(query_size)、值尺寸(value_size)、隐藏层大小(num_hiddens)、归一化形状(norm_shape)、FFN输入维度(ffn_num_input)、FFN隐藏层维度(ffn_num_hiddens)、注意力头数量(num_heads)、编码器层数量(num_layers)以及dropout率等。
创建一个词嵌入层:使用nn.Embedding来将输入的词索引映射到隐藏向量空间。
创建一个位置编码层:通过d2l.PositionalEncoding类为输入序列添加位置信息,以帮助模型理解序列中元素的位置关系。
构建编码器块:利用循环结构创建指定数量(num_layers)的EncoderBlock实例,并将其串联成一个序列,存储在self.blks属性中。
正向传播方法 forward:

输入参数为X(输入序列的词索引),valid_lens(有效序列长度列表,用于处理变长序列时的掩码操作)以及其他可能的额外参数。
首先,对输入序列进行词嵌入操作并应用位置编码。这里乘以math.sqrt(self.num_hiddens)是为了确保在加入位置编码后,数值范围保持合理,同时避免了因维度增大而导致的梯度消失或爆炸问题。
然后,遍历所有的编码器块,对每个编码块执行前向传播计算,并将当前块的注意力权重保存在self.attention_weights列表中,便于后续可视化或分析。
最终返回经过所有编码块处理后的输出表示X。
总结起来,TransformerEncoder类构建了一个完整的Transformer编码器结构,它包含了词嵌入、位置编码以及多层由多头注意力机制和前馈神经网络组成的编码块,在处理输入序列时能够捕获上下文依赖和位置信息。

3、解码器(待续)

Transformer解码器也是由多个相同的层组成。在DecoderBlock(解码器模块)类中实现的每个层包含三个子层:解码器自注意力(decoder attention)、编码器-解码器注意力(encoder-decoder attention)和基于位置的前馈网络(PositionWiseFFN)

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

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

相关文章

Java重修第三天—“方法“的案例练习

案例一:买飞机票 题目 用户购买机票时,机票原价会按照淡季、旺季,头等舱还是经济舱的情况进行相应的优惠,优惠方案如下:5-10月为旺季,头等舱9折,经济舱8.5折。11月到来年4月为淡季,头等舱7折&…

内核线程创建-kthread_create

文章参考Linux内核线程kernel thread详解 - 知乎 大概意思就是早期创建内核线程,是交由内核处理,由内核自己完成(感觉好像也不太对呢),创建一个内核线程比较麻烦,会导致内核阻塞。因此就诞生了工作队列以及…

美格智能5G RedCap模组SRM813Q通过广东联通5G创新实验室测试认证

近日,美格智能5G RedCap轻量化模组SRM813Q正式通过广东联通5G创新实验室端到端的测试验收,获颁测评证书。美格智能已连续通过业内两家权威实验室的测试认证,充分验证SRM813Q系列模组已经具备了成熟的商用能力,将为智慧工业、安防监…

docker - 常用容器部署命令大全(MySQL、Redis、RabbitMQ、ES、Kibana、Nacos、Sentinel)

目录 一、常用容器运行指令 MySQL Redis RabbitMQ ElasticSearch & kibana Nacos Sentinel 一、常用容器运行指令 MySQL docker run -d --name mysql -p 3306:3306 -e TZAsia/Shanghai -e MYSQL_ROOT_PASSWORD1111 mysql:5.7 -e TZAsia/Shanghai:指定…

听GPT 讲Rust源代码--compiler(26)

File: rust/compiler/rustc_target/src/abi/call/mips.rs 在Rust源代码中的rust/compiler/rustc_target/src/abi/call/mips.rs文件是关于MIPS架构的函数调用ABI(Aplication Binary Interface)定义。ABI是编程语言与底层平台之间的接口规范,用于定义函数调用、参数传…

centos7部署minio单机版

一、目标 在centos7上部署minio单机版 二、centos7部署minio 1、下载minio mkdir /usr/local/minio cd /usr/local/minio wget https://dl.minio.io/server/minio/release/linux-amd64/minio chmod x minio 2、新建minio存储数据的目录 mkdir -p /data/minio/data3、新建…

首次引入大模型!Bert-vits2-Extra中文特化版40秒素材复刻巫师3叶奈法

Bert-vits2项目又更新了,更新了一个新的分支:中文特化,所谓中文特化,即针对中文音色的特殊优化版本,纯中文底模效果百尺竿头更进一步,同时首次引入了大模型,使用国产IDEA-CCNL/Erlangshen-Megat…

外包干了1个月,技术退步一大半。。。

先说一下自己的情况,本科生,19年通过校招进入广州某软件公司,干了接近4年的功能测试,今年年初,感觉自己不能够在这样下去了,长时间呆在一个舒适的环境会让一个人堕落!而我已经在一个企业干了四年的功能测试…

FFmpeg读取Assets资源文件

在Android开发中我们经常把原生资源文件放在assets目录下以供需要时读取,通过API提供的resources.assets.open(filename)/openFd(filenam)方法可以非常方便获得InputStream或FileDescriptor(文件标识符),但是在使用FFmpeg读取Asse…

Keil使用手册

文章目录 1 设置1.1 背景1.2 Project窗口显示.h文件1.3 注释1.4 Project窗口消失TAB转空格的设置keilsourceInsight 显示cannot evaluate普通局部变量静态全局变量静态局部变量 2 报错与解决2.1 warning:#1-D last line of file ends without anewline2.2 中文乱码 …

13. 强化学习编程实验1-在格子世界中寻宝(1)

文章目录 1.实验目的2.任务描述3.任务分析3.1 待求问题是多步决策问题否3.2 问题求解过程是一个马尔科夫决策过程3.3 状态空间S的确定3.4 动作空间A的确定3.5 状态转移概率P的确定3.6 立即回报R的确定3.7 折扣 γ \gamma γ的确定 4. 编程架构4.1 程序中有哪些对象和类4.2 环境…

Python中的@abstractmethod

abstractmethod 是 Python 中 abc 模块(Abstract Base Classes)提供的一个装饰器,用于声明抽象方法。抽象方法是指在抽象类中声明但没有提供具体实现的方法,而是由其子类提供具体实现。 使用 abstractmethod 装饰器可以使得子类在…

ES -极客学习

Elasticsearch 简介及其发展历史 起源 Lucene 于 Java 语言开发的搜索引擎库类创建于 1999 年,2005 年成为 Apache 顶级开源项目Lucene 具有高性能、易扩展的优点Lucene 的局限性 只能基于 Java 语言开发类库的接口学习曲线陡峭原生并不支持水平扩展原生并不支持水…

TypeScript 从入门到进阶之基础篇(三) 元组类型篇

系列文章目录 TypeScript 从入门到进阶系列 TypeScript 从入门到进阶之基础篇(一) ts基础类型篇TypeScript 从入门到进阶之基础篇(二) ts进阶类型篇TypeScript 从入门到进阶之基础篇(三) 元组类型篇TypeScript 从入门到进阶之基础篇(四) symbol类型篇 持续更新中… 文章目录 …

【编译原理】期末预习PPT后三章笔记+LL(1) II

继续预习O.o 从这一章开始看自己班发的 PPT 了 LL(1)的部分因为班里发了所以又看了一遍hhh感觉比之前那个清楚一点 目录 I. 自顶向下 一、概念(看一眼) 1、语法分析的两大类分析方法 2、算法基本思想 3、自顶向下介绍 1)一般过程 2&a…

初识大数据,一文掌握大数据必备知识文集(12)

🏆作者简介,普修罗双战士,一直追求不断学习和成长,在技术的道路上持续探索和实践。 🏆多年互联网行业从业经验,历任核心研发工程师,项目技术负责人。 🎉欢迎 👍点赞✍评论…

求实创新 不断探索 浙江移动基于亚信科技AntDB数据库率先完成CRM系统全域改造

12日20日,中国信息通信研究院(简称:信通院)和中国通信标准化协会大数据库技术推进委员会(CCSA TC601)共同组织的2023年大数据库“星河(Galaxy)”案例评选结果发布。中国移动通信集团…

k8s声明式资源管理

三种常见的项目发布方式 1、蓝绿发布 2、金丝雀发布(灰度发布) 3、滚动发布 应用程序升级,面临的最大的问题是新旧业务之间的切换,立项-----定稿------需求发布-----开发------测试------发布,测试之后上线&#x…

YOLOv5改进 | Neck篇 | 利用Damo-YOLO的RepGFPN改进特征融合层

一、本文介绍 本文给大家带来的改进机制是Damo-YOLO的RepGFPN(重参数化泛化特征金字塔网络),利用其优化YOLOv5的Neck部分,可以在不影响计算量的同时大幅度涨点(亲测在小目标和大目标检测的数据集上效果均表现良好涨点幅度超级高!)。RepGFPN不同于以往提出的改进模块,其…