从零开始训练Llama



训练Llama从零开始非常消耗资源,但也很有意义。在做好训练数据集的准备和正确设置训练参数的情况下运行训练循环,将确保您能够生成足够可靠的语言模型,应用于许多NLP任务。成功的秘诀在于训练过程中的适当预处理、参数调整和优化。

与其他GPT风格的模型相比,Llama版本是一个开源版本。该模型需要大量资源、周密的准备工作,以及更多才能从零开始训练。本章报告了从零开始训练Llama的过程。该方法包括从准备训练数据集到配置训练参数并实际进行训练的所有内容。

Llama旨在支持几乎所有NLP应用,包括但不限于文本生成、翻译和摘要。大型语言模型可以通过三个关键步骤从零开始训练:

  • 准备训练数据集
  • 合适的训练参数
  • 管理过程并确保实施正确的优化

所有步骤都将通过代码片段和输出含义逐步进行说明。

准备您的训练数据集

训练任何LLM最重要的第一步是为其提供一个优秀、多样化且广泛的数据集。Llama需要海量的文本数据来捕捉人类语言的丰富性。

收集数据

训练Llama需要一个庞大的数据集,其中包含来自各个领域的各种文本样本。一些用于训练LLM的示例数据集包括Common Crawl、维基百科、BooksCorpus和OpenWebText。

示例:下载数据集

import requests
import os

# Create a directory for datasets
os.makedirs("datasets", exist_ok=True)

# URL to dataset
url = "https://example.com/openwebtext.zip"
output = "datasets/openwebtext.zip"

# Download the dataset
response = requests.get(url)
with open(output, "wb") as file:
    file.write(response.content)
print(f"Dataset downloaded and saved at {output}")

输出

Dataset downloaded and saved at datasets/openwebtext.zip

下载数据集后,您需要在训练前预处理文本数据。大多数预处理涉及标记化、小写化、去除特殊字符以及设置数据以适应给定的结构。

示例:预处理数据集

from transformers import LlamaTokenizer

# Load pre-trained tokenizer 
tokenizer = LlamaTokenizer.from_pretrained("meta-llama/Llama-2-7b-hf", token=token)

# Load raw text
with open('/content/raw_data.txt', 'r') as file:
    raw_text = file.read()

# Tokenize the text
tokens = tokenizer.encode(raw_text, add_special_tokens=True)

# Save tokens to a file
with open('/tokenized_text.txt', 'w') as token_file:
    token_file.write(str(tokens))
    
print(f"Text tokenized and saved as tokens.")

输出

Text tokenized and saved as tokens.

设置模型训练参数

现在,我们将继续设置训练参数。这些参数设定了您的模型将如何从数据集中学习;因此,它们直接影响模型的性能。

主要训练参数

  • 批次大小 - 在更新模拟权重之前经过的样本数量。
  • 学习率 - 设置根据损失梯度更新模型参数的程度。
  • 轮次 - 模型遍历整个数据集的次数。
  • 优化器 - 用于通过更改权重来最小化损失函数。

您可以使用AdamW作为优化器,并使用预热学习率调度器来训练Llama。

示例:训练参数配置

import torch
from transformers import LlamaForCausalLM, AdamW, get_linear_schedule_with_warmup
# token="you_token"

# Load the model
model = LlamaForCausalLM.from_pretrained('meta-llama/Llama-2-7b-chat-hf', token=token)

model = model.to("cuda") if torch.cuda.is_available() else model.to("cpu")
# Training parameters
epochs = 3
batch_size = 8
learning_rate = 5e-5
warmup_steps = 200

# Set the optimizer and scheduler
optimizer = AdamW(model.parameters(), lr=learning_rate)
scheduler = get_linear_schedule_with_warmup(optimizer, num_warmup_steps=warmup_steps, num_training_steps=epochs)
print("Training parameters set.")

输出

Training parameters set.

批次数据加载器

训练需要批量数据。这可以通过PyTorch的DataLoader轻松实现。

from torch.utils.data import DataLoader, Dataset
# Custom dataset class
class TextDataset(Dataset):
    def __init__(self, tokenized_text):
       self.data = tokenized_text
    def __len__(self): 
        return len(self.data) // batch_size 
    def __getitem__(self, idx): 
        return self.data[idx * batch_size : (idx + 1) * batch_size]

with open("/tokenized_text.txt", 'r') as f:
  tokens_str = f.read()
tokens = eval(tokens_str)  # Evaluate the string to get the list

# DataLoader definition
train_data = TextDataset(tokens)
train_loader = DataLoader(train_data, batch_size=batch_size, shuffle=True)

print(f"DataLoader created with batch size {batch_size}.")

输出

DataLoader created with batch size 8.

现在,学习过程的要求和数据加载过程已经建立,是时候进入实际的训练阶段了。

训练模型

所有这些准备工作在运行训练循环中协同工作。训练数据集只不过是将模型分批馈送,然后使用损失函数更新其参数。

运行训练循环

现在到了整个训练过程的阶段,所有这些准备工作都将与现实世界相结合。分阶段地向算法提供数据集合,以便可以根据其变量的损失函数对其进行更新。

import tqdm

# Move model to GPU if available
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model.to(device)

for epoch in range(epochs):
   print(f"Epoch {epoch + 1}/{epochs}")
   model.train
   total_loss = 0  
   for batch in tqdm.tqdm(train_loader
      batch = [torch.tensor(sub_batch, device=device) for sub_batch in batch]
      max_len = max(len(seq) for seq in batch)
      padded_batch = torch.zeros((len(batch), max_len), dtype=torch.long, device=device)
      for i, seq in enumerate(batch):
         padded_batch[i, :len(seq)] = seq

       # Forward pass, use padded_batch 
       outputs = model(padded_batch, labels=padded_batch
       loss = outputs.loss  
       # Backward pass
       optimizer.zero_grad()  # Reset gradients.
       loss.backward()  # Calculate gradients.
       optimizer.step()  # Update model parameters.
       scheduler.step()  # Update learning rate.
        
       total_loss += loss.item()  # Accumulate loss.

   print(f"Epoch {epoch + 1} completed. Loss: {total_loss:.4f}")  

输出

Epoch 1 completed. Loss: 424.4011
Epoch 2 completed. Loss: 343.4245
Epoch 3 completed. Loss: 328.7054

保存模型

训练完成后,保存模型;否则,每次训练时都需要保存。

# Save the trained model
model.save_pretrained('trained_Llama_model')
print("Model saved successfully.")

输出

Model saved successfully.

现在我们已经从零开始训练了模型并保存了它。我们可以使用该模型来预测新的字符/单词。我们将在接下来的章节中详细介绍。

广告