手搓Transformer代码(简易版)复现

环境配置

1.创建环境

2.下包 

math、torch、numpy

代码流程

1.基本设置

1.导包

import math
import torch
import numpy as np
import torch.nn as nn
import torch.optim as optim
import torch.utils.data as Data

2.基本设置

#设置设备为cuda
device = 'cuda'

# 周期为50
epochs = 50

2.设置数据集及处理

1.设置手动数据集

定义了一个训练数据集sentence,其中包含了三对中文到英语的句子。每个句子都被分成了三个部分:enc_input编码器的输入,即中文句子),dec_input解码器的输入,包含了一个开始符号S和英语句子),dec_output解码器的输出,包含了英语句子和一个结束符号E)。

# 训练集
sentences = [
    # 中文和英语的单词个数不要求相同
    # enc_input                dec_input           dec_output
    ['我 有 一 个 好 朋 友 P', 'S I have a good friend .', 'I have a good friend . E'],
    ['我 有 零 个 女 朋 友 P', 'S I have zero girl friend .', 'I have zero girl friend . E'],
    ['我 有 一 个 男 朋 友 P', 'S I have a boy friend .', 'I have a boy friend . E']
]

为中文(源语言)和英语(目标语言)分别创建了词汇表src_vocabtgt_vocab
src_idx2word为一个字典,将单词映射到唯一的索引。同时创建了索引到单词的映射src_idx2wordidx2word,以及计算词汇表的大小src_vocab_sizetgt_vocab_size

# 中文和英语的单词要分开建立词库
# Padding Should be Zero
src_vocab = {'P': 0, '我': 1, '有': 2, '一': 3,
             '个': 4, '好': 5, '朋': 6, '友': 7, '零': 8, '女': 9, '男': 10}
src_idx2word = {i: w for i, w in enumerate(src_vocab)}
src_vocab_size = len(src_vocab)

tgt_vocab = {'P': 0, 'I': 1, 'have': 2, 'a': 3, 'good': 4,
             'friend': 5, 'zero': 6, 'girl': 7,  'boy': 8, 'S': 9, 'E': 10, '.': 11}
idx2word = {i: w for i, w in enumerate(tgt_vocab)}
tgt_vocab_size = len(tgt_vocab)

源语言和目标语言句子的最大长度src_lentgt_len

d_model:模型中嵌入向量的维度,也是位置编码的维度。

d_ff:前馈神经网络中间层的维度。

d_kd_v:注意力机制中查询(Q)和键(K)、值(V)的维度。

n_layers:编码器和解码器中层的数量。

n_heads:多头注意力机制中的头数。

src_len = 8  # (源句子的长度)enc_input max sequence length
tgt_len = 7  # dec_input(=dec_output) max sequence length

# Transformer Parameters
d_model = 512  # Embedding Size(token embedding和position编码的维度)
# FeedForward dimension (两次线性层中的隐藏层 512->2048->512,线性层是用来做特征提取的),当然最后会再接一个projection层
d_ff = 2048
d_k = d_v = 64  # dimension of K(=Q), V(Q和K的维度需要相同,这里为了方便让K=V)
n_layers = 6  # number of Encoder of Decoder Layer(Block的个数)
n_heads = 8  # number of heads in Multi-Head Attention(有几套头)

2.处理加工数据集

定义了一个函数make_data,其目的是将句子中的单词转换成对应的数字序列,这些数字序列可以用于训练机器翻译模型。

函数接受一个参数sentence,这是一个列表,其中包含了多个句子,每个句子都是一个包含三个字符串的列表:中文句子(编码器输入)、带有开始符号的英文句子(解码器输入)、以及英文句子(解码器输出)。

首先初始化了三个空列表enc_inputsdec_inputsdec_outputs,用于存储转换后的数字序列。然后,它遍历sentence中的每个句子,并将每个句子的单词转换成对应的数字。这是通过使用之前定义的src_vocabtgt_vocab词汇表来完成的,这些词汇表将单词映射到唯一的整数索引。

对于每个句子,代码执行以下操作:

  • enc_input:将中文句子中的每个单词转换为其在src_vocab中的索引,并将结果存储为一个列表。
  • dec_input:将带有开始符号的英文句子中的每个单词转换为其在tgt_vocab中的索引,并将结果存储为一个列表。
  • dec_output:将英文句子中的每个单词(不包括开始符号)转换为其在tgt_vocab中的索引,并将结果存储为一个列表。

