当前位置: 首页 > news >正文

大语言模型系列——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 的原理和使用有了更深入的理解,并能够将其应用于实际项目中。如果你有任何疑问或想要了解更多细节,请随时查阅官方文档或社区资源。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • Dav_笔记11:SQL Tuning Overview-sql调优 之 3
  • springboot整合 knife4j 接口文档
  • uniapp的h5,读取本地txt带标签的文件
  • 2024 暑假友谊赛 2
  • Win7电脑怎么录屏?分享3个方法,让您高效录制
  • Java中的模块(Module)入门介绍
  • 2D图像打包成一张图片
  • w30-python02-pytest入门
  • 二分查找代码详解
  • 【Vulnhub系列】Vulnhub_DC-1靶场渗透(原创)
  • IP协议+网络层
  • UDP程序设计
  • 使用 WebSocket 实现实时聊天
  • 大语言模型赋能设施农业:透过“智慧大脑“看智能环境调控
  • VUE3——001(03)、开发环境配置(node.js/mvn/java/ngix/tomact/vue3)
  • axios请求、和返回数据拦截,统一请求报错提示_012
  • export和import的用法总结
  • iOS 系统授权开发
  • Java 实战开发之spring、logback配置及chrome开发神器(六)
  • JavaScript对象详解
  • Java到底能干嘛?
  • mongo索引构建
  • node.js
  • ReactNative开发常用的三方模块
  • Stream流与Lambda表达式(三) 静态工厂类Collectors
  • yii2中session跨域名的问题
  • 包装类对象
  • 产品三维模型在线预览
  • 力扣(LeetCode)56
  • 微信支付JSAPI,实测!终极方案
  • 远离DoS攻击 Windows Server 2016发布DNS政策
  • MyCAT水平分库
  • #Linux(帮助手册)
  • #VERDI# 关于如何查看FSM状态机的方法
  • #传输# #传输数据判断#
  • (+3)1.3敏捷宣言与敏捷过程的特点
  • (ISPRS,2023)深度语义-视觉对齐用于zero-shot遥感图像场景分类
  • (pytorch进阶之路)CLIP模型 实现图像多模态检索任务
  • (Redis使用系列) Springboot 使用redis的List数据结构实现简单的排队功能场景 九
  • (八)Flink Join 连接
  • (附源码)springboot高校宿舍交电费系统 毕业设计031552
  • (十三)Maven插件解析运行机制
  • (转)C语言家族扩展收藏 (转)C语言家族扩展
  • (转)大道至简,职场上做人做事做管理
  • **Java有哪些悲观锁的实现_乐观锁、悲观锁、Redis分布式锁和Zookeeper分布式锁的实现以及流程原理...
  • .“空心村”成因分析及解决对策122344
  • .NET 4.0中使用内存映射文件实现进程通讯
  • .Net Core 中间件与过滤器
  • .Net Core中的内存缓存实现——Redis及MemoryCache(2个可选)方案的实现
  • .NET 中小心嵌套等待的 Task,它可能会耗尽你线程池的现有资源,出现类似死锁的情况
  • .net2005怎么读string形的xml,不是xml文件。
  • .net使用excel的cells对象没有value方法——学习.net的Excel工作表问题
  • .NET中的Event与Delegates,从Publisher到Subscriber的衔接!
  • .pyc文件还原.py文件_Python什么情况下会生成pyc文件?
  • /etc/fstab 只读无法修改的解决办法