Transformer中的编码器和解码器结构有什么不同?

news2024/9/30 1:39:41

Transformer背后的核心概念:注意力机制;编码器-解码器结构;多头注意力等;

 例如:The cat sat on the mat;

1、嵌入:

        首先,模型将输入序列中的每个单词嵌入到一个高维向量中表示,这个嵌入过程允许模型捕捉单词之间的语义相似性。

2、查询,键,和值向量;

        接下来,模型为序列中的每个单词计算向量:查询向量、键和值向量。在训练过程中,模型学习这些向量,每个向量都有不同的作用。查询向量表示单词的查询,即模型在序列中寻找的内容。键向量表示单词的键,即序列中其他单词应该注意的内容。值向量表示单词的值,即单词对输出所贡献的信息。

3、注意力分数;

        一旦模型计算了每个单词的查询、键和值向量,它就会为序列中的每一对单词计算注意力分数。这通常通过取查询向量和键向量的点积来实现,以评估单词之间的相似性

4、softmax归一化:

        然后,使用 softmax 函数对注意力分数进行归一化,以获得注意力权重。这些权重表示每个单词应该关注序列中其他单词的程度。注意力权重较高的单词被认为对正在执行的任务更为关键。

5、加权求和:

        最后,使用注意力权重计算值向量的加权和。这产生了每个序列中单词的自注意力机制输出,捕获了来自其他单词的上下文信息。

代码举例:



# 导入库
import torch
import torch.nn.functional as F

# 示例输入序列
input_sequence = torch.tensor([[0.1, 0.2, 0.3], [0.4, 0.5, 0.6], [0.7, 0.8, 0.9]])

# 生成 Key、Query 和 Value 矩阵的随机权重
random_weights_key = torch.randn(input_sequence.size(-1), input_sequence.size(-1))
random_weights_query = torch.randn(input_sequence.size(-1), input_sequence.size(-1))
random_weights_value = torch.randn(input_sequence.size(-1), input_sequence.size(-1))

# 计算 Key、Query 和 Value 矩阵
key = torch.matmul(input_sequence, random_weights_key)
query = torch.matmul(input_sequence, random_weights_query)
value = torch.matmul(input_sequence, random_weights_value)

# 计算注意力分数
attention_scores = torch.matmul(query, key.T) / torch.sqrt(torch.tensor(query.size(-1), dtype=torch.float32))

# 使用 softmax 函数获得注意力权重
attention_weights = F.softmax(attention_scores, dim=-1)

# 计算 Value 向量的加权和
output = torch.matmul(attention_weights, value)

print("自注意力机制后的输出:")
print(output)

Transformer基础:

1、编码器-解码器结构:

        在transforemr的核心是编码器-解码器结构;两个关键组件之间的共生关系;分别负责输入序列和生成输出序列;编码器和解码器中的每一层都包含相同的子层;包括自注意力机制和前馈网络;这种架构不仅有助于全面理解输入序列,而且能够生成上下文丰富的输出序列;

2、位置编码

        尽管Transformer模型具有强大的功能,但它缺乏对元素顺序的内在理解——这是位置编码所解决的一个缺点。通过将输入嵌入与位置信息结合起来,位置编码使模型能够区分序列中元素的相对位置。这种细致的理解对于捕捉语言的时间动态和促进准确理解至关重要。

3、多头注意力

        Transformer模型的一个显著特征是它能够同时关注输入序列的不同部分——这是多头注意力实现的。通过将查询、键和值向量分成多个头,并进行独立的自注意力计算,模型获得了对输入序列的细致透视,丰富了其表示,带有多样化的上下文信息

4、前馈网络

        与人类大脑能够并行处理信息的能力类似,Transformer模型中的每一层都包含一个前馈网络——一种能够捕捉序列中元素之间复杂关系的多功能组件。通过使用线性变换和非线性激活函数,前馈网络使模型能够在语言的复杂语义景观中航行,促进文本的稳健理解和生成。

Transformer 组件的详细说明代码

        要实现,首先运行位置编码、多头注意力机制和前馈网络的代码,然后是编码器、解码器和Transformer架构。

import math
import torch
import torch.nn as nn
import torch.optim as optim
import torch.nn.functional as F

