大语言模型系列——Transformer 介绍与使用

引言

自从 Google 在 2017 年发表了一篇题为《Attention Is All You Need》的论文以来,Transformer 已经成为了自然语言处理领域的一个重要里程碑。与传统的 RNN 和 LSTM 不同,Transformer 通过自注意力机制(Self-Attention Mechanism)实现了更快、更高效的数据处理方式。本文将详细介绍 Transformer 的原理、架构以及如何在实际项目中使用 Transformer 模型。

1. Transformer 的背景

在 Transformer 问世之前,大多数 NLP 任务都是基于循环神经网络(RNN)或长短期记忆网络(LSTM)完成的。这些模型能够很好地处理序列数据,但在训练大型数据集时存在效率低下和难以并行化的问题。Transformer 的出现解决了这些问题,同时也极大地推动了自然语言处理的发展。

2. Transformer 的核心概念
  • 自注意力机制:Transformer 使用自注意力机制来捕捉输入序列中的全局上下文关系。
  • 位置编码:由于 Transformer 没有像 RNN 那样的序列依赖性,因此需要位置编码来保留序列的位置信息。
  • 编码器-解码器架构:Transformer 采用了编码器-解码器架构,其中编码器负责处理输入序列,而解码器则负责生成输出序列。
3. Transformer 的架构

Transformer 的架构主要包括以下几个部分:

  • 编码器(Encoder):由多层相同的子层组成,每一层包括一个多头自注意力机制和一个前馈神经网络。
  • 解码器(Decoder):同样由多层相同的子层组成,除了多头自注意力机制和前馈神经网络外,还包括一个额外的多头注意力层,用于关注编码器的输出。
  • 多头注意力(Multi-Head Attention):通过将注意力分成多个头,每个头独立计算注意力权重,从而提高模型的并行性和表达能力。
  • 前馈网络(Feed Forward Network):每个子层之后都有一个前馈网络,用于增加模型的非线性变换能力。
  • 残差连接与层归一化(Residual Connections & Layer Normalization):每个子层前后都加入了残差连接,并在其之后使用了层归一化来加速训练过程。
4. Transformer 的工作流程
  1. 输入嵌入:每个输入词被转换为一个固定大小的向量。
  2. 位置编码:为了保留词的位置信息,添加了位置编码。
  3. 多头自注意力:编码器和解码器的第一步是通过多头自注意力机制来处理输入序列。
  4. 前馈网络:通过前馈网络进行非线性变换。
  5. 解码器处理:解码器不仅处理自己的输入序列,还通过多头注意力层关注编码器的输出。
5. 使用 Transformer 的实践

为了展示如何在实际项目中使用 Transformer,我们将使用 Python 和 PyTorch 框架来构建一个简单的翻译模型。

5.1 环境搭建

确保你的环境中已安装 Python 和 PyTorch。你可以通过 pip 安装 PyTorch:

Bash

1pip install torch
5.2 数据准备

使用一个简单的翻译数据集,例如英语到法语的翻译数据集。

Python

1import torch
2from torchtext.data import Field, TabularDataset, BucketIterator
3from torchtext.data.metrics import bleu_score
4
5# 定义字段
6SRC = Field(tokenize='spacy', tokenizer_language='en_core_web_sm', init_token='<sos>', eos_token='<eos>', lower=True)
7TRG = Field(tokenize='spacy', tokenizer_language='fr_core_news_sm', init_token='<sos>', eos_token='<eos>', lower=True)
8
9# 加载数据
10train_data, valid_data, test_data = TabularDataset.splits(
11    path='data/', train='train.csv', validation='val.csv', test='test.csv',
12    format='csv', fields=[('src', SRC), ('trg', TRG)])
13
14# 构建词汇表
15SRC.build_vocab(train_data, min_freq=2)
16TRG.build_vocab(train_data, min_freq=2)
17
18# 创建迭代器
19device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
20train_iterator, valid_iterator, test_iterator = BucketIterator.splits(
21    (train_data, valid_data, test_data), batch_size=128, device=device)
5.3 构建 Transformer 模型

接下来,我们将定义 Transformer 模型。

Python