然后,使用extend方法将这些转换后的列表添加到enc_inputsdec_inputsdec_outputs中。最后,函数返回三个torch.LongTensor对象,这些对象包含了所有转换后的数字序列,可以用于训练PyTorch模型。

在函数调用make_data(sentences)之后,enc_inputsdec_inputsdec_outputs将包含转换后的数字序列,这些序列可以用于训练Transformer模型进行机器翻译。

def make_data(sentences):
    """把单词序列转换为数字序列"""
    enc_inputs, dec_inputs, dec_outputs = [], [], []
    for i in range(len(sentences)):
 
        enc_input = [[src_vocab[n] for n in sentences[i][0].split()]]
        dec_input = [[tgt_vocab[n] for n in sentences[i][1].split()]]
        dec_output = [[tgt_vocab[n] for n in sentences[i][2].split()]]

        #[[1, 2, 3, 4, 5, 6, 7, 0], [1, 2, 8, 4, 9, 6, 7, 0], [1, 2, 3, 4, 10, 6, 7, 0]]
        enc_inputs.extend(enc_input)
        #[[9, 1, 2, 3, 4, 5, 11], [9, 1, 2, 6, 7, 5, 11], [9, 1, 2, 3, 8, 5, 11]]
        dec_inputs.extend(dec_input)
        #[[1, 2, 3, 4, 5, 11, 10], [1, 2, 6, 7, 5, 11, 10], [1, 2, 3, 8, 5, 11, 10]]
        dec_outputs.extend(dec_output)

    return torch.LongTensor(enc_inputs), torch.LongTensor(dec_inputs), torch.LongTensor(dec_outputs)


enc_inputs, dec_inputs, dec_outputs = make_data(sentences)

3.构建Transformer模型

1.全部代码

# ====================================================================================================
# Transformer模型

class PositionalEncoding(nn.Module):
    def __init__(self, d_model, dropout=0.1, max_len=5000):
        super(PositionalEncoding, self).__init__()
        self.dropout = nn.Dropout(p=dropout)

   
### 构建基于Transformer的大规模对话模型 #### 选择合适的框架和库 为了高效开发并利用现有的优化成果,建议选用成熟的深度学习框架如 TensorFlow 或 PyTorch 来搭建 Transformer 模型。Hugging Face 提供了一个名为 `transformers` 的Python 库[^2],该库不仅简化了预训练模型的加载过程,还支持多种主流的语言模型。 #### 数据准备与预处理 对于对话系统而言,高质量的数据集至关重要。理想情况下,应当收集大量的人类真实对话记录作为训练素材。这些原始文本需经过清洗、分词以及转换成适合喂给神经网络的形式——通常是整数索引列表。此外,还需考虑加入特殊的标记符(如 `[CLS]`, `[SEP]`),以便于模型理解上下文关系[^1]。 #### 自定义Transformer架构设计 核心在于重新定义编码器(encoder)-解码器(decoder)结构中的各个组件: - **位置编码(Positional Encoding)**:由于标准RNN/LSTM/CNN无法捕捉到序列的位置信息,在此引入固定或可学习的位置嵌入向量来弥补这一缺陷。 - **多头自注意力(Multi-head Self Attention)**:这是使 Transformer 能够关注不同部分输入的能力的关键所在;通过多个平行运行的关注机制,允许模型在同一时间点上聚焦于源句子的不同片段。 ```python import torch.nn as nn from transformers import BertConfig, EncoderDecoderModel config_encoder = BertConfig(vocab_size=..., hidden_size=...) config_decoder = BertConfig(vocab_size=..., hidden_size=...) model = EncoderDecoderModel.from_encoder_decoder_pretrained( 'bert-base-uncased', 'bert-base-uncased', config_encoder=config_encoder, config_decoder=config_decoder ) ``` #### 训练策略 考虑到计算资源有限而所需参数众多的特点,推荐采取迁移学习的方式初始化权重,并针对特定任务微调(fine-tune)整个体系。同时设置合理的超参组合(比如批次大小(batch size),初始学习率(initial learning rate)等),并通过早停法(early stopping)防止过拟合现象的发生。 #### 部署上线 完成离线评估后,可通过 RESTful API 形式对外提供服务接口,方便前端应用程序集成调用。另外也可以探索实时推理加速技术,例如量化(quantization)或者剪枝(pruning)[^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值