1、位置编码;

        在Transformer模型中,位置编码是一个关键组件,它将关于标记位置的信息注入到输入嵌入中。

        与循环神经网络(RNNs)或卷积神经网络(CNNs)不同,Transformer 模型由于其结构性质,缺乏对序列中标记位置的内在知识。这是因为 Transformer 主要依赖于自注意力机制,该机制在处理输入序列时是置换不变的。这意味着自注意力机制本身无法区分序列中标记的位置,也就是说,它对输入序列的排列顺序不敏感。

        1、问题:缺乏位置信息:RNNs 通过其递归结构自然地捕捉序列的顺序信息,因为它们逐步处理输入序列的每个元素。CNNs 则通过卷积核和池化层在空间上逐步缩小范围,保留局部空间关系。相比之下,Transformers 的自注意力机制在处理序列时可以在任意位置之间建立依赖关系,这种特性使得它们缺乏对输入标记位置的内在感知。

        2、解决办法:位置编码:为了使 Transformer 模型能够感知输入序列中的位置信息,研究人员引入了位置编码(Positional Encoding)。位置编码是一种向量,添加到输入序列的每个标记的嵌入向量中,以提供位置信息。这些位置编码使模型能够区分序列中不同位置的标记,并按照正确的顺序处理序列。(可学习的位置编码是将位置编码作为模型参数进行学习。与固定位置编码不同,可学习的位置编码在训练过程中会根据数据自动调整,从而可能更适应特定任务和数据集。)

        3、位置编码的作用:位置编码的主要作用是将位置信息显式地注入到输入序列中,使得 Transformer 模型能够正确处理和理解序列顺序。这使得 Transformer 可以处理各种序列任务,例如机器翻译、文本生成和时间序列预测。

        代码:

import torch
import torch.nn as nn
import math

class PositionalEncoding(nn.Module):
    def __init__(self, embed_size, max_len=5000):
        super(PositionalEncoding, self).__init__()
        pe = torch.zeros(max_len, embed_size)
        position = torch.arange(0, max_len, dtype=torch.float).unsqueeze(1)
        div_term = torch.exp(torch.arange(0, embed_size, 2).float() * (-math.log(10000.0) / embed_size))
        pe[:, 0::2] = torch.sin(position * div_term)
        pe[:, 1::2] = torch.cos(position * div_term)
        pe = pe.unsqueeze(0).transpose(0, 1)
        self.register_buffer('pe', pe)

    def forward(self, x):
        x = x + self.pe[:x.size(0), :]
        return x

# 使用示例
embed_size = 512
max_len = 100
pos_encoder = PositionalEncoding(embed_size, max_len)
input_tensor = torch.randn(max_len, 1, embed_size)  # (sequence length, batch size, embed size)
output_tensor = pos_encoder(input_tensor)
print(output_tensor.shape)  # 应输出 torch.Size([100, 1, 512])

         在这个示例中,PositionalEncoding 类定义了位置编码,并在 forward 方法中将位置编码添加到输入张量上。这样,输入序列的每个标记都会有一个唯一的位置编码,使得模型能够感知和利用位置信息。

        总结:位置编码通过为 Transformer 模型提供位置信息,解决了其缺乏对序列位置的内在感知的问题。通过将位置信息注入到输入序列中,位置编码使得 Transformer 能够正确处理序列任务,并在各种自然语言处理任务中取得了显著的效果。

        位置编码的概念
        
通常在将输入嵌入传入Transformer模型之前,会将位置编码添加到嵌入中。它由一组具有不同频率和相位的正弦函数组成,允许模型根据它们在序列中的位置区分标记。

        位置编码的公式如下:

        

        不同的位置编码方案:

在Transformer中使用了各种位置编码方案,每种方案都有其优点和缺点:

  • 固定位置编码:在这种方案中,位置编码是预定义的,并对所有序列固定不变。虽然简单高效,但固定位置编码可能无法捕捉序列中的复杂模式。

  • 学习位置编码:另一种选择是在训练过程中学习位置编码,使模型能够自适应地从数据中捕捉位置信息。学习位置编码提供了更大的灵活性,但需要更多的参数和计算资源。

