从零开始在本地部署大模型:基于Llama 3.1

目录

1. 简介

2. 准备工作

3. 核心实现步骤

3.1 加载分词器

3.2 读取模型文件

3.3 文本到Token的转换

3.4 Token到Embedding的转换

3.5 归一化Embedding

3.6 构建Transformer层

3.7 位置编码(RoPE)

3.8 Key的实现

3.9 计算Self-Attention

3.10 Query Key Scores Masking

4. 微调模型

4.1 准备数据集

4.2 定义损失函数和优化器

4.3 训练循环

4.4 保存模型

5. 实战项目

5.1 项目简介与数据集选择

5.2 数据预处理

5.3 模型训练与评估

5.4 模型优化

5.5 部署模型


本文免费发表于我的微信公众号:“AI与编程之窗”,请关注我的公众号后免费阅读,搜索“AI与编程之窗”或扫描以下二维码添加关注。


 

1. 简介

Llama 3.1 是 Meta 公司于 2024 年 7 月 23 日发布的最新开源大语言模型。这一版本在先前 Llama 3 的基础上进行了增强,支持多模态处理,并具有多种参数规模,包括 8B、70B 和 405B 参数。Llama 3.1 经过大规模文本数据的预训练,并结合了超过 1000 万个人工标注的示例,显著提高了模型的性能和适应性。Llama 3.1 尤其在多语言对话和编码能力方面表现出色,是目前 Meta 最先进的大语言模型之一。

Meta公司开源了Llama 3.1大模型,任何人都可以下载并用于二次开发。本教程的目的是帮助用户从头开始构建自己的Llama 3.1模型,包括在本地搭建自己的大模型和对大模型进行微调。通过详细的步骤讲解,我们将引导您完成Llama 3.1模型的安装、配置、训练以及微调,帮助您充分利用这个先进的开源大语言模型。

2. 准备工作

2.1 系统要求

在开始之前,确保您的系统满足以下要求:

  • 操作系统:Linux (推荐Ubuntu)
  • Python 版本:Python 3.8及以上
  • GPU:NVIDIA GPU,支持CUDA 11及以上
  • CUDA和cuDNN已正确安装

2.2 安装必要的依赖库

首先,安装所需的Python库:

pip install torch matplotlib tiktoken

2.3 下载模型和分词器

从Meta的官方网站下载Llama 3.1模型权重和分词器文件。假设下载链接如下:

  • 模型权重: https://llama.meta.com/llama3.1/model.pth
  • 分词器: https://llama.meta.com/llama3.1/tokenizer.model

下载后,将它们保存在您的工作目录中。

3. 核心实现步骤

3.1 加载分词器

使用 tiktoken 库加载和使用 Llama 3.1 的分词器。以下是下载分词器模型并进行初始化的详细步骤。

安装 tiktoken

首先,确保您已经安装了 tiktoken 库。如果没有安装,请使用以下命令进行安装:

pip install tiktoken
下载分词器模型

从Meta的官方网站下载Llama 3.1的分词器模型。假设下载链接为:

  • 分词器模型: https://llama.meta.com/llama3.1/tokenizer.model

将下载的文件保存到您的工作目录中,例如 path/to/tokenizer.model

初始化分词器

接下来,使用 tiktoken 库加载并初始化分词器模型。以下是示例代码:

from pathlib import Path
import tiktoken

# 指定分词器模型的路径
tokenizer_path = "path/to/tokenizer.model"

# 特殊令牌,可以根据需要添加更多的特殊令牌
special_tokens = ["<|startoftext|>", "<|endoftext|>"]

# 加载分词器模型
mergeable_ranks = tiktoken.load(tokenizer_path)

# 初始化分词器
tokenizer = tiktoken.Encoding(
    name=Path(tokenizer_path).name,
    mergeable_ranks=mergeable_ranks,
    special_tokens={token: len(mergeable_ranks) + i for i, token in enumerate(special_tokens)},
)

# 测试分词器
encoded = tokenizer.encode("hello world!")
decoded = tokenizer.decode(encoded)

