Transformer是怎样处理序列数据的?

Transformer模型最初是一种广泛应用于自然语言处理(NLP)和其他序列建模任务的架构。它由编码器(encoder)和解码器(decoder)组成。
Transformer结构

以下是Transformer模型输入和输出的详细介绍:

输入

1. 输入序列(Input Sequence)

输入的内容可以是一句话,比如"Hello, how are you?"。输入序列是指用分词器(tokenizer)将文本转化为一系列标识符(token IDs)。这些标识符是一个词汇表中不同词汇的索引。Transformer模型的词汇表大小(vocabulary size)取决于具体任务和所使用的预训练模型。词汇表大小表示模型在处理输入序列时可以识别的不同词汇或子词的数量。BERT-base和BERT-large模型的词汇表大小通常为30,000。GPT-2模型的词汇表大小为50,257。常见的预训练模型的词汇表大小在30,000到50,000之间。

  • Token IDs:因此,句子“Hello, how are you?”可能会被分词为[101, 7592, 1010, 2129, 2024, 2017, 1029, 102],其中每个数字对应一个词汇或标点的唯一ID。
  • Shape:输入序列的形状通常是(batch_size, sequence_length),其中batch_size是一次输入的序列数量,sequence_length是每个序列的长度。

2. 输入嵌入(Input Embedding)

嵌入层是一个查找表,将每个token ID映射到一个固定维度的向量表示。例如,对于词汇表大小为vocab_size,嵌入维度为embedding_dim,嵌入层是一个形状为(vocab_size, embedding_dim)的矩阵。

  • Shape:形状为(batch_size, sequence_length, embedding_dim),这是通过将Token IDs通过嵌入层(embedding layer)转换得到的。

3. 位置编码(Positional Encoding)

  • Purpose:因为Transformer没有内置的顺序信息,位置编码被添加到输入的token嵌入中,以引入序列的顺序信息。
  • Shape:形状为(sequence_length, embedding_dim),位置编码会与输入嵌入相加。
    在实际操作中,位置编码通常会扩展维度,使其形状为(1, sequence_length, embedding_dim),这样可以方便地与输入嵌入进行广播相加。

4. 注意力掩码(Attention Mask)

  • Purpose:掩码用于指示哪些位置的token应该被注意力机制忽略(例如,填充token)。
  • Shape:形状通常是(batch_size, sequence_length),每个位置上是0或1。

5. 目标序列(Target Sequence,解码器输入)

  • Token IDs:对于训练解码器时,目标序列也会被转化为token IDs,形状类似于输入序列。
  • Shape:形状通常是(batch_size, target_sequence_length)。

输出

1. 编码器输出(Encoder Output)

  • Contextualized Representations:编码器输出每个输入token的上下文表示,是一个三维张量。
  • Shape:通常是(batch_size, sequence_length, hidden_size),其中hidden_size是编码器的隐藏层大小。

2. 解码器输出(Decoder Output)

  • Logits:解码器在每个时间步输出的是未归一化的概率分布,即logits。
  • Shape:形状通常是(batch_size, target_sequence_length, vocab_size),vocab_size是词汇表的大小。

3. 注意力权重(Attention Weights)

  • Attention Scores:有时我们需要注意力机制的权重,表示模型在每个时间步对输入序列中每个位置的关注程度。
  • Shape:通常是(batch_size, num_heads, sequence_length, sequence_length),其中num_heads是多头注意力机制的头数。

Transformer的结构

编码器(Encoder)

  • 输入嵌入(Input Embedding):将输入token IDs转化为嵌入向量。
  • 位置编码(Positional Encoding):将位置编码添加到嵌入向量中。
  • 多头自注意力机制(Multi-head Self Attention):每个token与其他token进行交互以获得上下文表示。
  • 前馈神经网络(Feed-forward Neural Network):非线性变换每个位置的表示。
  • 层归一化(Layer Normalization)和残差连接(Residual Connection):提高训练稳定性和深度表示。