2、多头注意力机制

        在Transformer架构中,多头注意力机制是一个关键组件,它使模型能够同时关注输入序列的不同部分。它允许模型捕捉序列内的复杂依赖关系和关联,从而提高了语言翻译、文本生成和情感分析等任务的性能;

        多头注意力机制的重要性:

        多头注意力机制具有几个优点:

  • 并行化:通过同时关注输入序列的不同部分,多头注意力显著加快了计算速度,使其比传统的注意力机制更加高效。

  • 增强表示:每个注意力头都关注输入序列的不同方面,使模型能够捕捉各种模式和关系。这导致输入的表示更丰富、更强大,增强了模型理解和生成文本的能力

  • 改进泛化性:多头注意力使模型能够关注序列内的局部和全局依赖关系,从而提高了跨不同任务和领域的泛化性。

        多头注意力的计算:

        让我们分解计算多头注意力所涉及的步骤:

  • 线性变换:输入序列经历可学习的线性变换,将其投影到多个较低维度的表示,称为“头”。每个头关注输入的不同方面,使模型能够捕捉各种模式。

  • 缩放点积注意力:每个头独立地计算输入序列的查询、键和值表示之间的注意力分数。这一步涉及计算令牌及其上下文之间的相似度,乘以模型深度的平方根进行缩放。得到的注意力权重突出了每个令牌相对于其他令牌的重要性。

  • 连接和线性投影:来自所有头的注意力输出被连接并线性投影回原始维度。这个过程将来自多个头的见解结合起来,增强了模型理解序列内复杂关系的能力

  • 代码:

# 多头注意力的代码实现
class MultiHeadAttention(nn.Module):
    def __init__(self, d_model, num_heads):
        super(MultiHeadAttention, self).__init__()
        self.num_heads = num_heads
        self.d_model = d_model
        assert d_model % num_heads == 0
        self.depth = d_model // num_heads
        
        # 查询、键和值的线性投影
        self.query_linear = nn.Linear(d_model, d_model)
        self.key_linear = nn.Linear(d_model, d_model)
        self.value_linear = nn.Linear(d_model, d_model)
        
        # 输出线性投影
        self.output_linear = nn.Linear(d_model, d_model)
    
    def split_heads(self, x):
      batch_size, seq_length, d_model = x.size()
      return x.view(batch_size, seq_length, self.num_heads, self.depth).transpose(1, 2)
    
    def forward(self, query, key, value, mask=None):
        
        # 线性投影
        query = self.query_linear(query)
        key = self.key_linear(key)
        value = self.value_linear(value)
        
        # 分割头部
        query = self.split_heads(query)
        key = self.split_heads(key)
        value = self.split_heads(value)
        
        # 缩放点积注意力
        scores = torch.matmul(query, key.transpose(-2, -1)) / math.sqrt(self.depth)
        
        # 如果提供了掩码,则应用掩码
        if mask is not None:
            scores += scores.masked_fill(mask == 0, -1e9)
        
        # 计算注意力权重并应用softmax
        attention_weights = torch.softmax(scores, dim=-1)
        
        # 应用注意力到值
        attention_output = torch.matmul(attention_weights, value)
        
        # 合并头部
        batch_size, _, seq_length, d_k = attention_output.size()
        attention_output = attention_output.transpose(1, 2).contiguous().view(batch_size,
        seq_length, self.d_model)
        
        # 线性投影
        attention_output = self.output_linear(attention_output)
        
        return attention_output

# 示例用法
d_model = 512
max_len = 100
num_heads = 8
d_ff = 2048

# 多头注意力
multihead_attn = MultiHeadAttention(d_model, num_heads)

# 示例输入序列
input_sequence = torch.randn(5, max_len, d_model)

# 多头注意力
attention_output= multihead_attn(input_sequence, input_sequence, input_sequence)
print("attention_output shape:", attention_output.shape)