1import torch.nn as nn
2
3class Transformer(nn.Module):
4    def __init__(self, input_dim, output_dim, hid_dim, n_layers, n_heads, pf_dim, dropout, device, max_length=100):
5        super().__init__()
6        
7        self.tok_embedding = nn.Embedding(input_dim, hid_dim)
8        self.pos_embedding = nn.Embedding(max_length, hid_dim)
9        
10        self.layers = nn.ModuleList([EncoderLayer(hid_dim, n_heads, pf_dim, dropout, device) for _ in range(n_layers)])
11        
12        self.fc_out = nn.Linear(hid_dim, output_dim)
13        self.dropout = nn.Dropout(dropout)
14        self.device = device
15        
16    def forward(self, src, src_mask):
17        # src = [batch size, src len]
18        # src_mask = [batch size, 1, 1, src len]
19        
20        batch_size = src.shape[0]
21        src_len = src.shape[1]
22        
23        pos = torch.arange(0, src_len).unsqueeze(0).repeat(batch_size, 1).to(self.device)
24        
25        # pos = [batch size, src len]
26        
27        src = self.dropout((self.tok_embedding(src) + self.pos_embedding(pos)))
28        
29        # src = [batch size, src len, hid dim]
30        
31        for layer in self.layers:
32            src = layer(src, src_mask)
33            
34        # src = [batch size, src len, hid dim]
35            
36        output = self.fc_out(src)
37        
38        # output = [batch size, src len, output dim]
39        
40        return output
41
42class EncoderLayer(nn.Module):
43    def __init__(self, hid_dim, n_heads, pf_dim, dropout, device):
44        super().__init__()
45        
46        self.self_attn_layer_norm = nn.LayerNorm(hid_dim)
47        self.ff_layer_norm = nn.LayerNorm(hid_dim)
48        self.self_attention = MultiHeadAttentionLayer(hid_dim, n_heads, dropout, device)
49        self.positionwise_feedforward = PositionwiseFeedforwardLayer(hid_dim, pf_dim, dropout)
50        self.dropout = nn.Dropout(dropout)
51        
52    def forward(self, src, src_mask):
53        # src = [batch size, src len, hid dim]
54        # src_mask = [batch size, 1, 1, src len]
55        
56        _src, _ = self.self_attention(src, src, src, src_mask)
57        
58        # _src = [batch size, src len, hid dim]
59        
60        src = self.self_attn_layer_norm(src + self.dropout(_src))
61        
62        # src = [batch size, src len, hid dim]
63        
64        _src = self.positionwise_feedforward(src)
65        
66        # _src = [batch size, src len, hid dim]
67        
68        src = self.ff_layer_norm(src + self.dropout(_src))
69        
70        # src = [batch size, src len, hid dim]
71        
72        return src
5.4 训练模型

现在我们来训练我们的 Transformer 模型。

Python