print("Encoded:", encoded)
print("Decoded:", decoded)
代码解析
  1. 安装和导入库:首先确保安装了 tiktoken 库,并导入需要的模块。
  2. 指定路径:设置分词器模型的路径为 tokenizer_path
  3. 定义特殊令牌:定义一些特殊令牌,如文本开始和结束标记。
  4. 加载模型:使用 tiktoken.load 方法加载分词器模型。
  5. 初始化分词器:通过 tiktoken.Encoding 初始化分词器,将模型名称、可合并的词汇表(mergeable_ranks)和特殊令牌传递给它。
  6. 测试分词器:使用 encode 方法将文本转换为 token,并使用 decode 方法将 token 转换回文本,以验证分词器的工作是否正常。

3.2 读取模型文件

从模型文件中读取参数和权重是构建 Llama 3.1 模型的关键步骤之一。这部分将详细介绍如何读取模型文件中的参数和权重,并进行初始化设置。

安装依赖库

确保安装了 PyTorch 库,因为我们将使用 PyTorch 来加载模型文件。

pip install torch
读取模型文件

首先,我们需要从模型文件中加载模型权重和配置参数。假设我们已经下载了模型权重文件 model.pth 和配置文件 params.json

import torch
import json

# 加载模型权重
model_path = "path/to/model.pth"
model = torch.load(model_path)

# 打印模型的部分键以验证加载
print(json.dumps(list(model.keys())[:20], indent=4))

# 加载配置参数
config_path = "path/to/params.json"
with open(config_path, "r") as f:
    config = json.load(f)

# 提取配置参数
dim = config["dim"]
n_layers = config["n_layers"]
n_heads = config["n_heads"]
n_kv_heads = config["n_kv_heads"]
vocab_size = config["vocab_size"]
multiple_of = config["multiple_of"]
ffn_dim_multiplier = config["ffn_dim_multiplier"]
norm_eps = config["norm_eps"]
rope_theta = torch.tensor(config["rope_theta"])

# 打印配置参数以验证加载
print(f"Model Dimension: {dim}")
print(f"Number of Layers: {n_layers}")
print(f"Number of Heads: {n_heads}")
print(f"Vocabulary Size: {vocab_size}")
代码解析
  1. 安装和导入库:首先,确保安装了 PyTorch,并导入必要的库。
  2. 加载模型权重:使用 torch.load 方法加载模型文件 model.pth。加载后,可以通过打印模型的键来验证权重是否正确加载。
  3. 加载配置文件:打开并读取配置文件 params.json,该文件包含了模型的超参数和其他设置。
  4. 提取配置参数:从配置文件中提取必要的参数,如模型维度、层数、头数、词汇表大小等。这些参数将在后续步骤中用于初始化模型结构。
  5. 打印配置参数:为了确保配置参数正确加载,打印一些关键参数进行验证。

3.3 文本到Token的转换

在构建语言模型时,首先需要将输入的自然语言文本转换为模型所需的 tokens。Llama 3.1 使用的分词器可以将文本转换为一系列 tokens,这些 tokens 是模型可以理解和处理的基本单元。

转换步骤

以下是将输入文本转换为模型所需 tokens 的详细步骤:

  1. 定义输入文本:首先,我们需要定义要转换的输入文本。
  2. 使用分词器进行编码:使用已经加载和初始化的分词器将输入文本转换为 tokens。
  3. 添加特殊 tokens:在模型的要求下,有时需要在 tokens 序列的开头或结尾添加特殊 tokens。
  4. 将 tokens 转换为张量:为了便于后续的处理,将 tokens 序列转换为 PyTorch 张量。
示例代码

以下是具体的代码实现:

# 定义输入文本
prompt = "the answer to the ultimate question of life, the universe, and everything is "

# 使用分词器将文本编码为 tokens
tokens = tokenizer.encode(prompt)

# 打印编码后的 tokens
print(f"Encoded tokens: {tokens}")

# 添加特殊 tokens
# 假设 128000 是模型要求的特殊 token
tokens = [128000] + tokens

# 将 tokens 转换为 PyTorch 张量
tokens_tensor = torch.tensor(tokens)

