三种Transformer模型中的注意力机制介绍及Pytorch实现:从自注意力到因果自注意力

注意力机制模块 阅读详情

本文深入探讨Transformer模型中三种关键的注意力机制:自注意力、交叉注意力和因果自注意力。这些机制是GPT-4、Llama等大型语言模型(LLMs)的核心组件。通过理解这些注意力机制,我们可以更好地把握这些模型的工作原理和应用潜力。

我们不仅会讨论理论概念,还将使用Python和PyTorch从零开始实现这些注意力机制。通过实际编码,我们可以更深入地理解这些机制的内部工作原理。

文章目录

  1. 自注意力机制
  • 理论基础

  • PyTorch实现

  • 多头注意力扩展

  1. 交叉注意力机制
  • 概念介绍

  • 与自注意力的区别

  • PyTorch实现

  1. 因果自注意力机制
  • 在语言模型中的应用

  • 实现细节

  • 优化技巧

通过这种结构,我们将逐步深入每种注意力机制从理论到实践提供全面的理解。让我们首先从自注意力机制开始,这是Transformer架构的基础组件。

自注意力概述

自注意力机制自2017年在开创性论文《Attention Is All You Need》中被提出以来,已成为最先进深度学习模型的核心,尤其是在自然语言处理(NLP)领域。考虑到其广泛应用,深入理解自注意力的运作机制变得尤为重要。

在这里插入图片描述

图1:原始Transformer架构

在深度学习中,"注意力"概念的引入最初是为了改进递归神经网络(RNNs)处理长序列或句子的能力。例如,在机器翻译任务中,逐字翻译通常无法捕捉语言的复杂语法和表达方式,导致翻译质量低下。

为解决这一问题,注意力机制使模型能够在每个步骤考虑整个输入序列,有选择地关注上下文中最相关的部分。2017年引入的Transformer架构进一步发展了这一概念,将自注意力作为独立机制整合,使得RNNs不再必要。

图2:注意力机制可视化

自注意力允许模型通过整合上下文信息来增强输入嵌入,使其能够动态地权衡序列中不同元素的重要性。这一特性在NLP中尤其有价值,因为词语的含义往往随其在句子或文档中的上下文而变化。

尽管已提出多种高效版本的自注意力,但《Attention Is All You Need》中引入的原始缩放点积注意力机制仍然是应用最广泛的。由于其在大规模Transformer模型中表现出色的实际性能和计算效率,它仍然是许多模型的基础。

输入句子嵌入

在深入探讨自注意力机制之前,我们先通过一个示例句子"The sun rises in the east"来演示操作过程。与其他文本处理模型(如递归或卷积神经网络)类似,第一步是创建句子嵌入。

为简化说明,我们的字典dc仅包含输入句子中的单词。在实际应用中,字典通常从更大的词汇表构建,一般包含30,000到50,000个单词。

 sentence = 'The sun rises in the east'    
   
 dc = {s:i for i,s in enumerate(sorted(sentence.split()))}    
   
 print(dc)

输出:

 {'The': 0, 'east': 1, 'in': 2, 'rises': 3, 'sun': 4, 'the': 5}

接下来,我们使用这个字典将句子中的每个单词转换为其对应的整数索引。

 import torch    
   
 sentence_int = torch.tensor(    
    [dc[s] for s in sentence.split()]    
 )    
 print(sentence_int)

输出:

 tensor([0, 4, 3, 2, 5, 1])

有了这个输入句子的整数表示,可以使用嵌入层将每个单词转换为向量。为简化演示,我们这里使用3维嵌入,但在实际应用中,嵌入维度通常要大得多(例如,Llama 2模型中使用4,096维)。较小的维度有助于直观理解向量而不会使页面充满数字。

由于句子包含6个单词,嵌入将生成一个6×3维矩阵。

 vocab_size = 50_000    
   
 torch.manual_seed(123)    
 embed = torch.nn.Embedding(vocab_size, 3)    
 embedded_sentence = embed(sentence_int).detach()    
   
 print(embedded_sentence)    
 print(embedded_sentence.shape)

输出:

 tensor([[ 0.3374, -0.1778, -0.3035],    
        [ 0.1794, 1.8951, 0.4954],    
        [ 0.2692, -0.0770, -1.0205],    
        [-0.2196, -0.3792, 0.7671],    
        [-0.5880, 0.3486, 0.6603],    
        [-1.1925, 0.6984, -1.4097]])    
 torch.Size([6, 3])

这个6×3矩阵表示输入句子的嵌入版本,每个单词被编码为一个3维向量。虽然实际模型中的嵌入维度通常更高,但这个简化示例有助于我们理解嵌入的工作原理。

缩放点积注意力的权重矩阵

完成输入嵌入后,首先探讨自注意力机制,特别是广泛使用的_缩放点积注意力_,这是Transformer模型的核心元素。

缩放点积注意力机制使用三个权重矩阵:Wq、Wk和Wv。这些矩阵在模型训练过程中优化,用于转换输入数据。

查询、键和值的转换

权重矩阵将输入数据投影到三个组成部分:

  1. 查询 (q)

  2. 键 (k)

  3. 值 (v)

这些组成部分通过矩阵乘法计算得出:

  • 查询:q(i) = x(i)Wq

  • 键:k(i) = x(i)Wk

  • 值:v(i) = x(i)Wv

