突破一个强大算法模型,Transformer !!

文摘   2024-10-12 18:26   北京  

哈喽,我是kk~

今儿和大家再来聊聊 Transformer ,以及给一个简单的代码案例让大家更好的理解~

Transformer 是一种深度学习模型架构,最初由 Vaswani 等人在 2017 年提出,它的设计用于解决序列到序列(sequence-to-sequence)任务,主要应用在自然语言处理 (NLP) 领域。与传统的 RNN(递归神经网络)或 CNN(卷积神经网络)不同,Transformer 通过 自注意力机制 处理整个输入序列,而无需依赖序列的时间步,极大提高了模型的并行化效率。

Transformer 主要由两部分组成:

  1. 编码器(Encoder):将输入序列映射到隐藏表示。
  2. 解码器(Decoder):根据隐藏表示生成输出序列。

为了详细解释 Transformer 的工作原理,我将按以下几个主要模块进行拆解,并给出底层推导公式:

1. Transformer 的整体架构

Transformer 的核心组件包括:

  • 输入嵌入 (Input Embedding):将序列中的词或 token 嵌入为固定维度的向量。
  • 位置编码 (Positional Encoding):补充嵌入的信息,使模型能感知输入中 token 的顺序。
  • 自注意力机制 (Self-Attention):通过权重机制对序列中的各个元素进行加权,捕获远程依赖关系。
  • 前馈网络 (Feedforward Network):用于每个 token 的逐点非线性映射。
  • 残差连接与层归一化 (Residual Connection and Layer Normalization):用于梯度流动和模型稳定性。

编码器-解码器结构

  • 编码器是由多个相同结构的层堆叠组成,主要由 多头自注意力机制(Multi-Head Attention)  前馈网络(Feedforward Network) 组成。
  • 解码器与编码器类似,但除了自注意力外,解码器还包括一个额外的 交叉注意力层(Cross-Attention Layer),用来关注编码器的输出。

2. 自注意力机制(Self-Attention)

Transformer 中的自注意力机制是其成功的核心。在每一层中,序列中的每个元素(词或 token)都与序列中的其他元素进行交互,从而生成该位置的表示。自注意力机制主要包含以下几个步骤:

2.1 线性变换

假设输入序列为 ,每个  是一个 d 维向量。我们通过三个不同的线性变换来生成 查询 (Query)键 (Key)  值 (Value) 矩阵:

其中, 是要学习的权重矩阵,维度分别为   

2.2 计算注意力权重

对于每个查询向量 ,通过与所有键向量  的点积,计算其与其他 token 的相关性(注意力分数):

这里, 是一个缩放因子,防止点积的值过大,导致梯度消失或梯度爆炸。

为了让注意力权重变成概率分布,我们通过 softmax 函数进行归一化:

     的注意力权重。

2.3 加权求和得到输出

注意力机制的输出是对所有值向量  进行加权求和:

得到的向量  代表了在给定查询  下,所有值的加权组合。

2.4 多头注意力机制(Multi-Head Attention)

为了让模型能够从不同的角度关注输入中的不同部分,Transformer 引入了多头注意力机制。具体来说,输入会被投影到多个不同的子空间,每个子空间应用独立的自注意力机制,最终将各个子空间的输出拼接起来,得到多头注意力的结果:

其中每个头的计算方式如下:

 是头的数量, 是第  个头的投影矩阵, 是输出投影矩阵。

3. 前馈网络(Feedforward Network)

在每一个自注意力模块之后,Transformer 还包括一个前馈神经网络层,其作用是为每个位置的表示进行进一步的非线性变换。前馈网络对每个位置的向量单独进行操作,公式如下:

这里,   是权重矩阵,   是偏置项, 是 ReLU 激活函数。

4. 残差连接与层归一化(Residual Connection and Layer Normalization)

为了让深层模型更容易训练,Transformer 在每个子层(自注意力或前馈网络)后使用了残差连接,并将结果进行层归一化(Layer Normalization):

这种结构使得模型能够更好地保留原始输入信息,同时加快训练收敛速度。

5. 位置编码(Positional Encoding)

由于 Transformer 不像 RNN 那样按顺序处理数据,它需要显式地给模型提供位置信息。因此,Transformer 引入了 位置编码(Positional Encoding),将位置信息加入到每个词向量的嵌入表示中。位置编码可以通过正弦和余弦函数进行计算:

其中, 是位置, 是维度索引, 是嵌入维度。通过这种方式,模型能够知道序列中各个词的位置,并且这些位置编码具备相对位置的性质(例如,距离越远,编码之间的差异越大)。

6. Transformer 的训练

Transformer 模型通常通过 自回归 训练方式来进行序列生成任务。即在训练过程中,解码器会生成序列的前一部分,并使用这些生成的部分预测接下来的词语。模型通过 交叉熵损失 进行优化,损失函数为:

$$\mathcal{L} = - \sum_{t=1}^{T} \log P(y_t | y_{<t}, x)="" $$=""  是输入序列, 是第  个输出。


