目录
前言
前馈全连接层
学习目标
什么是前馈全连接层
前馈全连接层的作用
前馈全连接层代码实现
规范化层
学习目标
规范化层的作用
规范化层的代码实现
子层(残差)连接结构
学习目标
什么是子层(残差)连接结构
子层连接结构代码实现
前言
我们之前学习了输入层(词嵌入层(经过词向量编码),位置编码(通过词位置信息向量和词特征矩阵得到))。注意力机制(注意力计算规则,自注意力和注意力区别,注意力机制,多头注意力机制)
前馈全连接层
学习目标
了解什么是前馈全连接层及其作用
掌握前馈全连接层的实现过程
什么是前馈全连接层
在transformer中前馈全连接层就是具有两层线性层的全连接网络
前馈全连接层的作用
考虑到注意力机制可能对复杂过程的拟合程度不够,通过增加两层网络来增强模型能力
前馈全连接层代码实现
#前馈全连接层的代码分析
class PositionwiseFeedForward(nn.Module):def __init__(self, d_model,d_ff, dropout = 0.1):#输入的参数分别是:d_model词嵌入的维度,d_ff全连接网络的中间层维度,dropout=0.1置零比率super(PositionwiseFeedForward,self).__init__()#首先先使用nn实例化两个线性层对象self.w1,self.w2#参数是d_mdoel,d_ff,d_modelself.w1 = nn.Linear(d_model,d_ff)self.w2 = nn.Linear(d_ff,d_model)#然后使用nn实例化dropout对象self.dropout = nn.Dropout(p=dropout)def forward(self,x):#输入参数x表示上一层的输出#首先经过第一个线性层,然后使用Funtional中的relu函数激活#之后在使用dropout进行随即处置0,最后经过第二个线性层w2,返回结果return self.w2(self.dropout(F.relu(self.w1(x))))
#实例化参数
d_model = 512
d_ff = 128
dropout = 0.2
x = mha_result
pwf = PositionwiseFeedForward(d_model,d_ff,dropout=dropout)
pwf_result = pwf(x)
print(pwf_result)
print(pwf_result.shape)
规范化层
学习目标
了解规范化层的作用
掌握规范化层的实现过程
规范化层的作用
它是所有深层网络模型都需要的标准网络层,因为随着网络层数的增加,通过多层计算后的参数可能开始出现过大的或者过小的情况,这样会导致模型收敛的非常慢,因此都会在一定层数后接入规范化层进行数值规范化,使其数值特征在合理范围内。
规范化层的代码实现
#规范化层的代码实现
#通过layerNorm实现规范化操作的类
class LayerNorm(nn.Module):def __init__(self, features,eps=1e-6):#初始化参数:features表示词嵌入的维度,eps表示一个足够小的数,在规范化公式分母出现,防止分母为0super(LayerNorm,self).__init__()#根据features初始化两个张量a2,b2,第一个初始化张量为1张量。就是说里面所有元素都是1,第二个初始化为0张量#里面所有元素都为0,这两张张量就是规范化层的参数。#因为直接对上一层得到的结果做规范化计算,将改变的结果正常表征,因此就需要有参数作为调节因子,#使其既能满足规范化要求,又不能改变针对目标的表征。最后使用nn.parameter封装,代表他们是模型的参数self.a2 = nn.Parameter(torch.ones(features))self.b2 = nn.Parameter(torch.zeros(features))#把eps传入类中self.eps = epsdef forward(self,x):#输入的参数来自上一层的输出#在函数中,首先对输入变量x求其最后一个维度的均值,并保持如输入维度一致#接着再求最后一个维度的标准差,然后就是根据规范化公式,用x减去均值除以标准差获得规范化的结果#最后对结果乘以缩放系数,即a2,加上位移参数b2mean = x.mean(-1,keepdim=True) #-1表示最后一个维度std = x.std(-1,keepdim = True)return self.a2 *(x - mean) / (std + self.eps) + self.b2
features = d_model = 512
eps = 1e-6#x是前馈全连接层的输出
x = pwf_result
ln = LayerNorm(features,eps=eps)
ln_result = ln(x)
print(ln_result)
print(ln_result.shape)
子层(残差)连接结构
学习目标
了解什么是子层连接结构
掌握子层连接结构的实现过程
什么是子层(残差)连接结构
输入到每个子层以及规范化层的过程中,还使用了残差链接(跳跃链接),我们把这一部分结构叫做子层连接结构(代表子层及其链接结构),在每个编码器层,都有两个子层,这两个子层加上周围的链接结构形成了两个子层链接结构
子层链接结构图:
子层连接结构代码实现
#子层连接结构
#使用SublayerConnection来实现子层连接结构的类
class SublayerConnection(nn.Module):def __init__(self, size,dropout=0.1):#输入两个参数size表示词嵌入的维度,dropout对输出矩阵的随机置0super(SublayerConnection,self).__init__()#实例化规范化层self.norm = LayerNorm(size)#使用nn中预定义的dropout实例化一个self.dropout对象self.dropout = nn.Dropout(p=dropout)def forward(self,x,sublayer):#该逻辑函数中,接收上一个子层或者子层的输入作为第一个参数#将该子层连接中的子层函数作为第二个参数#我们首先对输入做规范化处理,然后将结果传入子层做处理,之后在再对子层进行dropout操作#随机停止一些网络中的神经元的作用,防止过拟合,最后还有一个add的操作#因为存在跳跃连接,所以将输入x与dropout后的子层输出结果相加作为最终子层的连接输出return x + self.dropout(sublayer(self.norm(x)))
#实例化参数
size = 512
dropout = 0.2
head = 8
d_model = 512
#输入参数
#令x为编码器的输出
x = pe_result
#print(x)
mask = Variable(torch.zeros(2,4,4))#假设子层中装的是多层注意力层,实例化
self_attn = MutiHeadedAttention(head,d_model)#使用lambda获得一个函数类型的子层
sublayer = lambda x: self_attn(x,x,x,mask)sc = SublayerConnection(size=size,dropout=dropout)
sc_result = sc(x,sublayer)
print(sc_result)
print(sc_result.shape)