这里,'i’表示输入序列中长度为T的token位置。

在这里插入图片描述

图3:通过输入x和权重W计算查询、键和值向量

这个操作实际上是将每个输入token x(i)投影到这三个不同的空间中。

关于维度,q(i)和k(i)都是具有dk个元素的向量。投影矩阵Wq和Wk的形状为d × dk,而Wv为d × dv。这里,d是每个词向量x的大小。

需要注意的是q(i)和k(i)必须具有相同数量的元素(dq = dk),因为后续会计算它们的点积。许多大型语言模型为简化设置dq = dk = dv,但v(i)的大小可以根据需要不同。

以下是一个代码示例:

 torch.manual_seed(123)    
   
 d = embedded_sentence.shape[1]    
   
 d_q, d_k, d_v = 2, 2, 4    
   
 W_query = torch.nn.Parameter(torch.rand(d, d_q))    
 W_key = torch.nn.Parameter(torch.rand(d, d_k))    
 W_value = torch.nn.Parameter(torch.rand(d, d_v))

在这个例子中将dq和dk设置为2,dv设置为4。实际应用中这些维度通常要大得多,这里使用小数值是为了便于理解概念。

通过操作这些矩阵和维度,可以控制模型如何关注输入的不同部分从而捕捉数据中的复杂关系和依赖性。

计算自注意力机制中的非归一化注意力权重

在自注意力机制中,计算非归一化注意力权重是一个关键步骤。下面将以输入序列的第三个元素(索引为2)作为查询来演示这个过程。

首先将这个输入元素投影到查询、键和值空间:

 x_3 = embedded_sentence[2]  # 第三个元素(索引2)  
 query_3 = x_3 @ W_query    
 key_3 = x_3 @ W_key    
 value_3 = x_3 @ W_value    
   
 print("Query shape:", query_3.shape)    
 print("Key shape:", key_3.shape)    
 print("Value shape:", value_3.shape)

输出:

Query shape: torch.Size([2])    
Key shape: torch.Size([2])    
Value shape: torch.Size([4])  

这些形状与我们之前设定的d_q = d_k = 2和d_v = 4相符。接下来计算所有输入元素的键和值:

keys = embedded_sentence @ W_key    
values = embedded_sentence @ W_value    
  
print("All keys shape:", keys.shape)    
print("All values shape:", values.shape)  

输出:

All keys shape: torch.Size([6, 2])    
All values shape: torch.Size([6, 4])  

计算非归一化注意力权重。这是通过查询与每个键的点积来实现的。以query_3为例:

omega_3 = query_3 @ keys.T    
print("Unnormalized attention weights for query 3:")    
print(omega_3)  

输出:

Unnormalized attention weights for query 3:    
tensor([ 0.8721, -0.5302,  2.1436, -1.7589,  0.9103,  1.3245])  

这六个值表示我们的第三个输入(查询)与序列中每个输入的兼容性得分。

为了更好地理解这些得分的含义,我们来看最高和最低的得分:

max_score = omega_3.max()    
min_score = omega_3.min()    
max_index = omega_3.argmax()    
min_index = omega_3.argmin()    
  
print(f"Highest compatibility: {max_score:.4f} with input {max_index+1}")    
print(f"Lowest compatibility: {min_score:.4f} with input {min_index+1}")  

输出:

Highest compatibility: 2.1436 with input 3    
Lowest compatibility: -1.7589 with input 4  

值得注意的是,第三个输入(我们的查询)与自身具有最高的兼容性。这在自注意力中是常见的,因为一个输入通常包含与其自身上下文高度相关的信息。而在这个例子中,第四个输入与我们的查询似乎关联性最低。

这些非归一化的注意力权重提供了一个原始度量,表示每个输入应如何影响我们查询输入的表示。它们捕捉了输入序列不同部分之间的初始关系,为模型理解数据中的复杂依赖关系奠定了基础。

在实际应用中,这些得分会进一步经过处理(如softmax归一化)以得到最终的注意力权重,但这个初始步骤在确定每个输入元素的相对重要性方面起着关键作用。

注意力权重归一化与上下文向量计算

计算非归一化注意力权重(ω)后,自注意力机制的下一个关键步骤是对这些权重进行归一化,并利用它们计算上下文向量。这个过程使模型能够聚焦于输入序列中最相关的部分。

我们首先对非归一化注意力权重进行归一化。使用softmax函数并按1/√(dk)进行缩放,其中dk是键向量的维度:

import torch.nn.functional as F    
  
d_k = 2  # 键向量的维度    
omega_3 = query_3 @ keys.T  # 使用前面的例子    
  
attention_weights_3 = F.softmax(omega_3 / d_k**0.5, dim=0)    
print("Normalized attention weights for input 3:")    
print(attention_weights_3)  

输出:

Normalized attention weights for input 3:    
tensor([0.1834, 0.0452, 0.6561, 0.0133, 0.1906, 0.2885])  

缩放(1/√dk)至关有助于在模型深度增加时维持梯度的合适大小,促进稳定训练。如果没有这种缩放点积可能会变得过大,将softmax函数推入梯度极小的区域。

下面解释这些归一化权重:

max_weight = attention_weights_3.max()    
max_weight_index = attention_weights_3.argmax()    
  
print(f"Input {max_weight_index+1} has the highest attention weight: {max_weight:.4f}")  