解码器(Decoder)

  • 输入嵌入和位置编码:与编码器类似,但输入是目标序列。
  • 多头自注意力机制:处理目标序列自身的依赖关系。
  • 编码器-解码器注意力(Encoder-Decoder Attention):将编码器的上下文表示整合到解码器中。
  • 前馈神经网络:类似于编码器。
  • 输出层(Output Layer):生成词汇表中每个词的概率分布。

Transformer的工作流程

  1. 编码器处理输入序列

    • 将输入token IDs通过嵌入层转化为嵌入向量,并添加位置编码。
    • 多头自注意力机制计算每个位置的上下文表示。
    • 前馈神经网络对上下文表示进行变换。
  2. 解码器生成输出序列

    • 解码器接收目标序列的前缀(训练时是完整的目标序列,推理时是已经生成的部分)。
    • 多头自注意力机制处理目标序列自身的依赖关系。
    • 编码器-解码器注意力将编码器的输出整合到解码器中。
    • 前馈神经网络对解码器的表示进行变换,生成logits。
    • 通过softmax层将logits转化为概率分布。

这种结构使得Transformer能够高效地处理长序列并捕捉远距离依赖关系,成为目前许多NLP任务的首选模型架构。
下面是一个简化的Transformer模型的编码器和解码器的实现代码,使用了PyTorch框架。这段代码实现了一个基础的Transformer架构,包括编码器和解码器部分。

Transformer编码器和解码器代码

import torch
import torch.nn as nn
import torch.nn.functional as F
import math

# 定义位置编码类
class PositionalEncoding(nn.Module):
    def __init__(self, d_model, max_len=5000):
        super(PositionalEncoding, self).__init__()
        self.pe = torch.zeros(max_len, d_model)
        position = torch.arange(0, max_len, dtype=torch.float).unsqueeze(1)
        div_term = torch.exp(torch.arange(0, d_model, 2).float() * (-math.log(10000.0) / d_model))
        self.pe[:, 0::2] = torch.sin(position * div_term)
        self.pe[:, 1::2] = torch.cos(position * div_term)
        self.pe = self.pe.unsqueeze(0).transpose(0, 1)

    def forward(self, x):
        return x + self.pe[:x.size(0), :]

# 定义编码器层类
class EncoderLayer(nn.Module):
    def __init__(self, d_model, nhead, dim_feedforward=2048, dropout=0.1):
        super(EncoderLayer, self).__init__()
        self.self_attn = nn.MultiheadAttention(d_model, nhead, dropout=dropout)
        self.linear1 = nn.Linear(d_model, dim_feedforward)
        self.dropout = nn.Dropout(dropout)
        self.linear2 = nn.Linear(dim_feedforward, d_model)
        self.norm1 = nn.LayerNorm(d_model)
        self.norm2 = nn.LayerNorm(d_model)
        self.dropout1 = nn.Dropout(dropout)
        self.dropout2 = nn.Dropout(dropout)

    def forward(self, src, src_mask=None, src_key_padding_mask=None):
        src2 = self.self_attn(src, src, src, attn_mask=src_mask, key_padding_mask=src_key_padding_mask)[0]
        src = src + self.dropout1(src2)
        src = self.norm1(src)
        src2 = self.linear2(self.dropout(F.relu(self.linear1(src))))
        src = src + self.dropout2(src2)
        src = self.norm2(src)
        return src

# 定义编码器类
class Encoder(nn.Module):
    def __init__(self, num_layers, d_model, nhead, dim_feedforward=2048, dropout=0.1):
        super(Encoder, self).__init__()
        self.layers = nn.ModuleList([EncoderLayer(d_model, nhead, dim_feedforward, dropout) for _ in range(num_layers)])
        self.norm = nn.LayerNorm(d_model)

    def forward(self, src, mask=None, src_key_padding_mask=None):
        for layer in self.layers:
            src = layer(src, src_mask=mask, src_key_padding_mask=src_key_padding_mask)
        return self.norm(src)