# 打印转换后的张量
print(f"Tokens Tensor: {tokens_tensor}")
代码解析
  1. 定义输入文本prompt 是我们要转换的输入文本。
  2. 使用分词器进行编码tokenizer.encode(prompt) 方法将输入文本转换为 tokens。tokenizer 是之前加载并初始化的分词器对象。
  3. 打印编码后的 tokens:打印编码后的 tokens 序列以验证分词器的输出。
  4. 添加特殊 tokens:根据模型的要求,可能需要在 tokens 序列的开头添加特殊 tokens。在此示例中,我们假设 128000 是一个特殊 token,并将其添加到 tokens 序列的开头。
  5. 将 tokens 转换为 PyTorch 张量:使用 torch.tensor(tokens) 方法将 tokens 序列转换为 PyTorch 张量。这一步是为了便于后续的模型处理,因为 PyTorch 模型通常处理张量数据。
  6. 打印转换后的张量:打印转换后的张量以验证最终的 tokens 张量。

3.4 Token到Embedding的转换

将 tokens 转换为 embeddings 是深度学习模型处理文本数据的重要步骤。Embedding 是一种将离散的 tokens 转换为连续向量表示的方法,使模型能够处理和理解文本数据。

依赖库

确保您已经安装并导入了必要的库:

import torch
import torch.nn as nn
步骤详解
  1. 初始化 Embedding 层:使用模型的词汇表大小和向量维度初始化一个 Embedding 层。
  2. 加载预训练的 Embedding 权重:将模型中预训练的权重加载到 Embedding 层。
  3. 转换 Tokens:将 tokens 转换为 embeddings。
  4. 处理数据类型:将 embeddings 转换为适当的数据类型,以适应模型的需求。
示例代码

以下是将 tokens 转换为 embeddings 的具体代码实现:

# 定义模型参数
vocab_size = 50257  # 假设词汇表大小为 50257
dim = 768  # 假设每个 token 的 embedding 维度为 768

# 初始化 Embedding 层
embedding_layer = nn.Embedding(vocab_size, dim)

# 加载预训练的 Embedding 权重
embedding_layer.weight.data.copy_(model["tok_embeddings.weight"])

# 将 tokens 转换为 embeddings
token_embeddings_unnormalized = embedding_layer(tokens_tensor).to(torch.bfloat16)

# 打印 Embeddings 的形状
print(f"Token Embeddings Shape: {token_embeddings_unnormalized.shape}")
代码解析
  1. 定义模型参数:首先,定义模型的词汇表大小 (vocab_size) 和 embedding 向量的维度 (dim)。
  2. 初始化 Embedding 层:使用 nn.Embedding 初始化一个 Embedding 层。这个层将词汇表中的每个 token 映射到一个维度为 dim 的向量。
  3. 加载预训练的 Embedding 权重:从模型中加载预训练的 embedding 权重。model["tok_embeddings.weight"] 包含了预训练的 embedding 权重,通过 embedding_layer.weight.data.copy_ 方法将这些权重复制到初始化的 Embedding 层中。
  4. 将 tokens 转换为 embeddings:使用 embedding_layer 将 tokens 转换为 embeddings。tokens_tensor 是之前步骤中转换的 tokens 张量。.to(torch.bfloat16) 将 embeddings 转换为 bfloat16 数据类型,以适应后续的模型处理需求。
  5. 打印 Embeddings 的形状:通过 print 打印 embeddings 的形状,以验证转换是否正确。输出的形状应该是 (序列长度, embedding 维度)

3.5 归一化Embedding

对 embeddings 进行归一化处理是确保模型稳定性和性能的重要步骤。归一化有助于避免数值不稳定,确保各层之间的数值范围一致,从而提升训练效率和模型性能。

归一化的原理

在本教程中,我们使用均方根归一化(RMS Normalization)来处理 embeddings。均方根归一化是一种对向量进行归一化的方法,它通过计算向量的均方根(RMS)并使用该值对向量进行缩放。

均方根的计算方法如下:

\text{RMS}(x) = \sqrt{\frac{1}{n} \sum_{i=1}{n} x_i2}
归一化后的向量为:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AI与编程之窗

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值