输出:

Input 3 has the highest attention weight: 0.6561  

可以看到第三个输入(我们的查询)获得了最高的注意力权重,这在自注意力机制中是常见的现象。

最后一步是计算上下文向量。这个向量是值向量的加权和,其中权重是我们归一化的注意力权重:

context_vector_3 = attention_weights_3 @ values    
  
print("Context vector shape:", context_vector_3.shape)    
print("Context vector:")    
print(context_vector_3)  

输出:

Context vector shape: torch.Size([4])    
Context vector:    
tensor([0.6237, 0.9845, 1.0523, 1.2654])  

这个上下文向量代表了原始输入(在这里是x(3))经过所有其他输入信息的丰富,这些信息根据注意力机制确定的相关性进行加权。

我们的上下文向量有4个维度,这与之前选择的dv = 4相匹配。这个维度可以独立于输入维度选择,为模型设计提供了灵活性。

这样就已经将原始输入转换为一个上下文感知的表示。这个向量不仅包含了来自输入本身的信息,还包含了来自整个序列的相关信息,这些信息根据计算出的注意力分数进行加权。这种能够动态关注输入相关部分的能力是Transformer模型在处理序列数据时表现卓越的关键原因。

自注意力的PyTorch实现

为了便于集成到更大的神经网络架构中,可以将自注意力机制封装为一个PyTorch模块。以下是SelfAttention类的实现,它包含了我们之前讨论的整个自注意力过程:

import torch    
import torch.nn as nn    
  
class SelfAttention(nn.Module):    
    def __init__(self, d_in, d_out_kq, d_out_v):    
        super().__init__()    
        self.d_out_kq = d_out_kq    
        self.W_query = nn.Parameter(torch.rand(d_in, d_out_kq))    
        self.W_key = nn.Parameter(torch.rand(d_in, d_out_kq))    
        self.W_value = nn.Parameter(torch.rand(d_in, d_out_v))    
    
    def forward(self, x):    
        keys = x @ self.W_key    
        queries = x @ self.W_query    
        values = x @ self.W_value    
            
        attn_scores = queries @ keys.T    
        attn_weights = torch.softmax(    
            attn_scores / self.d_out_kq**0.5, dim=-1    
        )    
            
        context_vec = attn_weights @ values    
        return context_vec  

这个类封装了以下步骤:

  1. 将输入投影到键、查询和值空间

  2. 计算注意力分数

  3. 缩放和归一化注意力权重

  4. 生成最终的上下文向量

关键组件说明:

  • 在__init__中,我们将权重矩阵初始化为nn.Parameter对象,使PyTorch能够在训练过程中自动跟踪和更新它们。

  • forward方法以简洁的方式实现了整个自注意力过程。

  • 我们使用@运算符进行矩阵乘法,这等同于torch.matmul。

  • 缩放因子self.d_out_kq**0.5在softmax之前应用,如前所述。

使用这个SelfAttention模块示例如下:

torch.manual_seed(123)    
  
d_in, d_out_kq, d_out_v = 3, 2, 4    
  
sa = SelfAttention(d_in, d_out_kq, d_out_v)    
  
# 假设embedded_sentence是我们的输入张量    
output = sa(embedded_sentence)    
print(output)  

输出:

tensor([[-0.1564,  0.1028, -0.0763, -0.0764],    
        [ 0.5313,  1.3607,  0.7891,  1.3110],    
        [-0.3542, -0.1234, -0.2627, -0.3706],    
        [ 0.0071,  0.3345,  0.0969,  0.1998],    
        [ 0.1008,  0.4780,  0.2021,  0.3674],    
        [-0.5296, -0.2799, -0.4107, -0.6006]], grad_fn=<MmBackward0>)  

这个输出张量中的每一行代表相应输入token的上下文向量。值得注意的是,第二行[0.5313, 1.3607, 0.7891, 1.3110]与我们之前为第二个输入元素计算的结果一致。

这个实现高效且可并行处理所有输入token。它还具有灵活性,我们可以通过调整d_out_kq和d_out_v参数轻松改变键/查询和值投影的维度。

多头注意力机制:自注意力的高级扩展

图4:原始Transformer架构中的多头注意力模块

多头注意力机制是对前面探讨的自注意力机制的一个强大扩展。它允许模型在不同位置同时关注来自不同表示子空间的信息。下面我们将详细分析这个概念并实现它。

多头注意力的核心概念

多头注意力机制的主要特点包括:

  1. 创建多组查询、键和值权重矩阵。

  2. 每组矩阵形成一个"注意力头"。

  3. 每个头可能关注输入序列的不同方面。

  4. 所有头的输出被连接并进行线性变换,生成最终输出。

这种方法使模型能够同时捕捉数据中的多种类型的关系和模式。

多头注意力的实现

以下是MultiHeadAttentionWrapper类的实现,它利用了我们之前定义的SelfAttention类:

class MultiHeadAttentionWrapper(nn.Module):    
    def __init__(self, d_in, d_out_kq, d_out_v, num_heads):    
        super().__init__()    
        self.heads = nn.ModuleList(    
            [SelfAttention(d_in, d_out_kq, d_out_v)     
             for _ in range(num_heads)]    
        )    
    
    def forward(self, x):    
        return torch.cat([head(x) for head in self.heads], dim=-1)  