# 定义解码器层类
class DecoderLayer(nn.Module):
    def __init__(self, d_model, nhead, dim_feedforward=2048, dropout=0.1):
        super(DecoderLayer, self).__init__()
        self.self_attn = nn.MultiheadAttention(d_model, nhead, dropout=dropout)
        self.multihead_attn = nn.MultiheadAttention(d_model, nhead, dropout=dropout)
        self.linear1 = nn.Linear(d_model, dim_feedforward)
        self.dropout = nn.Dropout(dropout)
        self.linear2 = nn.Linear(dim_feedforward, d_model)
        self.norm1 = nn.LayerNorm(d_model)
        self.norm2 = nn.LayerNorm(d_model)
        self.norm3 = nn.LayerNorm(d_model)
        self.dropout1 = nn.Dropout(dropout)
        self.dropout2 = nn.Dropout(dropout)
        self.dropout3 = nn.Dropout(dropout)

    def forward(self, tgt, memory, tgt_mask=None, memory_mask=None, tgt_key_padding_mask=None, memory_key_padding_mask=None):
        tgt2 = self.self_attn(tgt, tgt, tgt, attn_mask=tgt_mask, key_padding_mask=tgt_key_padding_mask)[0]
        tgt = tgt + self.dropout1(tgt2)
        tgt = self.norm1(tgt)
        tgt2 = self.multihead_attn(tgt, memory, memory, attn_mask=memory_mask, key_padding_mask=memory_key_padding_mask)[0]
        tgt = tgt + self.dropout2(tgt2)
        tgt = self.norm2(tgt)
        tgt2 = self.linear2(self.dropout(F.relu(self.linear1(tgt))))
        tgt = tgt + self.dropout3(tgt2)
        tgt = self.norm3(tgt)
        return tgt

# 定义解码器类
class Decoder(nn.Module):
    def __init__(self, num_layers, d_model, nhead, dim_feedforward=2048, dropout=0.1):
        super(Decoder, self).__init__()
        self.layers = nn.ModuleList([DecoderLayer(d_model, nhead, dim_feedforward, dropout) for _ in range(num_layers)])
        self.norm = nn.LayerNorm(d_model)

    def forward(self, tgt, memory, tgt_mask=None, memory_mask=None, tgt_key_padding_mask=None, memory_key_padding_mask=None):
        for layer in self.layers:
            tgt = layer(tgt, memory, tgt_mask=tgt_mask, memory_mask=memory_mask, tgt_key_padding_mask=tgt_key_padding_mask, memory_key_padding_mask=memory_key_padding_mask)
        return self.norm(tgt)

# 定义完整的Transformer模型
class Transformer(nn.Module):
    def __init__(self, src_vocab_size, tgt_vocab_size, d_model=512, nhead=8, num_encoder_layers=6, num_decoder_layers=6, dim_feedforward=2048, dropout=0.1, max_len=5000):
        super(Transformer, self).__init__()
        self.src_embedding = nn.Embedding(src_vocab_size, d_model)
        self.tgt_embedding = nn.Embedding(tgt_vocab_size, d_model)
        self.positional_encoding = PositionalEncoding(d_model, max_len)
        self.encoder = Encoder(num_encoder_layers, d_model, nhead, dim_feedforward, dropout)
        self.decoder = Decoder(num_decoder_layers, d_model, nhead, dim_feedforward, dropout)
        self.fc_out = nn.Linear(d_model, tgt_vocab_size)

    def forward(self, src, tgt, src_mask=None, tgt_mask=None, src_key_padding_mask=None, tgt_key_padding_mask=None):
        src_embedded = self.positional_encoding(self.src_embedding(src))
        tgt_embedded = self.positional_encoding(self.tgt_embedding(tgt))
        memory = self.encoder(src_embedded, mask=src_mask, src_key_padding_mask=src_key_padding_mask)
        output = self.decoder(tgt_embedded, memory, tgt_mask=tgt_mask, memory_mask=src_mask, tgt_key_padding_mask=tgt_key_padding_mask, memory_key_padding_mask=src_key_padding_mask)
        return self.fc_out(output)

# 示例用法
# 假设我们有源语言和目标语言的词汇表大小分别为SRC_VOCAB_SIZE和TGT_VOCAB_SIZE
SRC_VOCAB_SIZE = 10000
TGT_VOCAB_SIZE = 10000
src = torch.randint(0, SRC_VOCAB_SIZE, (10, 32))  # (序列长度, 批次大小)
tgt = torch.randint(0, TGT_VOCAB_SIZE, (20, 32))  # (序列长度, 批次大小)