3、前馈网络

        在Transformer的背景下,前馈网络在处理信息和从输入序列中提取特征方面发挥着关键作用。它们是模型的支柱,促进了不同层之间表示的转换。

        前馈网络的作用:

        每个Transformer层内的前馈网络负责对输入表示应用非线性变换。它使模型能够捕捉数据中的复杂模式和关系,促进了高级特征的学习。

        前馈层的结构和功能:

        前馈层由两个线性变换组成,两者之间通过一个非线性激活函数(通常是ReLU)分隔。让我们来解析一下结构和功能:

  • 线性变换1:使用可学习的权重矩阵将输入表示投影到更高维度的空间中。

  • 非线性激活:第一个线性变换的输出通过非线性激活函数(例如ReLU)传递。这引入了模型的非线性,使其能够捕捉数据中的复杂模式和关系。

  • 线性变换2:激活函数的输出然后通过另一个可学习的权重矩阵投影回原始的维度空间中。

# 前馈网络的代码实现
class FeedForward(nn.Module):
    def __init__(self, d_model, d_ff):
        super(FeedForward, self).__init__()
        self.linear1 = nn.Linear(d_model, d_ff)
        self.linear2 = nn.Linear(d_ff, d_model)
        self.relu = nn.ReLU()

    def forward(self, x):
        # 线性变换1
        x = self.relu(self.linear1(x))
        
        # 线性变换2
        x = self.linear2(x)
        
        return x

# 示例用法
d_model = 512
max_len = 100
num_heads = 8
d_ff = 2048

# 多头注意力
multihead_attn = MultiHeadAttention(d_model, num_heads)

# 前馈网络
ff_network = FeedForward(d_model, d_ff)

# 示例输入序列
input_sequence = torch.randn(5, max_len, d_model)

# 多头注意力
attention_output= multihead_attn(input_sequence, input_sequence, input_sequence)

# 前馈网络
output_ff = ff_network(attention_output)
print('input_sequence',input_sequence.shape)
print("output_ff", output_ff.shape)

4、编码器:

        在Transformer模型中起着至关重要的作用,其主要任务是将输入序列转换为有意义的表示,捕捉输入的重要信息。

每个编码器层的结构和功能

        编码器由多个层组成,每个层依次包含以下组件:输入嵌入、位置编码、多头自注意力机制和位置逐点前馈网络。

  1. 输入嵌入:我们首先将输入序列转换为密集向量表示,称为输入嵌入。我们使用预训练的词嵌入或在训练过程中学习的嵌入,将输入序列中的每个单词映射到高维向量空间中。

  2. 位置编码:我们将位置编码添加到输入嵌入中,以将输入序列的顺序信息合并到其中。这使得模型能够区分序列中单词的位置,克服了传统神经网络中缺乏顺序信息的问题。

  3. 多头自注意力机制:在位置编码之后,输入嵌入通过一个多头自注意力机制。这个机制使编码器能够根据单词之间的关系权衡输入序列中不同单词的重要性。通过关注输入序列的相关部分,编码器可以捕捉长距离的依赖关系和语义关系。

  4. 位置逐点前馈网络:在自注意力机制之后,编码器对每个位置独立地应用位置逐点前馈网络。这个网络由两个线性变换组成,两者之间通过一个非线性激活函数(通常是ReLU)分隔。它有助于捕捉输入序列中的复杂模式和关系。

代码:

# 编码器的代码实现
class EncoderLayer(nn.Module):
    def __init__(self, d_model, num_heads, d_ff, dropout):
        super(EncoderLayer, self).__init__()
        self.self_attention = MultiHeadAttention(d_model, num_heads)
        self.feed_forward = FeedForward(d_model, d_ff)
        self.norm1 = nn.LayerNorm(d_model)
        self.norm2 = nn.LayerNorm(d_model)
        self.dropout = nn.Dropout(dropout)
    
    def forward(self, x, mask):
        
        # 自注意力层
        attention_output= self.self_attention(x, x,
        x, mask)
        attention_output = self.dropout(attention_output)
        x = x + attention_output
        x = self.norm1(x)
        
        # 前馈层
        feed_forward_output = self.feed_forward(x)
        feed_forward_output = self.dropout(feed_forward_output)
        x = x + feed_forward_output
        x = self.norm2(x)
        
        return x

d_model = 512
max_len = 100
num_heads = 8
d_ff = 2048


# 多头注意力
encoder_layer = EncoderLayer(d_model, num_heads, d_ff, 0.1)

# 示例输入序列
input_sequence = torch.randn(1, max_len, d_model)

