深度学习---------------------------------Transformer

目录

  • Transformer架构
  • 多头注意力
  • 有掩码的多头注意力
  • 基于位置的前馈网络
  • 层归一化
  • 信息传递
  • 预测
  • 总结
  • 代码
    • 多头注意力
      • 使用多个头并行计算
      • 选择缩放点积注意力作为每一个注意力头
      • 测试
      • 该部分总代码
    • Transformer
      • 基于位置的前馈网络
        • 改变张量的最里层维度的尺寸
        • 对比不同维度的层归一化和批量归一化的效果
      • 使用残差连接和层归一化
        • 加法操作后输出张量的形状相同
        • 该部分总代码
      • 实现编码器中的一个层
        • Transformer编码器中的任何层都不会改变其输入的状态
        • 该部分总代码
      • Transformer编码器
        • 创建一个两层的Transformer编码器
        • 该部分总代码
      • 实现解码块
        • 编码器和解码器的特征维度都是num_hiddens
      • Transformer解码器
      • 训练
        • 该部分从零实现代码
        • 该部分简洁代码
      • 将一些英语句子翻译成法语
      • 查看编码器的注意力权重形状
        • 该部分总代码
      • 展示编码器注意力权重的热图
        • 该部分总代码
      • 查看解码器注意力的权重形状
        • 该部分总代码
      • 展示解码器自注意力权重的热图
      • 该部分总代码
      • 展示解码器"编码器-解码器"注意力权重的热图
        • 该部分总代码
  • 总流程图

Transformer架构

基于编码器-解码器架构来处理序列对

跟使用注意力的seq2seq不同,Transformer是纯基于注意力(或者说是纯基于self.attention的架构,里面没有RNN了)。

seq2seq里面加了个注意力进来

在这里插入图片描述

现在是:把里面的RNN全部换成transformer

在这里插入图片描述

在这里插入图片描述

最后一层的输出作为之后层的输入来完成信息传递

在这里插入图片描述




多头注意力

在这里插入图片描述

对同一key、value、query,希望抽取不同的信息。
    例如:短距离关系和长距离关系



多头注意力使用h个独立的注意力池化
    合并各个头输出得到最终输出
在这里插入图片描述

