人工智能 自然语言处理 Transformer模型初识

文章介绍了Transformer模型的结构,包括输入、输出部分,以及编码器和解码器的组成。编码器由多个子层堆叠,包含多头自注意力和前馈全连接层。解码器在编码器基础上增加了一个子层。位置编码器用于补充词序信息,通过正弦和余弦函数实现。整个模型适用于机器翻译、文本生成等NLP任务。
摘要由CSDN通过智能技术生成

架构图

在这里插入图片描述

结构组成

输入部分

  • Input Embedding: 源文本嵌入层
  • Output Embedding:目标文本嵌入层
  • Positional Encoding:位置编码器

输出部分

  • Linear:线性层
  • softmax层

编码器部分

Nx:由N个编码器层堆叠而成
每个编码器层由两个子层连接结构组成
第一个子层连接结构包括一个多头自注意力子层和规范化层以及一个残差连接
第二个子层连接结构包括一个前馈全连接子层和规范化层以及一个残差连接

解码器部分

相比于编码器部分,每层增加一个子层:多头自注意力子层和规范化层以及一个残差连接

作用

基于seq2seq架构的transformer模型可以完成NLP领域研究的典型任务, 如机器翻译, 文本生成等. 同时又可以构建预训练语言模型,用于不同任务的迁移学习.

位置编码器

因为在Transformer的编码器结构中, 并没有针对词汇位置信息的处理,因此需要在Embedding层后加入位置编码器,将词汇位置不同可能会产生不同语义的信息加入到词嵌入张量中, 以弥补位置信息的缺失.

实现

import torch
import torch.nn as nn
import math

from torch.autograd import Variable


class Embeddings(nn.Module):
    def __init__(self, vocab, d_model):
        super(Embeddings, self).__init__()
        self.lut = nn.Embedding(vocab, d_model)
        self.d_model = d_model

    def forward(self, x):
        return self.lut(x) * math.sqrt(self.d_model)


class PositionalEncoding(nn.Module):
    def __init__(self, d_model, dropout, max_len=5000):
        """
        位置编码器类的初始化函数
        :param d_model: 词嵌入维度
        :param dropout: 置0比例
        :param max_len: 句子最大长度
        """
        super(PositionalEncoding, self).__init__()

        self.dropout = nn.Dropout(p=dropout)

        # 初始化位置编码矩阵
        # shape:max_len x d_model.
        pe = torch.zeros(max_len, d_model)

        # 初始化一个绝对位置矩阵, 在我们这里,词汇的绝对位置就是用它的索引去表示.
        # shape:max_len x 1
        position = torch.arange(0, max_len).unsqueeze(1)

        # 将位置信息存入位置编码矩阵:
        # 思路,矩阵变换,shape:max_len x 1 -> max_len x d_model
        # 将自然数的绝对位置编码缩放成足够小的数字,有助于在之后的梯度下降过程中更快的收敛
        div_term = torch.exp(torch.arange(0, d_model, 2) * -(math.log(10000.0) / d_model))  # arrange跳跃2,但后面应用了两次
        # 分别填充在位置编码矩阵的偶数和奇数位置上,组成最终的位置编码矩阵.
        pe[:, 0::2] = torch.sin(position * div_term)  # 将初始化的变换矩阵分布在正弦波
        pe[:, 1::2] = torch.cos(position * div_term)  # 将初始化的变换矩阵分布在余弦波

        # 这样我们就得到了位置编码矩阵pe, pe现在还只是一个二维矩阵,要想和embedding的输出(一个三维张量)相加,
        # 就必须拓展一个维度,所以这里使用unsqueeze拓展维度.
        pe = pe.unsqueeze(0)

        # 最后把pe位置编码矩阵注册成模型的buffer
        # buffer:我们把它认为是对模型效果有帮助的,但是却不是模型结构中超参数或者参数,不需要随着优化步骤进行更新的增益对象.
        # 注册之后我们就可以在模型保存后重加载时和模型结构与参数一同被加载.
        self.register_buffer('pe', pe)

    def forward(self, x):
        """forward函数的参数是x, 表示文本序列的词嵌入表示"""
        # 在相加之前我们对pe做一些适配工作, 将这个三维张量的第二维也就是句子最大长度的那一维将切片到与输入的x的第二维相同即x.size(1),
        # 因为我们默认max_len为5000一般来讲实在太大了,很难有一条句子包含5000个词汇,所以要进行与输入张量的适配.
        # 最后使用Variable进行封装,使其与x的样式相同,但是它是不需要进行梯度求解的,因此把requires_grad设置成false.
        x = x + Variable(self.pe[:, :x.size(1)], requires_grad=False)
        # 最后使用self.dropout对象进行'丢弃'操作, 并返回结果.
        return self.dropout(x)


d_model = 512
dropout = 0.1
max_len = 60

# 模拟通过文本嵌入层
x = Variable(torch.LongTensor([[100, 2, 421, 508], [491, 998, 1, 221]]))  # 数字表示词典中的索引,相当于2个句子,每个句子4个单词
emb = Embeddings(1000, d_model)
embr = emb(x)
print("embr:", embr)
print("embr shape:", embr.shape)

# 文本嵌入层输出shape:2 x 4 x 512
x = embr
pe = PositionalEncoding(d_model, dropout, max_len)
pe_result = pe(x)
print("pe_result:", pe_result)

输出
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

鹏晓星

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值