# 多头注意力
encoder_output= encoder_layer(input_sequence, None)
print("encoder output shape:", encoder_output.shape)

        在 Transformer 模型中,掩码(mask)有几个关键的用途,主要是为了确保模型正确处理输入序列中的特定位置,防止不相关的信息影响注意力机制的计算。下面解释掩码的具体原因和作用:

        填充掩码(Padding Mask)

        原因: 在处理变长序列时,为了使得序列长度一致,我们通常会在较短的序列末尾添加填充标记(padding tokens)。这些填充标记并不包含有用的信息,因此在计算注意力权重时需要忽略这些位置。

        作用: 填充掩码用于屏蔽填充位置,确保这些位置的值不会对注意力计算产生影响。这可以防止模型在训练时将填充位置误认为有意义的数据,从而提高模型的性能和稳定性。

        示例: 假设输入序列 [A, B, C, <PAD>, <PAD>],其中 <PAD> 表示填充标记。掩码会确保注意力计算时忽略 <PAD> 位置,只考虑实际数据 [A, B, C]

        序列掩码(Sequence Mask)

        在自回归任务(如文本生成、翻译等)中,解码器在生成每个位置的输出时,只能使用之前生成的标记,而不能看到未来的标记。

        作用: 序列掩码用于屏蔽解码器中未来位置的信息,确保在生成第 t 个标记时,只能使用第 1 到第 t-1 个标记。这可以防止模型在训练过程中作弊,从而提高生成任务的性能。

        示例: 假设解码器在生成序列 ['X1', 'X2', 'X3'] 时,在生成 X2 时只能看到 X1,而不能看到 X3

        这样,通过使用掩码,我们可以确保模型在处理序列数据时正确忽略填充位置,只关注实际的数据,避免不相关信息的干扰,提高模型的性能和稳定性。

 5、解码器

        在Transformer模型中,解码器在基于输入序列的编码表示生成输出序列方面起着至关重要的作用。它接收来自编码器的编码输入序列,并将其用于生成最终的输出序列。

        

        解码器的功能:

        解码器的主要功能是生成输出序列,同时注意到输入序列的相关部分和先前生成的标记。它利用输入序列的编码表示来理解上下文,并对生成下一个标记做出明智的决策。

        解码器层及其组件:

        解码器层包括以下组件:

  1. 输出嵌入右移:在处理输入序列之前,模型将输出嵌入向右移动一个位置。这确保解码器中的每个标记在训练期间都能从先前生成的标记接收到正确的上下文解释:(在序列生成任务中(例如机器翻译、文本生成等),我们希望模型能够逐步生成序列中的每一个标记。假设我们有一个目标序列 [y1, y2, y3, y4],在生成标记 yt 时,我们希望模型只能使用之前生成的标记 [y1, ..., yt-1] 作为上下文,而不能看到未来的标记 [yt+1, ..., y4]。在训练过程中,我们一次性提供整个目标序列 [y1, y2, y3, y4] 给模型。训练过程中的问题:如果不做任何处理,模型在生成每个标记时都可以看到整个目标序列,这与实际推理过程不符,因为在推理过程中,模型生成每个标记时只能依赖之前生成的标记。解决方案:右移目标序列:为了模拟推理时逐步生成的过程,我们在训练时将目标序列右移一个位置,形成一个新的输入序列。这样,模型在生成第 t 个标记时,只能看到前面的 t-1 个标记,而看不到第 t 个及后面的标记。具体操作:假设目标序列是 [BOS, y1, y2, y3, EOS],其中 BOS 是序列开始标记,EOS 是序列结束标记。

    实际操作中的示例

    假设我们有一个目标序列 [1, 2, 3, 4],模型在训练时需要生成该序列。原始目标序列:[1, 2, 3, 4]。右移后的序列:[<BOS>, 1, 2, 3]。模型输入和目标输出,模型输入:[<BOS>, 1, 2, 3],目标输出:[1, 2, 3, 4];

    通过这种方式,模型在生成每个标记时,只能看到前面的标记。例如:在生成 1 时,只能看到 <BOS>。在生成 2 时,只能看到 <BOS>1。在生成 3 时,只能看到 <BOS>12。在生成 4 时,只能看到 <BOS>123。)

  2. 位置编码:与编码器类似,模型将位置编码添加到输出嵌入中,以合并标记的顺序信息。这种编码帮助解码器根据标记在序列中的位置进行区分。

  3. 掩码的多头自注意力机制:解码器采用掩码的多头自注意力机制,以便注意输入序列的相关部分和先前生成的标记。在训练期间,模型应用掩码以防止注意到未来的标记,确保每个标记只能注意到前面的标记(在 Transformer 模型中,掩码的多头自注意力机制是一个关键组件,尤其是在解码器部分。它通过引入掩码,确保每个标记在生成过程中只能关注到之前生成的标记,而不会看到未来的标记。这对于确保模型在训练和推理过程中行为一致至关重要。多头自注意力机制允许模型在输入序列中不同位置之间建立依赖关系。然而,为了确保模型在生成序列时只关注之前的标记,我们引入了掩码(mask)。)总结:输出嵌入右移:确保输入序列在每一步生成时只包含之前的标记。掩码:进一步确保注意力计算时,只关注到之前的位置。

  4. 编码器-解码器注意力机制:除了掩码的自注意力机制外,解码器还包括编码器-解码器注意力机制。这种机制使解码器能够注意到输入序列的相关部分,有助于生成受输入上下文影响的输出标记。

  5. 位置逐点前馈网络:在注意力机制之后,解码器对每个标记独立地应用位置逐点前馈网络。这个网络捕捉输入和先前生成的标记中的复杂模式和关系,有助于生成准确的输出序列。