model = Transformer(SRC_VOCAB_SIZE, TGT_VOCAB_SIZE)
output = model(src, tgt)
print(output.shape)  # 输出形状应该为 (目标序列长度, 批次大小, 目标词汇表大小)

代码说明

  • PositionalEncoding:位置编码,用于给序列中每个标记提供位置信息。
  • EncoderLayer:编码器层,包含一个多头自注意力层和一个前馈神经网络。
  • Encoder:编码器,由多个编码器层堆叠而成。
  • DecoderLayer:解码器层,包含一个自注意力层、一个交叉注意力层和一个前馈神经网络。
  • Decoder:解码器,由多个解码器层堆叠而成。
  • Transformer:完整的Transformer模型,包括嵌入层、位置编码、编码器和解码器,以及最终的线性层用于生成输出。

示例用法

代码示例展示了如何初始化Transformer模型,并用随机生成的源序列和目标序列进行前向传播。输出的形状应该为[目标序列长度, 批次大小, 目标词汇表大小]。

这个实现是基础版本,实际应用中可能需要更多的细节处理,如掩码的正确设置、优化器和损失函数的定义等。

### 使用Transformer模型处理序列数据 #### 编码解码过程 Transformer模型通过编码器和解码器来处理序列数据。编码器接收输入序列并将其转换成高维向量表示,这一过程中利用了自注意力机制,允许每个位置上的元素关注整个序列中的其他元素[^1]。 ```python import torch from transformers import BertTokenizer, BertModel tokenizer = BertTokenizer.from_pretrained('bert-base-uncased') model = BertModel.from_pretrained('bert-base-uncased') input_text = "This is a sample sentence." tokens = tokenizer(input_text, return_tensors='pt') outputs = model(**tokens) hidden_states = outputs.last_hidden_state ``` 上述代码片段展示了如何使用预训练的BERT模型作为编码器的一部分来获取输入文本的隐藏状态表示。对于完整的Transformer架构,在得到编码后的特征之后,会传递给解码器进一步加工以生成目标序列。解码阶段同样依赖于自注意力建立上下文关联,并且还加入了跨注意力层用于捕捉源端与目的端之间的关系。 #### 应用场景 在不同领域内,根据具体需求可以选择仅采用编码组件或者构建全功能版的Transformers: - **自然语言理解任务**:如情感分析、问答系统等通常只需要强大的表征学习能力,因此往往只需部署编码部分即可满足要求; - **机器翻译/对话生成类的任务**:则需依靠完整的编解码框架完成从一种表达形式到另一种的有效映射; - **时间序列预测**:考虑到此类数据特有的模式(比如季节性和趋势),某些改进型变体像Autoformer被设计出来专门应对这类挑战,它引入了特定的时间分解模块以及自动相关性计算方式提升性能表现[^4]。 #### 实现方法 实际操作中,借助开源工具包能够极大简化开发流程。例如Hugging Face Transformers提供了丰富的API接口支持快速搭建基于Transformer的各种解决方案。下面给出一段简单的例子说明怎样调用该库来进行英德互译工作[^2]: ```python from transformers import MarianMTModel, MarianTokenizer src_lang = 'en' tgt_lang = 'de' model_name = f'Helsinki-NLP/opus-mt-{src_lang}-{tgt_lang}' tokenizer = MarianTokenizer.from_pretrained(model_name) model = MarianMTModel.from_pretrained(model_name) source_sentence = ["Hello world!"] translated = model.generate(**tokenizer(source_sentence, return_tensors="pt", padding=True)) print([tokenizer.decode(t, skip_special_tokens=True) for t in translated]) ``` 此段脚本首先指定了源语言和目标语言,接着选择了合适的多语种Marian NMT模型及其配套字典文件,最后实现了基本的翻译逻辑并通过控制台打印输出结果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

yiruzhao

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

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

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

打赏作者

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

抵扣说明:

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

余额充值