使用这个多头注意力包装器:

torch.manual_seed(123)    
  
d_in, d_out_kq, d_out_v = 3, 2, 1    
num_heads = 4    
  
mha = MultiHeadAttentionWrapper(d_in, d_out_kq, d_out_v, num_heads)    
  
context_vecs = mha(embedded_sentence)    
  
print(context_vecs)    
print("context_vecs.shape:", context_vecs.shape)  

输出:

tensor([[-0.0185,  0.0170,  0.1999, -0.0860],    
        [ 0.4003,  1.7137,  1.3981,  1.0497],    
        [-0.1103, -0.1609,  0.0079, -0.2416],    
        [ 0.0668,  0.3534,  0.2322,  0.1008],    
        [ 0.1180,  0.6949,  0.3157,  0.2807],    
        [-0.1827, -0.2060, -0.2393, -0.3167]], grad_fn=<CatBackward0>)    
context_vecs.shape: torch.Size([6, 4])  

多头注意力的优势

  1. 多样化特征学习:每个头可以学习关注输入的不同方面。例如,一个头可能专注于局部关系而另一个可能捕捉长距离依赖。

  2. 增强模型容量:多个头允许模型表示数据中更复杂的关系,而不显著增加参数数量。

  3. 并行处理效率:每个头的独立性使得在GPU或TPU上能进行高效的并行计算。

  4. 提高模型稳定性和鲁棒性:使用多个头可以使模型更加鲁棒,因为它不太可能过度拟合单一注意力机制捕捉到的特定模式。

多头注意力与单头大输出的比较

虽然增加单个自注意力头的输出维度(例如,在单个头中设置d_out_v = 4)可能看起来与使用多个头相似,但它们之间存在关键差异:

  1. 独立学习能力:多头注意力中的每个头学习自己的查询、键和值投影集,允许更多样化的特征提取。

  2. 计算效率优势:多头注意力可以更高效地并行化,可能导致更快的训练和推理速度。

  3. 集成学习效果:多个头的作用类似于注意力机制的集成,每个头可能专门处理输入的不同方面。

实际应用考虑

在实际应用中,注意力头的数量是一个可调整的超参数。例如,7B参数的Llama 2模型使用32个注意力头。头的数量选择通常取决于特定任务、模型大小和可用的计算资源。

通过利用多头注意力机制,Transformer模型能够捕捉输入数据中的丰富关系集,这是它们在各种自然语言处理任务中表现卓越的关键因素。

交叉注意力:连接不同输入序列的桥梁

交叉注意力是注意力机制的一个强大变体,它允许模型处理来自两个不同输入序列的信息。这在需要一个序列为另一个序列的处理提供信息或指导的场景中特别有用。接下来将深入探讨交叉注意力的概念和实现。

交叉注意力的核心概念

交叉注意力的主要特点包括:

  1. 处理两个不同的输入序列。

  2. 查询由一个序列生成,而键和值来自另一个序列。

  3. 允许模型基于另一个序列的内容有选择地关注一个序列的部分。

交叉注意力的实现

以下是CrossAttention类的实现:

class CrossAttention(nn.Module):    
    def __init__(self, d_in, d_out_kq, d_out_v):    
        super().__init__()    
        self.d_out_kq = d_out_kq    
        self.W_query = nn.Parameter(torch.rand(d_in, d_out_kq))    
        self.W_key = nn.Parameter(torch.rand(d_in, d_out_kq))    
        self.W_value = nn.Parameter(torch.rand(d_in, d_out_v))    
    
    def forward(self, x_1, x_2):    
        queries_1 = x_1 @ self.W_query    
        keys_2 = x_2 @ self.W_key    
        values_2 = x_2 @ self.W_value    
            
        attn_scores = queries_1 @ keys_2.T    
        attn_weights = torch.softmax(    
            attn_scores / self.d_out_kq**0.5, dim=-1)    
            
        context_vec = attn_weights @ values_2    
        return context_vec  

使用这个交叉注意力模块:

torch.manual_seed(123)    
  
d_in, d_out_kq, d_out_v = 3, 2, 4    
  
crossattn = CrossAttention(d_in, d_out_kq, d_out_v)    
  
first_input = embedded_sentence    
second_input = torch.rand(8, d_in)    
  
print("First input shape:", first_input.shape)    
print("Second input shape:", second_input.shape)    
  
context_vectors = crossattn(first_input, second_input)    
  
print(context_vectors)    
print("Output shape:", context_vectors.shape)  

输出:

First input shape: torch.Size([6, 3])    
Second input shape: torch.Size([8, 3])    
tensor([[0.4231, 0.8665, 0.6503, 1.0042],    
        [0.4874, 0.9718, 0.7359, 1.1353],    
        [0.4054, 0.8359, 0.6258, 0.9667],    
        [0.4357, 0.8886, 0.6678, 1.0311],    
        [0.4429, 0.9006, 0.6775, 1.0460],    
        [0.3860, 0.8021, 0.5985, 0.9250]], grad_fn=<MmBackward0>)    
Output shape: torch.Size([6, 4])  

交叉注意力与自注意力的主要区别

  1. 双输入序列:交叉注意力接受两个输入,x_1和x_2,而不是单一输入。

  2. 查询-键交互方式:查询来自x_1,而键和值来自x_2。

  3. 序列长度灵活性:两个输入序列可以具有不同的长度。