5、Transformer 模型架构

 Transformer模型概述;

在其核心,Transformer模型由编码器和解码器模块堆叠在一起,用于处理输入序列并生成输出序列。以下是架构的高级概述:

编码器

  • 编码器模块处理输入序列,提取特征并创建输入的丰富表示。

  • 它由多个编码器层组成,每个层包含自注意力机制和前馈网络。

  • 自注意力机制允许模型同时关注输入序列的不同部分,捕捉依赖关系和关联。

  • 我们将位置编码添加到输入嵌入中,以提供有关序列中标记位置的信息。

解码器

  • 解码器模块以编码器的输出作为输入,并生成输出序列。

  • 与编码器类似,它由多个解码器层组成,每个层包含自注意力、编码器-解码器注意力和前馈网络。

  • 除了自注意力外,解码器还包含编码器-解码器注意力,以在生成输出时关注输入序列。

  • 与编码器类似,我们将位置编码添加到输入嵌入中,以提供位置信息。

连接和标准化

  • 在编码器和解码器模块的每一层之间,都有残差连接后跟层标准化。

  • 这些机制有助于在网络中流动梯度,并有助于稳定训练。

6、模型的训练与评估

        训练Transformer模型涉及优化其参数以最小化损失函数,通常使用梯度下降和反向传播。一旦训练完成,就会使用各种指标评估模型的性能,以评估其解决目标任务的有效性。

        训练过程:

  • 在训练期间,将输入序列输入模型,并生成输出序列。

  • 将模型的预测与GT进行比较,涉及使用损失函数(例如交叉熵损失)来衡量预测值与实际值之间的差异。

  • 梯度下降用于更新模型的参数,使损失最小化的方向。

  • 优化器根据这些梯度调整参数,迭代更新它们以提高模型性能。

        学习率调度:    

  • 可以应用学习率调度技术来动态调整训练期间的学习率。

  • 常见策略包括热身计划,其中学习率从低开始逐渐增加,以及衰减计划,其中学习率随时间降低。

        评估指标

        困惑度:

  • 困惑度是用于评估语言模型性能的常见指标,包括Transformer。

  • 它衡量模型对给定标记序列的预测能力。

  • 较低的困惑度值表示更好的性能,理想值接近词汇量大小。

        BLEU分数:

  • BLEU(双语评估研究)分数通常用于评估机器翻译文本的质量。

  • 它将生成的翻译与一个或多个由人类翻译人员提供的参考翻译进行比较。

  • BLEU分数范围从0到1,较高的分数表示更好的翻译质量。

Ref:一文彻底搞懂 Transformer(图解+手撕)

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

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