1import math
2
3def train(model, iterator, optimizer, criterion, clip):
4    model.train()
5    
6    epoch_loss = 0
7    
8    for i, batch in enumerate(iterator):
9        src = batch.src
10        trg = batch.trg
11        
12        optimizer.zero_grad()
13        
14        output = model(src, trg[:, :-1])
15                
16        # output = [batch size, trg len - 1, output dim]
17        # trg = [batch size, trg len]
18            
19        output_dim = output.shape[-1]
20            
21        output = output.contiguous().view(-1, output_dim)
22        trg = trg[:, 1:].contiguous().view(-1)
23                
24        # output = [batch size * trg len - 1, output dim]
25        # trg = [batch size * trg len - 1]
26            
27        loss = criterion(output, trg)
28        loss.backward()
29        
30        torch.nn.utils.clip_grad_norm_(model.parameters(), clip)
31        
32        optimizer.step()
33        epoch_loss += loss.item()
34        
35    return epoch_loss / len(iterator)
36
37def evaluate(model, iterator, criterion):
38    model.eval()
39    
40    epoch_loss = 0
41    
42    with torch.no_grad():
43        for i, batch in enumerate(iterator):
44            src = batch.src
45            trg = batch.trg
46
47            output = model(src, trg[:, :-1])
48            
49            # output = [batch size, trg len - 1, output dim]
50            # trg = [batch size, trg len]
51            
52            output_dim = output.shape[-1]
53            
54            output = output.contiguous().view(-1, output_dim)
55            trg = trg[:, 1:].contiguous().view(-1)
56            
57            # output = [batch size * trg len - 1, output dim]
58            # trg = [batch size * trg len - 1]
59            
60            loss = criterion(output, trg)
61
62            epoch_loss += loss.item()
63        
64    return epoch_loss / len(iterator)
65
66def epoch_time(start_time, end_time):
67    elapsed_time = end_time - start_time
68    elapsed_mins = int(elapsed_time / 60)
69    elapsed_secs = int(elapsed_time - (elapsed_mins * 60))
70    return elapsed_mins, elapsed_secs
71
72INPUT_DIM = len(SRC.vocab)
73OUTPUT_DIM = len(TRG.vocab)
74HID_DIM = 256
75ENC_LAYERS = 3
76DEC_LAYERS = 3
77ENC_HEADS = 8
78DEC_HEADS = 8
79ENC_PF_DIM = 512
80DEC_PF_DIM = 512
81ENC_DROPOUT = 0.1
82DEC_DROPOUT = 0.1
83
84enc = Encoder(INPUT_DIM, HID_DIM, ENC_LAYERS, ENC_HEADS, ENC_PF_DIM, ENC_DROPOUT, device)
85dec = Decoder(OUTPUT_DIM, HID_DIM, DEC_LAYERS, DEC_HEADS, DEC_PF_DIM, DEC_DROPOUT, device)
86
87model = Seq2Seq(enc, dec, device).to(device)
88
89def count_parameters(model):
90    return sum(p.numel() for p in model.parameters() if p.requires_grad)
91
92print(f'The model has {count_parameters(model):,} trainable parameters')
93
94optimizer = torch.optim.Adam(model.parameters())
95
96PAD_IDX = TRG.vocab.stoi['<pad>']
97
98criterion = nn.CrossEntropyLoss(ignore_index=PAD_IDX)
99
100N_EPOCHS = 10
101CLIP = 1
102
103best_valid_loss = float('inf')
104
105for epoch in range(N_EPOCHS):
106    
107    start_time = time.time()
108    
109    train_loss = train(model, train_iterator, optimizer, criterion, CLIP)
110    valid_loss = evaluate(model, valid_iterator, criterion)
111    
112    end_time = time.time()
113    
114    epoch_mins, epoch_secs = epoch_time(start_time, end_time)
115    
116    if valid_loss < best_valid_loss:
117        best_valid_loss = valid_loss
118        torch.save(model.state_dict(), 'tut6-model.pt')
119    
120    print(f'Epoch: {epoch+1:02} | Time: {epoch_mins}m {epoch_secs}s')
121    print(f'\tTrain Loss: {train_loss:.3f} | Train PPL: {math.exp(train_loss):7.3f}')
122    print(f'\t Val. Loss: {valid_loss:.3f} |  Val. PPL: {math.exp(valid_loss):7.3f}')
6. 结论

Transformer 模型彻底改变了自然语言处理领域的面貌,它不仅提高了模型的训练速度,而且在许多任务上取得了显著的效果。通过本文的介绍,你应该对 Transformer 的原理和使用有了更深入的理解,并能够将其应用于实际项目中。如果你有任何疑问或想要了解更多细节,请随时查阅官方文档或社区资源。

相关推荐
Doctor老王3 小时前
TR3:Pytorch复现Transformer
人工智能·pytorch·transformer
CSDN云计算16 小时前
性能高于Transformer模型1.7-2倍,彩云科技发布基于DCFormer架构通用大模型云锦天章
大模型·transformer·dcformer·彩云天气·彩云小梦·云锦天章
小毕超1 天前
基于 PyTorch 从零手搓一个GPT Transformer 对话大模型
pytorch·gpt·transformer
小言从不摸鱼1 天前
【AI大模型】ELMo模型介绍:深度理解语言模型的嵌入艺术
人工智能·深度学习·语言模型·自然语言处理·transformer
irrationality2 天前
昇思大模型平台打卡体验活动:项目5基于MindSpore实现Transformer机器翻译
深度学习·transformer·机器翻译
神奇的布欧2 天前
TransFormer--注意力机制:位置编码
人工智能·python·深度学习·学习·transformer
陌上阳光2 天前
动手学深度学习68 Transformer
人工智能·深度学习·transformer
deephub3 天前
TSMamba:基于Mamba架构的高效时间序列预测基础模型
人工智能·深度学习·transformer·时间序列·mamba
Lor :)3 天前
深入浅出 ChatGPT 底层原理:Transformer
深度学习·chatgpt·transformer
Jacob_AI3 天前
P-tuning、Prompt-tuning和Prefix-tuning区别是什么?
语言模型·nlp·prompt·transformer