交叉注意力的应用领域

  1. 机器翻译:在原始Transformer模型中,交叉注意力允许解码器在生成翻译时关注源句子的相关部分。

  2. 图像描述生成:模型可以在生成描述的每个词时关注图像的不同部分(表示为图像特征序列)。

  3. Stable Diffusion模型:交叉注意力用于将图像生成与文本提示相关联,允许模型将文本信息整合到视觉生成过程中。

  4. 问答系统:模型可以根据问题的内容关注上下文段落的不同部分。

交叉注意力的优势

  1. 信息整合能力:允许模型有选择地将一个序列的信息整合到另一个序列的处理中。

  2. 处理多模态输入的灵活性:可以处理不同长度和模态的输入。

  3. 增强可解释性:注意力权重可以提供洞察,说明模型如何关联两个序列的不同部分。

实际应用中的考虑因素

  • 嵌入维度(d_in)必须对两个输入序列保持一致,即使它们的长度不同。

  • 对于长序列,交叉注意力可能计算密集,需要考虑计算效率。

  • 与自注意力类似,交叉注意力也可以扩展到多头版本,以获得更强的表达能力。

交叉注意力是一个多功能工具,使模型能够处理来自多个来源或模态的信息,这在许多高级AI应用中至关重要。它能够动态关注不同输入之间的相关信息,这显著促进了模型在需要整合多样信息源的任务中的成功。

Stable Diffusion模型也利用了交叉注意力机制。在该模型中交叉注意力发生在U-Net架构内生成的图像特征和用于指导的文本提示之间。这种技术最初在介绍Stable Diffusion概念的论文《High-Resolution Image Synthesis with Latent Diffusion Models》中被提出。随后Stability AI采用了这种方法来实现广受欢迎的Stable Diffusion模型。

因果自注意力

图7:原始Transformer架构中的因果自注意力模块(来源:“Attention Is All You Need”)

我们下面介绍如何将先前探讨的自注意力机制调整为因果自注意力机制,这种机制特别适用于GPT类(解码器风格)的大型语言模型(LLMs)进行文本生成。这种机制也被称为"掩码自注意力"。在原始Transformer架构中,它对应于"掩码多头注意力"模块。为了简化说明将重点关注单个注意力头,但这个概念同样适用于多头注意力。

因果自注意力确保给定位置的输出仅基于序列中前面位置的已知输出,而不依赖于后续位置的信息。简而言之,在预测每个下一个词时,模型应该只考虑之前的词。为了在GPT类LLM中实现这一点,我们对输入文本中每个被处理的token的未来token进行掩码处理。

为了说明这个过程,让我们考虑一个训练文本样本:“The cat sits on the mat”。在因果自注意力中,我们会有以下设置,其中箭头右侧的单词的上下文向量应该只包含自身和前面的单词:

“The” → “cat”“The cat” → “sits”“The cat sits” → “on”“The cat sits on” → “the”“The cat sits on the” → “mat”

这种设置确保在生成文本时,模型只使用在生成过程的每个步骤中可用的信息。

回顾前面自注意力部分的注意力分数计算:

torch.manual_seed(123)    
  
d_in, d_out_kq, d_out_v = 3, 2, 4    
  
W_query = nn.Parameter(torch.rand(d_in, d_out_kq))    
W_key = nn.Parameter(torch.rand(d_in, d_out_kq))    
W_value = nn.Parameter(torch.rand(d_in, d_out_v))    
  
x = embedded_sentence    
  
keys = x @ W_key    
queries = x @ W_query    
values = x @ W_value    
  
attn_scores = queries @ keys.T     
  
print(attn_scores)    
print(attn_scores.shape)  

输出:

tensor([[ 0.0613, -0.3491,  0.1443, -0.0437, -0.1303,  0.1076],    
        [-0.6004,  3.4707, -1.5023,  0.4991,  1.2903, -1.3374],    
        [ 0.2432, -1.3934,  0.5869, -0.1851, -0.5191,  0.4730],    
        [-0.0794,  0.4487, -0.1807,  0.0518,  0.1677, -0.1197],    
        [-0.1510,  0.8626, -0.3597,  0.1112,  0.3216, -0.2787],    
        [ 0.4344, -2.5037,  1.0740, -0.3509, -0.9315,  0.9265]],    
       grad_fn=<MmBackward0>)    
torch.Size([6, 6])  

得到了一个6x6的张量,表示6个输入token的成对非归一化注意力权重(注意力分数)。

接下来通过softmax函数计算缩放点积注意力:

attn_weights = torch.softmax(attn_scores / d_out_kq**0.5, dim=1)    
print(attn_weights)  

输出:

tensor([[0.1772, 0.1326, 0.1879, 0.1645, 0.1547, 0.1831],    
        [0.0386, 0.6870, 0.0204, 0.0840, 0.1470, 0.0229],    
        [0.1965, 0.0618, 0.2506, 0.1452, 0.1146, 0.2312],    
        [0.1505, 0.2187, 0.1401, 0.1651, 0.1793, 0.1463],    
        [0.1347, 0.2758, 0.1162, 0.1621, 0.1881, 0.1231],    
        [0.1973, 0.0247, 0.3102, 0.1132, 0.0751, 0.2794]],    
       grad_fn=<SoftmaxBackward0>)  