相关文章

JavaScript包管理器:yarn的安装与配置详解

Yarn是一个流行的JavaScript包管理器&#xff0c;它允许开发者使用代码来安装、更新和删除项目中的依赖包。Yarn的安装与配置过程相对简单&#xff0c;以下将详细说明这一过程&#xff1a; 一、Yarn的安装 Yarn的安装可以通过多种方式进行&#xff0c;主要取决于你的操作系统…

深入剖析C++的 “属性“(Attribute specifier sequence)

引言 在阅读开源项目源代码是&#xff0c;发现了一个有趣且特殊的C特性&#xff1a;属性。 属性&#xff08;attribute specifier sequences&#xff09;是在C11标准引入的。在C11之前&#xff0c;编译器特有的扩展被广泛用来提供额外的代码信息。例如&#xff0c;GNU编译器&…

3年经验的B端产品经理,应该是什么水平?

问你一个问题&#xff1a;你觉得3年经验的B端产品经理&#xff0c;应该是什么水平&#xff1f;很多朋友可能也没有仔细想过&#xff0c;自己3年后应该达到一个什么水平&#xff1f;能做什么体量的业务&#xff1f;要能拿多少薪资&#xff1f; 前几天和一个B端产品经理聊天&…

LangChain教程:构建基于GPT的应用程序

ChatGPT和GPT-4的成功表明&#xff0c;通过使用强化学习训练的大型语言模型&#xff0c;可以构建可扩展且功能强大的自然语言处理应用程序。 然而&#xff0c;响应的有用性取决于提示信息&#xff0c;这导致用户探索了提示工程领域。此外&#xff0c;大多数现实世界的自然语言…

突破AI性能瓶颈 揭秘LLaMA-MoE模型的高效分配策略

获取本文论文原文PDF&#xff0c;请在公众号【AI论文解读】留言&#xff1a;论文解读 本文介绍了一种名为“LLaMA-MoE”的方法&#xff0c;通过将现有的大型语言模型&#xff08;LLMs&#xff09;转化为混合专家网络&#xff08;MoE&#xff09;&#xff0c;从而解决了训练MoE…

3DMAX卡死也要安装的10大插件

在探索3DMAX的无限创意边界时&#xff0c;有些插件如同星辰般璀璨&#xff0c;即便面对插件偶尔的“倔强”卡顿&#xff0c;设计师们依然对其爱不释手&#xff0c;誓要将其纳入麾下。以下便是那份令人心动的“卡死也要安装”的10大插件清单&#xff0c;每个都蕴含着设计师对美的…

HKT DICT解决方案,为您量身打造全方位的一站式信息管理服务

随着大数据时代的到来&#xff0c;企业对现代化管理、数据整合与呈现的解决方案需求不断增长。为满足更多企业客户的多元化信息管理发展需求&#xff0c;香港电讯&#xff08;HKT&#xff09;强势推出全面、高效、安全、可靠的一站式DICT&#xff08;Digital Information and C…

Python数据处理之高效校验各种空值技巧详解

概要 在编程中,处理空值是一个常见且重要的任务。空值可能会导致程序异常,因此在进行数据处理时,必须确保数据的有效性。Python 提供了多种方法来处理不同数据对象的空值校验。本文将详细介绍如何对Python中的各种数据对象进行空值校验,并包含相应的示例代码,帮助全面掌握…

mipi协议中的calibration和scramble模式

在MIPI(Mobile Industry Processor Interface)协议中,calibration(校准)和scramble(加扰)模式是两个重要的特性,它们分别用于优化数据传输的准确性和减少信号干扰。以下是对这两个模式的详细解析: Calibration(校准)模式 目的与功能: 校准模式主要用于优化和补偿由…

备考无忧,张驰课堂与刷题共筑六西格玛考试坚实后盾

刷题对考中质协&#xff08;中国质量协会&#xff09;的六西格玛绿带和黑带考试具有显著的帮助&#xff0c;主要体现在以下几个方面&#xff1a; 一、巩固知识点 加深理解&#xff1a;刷题可以帮助考生更深入地理解和记忆六西格玛管理的相关知识点。通过反复练习&#xff0c;…

