Transformer--详解

news/2024/12/22 16:31:40/

Transformer旨在解决自然语言处理任务中的长依赖性问题。与传统的递归神经网络(如LSTM、GRU)不同,Transformer完全摒弃了递归结构,依赖自注意力机制(Self-Attention)来建模输入序列中的所有位置之间的关系。因此,Transformer能够并行处理整个序列,这极大地提高了训练速度和效率。

Transformer在许多自然语言处理任务(如机器翻译、文本生成、文本分类等)中表现优异,尤其是大规模语言模型(如BERT、GPT、T5等)的基础架构。

Transformer的基本结构

Transformer模型由编码器(Encoder)解码器(Decoder)两个部分组成,二者都由堆叠的多层相似结构组成。以下是各部分的基本结构:

  1. 编码器(Encoder)

    • 编码器由多个层堆叠组成,每一层包括两个子层:

      1. 多头自注意力机制(Multi-Head Self-Attention):输入序列的所有位置之间进行相互注意,允许模型关注序列中不同部分的信息。

      2. 前馈神经网络(Feed-Forward Network):独立应用于每个位置。

    • 每个子层后都有一个残差连接和层归一化(Layer Normalization),使得梯度传播更为稳定。

  2. 解码器(Decoder)

    • 解码器也由多个层堆叠组成,但每层有三个子层:

      1. Masked 多头自注意力机制:确保模型在生成序列时,每个位置只能关注之前的位置。

      2. 编码器-解码器注意力:解码器关注编码器的输出。

      3. 前馈神经网络

    • 同样每个子层后都有残差连接和层归一化。

  3. 注意力机制(Attention Mechanism)

    • Transformer依赖于一种称为Scaled Dot-Product Attention的注意力机制。它通过计算查询(Query)、键(Key)和值(Value)之间的点积来生成注意力分数。

  4. 位置编码(Positional Encoding)

    • Transformer没有递归结构,因此模型需要一种方式来捕捉序列中的位置信息。位置编码通过正弦和余弦函数添加到输入嵌入上,帮助模型捕获位置信息。

Transformer的经典代码

以下是使用Keras实现Transformer编码器的简化代码示例:

import numpy as np
import tensorflow as tf
from tensorflow.keras.layers import Dense, LayerNormalization, Dropout, Embedding
from tensorflow.keras.models import Model
​
# Scaled Dot-Product Attention
def scaled_dot_product_attention(query, key, value, mask=None):matmul_qk = tf.matmul(query, key, transpose_b=True)  # 计算Q和K的点积dk = tf.cast(tf.shape(key)[-1], tf.float32)scaled_attention_logits = matmul_qk / tf.math.sqrt(dk)  # 缩放
​if mask is not None:scaled_attention_logits += (mask * -1e9)  # 如果有mask,填充为负无穷
​attention_weights = tf.nn.softmax(scaled_attention_logits, axis=-1)  # 归一化output = tf.matmul(attention_weights, value)  # 计算权重与V的乘积return output, attention_weights
​
# Multi-head Attention Layer
class MultiHeadAttention(tf.keras.layers.Layer):def __init__(self, d_model, num_heads):super(MultiHeadAttention, self).__init__()self.num_heads = num_headsself.d_model = d_model
​assert d_model % self.num_heads == 0  # 确保可以均匀分成多个头
​self.depth = d_model // self.num_heads
​self.wq = Dense(d_model)self.wk = Dense(d_model)self.wv = Dense(d_model)self.dense = Dense(d_model)
​def split_heads(self, x, batch_size):# 将最后一个维度分成多个头x = tf.reshape(x, (batch_size, -1, self.num_heads, self.depth))return tf.transpose(x, perm=[0, 2, 1, 3])
​def call(self, v, k, q, mask=None):batch_size = tf.shape(q)[0]
​# 通过线性层获得Q, K, Vq = self.wq(q)k = self.wk(k)v = self.wv(v)
​# 分割为多个头q = self.split_heads(q, batch_size)k = self.split_heads(k, batch_size)v = self.split_heads(v, batch_size)
​# 计算注意力scaled_attention, attention_weights = scaled_dot_product_attention(q, k, v, mask)
​# 合并所有头scaled_attention = tf.transpose(scaled_attention, perm=[0, 2, 1, 3])concat_attention = tf.reshape(scaled_attention, (batch_size, -1, self.d_model))
​output = self.dense(concat_attention)  # 通过最后的线性层return output, attention_weights
​
# 前馈网络
def point_wise_feed_forward_network(d_model, dff):return tf.keras.Sequential([Dense(dff, activation='relu'),  # 第一层Dense(d_model)  # 第二层])
​
# Transformer Encoder Layer
class EncoderLayer(tf.keras.layers.Layer):def __init__(self, d_model, num_heads, dff, rate=0.1):super(EncoderLayer, self).__init__()
​self.mha = MultiHeadAttention(d_model, num_heads)  # 多头注意力self.ffn = point_wise_feed_forward_network(d_model, dff)  # 前馈网络
​self.layernorm1 = LayerNormalization(epsilon=1e-6)self.layernorm2 = LayerNormalization(epsilon=1e-6)
​self.dropout1 = Dropout(rate)self.dropout2 = Dropout(rate)
​def call(self, x, mask=None):attn_output, _ = self.mha(x, x, x, mask)  # 自注意力attn_output = self.dropout1(attn_output)out1 = self.layernorm1(x + attn_output)  # 残差连接 + LayerNorm
​ffn_output = self.ffn(out1)  # 前馈ffn_output = self.dropout2(ffn_output)out2 = self.layernorm2(out1 + ffn_output)  # 残差连接 + LayerNorm
​return out2
​
# Transformer Encoder
class Encoder(tf.keras.layers.Layer):def __init__(self, num_layers, d_model, num_heads, dff, input_vocab_size, maximum_position_encoding, rate=0.1):super(Encoder, self).__init__()
​self.d_model = d_modelself.num_layers = num_layers
​self.embedding = Embedding(input_vocab_size, d_model)self.pos_encoding = positional_encoding(maximum_position_encoding, self.d_model)
​self.enc_layers = [EncoderLayer(d_model, num_heads, dff, rate) for _ in range(num_layers)]
​self.dropout = Dropout(rate)
​def call(self, x, mask=None):seq_len = tf.shape(x)[1]
​# 添加embedding和位置编码x = self.embedding(x)x *= tf.math.sqrt(tf.cast(self.d_model, tf.float32))x += self.pos_encoding[:, :seq_len, :]
​x = self.dropout(x)
​for i in range(self.num_layers):x = self.enc_layers[i](x, mask)
​return x
​
# 位置编码
def positional_encoding(position, d_model):angle_rads = get_angles(np.arange(position)[:, np.newaxis], np.arange(d_model)[np.newaxis, :], d_model)angle_rads[:, 0::2] = np.sin(angle_rads[:, 0::2])  # apply sin to even indices in the arrayangle_rads[:, 1::2] = np.cos(angle_rads[:, 1::2])  # apply cos to odd indices in the arraypos_encoding = angle_rads[np.newaxis, ...]return tf.cast(pos_encoding, dtype=tf.float32)
​
def get_angles(pos, i, d_model):angle_rates = 1 / np.power(10000, (2 * (i // 2)) / np.float32(d_model))return pos * angle_rates

文本生成任务的示例代码

接下来是如何使用Transformer架构进行文本生成。这种生成任务可以视为基于语言模型的任务,即给定一部分文本,预测接下来的文本。

使用一个已经训练好的Transformer语言模型来生成文本,以下是简化的文本生成代码:

import numpy as np
import tensorflow as tf
from tensorflow.keras.preprocessing.sequence import pad_sequences
​
# 假设已经有了一个训练好的Transformer模型
# 为了生成文本,需要以下步骤:
​
def generate_text(model, tokenizer, seed_text, max_sequence_len, num_words):for _ in range(num_words):token_list = tokenizer.texts_to_sequences([seed_text])[0]  # 将种子文本转换为token序列token_list = pad_sequences([token_list], maxlen=max_sequence_len-1, padding='pre')  # 填充序列predicted = model.predict(token_list, verbose=0)  # 预测下一个单词predicted_word_index = np.argmax(predicted, axis=-1)  # 获取最大概率的单词索引output_word = ""for word, index in tokenizer.word_index.items():if index == predicted_word_index:output_word = wordbreakseed_text += " " + output_word  # 更新种子文本return seed_text
​
# 使用示例:
seed_text = "The future of AI"
generated_text = generate_text(model, tokenizer, seed_text, max_sequence_len=10, num_words=50)
print(generated_text)

代码解释:

  1. 多头注意力机制:实现了Transformer中的核心模块——多头注意力机制,它可以让模型同时关注输入序列中的不同部分。

  2. 前馈神经网络:每一层中除了注意力机制外,还包含一个前馈网络以增强模型的表达能力。

  3. 位置编码:用于给Transformer提供序列位置信息。

  4. 文本生成函数:利用训练好的模型进行文本预测,逐步生成句子。

总结

Transformer凭借其并行化的结构、自注意力机制以及位置编码技术,能够非常有效地处理长距离依赖问题。它被广泛应用于各类自然语言处理任务,尤其是在大规模预训练语言模型中(如BERT、GPT等)。


http://www.ppmy.cn/news/1536184.html

相关文章

Bianchi模型、python计算及ns3验证_关于2~10 STA验证的补充

首先就是预设修改, NS3中bitrate是OfdmRate54Mbps,STA数目我设置了2-10,ack长度是14bytes,数据长36,头36(trace中只有1536和14两个长度,也就是数据长度1500,头36,ack14),SIFS和SLOT是16us和9us(在phy的定义中,11a的时候,sifs是16,slot是9),difs是34us(在bia…

苍穹外卖学习笔记(十五)

文章目录 一. 缓存菜品缓存菜品DishController.java清除缓存数据 缓存套餐Spring Cachemaven坐标常用注解 入门案例springcachedemo.sqlpom.xmlapplication.ymlCacheDemoApplication.javaWebMvcConfiguration.javaUserController.javaUser.javaUserMapper.java 套餐管理SkyAppl…

在Ubuntu 18.04上安装Webmin的方法

前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。 介绍 Webmin 是一个基于 Web 的控制面板,适用于任何 Linux 机器,它可以让你通过现代化的 Web 界面管理服务器。…

解锁空间距离计算的多种方式-含前端、空间数据库、后端

目录 前言 一、空间数据库求解 1、PostGIS实现 二、GIS前端组件求解 1、Leaflet.js距离测算 2、Turf.js前端计算 三、后台距离计算生成 1、欧式距离 2、Haversice球面距离 3、GeoTools距离计算 4、Gdal距离生成 5、geodesy距离计算 四、成果与生成对比 1、Java不…

深度学习-20-深入理解基于Streamlit和minimind小模型开发本地聊天工具

文章目录 1 Streamlit开发聊天工具1.1 初始化聊天信息1.2 渲染历史信息1.3 接收用户输入1.4 模拟调用LLM1.5 整体代码2 使用minimind2.1 下载模型2.2 使用模型3 Streamlit与minimind3.1 Streamlit相关知识点3.2 示例代码4 参考附录1 Streamlit开发聊天工具 Streamlit是一个开源…

FPGA时序分析和约束学习笔记(1、FPGA基本原理)

FPGA时序分析和约束学习笔记-(1、FPGA基本原理) Field现场Programmable可编程Gate门Array阵列 1、FPGA基本资源组成 可编程逻辑功能块(logic elements ,缩写LE) 片内互联线(interconnect,缩写…

Nginx的核心架构和设计原理

Nginx 是一个免费的、开源的、高性能 Http 服务器和反向代理。Nginx 的架构设计是为了提供高性能、稳定性和可扩展性。 Nginx 的主要架构组件和工作原理: 1、Master 进程:Nginx 的运行始于一个 master 进程,它负责管理所有的工作进程。mast…

基于少样本(小样本)的图像分割

在少样本学习(尤其是少样本分割)中,query branch 和 support branch 分别承担不同的任务,目的是通过少量标注的样本来实现对新图像的分割。它们的具体作用如下: Support Branch(支持分支)&#…