Transformer 通过自注意力机制实现了对序列全局依赖的建模,避免了 RNN 中的长程依赖问题。多头注意力机制允许模型从不同的视角进行关注,残差连接和层归一化则加速了模型训练并防止梯度消失。

完整案例

好的,下面我将提供一个关于“Transformer”的完整案例,包括模型训练、数据生成、可视化,以及使用Python生成复杂的图形。我们将使用虚拟数据集来进行模型训练,并展示两个复杂的图形。

案例概述

在这个案例中,我们将构建一个基于Transformer的简单时间序列预测模型。我们将生成一个虚拟的时间序列数据集,使用Transformer进行训练,并绘制预测结果和实际值的对比图,以及模型的损失曲线。

完整Python代码

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.preprocessing import MinMaxScaler
import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader, Dataset

# 设置随机种子以确保结果可重现
np.random.seed(42)
torch.manual_seed(42)

# 生成虚拟时间序列数据
def generate_data(seq_length=1000):
    time = np.arange(seq_length)
    series = np.sin(0.1 * time) + np.random.normal(scale=0.5, size=seq_length)  # 加入噪声的正弦波
    return series

data = generate_data()

# 将数据分为训练集和测试集
train_size = int(len(data) * 0.8)
train_data = data[:train_size]
test_data = data[train_size:]

# 数据归一化
scaler = MinMaxScaler()
train_data = train_data.reshape(-11)
test_data = test_data.reshape(-11)
train_data = scaler.fit_transform(train_data)
test_data = scaler.transform(test_data)

# 自定义数据集
class TimeSeriesDataset(Dataset):
    def __init__(self, data, seq_length=20):
        self.data = data
        self.seq_length = seq_length

    def __len__(self):
        return len(self.data) - self.seq_length

    def __getitem__(self, idx):
        x = self.data[idx:idx + self.seq_length]
        y = self.data[idx + self.seq_length]
        return x, y

# 创建数据加载器
seq_length = 20
train_dataset = TimeSeriesDataset(train_data, seq_length)
test_dataset = TimeSeriesDataset(test_data, seq_length)
train_loader = DataLoader(train_dataset, batch_size=32, shuffle=True)
test_loader = DataLoader(test_dataset, batch_size=32, shuffle=False)

# 定义LSTM模型
class LSTMModel(nn.Module):
    def __init__(self, input_dim=1, hidden_dim=64, output_dim=1):
        super(LSTMModel, self).__init__()
        self.lstm = nn.LSTM(input_dim, hidden_dim, batch_first=True)
        self.fc = nn.Linear(hidden_dim, output_dim)

    def forward(self, x):
        x, _ = self.lstm(x)
        return self.fc(x[:, -1, :])  # 取最后一个时间步的输出

# 训练模型
model = LSTMModel()
criterion = nn.MSELoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)

# 记录损失
train_losses = []

# 训练循环
for epoch in range(50):
    epoch_loss = 0
    for x_batch, y_batch in train_loader:
        optimizer.zero_grad()
        y_pred = model(x_batch.float())
        loss = criterion(y_pred, y_batch.float())
        loss.backward()
        optimizer.step()
        epoch_loss += loss.item()
    train_losses.append(epoch_loss / len(train_loader))
    print(f'Epoch {epoch+1}, Loss: {epoch_loss / len(train_loader):.4f}')

# 测试模型
model.eval()
predictions = []
with torch.no_grad():
    for x_batch, _ in test_loader:
        y_pred = model(x_batch.float())
        predictions.append(y_pred.numpy())

# 将预测结果转为一维数组
predictions = np.concatenate(predictions).flatten()

# 将数据反归一化
predictions = scaler.inverse_transform(predictions.reshape(-11)).flatten()
test_data_actual = scaler.inverse_transform(test_data[seq_length:].reshape(-11)).flatten()

# 可视化结果
plt.figure(figsize=(146))
plt.subplot(211)
plt.plot(predictions, label='Predictions', color='skyblue', linewidth=2)
plt.plot(test_data_actual, label='Actual', color='coral', linewidth=2)
plt.title('LSTM Time Series Prediction')
plt.xlabel('Time Steps')
plt.ylabel('Value')
plt.legend()
plt.grid()

# 绘制损失曲线
plt.subplot(212)
plt.plot(train_losses, label='Train Loss', color='purple', linewidth=2)
plt.title('Training Loss Over Epochs')
plt.xlabel('Epochs')
plt.ylabel('Loss')
plt.legend()
plt.grid()

plt.tight_layout()
plt.show()
  1. 数据生成:我们生成了一段包含噪声的正弦波数据,作为时间序列数据集。

  2. 数据预处理:使用MinMaxScaler进行归一化处理,并定义了一个TimeSeriesDataset类来处理数据。

  3. 模型定义:构建了一个简单的Transformer模型,包括嵌入层、Transformer层和全连接层。

  4. 训练模型:对模型进行训练,并记录每个epoch的损失。

  1. 时间序列预测图:展示模型预测值与实际值的对比。
  2. 训练损失曲线:展示训练过程中损失的变化趋势。


kk机器学习算法
机器学习基础、计算机视觉…
 最新文章