CAD应用程序开发工具CST CAD Navigator 1.4.0.1 正式发布—— 带来了 G 代码生成功能

CST CAD Navigator是一款兼容Windows和Linux的CAD应用程序。在其简单的界面下&#xff0c;有一个可以快速查看2D图纸和3D模型的强大核心。软件可以轻松地导入和导出文件&#xff0c;获取尺寸&#xff0c;并创建截面视图。 下载最新版CST CAD Navigatorhttps://www.evget.com/p…

七款知名电脑监控软件的介绍(2024年电脑监控软件整理推荐)

在信息化迅猛发展的今天&#xff0c;电脑监控软件成为企业管理和安全防护的重要工具。这类软件不仅有助于提高员工工作效率&#xff0c;还能防范数据泄露&#xff0c;保障企业的核心利益。以下是对几款知名电脑监控软件的介绍&#xff0c;它们在各自领域内都有出色表现。 固信…

帕金森患者营养小贴士

&#x1f44b;亲爱的小伙伴们&#xff0c;今天我要给大家带来一份特别的关怀——关于帕金森患者的营养小贴士&#x1f4d8;。帕金森病虽然是一种神经系统疾病&#xff0c;但合理的营养摄入对于患者的生活质量有着不可忽视的影响哦&#xff01;&#x1f4aa; &#x1f34e;多吃水…

如何探索高效知识管理:FlowUs知识库体验很好

在当今信息爆炸的时代&#xff0c;有效的知识管理对于个人和团队的发展至关重要。FlowUs 知识库作为一款创新的知识管理工具&#xff0c;正逐渐成为众多用户的首选&#xff0c;为他们带来了高效、便捷和有条理的知识管理体验。 FlowUs 知识库的一大特色在于其简洁直观的界面设计…

算法可以赋能教育业务的哪些场景?

本文内容就一个点&#xff0c;将算法应用到教育系统中的各场景&#xff0c;让每个业务模块都实现智能化 以下列举出所有的需求点 目录 一、千人千面&#xff0c;个性化推荐流&#xff0c;推荐用户感兴趣的内容 实现方案&#xff1a;CTR模型 应用场景&#xff1a;所有的内容…

java使用poi-tl模版引擎导出word之列表循环数据渲染

目录 1.模版制作2.开启spring表达式3.编写关键代码接口4. 导出结果 poi-tl模版引擎中&#xff0c;如果区块对的值是一个非空集合&#xff0c;区块中的文档元素会被迭代渲染一次或者N次&#xff0c;这取决于集合的大小&#xff0c;类似于foreach语法。 1.模版制作 在静态资源目…

制作电子名片的小程序系统源码 快速生成电子名片

在当今数字化时代&#xff0c;传统的纸质名片已逐渐被智能电子名片所取代。电子名片小程序作为一种基于微信生态的创新名片交换方式&#xff0c;凭借其便捷性、高效性和环保性&#xff0c;成为了众多商务人士的首选。小编分享一个制作电子名片的小程序系统源码&#xff0c;无忧…

【pyqt-实训训练LOG】串口助手

串口助手 前言一、ui设计二、ui的控件命名三、ui转py使用类的方法【扩展】使用ui文件导入&#xff01;P7的小错误解决办法 总结 前言 我的惯例就是万物之始&#xff0c;拜见吾师&#x1f970;⇨pyqt串口合集 最开始的时候我想的是&#xff0c;学了那么久的pyqt&#xff0c;我…

逻辑芯片:现代电子技术的基石

在现代科技飞速发展的时代&#xff0c;逻辑芯片作为集成电路的重要组成部分&#xff0c;已经渗透到我们生活的每一个角落&#xff0c;从计算机到智能手机&#xff0c;从通信设备到工业自动化系统&#xff0c;无一不彰显着其不可或缺的作用。本文将深入探讨逻辑芯片的基本概念、…

如何判断一个js对象为数组类型

如何判断一个js对象为数组类型? 能想到的最常见的intanceof是吗?开始是这么认为,但是不是哈,看下面的解释,也没有太明白,暂且记住吧 综上,判断js对象为数组的两种方式 Array.isArray([]) // trueObject.prototype.toString.call([]) ‘[object Array]’ //true