query(q∈ R d q R^{d_q} Rdq

key(k∈ R d k R^{d_k} Rdk

value(v∈ R d v R^{d_v} Rdv

在这里插入图片描述

头i可学习参数 W i ( q ) {W_i}^{(q)} Wi(q) R d q × d q R^{d_q×d_q} Rdq×dq W i ( k ) {W_i}^{(k)} Wi(k) R d k × d k R^{d_k×d_k} Rdk×dk W i ( v ) {W_i}^{(v)} Wi(v) R d v × d v R^{d_v×d_v} Rdv×dv

头i的输出 h i h_i hi=f( W i ( q ) {W_i}^{(q)} Wi(q)q, W i ( k ) {W_i}^{(k)} Wi(k)k, W i ( v ) {W_i}^{(v)} Wi(v)v)∈ R p v R^{p_v} Rpv

输出可学习参数 W o W_o Wo R p o × p v R^{p_o×p_v} Rpo×pv

多头注意力的输出

在这里插入图片描述




有掩码的多头注意力

在这里插入图片描述

解码器对序列中一个元素输出时,不应该考虑该元素之后的元素。
(因为attention没有时间信息的)

解决方法:
    可以通过掩码来实现
        也就是计算 x i x_i xi输出时,假装当前序列长度为i。(也就是把i后面的用掩码掩藏掉,就是在算softmax上的时候不会算它的权重,不会对后面的key、value给权重




基于位置的前馈网络

在这里插入图片描述
其实就是一个全连接层

1、将输入形状由(b,n,d)变换成(bn,d)
b:批量大小
n:序列长度
d:特征维度(每个元素的嵌入向量维度)

之前在卷积的时候,把nd换成一维{变成了(b,nd)}

2、作用两个全连接层
3、输出形状由(bn,d)变化成(b,n,d)
4、等价于两层核窗口为1的一维卷积层




层归一化

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

批量归一化对每个特征/通道里元素进行归一化
    不适合序列长度会变的NLP应用
层归一化对每个样本里元素进行归一化




信息传递

在这里插入图片描述

编码器中的输出 y 1 y_1 y1,…, y n y_n yn

将其作为解码中第i个Transformer块中多头注意力的key和value
    它的query来自目标序列
意味着编码器解码器块的个数输出维度都是一样的

在这里插入图片描述
(中间这个)




预测

在这里插入图片描述

预测第t+1个输出时
解码器中输入前t个预测值
    在自注意力中,前t个预测值作为key和value,第t个预测值还作为query




总结

    ①Transformer是一个纯使用注意力的编码-解码器。

    ②编码器和解码器都有n个transformer块

    ③每个块里使用多头(自)注意力,基于位置的前馈网络,和层归一化。




代码

多头注意力

import math
import os
import pandas as pd
import torch
from torch import nn
from d2l import torch as d2l



使用多个头并行计算

形状X从[batch_size,查询或者“键-值”对的个数,num_hiddens]
➡[batch_size,查询或者“键-值”对的个数,num_headsnum_hiddens/num_heads]
➡[batch_size,num_heads查询或者“键-值”对的个数,num_hiddens/num_heads]
➡[batch_size*num_heads,查询或者“键-值”对的个数,num_hiddens/num_heads]

通过将 batch_size 和 num_heads 维度合并,可以在一个批量中同时计算所有头的注意力,提高了计算效率。
def transpose_qkv(X, num_heads):"""为了多注意力头的并行计算而变换形状"""# 2,4,100➡2,4,5, 20# 输入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)# 将第二维度和第三维度交换一下顺序# 在多头自注意力机制中,通常将num_heads维度提前,以便在每个头上独立执行注意力计算,提高计算效率# 输出X的形状:(batch_size,num_heads,查询或者“键-值”对的个数,num_hiddens/num_heads)# 2,5,4,20X = X.permute(0, 2, 1, 3)# 最终输出的形状:(batch_size*num_heads,查询或者“键-值”对的个数,num_hiddens/num_heads)# 10,4,20return X.reshape(-1, X.shape[2], X.shape[3])# 在多头注意力机制的最后一步,将经过多头注意力计算后的张量恢复到原始形状。这样可以确保输出张量的形状与输入张量的形状一致
def transpose_output(X, num_heads):"""逆转transpose_qkv函数的操作"""# 10,4,20➡2,5,4, 20# 将 batch_size 和 num_heads 分离,以便后续操作。X = X.reshape(-1, num_heads, X.shape[1], X.shape[2])# 2,5,4, 20➡2,4,5, 20# 恢复 num_heads 维度的位置,使其与 transpose_qkv 函数的逆操作一致。X = X.permute(0, 2, 1, 3)# 2,5,4, 20➡2,4,100return X.reshape(X.shape[0], X.shape[1], -1)



选择缩放点积注意力作为每一个注意力头

class MultiHeadAttention(nn.Module):"""多头注意力"""# 100、100、100、100、5、0.5def __init__(self, key_size, query_size, value_size, num_hiddens, num_heads, dropout, bias=False, **kwargs):super(MultiHeadAttention, self).__init__(**kwargs)# 5self.num_heads = num_heads# 用的是缩放点积注意力所以里面不需要学习w了self.attention = d2l.DotProductAttention(dropout)# (2, 4, 100)self.W_q = nn.Linear(query_size, num_hiddens, bias=bias)# (2, 6, 100)self.W_k = nn.Linear(key_size, num_hiddens, bias=bias)# (2, 6, 100)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,查询的个数)# 线性变换:self.W_q、self.W_k和self.W_v的作用是将输入的查询、键和值张量映射到一个新的隐藏空间,学习新的表示,并投影到统一的隐藏空间。# 经过transpose_qkv变换后,输出的queries,keys,values 的形状:#                            (batch_size*num_heads,查询或者“键-值”对的个数,num_hiddens/num_heads)# (10, 4, 20)queries = transpose_qkv(self.W_q(queries), self.num_heads)# (10, 6, 20)keys = transpose_qkv(self.W_k(keys), self.num_heads)# (10, 6, 20)values = transpose_qkv(self.W_v(values), self.num_heads)if valid_lens is not None:# 在轴0,将第一项(标量或者矢量)复制num_heads次,确保每个头都有对应的有效长度。# valid_lens:torch.Size([2])➡torch.Size([10])valid_lens = torch.repeat_interleave(valid_lens, repeats=self.num_heads, dim=0)# 根据查询(queries)、键(keys)和值(values)计算注意力权重,并据此加权求和得到输出。# output的形状:(batch_size*num_heads,查询的个数,num_hiddens/num_heads)# (10, 4, 20)output = self.attention(queries, keys, values, valid_lens)# 逆转 transpose_qkv 函数的操作,将输出恢复到原始的批次和序列维度。# output_concat的形状:(batch_size,查询的个数,num_hiddens)output_concat = transpose_output(output, self.num_heads)return self.W_o(output_concat)



测试

num_hiddens, num_heads = 100, 5
# 100\100\100\100\5\0.5
attention = MultiHeadAttention(num_hiddens, num_hiddens, num_hiddens, num_hiddens, num_heads, 0.5)
attention.eval()
batch_size, num_queries = 2, 4
# 包含了两个整数元素3和2,所以形状是(2,)
num_kvpairs, valid_lens = 6, torch.tensor([3, 2])
# X:2,4,100
# Y:2,6,100
X = torch.ones((batch_size, num_queries, num_hiddens))
Y = torch.ones((batch_size, num_kvpairs, num_hiddens))
# 输出形状[2, 4, 100]
print(attention(X, Y, Y, valid_lens).shape)



该部分总代码

import torch
from torch import nn
from d2l import torch as d2l# 重塑和转置
def transpose_qkv(X, 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 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)# 5self.num_heads = num_headsself.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 = 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:valid_lens = torch.repeat_interleave(valid_lens, repeats=self.num_heads, dim=0)output = self.attention(queries, keys, values, valid_lens)output_concat = transpose_output(output, self.num_heads)return self.W_o(output_concat)num_hiddens, num_heads = 100, 5
attention = MultiHeadAttention(num_hiddens, num_hiddens, num_hiddens, num_hiddens, num_heads, 0.5)
attention.eval()
batch_size, num_queries = 2, 4
num_kvpairs, valid_lens = 6, torch.tensor([3, 2])
X = torch.ones((batch_size, num_queries, num_hiddens))
Y = torch.ones((batch_size, num_kvpairs, num_hiddens))
print(attention(X, Y, Y, valid_lens).shape)

架构图:

在这里插入图片描述

步骤:通过将多头注意力的计算转化为单头注意力的计算,可以简化实现逻辑

逻辑图:
在这里插入图片描述

数据形状步骤图:

在这里插入图片描述
在这里插入图片描述
最终线性变换的作用:

    1、self.W_o 的作用是将这些拼接后的结果重新映射回一个统一的隐藏空间确保输出的维度与输入的维度一致
    2、这个线性变换可以看作是一个权重矩阵,用于将多头注意力的结果进行加权组合,生成最终的输出。
    3、可以学习到更复杂的表示,从而更好地捕捉输入数据的特征和模式。




Transformer

import math
import os
import pandas as pd
import torch
from torch import nn
from d2l import torch as d2l



基于位置的前馈网络

pytorch的densel默认的实现:当输入不是二维的时候,把前面的维度都当作样本维,后面的维度当成特征维。

基于位置的前馈网络:实际上是一个单隐藏层的MLP

class PositionWiseFFN(nn.Module):def __init__(self, ffn_num_input, ffn_num_hiddens, ffn_num_outputs, **kwargs):super(PositionWiseFFN, self).__init__(**kwargs)# 第一个全连接层,将输入维度从ffn_num_input映射到ffn_num_hiddensself.dense1 = nn.Linear(ffn_num_input, ffn_num_hiddens)# ReLU激活函数,增加非线性特性self.relu = nn.ReLU()# 第二个全连接层,将输入维度从ffn_num_hiddens映射到ffn_num_outputsself.dense2 = nn.Linear(ffn_num_hiddens, ffn_num_outputs)def forward(self, X):# 前向传播过程# 通过第一个全连接层,将输入X映射到隐藏层# 应用ReLU激活函数,增加非线性特性# 通过第二个全连接层,将隐藏层映射到输出层return self.dense2(self.relu(self.dense1(X)))



改变张量的最里层维度的尺寸

其实就是把4变成8

# 创建一个PositionWiseFFN实例,输入维度为4,隐藏层维度为4,输出维度为8
ffn = PositionWiseFFN(4, 4, 8)
# 设置模型为评估模式,不进行训练
ffn.eval()
# 创建一个形状为(2, 3, 4)的张量,所有元素都设置为1
# 输入张量通过前馈网络进行前向传播,得到输出张量
# 取第一个样本的输出张量
X = torch.ones((2, 3, 4))
print(ffn(X)[0])



对比不同维度的层归一化和批量归一化的效果

在这里插入图片描述
layer norm:把每个样本变成均值为0方差为1

batch norm:每个特征变成均值为0方差为1

# 创建一个对最后一个维度进行层归一化的实例
ln = nn.LayerNorm(2)
# 创建一个对最后一个维度进行批量归一化的实例
bn = nn.BatchNorm1d(2)
# 创建一个形状为(2, 2)的张量
X = torch.tensor([[1, 2], [2, 3]], dtype=torch.float32)
# 对张量进行层归一化
# 对张量进行批量归一化
# 打印层归一化和批量归一化的结果
print('layer norm:', ln(X), '\nbatch norm:', bn(X))



使用残差连接和层归一化

class AddNorm(nn.Module):def __init__(self, normalized_shape, dropout, **kwargs):super(AddNorm, self).__init__(**kwargs)# 定义一个dropout层,用于随机丢弃部分神经元self.dropout = nn.Dropout(dropout)# 定义一个层归一化层,对输入进行归一化self.ln = nn.LayerNorm(normalized_shape)def forward(self, X, Y):# 前向传播过程# 使用残差连接:将dropout(Y)与X相加# 应用层归一化:对残差进行归一化return self.ln(self.dropout(Y) + X)



加法操作后输出张量的形状相同
# 创建一个AddNorm实例,输入的归一化维度为[3, 4],dropout率为0.5
add_norm = AddNorm([3, 4], 0.5)
# 设置模型为评估模式,不进行训练
add_norm.eval()
# 创建一个形状为(2, 3, 4)的张量作为X
# 创建一个形状为(2, 3, 4)的张量作为Y
# 输入X和Y通过AddNorm进行前向传播
# 打印输出结果的形状
print(add_norm(torch.ones((2, 3, 4)), torch.ones((2, 3, 4))).shape)



该部分总代码
import torch
from torch import nnclass 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)add_norm = AddNorm([3, 4], 0.5)
add_norm.eval()
print(add_norm(torch.ones((2, 3, 4)), torch.ones((2, 3, 4))).shape)

在这里插入图片描述




实现编码器中的一个层

ffn:前馈神经网络
在这里插入图片描述

class EncoderBlock(nn.Module):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):# 第一个残差连接和层归一化模块# 使用多头注意力机制计算X的自注意力输出,并将该输出与X相加(残差连接)# 然后进行层归一化Y = self.addnorm1(X, self.attention(X, X, X, valid_lens))# 位置前馈网络:对第一个残差连接和层归一化模块的输出进行位置前馈网络操作# 第二个残差连接和层归一化模块:# 将位置前馈网络输出与第一个残差连接和层归一化模块的输出相加并进行归一化return self.addnorm2(Y, self.ffn(Y))



Transformer编码器中的任何层都不会改变其输入的状态
# 创建一个形状为(2, 100, 24)的张量作为输入X
X = torch.ones((2, 100, 24))
# 创建一个形状为(2,)的张量作为有效长度
valid_lens = torch.tensor([3, 2])
encoder_blk = EncoderBlock(24, 24, 24, 24, [100, 24], 24, 48, 8, 0.5)
# 设置模型为评估模式,不进行训练
encoder_blk.eval()
# 输入X和有效长度通过EncoderBlock进行前向传播
print(encoder_blk(X, valid_lens).shape)

在这里插入图片描述




该部分总代码
import math
import os
import pandas as pd
import torch
from torch import nn
from d2l import torch as d2l# 基于位置的前馈网络
class PositionWiseFFN(nn.Module):def __init__(self, ffn_num_input, ffn_num_hiddens, ffn_num_outputs, **kwargs):super(PositionWiseFFN, self).__init__(**kwargs)# 第一个全连接层,将输入维度从ffn_num_input映射到ffn_num_hiddensself.dense1 = nn.Linear(ffn_num_input, ffn_num_hiddens)# ReLU激活函数,增加非线性特性self.relu = nn.ReLU()# 第二个全连接层,将输入维度从ffn_num_hiddens映射到ffn_num_outputsself.dense2 = nn.Linear(ffn_num_hiddens, ffn_num_outputs)def forward(self, X):# 前向传播过程# 通过第一个全连接层,将输入X映射到隐藏层# 应用ReLU激活函数,增加非线性特性# 通过第二个全连接层,将隐藏层映射到输出层return self.dense2(self.relu(self.dense1(X)))# 使用残差连接和层归一化
class AddNorm(nn.Module):def __init__(self, normalized_shape, dropout, **kwargs):super(AddNorm, self).__init__(**kwargs)# 定义一个dropout层,用于随机丢弃部分神经元self.dropout = nn.Dropout(dropout)# 定义一个层归一化层,对输入进行归一化self.ln = nn.LayerNorm(normalized_shape)def forward(self, X, Y):# 前向传播过程# 使用残差连接:将dropout(Y)与X相加# 应用层归一化:对残差进行归一化return self.ln(self.dropout(Y) + X)# 实现编码器中的一个层
class EncoderBlock(nn.Module):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):# 第一个残差连接和层归一化模块# 使用多头注意力机制计算X的自注意力输出,并将该输出与X相加(残差连接)# 然后进行层归一化Y = self.addnorm1(X, self.attention(X, X, X, valid_lens))# 位置前馈网络:对第一个残差连接和层归一化模块的输出进行位置前馈网络操作# 第二个残差连接和层归一化模块:# 将位置前馈网络输出与第一个残差连接和层归一化模块的输出相加并进行归一化return self.addnorm2(Y, self.ffn(Y))# Transformer编码器中的任何层都不会改变其输入的状态
# 创建一个形状为(2, 100, 24)的张量作为输入X
X = torch.ones((2, 100, 24))
# 创建一个形状为(2,)的张量作为有效长度
valid_lens = torch.tensor([3, 2])
encoder_blk = EncoderBlock(24, 24, 24, 24, [100, 24], 24, 48, 8, 0.5)
# 设置模型为评估模式,不进行训练
encoder_blk.eval()
# 输入X和有效长度通过EncoderBlock进行前向传播
print(encoder_blk(X, valid_lens).shape)



Transformer编码器

在这里插入图片描述

# Transformer编码器
class TransformerEncoder(d2l.Encoder):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,用于存储多个编码器块self.blks = nn.Sequential()# 通过循环迭代的方式,逐个添加编码器块到顺序容器self.blks中for i in range(num_layers):# 使用self.blks.add_module()方法将一个新的编码器块添加到顺序容器中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):# 前向传播过程# 词嵌入层:对输入进行词嵌入操作,将输入转换为高维向量表示# 将嵌入后的向量×隐藏层维度的平方根,目的是缩放嵌入向量,使其位置编码的尺度相匹配# 然后对缩放后的嵌入向量进行编码以便模型能够区分不同位置的输入。"""这种方式一般是用来处理序列数据的"""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列表中的对应位置self.attention_weights[i] = blk.attention.attention.attention_weightsreturn X



创建一个两层的Transformer编码器
# 创建一个两层的Transformer编码器,看倒数第二个参数
encoder = TransformerEncoder(200, 24, 24, 24, 24, [100, 24], 24, 48, 8, 2, 0.5)
# 将编码器设置为评估模式
encoder.eval()
# 对输入数据进行前向传播,获取输出的形状[批量大小,序列长度,隐藏层大小]
print(encoder(torch.ones((2, 100), dtype=torch.long), valid_lens).shape)

在这里插入图片描述



该部分总代码
import math
import os
import pandas as pd
import torch
from torch import nn
from d2l import torch as d2l# 基于位置的前馈网络
class PositionWiseFFN(nn.Module):def __init__(self, ffn_num_input, ffn_num_hiddens, ffn_num_outputs, **kwargs):super(PositionWiseFFN, self).__init__(**kwargs)# 第一个全连接层,将输入维度从ffn_num_input映射到ffn_num_hiddensself.dense1 = nn.Linear(ffn_num_input, ffn_num_hiddens)# ReLU激活函数,增加非线性特性self.relu = nn.ReLU()# 第二个全连接层,将输入维度从ffn_num_hiddens映射到ffn_num_outputsself.dense2 = nn.Linear(ffn_num_hiddens, ffn_num_outputs)def forward(self, X):# 前向传播过程# 通过第一个全连接层,将输入X映射到隐藏层# 应用ReLU激活函数,增加非线性特性# 通过第二个全连接层,将隐藏层映射到输出层return self.dense2(self.relu(self.dense1(X)))# 使用残差连接和层归一化
class AddNorm(nn.Module):def __init__(self, normalized_shape, dropout, **kwargs):super(AddNorm, self).__init__(**kwargs)# 定义一个dropout层,用于随机丢弃部分神经元self.dropout = nn.Dropout(dropout)# 定义一个层归一化层,对输入进行归一化self.ln = nn.LayerNorm(normalized_shape)def forward(self, X, Y):# 前向传播过程# 使用残差连接:将dropout(Y)与X相加# 应用层归一化:对残差进行归一化return self.ln(self.dropout(Y) + X)# 实现编码器中的一个层
class EncoderBlock(nn.Module):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_siz

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

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

相关文章

世界时区划分

1. AoE (Anywhere on Earth)代表地球上最后一个时区的时间,是全球范围内最晚的时间,通常用于截止日期。 2. UTC/GMT (协调世界时/格林威治时间)是全球的标准时间,所有时区都是基于UTC计算的。…

qt QImage详解

1、概述 QImage是Qt框架中用于处理图像数据的一个核心类。与QPixmap不同,QImage是在内存中直接存储图像像素数据的,这使得它适用于需要直接访问和修改像素的应用场景,比如图像处理算法、图像绘制以及图像分析等。QImage支持多种图像格式&…

DAY75WEB 攻防-验证码安全篇接口滥用识别插件复用绕过宏命令填入滑块类

知识点: 1、验证码简单机制-验证码过于简单可爆破 2、验证码重复使用-验证码验证机制可绕过 3、验证码智能识别-验证码图形码被可识别 4、验证码接口调用-验证码触发接口可枚举 图片验证码-识别插件-登录爆破&接口枚举 验证码识别绕过等技术适用于&#x…

字符串左旋 (干货无废话)

题目内容:实现一个函数,可以左旋字符串中的k个字符 例如:ABCD左旋一个字符得到BCDA ABCD左旋两个字符得到CDAB 画图解释: 上图分别是向左挪1次,2次,3次,4次,5次后的结果…

QML基础语法2

函数 函数格式: function关键字 函数名(参数名1:参数类型,参数名2:参数类型,...):返回值类型{} 其中: 函数名必须以小写字符开头,后面驼峰可以有多个参数或者没有参数参数类型可以不写返回值类型也可以不写 如何调用:通过id点…

Mac 配置SourceTree集成云效

1、背景 工作使用的是自己的笔记本,一个是比较卡,在一个是敏感信息比较多还是使用公司的电脑,但是系统是Mac就很麻烦,在网上找了帖子记录一下 2、配置 打开终端 ssh-keygen -t rsa #一直回车就行 cd .ssh cat id_rsa.pub #查…

Kubernetes中常见的volumes数据卷

华子目录 volumesk8s支持的卷的类型emptyDir卷功能emptyDir的使用场景示例 hostPath卷功能用法安全隐患示例 nfs卷功能应用示例:部署一台nfs服务器并在所有k8s节点中安装nfs-utils volumes 容器中文件在磁盘上是临时存放的,这给容器中运行的特殊应用程序…

PaddleNLP的FAQ问答机器人

项目源码获取方式见文章末尾! 600多个深度学习项目资料,快来加入社群一起学习吧。 《------往期经典推荐------》 项目名称 1.【DDRNet模型创新实现人像分割】 2.【卫星图像道路检测DeepLabV3Plus模型】 3.【GAN模型实现二次元头像生成】 4.【CNN模型实…

Windows的MySQL开机自动启动问题

标题 问题描述 问题描述 在Windows系统中,我设置好了MySQL服务为自动启动,但在开机后发现MySQL服务任没有自动运行。我有点苦恼,每次连接MySQL,都要进入计算机管理,手动打开。 解决方法: 1.前提安装好MySQ…

基于Spring Boot的私房菜定制上门服务系统的设计与实现

摘 要 如今社会上各行各业,都喜欢用自己行业的专属软件工作,互联网发展到这个时候,人们已经发现离不开了互联网。新技术的产生,往往能解决一些老技术的弊端问题。因为传统私房菜定制上门服务系统信息管理难度大,容错率…

计算机毕业设计 | 基于SpringBoot的健身房管理系统(附源码)

1,项目背景 随着人们生活水平的提高和健康意识的增强,健身行业逐渐兴起并迅速发展。而现代化的健身房管理系统已经成为健身房发展的必备工具之一。传统的健身房管理方式已经无法满足现代化健身房的需求,需要一种更加高效、智能、安全的管理系…

LeetCode 0685.冗余连接 II:并查集(和I有何不同分析)——详细题解(附图)

【LetMeFly】685.冗余连接 II:并查集(和I有何不同分析)——详细题解(附图) 力扣题目链接:https://leetcode.cn/problems/redundant-connection-ii/ 在本问题中,有根树指满足以下条件的 有向 图。该树只有一个根节点&…

前端请求后端接口报错(blocked:mixed-content),以及解决办法

报错原因:被浏览器拦截了,因为接口地址不是https的。 什么是混合内容(Mixed Content) 混合内容是指在同一页面中同时包含安全(HTTPS)和非安全(HTTP)资源的情况。当浏览器试图加载非…

SMTP协议,即简单邮件传输协议

SMTP协议,即简单邮件传输协议(Simple Mail Transfer Protocol),是一种用于发送电子邮件的互联网标准。以下是对SMTP协议的详细介绍: 一、定义与工作原理 SMTP定义了邮件服务器之间以及邮件客户端与服务器之间的通信规…

Xss_less靶场攻略(1-18)

xss-lab-less1 ur特殊字符转义 存在url中 转义符为 %2B& 转义符为 %26空格 转义符为 或 %20/ 转义符为 %2F? 转义符为 %3F% 转义符为 %25#转义符为 %23 转义符为 %3Dimg 标签懒加载 在XSS攻击中,img标签的src属性是一个常见的攻击向量,因为它可以…

Unity humanoid 模型头发动画失效问题

在上一篇【Unity实战笔记】第二十二 提到humanoid 模型会使原先的头发动画失效,如下图所示: 头发摆动的是generic模型和动画,不动的是humanoid模型和动画 一开始我是尝试过在模型Optimize Game objects手动添加缺失的头发骨骼的,奈…

基于MATLAB的战术手势识别

手势识别的研究起步于20世纪末,由于计算机技术的发展,特别是近年来虚拟现实技术的发展,手势识别的研究也到达一个新的高度。熵分析法是韩国的李金石、李振恩等人通过从背景复杂的视频数据中分割出人的手势形状,然后计算手型的质心…

CSS学习之Grid网格布局基本概念、容器属性

网格布局 网格布局(Grid)是将网页划分成一个个网格单元,可任意组合不同的网格,轻松实现各种布局效果,也是目前CSS中最强大布局方案,比Flex更强大。 基本概念 容器和项目 当一个 HTML 元素将 display 属性…

Yelp 数据集进行用户画像, 使用聚类做推荐

使用 Yelp 数据集进行用户画像(User Profiling)是一项有趣的任务,可以理解用户的偏好、行为和特征。以下是总结的一个基本的步骤,帮助构建用户画像 pandas 加载数据: import pandas as pd# 加载数据 users pd.read_…

JAVA题目笔记(十) 带有继承结构的JavaBean类

一、创建带有继承结构的标准JavaBean类(1) public class Worker {private String name;private int workid;private int salary;public Worker(){}public Worker(String name,int workid,int payment){this.namename;this.salarypayment;this.workidworkid;}public void eat(){…