要实现因果自注意力,需要掩盖所有未来的token。最直接的方法是在对角线上方对注意力权重矩阵应用掩码。我们可以使用PyTorch的tril函数来实现这一点:

block_size = attn_scores.shape[0]    
mask_simple = torch.tril(torch.ones(block_size, block_size))    
print(mask_simple)  

输出:

tensor([[1., 0., 0., 0., 0., 0.],    
        [1., 1., 0., 0., 0., 0.],    
        [1., 1., 1., 0., 0., 0.],    
        [1., 1., 1., 1., 0., 0.],    
        [1., 1., 1., 1., 1., 0.],    
        [1., 1., 1., 1., 1., 1.]])  

现在将注意力权重与这个掩码相乘,以将对角线上方的所有注意力权重置零:

masked_simple = attn_weights * mask_simple    
print(masked_simple)  

输出:

tensor([[0.1772, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000],    
        [0.0386, 0.6870, 0.0000, 0.0000, 0.0000, 0.0000],    
        [0.1965, 0.0618, 0.2506, 0.0000, 0.0000, 0.0000],    
        [0.1505, 0.2187, 0.1401, 0.1651, 0.0000, 0.0000],    
        [0.1347, 0.2758, 0.1162, 0.1621, 0.1881, 0.0000],    
        [0.1973, 0.0247, 0.3102, 0.1132, 0.0751, 0.2794]],    
       grad_fn=<MulBackward0>)  

但是这种方法导致每一行的注意力权重之和不再等于1。为了解决这个问题还需要对行进行归一化:

row_sums = masked_simple.sum(dim=1, keepdim=True)    
masked_simple_norm = masked_simple / row_sums    
print(masked_simple_norm)  

输出:

tensor([[1.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000],    
        [0.0532, 0.9468, 0.0000, 0.0000, 0.0000, 0.0000],    
        [0.3862, 0.1214, 0.4924, 0.0000, 0.0000, 0.0000],    
        [0.2232, 0.3242, 0.2078, 0.2449, 0.0000, 0.0000],    
        [0.1536, 0.3145, 0.1325, 0.1849, 0.2145, 0.0000],    
        [0.1973, 0.0247, 0.3102, 0.1132, 0.0751, 0.2794]],    
       grad_fn=<DivBackward0>)  

现在每一行的注意力权重之和都等于1,符合注意力权重的标准规范。

有一种更高效的方法来实现相同的结果,可以在应用softmax之前对注意力分数进行掩码,而不是在之后对注意力权重进行掩码:

mask = torch.triu(torch.ones(block_size, block_size), diagonal=1)    
masked = attn_scores.masked_fill(mask.bool(), float('-inf'))    
print(masked)  

输出:

tensor([[ 0.0613,    -inf,    -inf,    -inf,    -inf,    -inf],    
        [-0.6004,  3.4707,    -inf,    -inf,    -inf,    -inf],    
        [ 0.2432, -1.3934,  0.5869,    -inf,    -inf,    -inf],    
        [-0.0794,  0.4487, -0.1807,  0.0518,    -inf,    -inf],    
        [-0.1510,  0.8626, -0.3597,  0.1112,  0.3216,    -inf],    
        [ 0.4344, -2.5037,  1.0740, -0.3509, -0.9315,  0.9265]],    
       grad_fn=<MaskedFillBackward0>)  

现在应用softmax来获得最终的注意力权重:

attn_weights = torch.softmax(masked / d_out_kq**0.5, dim=1)    
print(attn_weights)  

输出:

tensor([[1.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000],    
        [0.0532, 0.9468, 0.0000, 0.0000, 0.0000, 0.0000],    
        [0.3862, 0.1214, 0.4924, 0.0000, 0.0000, 0.0000],    
        [0.2232, 0.3242, 0.2078, 0.2449, 0.0000, 0.0000],    
        [0.1536, 0.3145, 0.1325, 0.1849, 0.2145, 0.0000],    
        [0.1973, 0.0247, 0.3102, 0.1132, 0.0751, 0.2794]],    
       grad_fn=<SoftmaxBackward0>)  

这种方法更加高效,因为它避免了对掩码位置进行不必要的计算,并且不需要重新归一化。softmax函数有效地将-inf值视为零概率,因为e^(-inf)趋近于0。

通过这种方式实现因果自注意力可以确保了语言模型能够以从左到右的方式生成文本,在预测每个新token时只考虑先前的上下文。这对于在文本生成任务中产生连贯和上下文适当的序列至关重要。

总结

在本文中,我们深入探讨了自注意力机制的内部工作原理,通过实际编码来理解其实现。并以此为基础研究了多头注意力,这是大型语言Transformer模型的核心组件。

我们还扩展了讨论范围,探索了交叉注意力(自注意力的一个变体),特别适用于两个不同序列之间的信息交互。这种机制在机器翻译或图像描述等任务中特别有用,其中一个领域的信息需要指导另一个领域的处理。

最后,深入研究了因果自注意力,这是解码器风格LLM(如GPT和Llama)生成连贯和上下文适当序列的关键概念。这种机制确保模型的预测仅基于先前的token,模仿自然语言生成的从左到右的特性。

最后:本文中呈现的代码主要用于说明目的。在实际训练LLM时,自注意力的实现通常使用优化版本。例如,Flash Attention等技术显著减少了内存占用和计算负载,使大型模型的训练更加高效。

