目录
前言
我们之前学习了输入层(词嵌入层(经过词向量编码),位置编码(通过词位置信息向量和词特征矩阵得到))。注意力机制(注意力计算规则,自注意力和注意力区别,注意力机制,多头注意力机制)
前馈全连接层
学习目标
了解什么是前馈全连接层及其作用
掌握前馈全连接层的实现过程
什么是前馈全连接层
在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_model
self.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表示一个足够小的数,在规范化公式分母出现,防止分母为0
super(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 = eps
def forward(self,x):
#输入的参数来自上一层的输出
#在函数中,首先对输入变量x求其最后一个维度的均值,并保持如输入维度一致
#接着再求最后一个维度的标准差,然后就是根据规范化公式,用x减去均值除以标准差获得规范化的结果
#最后对结果乘以缩放系数,即a2,加上位移参数b2
mean = 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对输出矩阵的随机置0
super(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)