​

如何学习AI大模型?

作为一名热心肠的互联网老兵,我决定把宝贵的AI知识分享给大家。 至于能学习到多少就看你的学习毅力和能力了 。我已将重要的AI大模型资料包括AI大模型入门学习思维导图、精品AI大模型学习书籍手册、视频教程、实战学习等录播视频免费分享出来。

这份完整版的大模型 AI 学习资料已经上传优快云,朋友们如果需要可以微信扫描下方优快云官方认证二维码免费领取【保证100%免费】

一、全套AGI大模型学习路线

AI大模型时代的学习之旅:从基础到前沿,掌握人工智能的核心技能!

img

二、640套AI大模型报告合集

这套包含640份报告的合集,涵盖了AI大模型的理论研究、技术实现、行业应用等多个方面。无论您是科研人员、工程师,还是对AI大模型感兴趣的爱好者,这套报告合集都将为您提供宝贵的信息和启示。

img

三、AI大模型经典PDF籍

随着人工智能技术的飞速发展,AI大模型已经成为了当今科技领域的一大热点。这些大型预训练模型,如GPT-3、BERT、XLNet等,以其强大的语言理解和生成能力,正在改变我们对人工智能的认识。 那以下这些PDF籍就是非常不错的学习资源。

img

四、AI大模型商业化落地方案

img

作为普通人,入局大模型时代需要持续学习和实践,不断提高自己的技能和认知水平,同时也需要有责任感和伦理意识,为人工智能的健康发展贡献力量。

Ubuntu零基础入门到精通【1.1讲】:什么是 Ubuntu?一文带你彻底搞懂! 🏆 本文收录于 《滚雪球学 Ubuntu》 专栏。 本专栏面向有一定计算机基础,但尚未系统学习 Linux / Ubuntu 的读者,采用“滚雪球式学习法”:先装好、再会用、再理解、再优化、再实战,带你从第一次进入 Ubuntu 桌面 / 终端开始,逐步掌握 Ubuntu 的日常使用、命令操作、软件安装、系统配置、开发环境搭建与服务器部署能力。 阅读详情

相关推荐

STM32H743VIT6最小系统板PCB设计全流程(AD09实战教程+封装库分享)

本文详细介绍了基于STM32H743VIT6高性能MCU的最小系统板PCB设计全流程。内容涵盖从项目规划、原理图设计到PCB布局布线的AD09实战操作,重点解析了高速电路设计中的电源、时钟、去耦等关键模块的处理要点与常见陷阱,并分享了经过验证的封装库资源,旨在为工程师提供一套完整、可靠的设计方法与实战参考。

weixin_29194693的博客 119

【计算机视觉 | 注意力机制】13种即插即用涨点模块分享!含注意力机制、卷积变体、Transformer变体等

【计算机视觉 | 注意力机制】13种即插即用涨点模块分享!含注意力机制、卷积变体、Transformer变体等

wzk4869的博客 1万+

AI风控系统中的实时决策架构:架构师的关键设计

当用户点击「确认支付」时,一场毫秒级的“欺诈攻防战”正在后台悄然打响:系统需要在100ms内完成用户行为特征提取→欺诈模型推理→规则引擎校验→最终决策返回。这就是AI风控实时决策架构的核心——用技术对抗“实时化的欺诈手段”。本文将以「餐厅智能点餐系统」为类比,拆解实时风控架构的每一层逻辑:从“如何快速拿到用户的实时行为特征”(像服务员实时收集顾客的忌口),到“如何让模型和规则协同决策”(像厨师长结合菜谱和经验判断菜能不能做),再到“如何保证系统扛住大促的高并发”(像餐厅加桌子应对客流高峰)。我们会用。

2502_91592937的博客 1472

注意力模块

注意力机制

weixin_64043217的博客 1万+

立创EDA实战:基于NE555的夜间氛围呼吸灯电路设计与模式切换

本文详细介绍了使用立创EDA设计基于NE555芯片的夜间氛围呼吸灯电路。项目核心是利用NE555产生PWM信号,并通过RC充放电电路实现LED亮度的缓慢周期性变化,形成呼吸效果。文章手把手教学,涵盖从电路原理分析、元件参数计算,到在立创EDA中进行原理图绘制、PCB布局布线,直至焊接调试的完整硬件设计流程,是电子爱好者入门实战的经典项目。

weixin_42153793的博客 125

Python的单元测试之unittest

是一个功能类似 unittest 的库,它集合众家标准测试库之所长,和 unittest 相比,功能更为强大,使用更为简单,OpenStack 广泛的利用它编写单元测试。unittest 提供了自动匹配发现并执行测试用例的功能,随着项目代码结构越发庞大,势必有多个测试文件,自动匹配发现并测试用例的功能在此就显得非常有用,只要满足。unittest 提供了丰富的命令行入口,可以根据需要执行某些特定的用例。的测试用例都会被 unittest 发现并执行,测试用例文件的默认匹配规则为 test*.py。

1、测试博主技术知识分享 2、pos行业知识技术分享 3、java后端技术知识分享 4、嵌入式技术知识分享 5、运维部署相关知识分享 283

SE、CBAM、ECA注意力机制(网络结构详解+详细注释代码+核心思想讲解+注意力机制优化神经网络方法)——pytorch实现

这期博客我们来学习一下神秘已久的注意力机制,刚开始接触注意力机制的时候,感觉很有意思,事实上学会之后会发现比想象中的要简单,复杂的注意力机制后续会讲解,这期博客先讲解最常见的三种SE、CBAM、ECA注意力机制。

爱吃橘子的小翟 7万+

PLC批量读写优化:C# Modbus TCP多寄存器批量操作(效率提升50%)

效率提升:请求次数减少90%以上,通信耗时降低50%-95%;资源节约:减少网络带宽占用和PLC/上位机CPU负载;稳定性提升:更少的请求意味着更少的通信异常;适配高频采集:满足工业现场100ms/次的高频率数据采集需求。工业落地时需注意:批量操作的核心是地址连续化规划,提前与PLC工程师协同规划寄存器地址,是优化的前提;同时需配合重试、校验机制,确保批量操作的可靠性。

这里只有干货:从 Modbus 通信到 MES 对接,从 YOLO 训练到工控机部署,带你搞定工业软件开发全流程。 1259

常用的即插即用的注意力机制模块(SE、CBAM)

CBAM注意力机制是由通道注意力机制(channel)和空间注意力机制(spatial)组成。 传统基于卷积神经网络的注意力机制更多的是关注对通道域的分析,局限于考虑特征图通道之间的作用关系。CBAM从 channel 和 spatial 两个作用域出发,引入空间注意力和通道注意力两个分析维度,实现从通道到空间的顺序注意力结构。空间注意力可使神经网络更加关注图像中对分类起决定作用的像素区域而忽略无关紧要的区域,通道注意力则用于处理特征图通道的分配关系,同时对两个维度进行注意力分配增强了注意

weixin_43980331的博客 2万+

国科大学习资料--模式识别与机器学习(黄庆明)--2020期末考试题

国科大学习资料–模式识别与机器学习(黄庆明)–2020期末考试题 国科大学习资料–模式识别与机器学习(黄庆明)–2020期末考试题 国科大学习资料–模式识别与机器学习(黄庆明)–2020期末考试题 ============================================================================================================================================================

无名何许人的博客 2604

GPFS扩展技术原理(十一)-FMDN广播与EID加解密

GFPS扩展技术原理(十一)FMDN广播及EID加解密

十多年蓝牙协议软件开发,擅长蓝牙协议分析 935

三种 Transformer 模型中的注意力机制介绍及 Pytorch 实现:从自注意力到因果自注意力

自注意力机制自2017年在开创性论文《Attention Is All You Need》中被提出以来,已成为最先进深度学习模型的核心,尤其是在自然语言处理(NLP)领域。考虑到其广泛应用,深入理解自注意力的运作机制变得尤为重要。图1:原始Transformer架构在深度学习中,"注意力"概念的引入最初是为了改进递归神经网络(RNNs)处理长序列或句子的能力。例如,在机器翻译任务中,逐字翻译通常无法捕捉语言的复杂语法和表达方式,导致翻译质量低下。

python1234_的博客 2257

YOLOv11改进 | 注意力篇 | YOLOv11引入CBAM注意力机制

我们的实验表明各种模型的分类和检测性能得到了一致的改进,证明了 CBAM 的广泛适用性。简单介绍:CBAM的主要思想是通过关注重要的特征并抑制不必要的特征来增强网络的表示能力。模块首先应用通道注意力,关注"重要的"特征,然后应用空间注意力,关注这些特征的"重要位置"。到此本文的正式分享内容就结束了,在这里给大家推荐我的YOLOv11改进有效涨点专栏,本专栏目前为新开的,后期我会根据各种前沿顶会进行论文复现,也会对一些老的改进机制进行补充,如果大家觉得本文帮助到你了,订阅本专栏,关注后续更多的更新~

tsg6698的博客 2万+

三种Transformer模型中的注意力机制介绍及Pytorch实现:从自注意力到因果自注意力...

来源:Deephub Imba 本文约9000字,建议阅读9分钟本文深入探讨Transformer模型中三种关键的注意力机制:自注意力、交叉注意力和因果自注意力。这些机制是GPT-4、Llama等大型语言模型(LLMs)的核心组件。通过理解这些注意力机制,我们可以更好地把握这些模型的工作原理和应用潜力。我们不仅会讨论理论概念,还将使用Python和PyTorch从零开始实现这些注意力机制。通过实...

数据派THU 235

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

[转载]三种Transformer模型中的注意力机制介绍及Pytorch实现:从自注意力到因果自注意力

自注意力机制自2017年在开创性论文《Attention Is All You Need》中被提出以来,已成为最先进深度学习模型的核心,尤其是在自然语言处理(NLP)领域。考虑到其广泛应用,深入理解自注意力的运作机制变得尤为重要。图1:原始Transformer架构在深度学习中,"注意力"概念的引入最初是为了改进递归神经网络(RNNs)处理长序列或句子的能力。例如,在机器翻译任务中,逐字翻译通常无法捕捉语言的复杂语法和表达方式,导致翻译质量低下。

wuling129的专栏 986

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

上一篇: 这本书是真的牛啊!150页就能让你上手大模型应用开发 简单又透彻
下一篇: 2024AI大模型神级入门指南
AI_小站
博客等级 码龄3年 6255粉丝 1152原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值