AI算法 | 如何训练自己的大模型?

1、第一阶段:二次预训练模型选择与转换在开始训练之前,需要选择一个合适的基础模型。 本文以LLaMA-7B为例,简单介绍下。 为了方便后续的操作,将LLaMA-7B模型转换为Hugging Face格式。

AI算法 | 如何训练自己的大模型?

1、第一阶段:二次预训练

模型选择与转换

在开始训练之前,需要选择一个合适的基础模型。本文以LLaMA-7B为例,简单介绍下。为了方便后续的操作,将LLaMA-7B模型转换为Hugging Face格式。

复制
from transformers import AutoModelForCausalLM, AutoTokenizer
# 加载原始LLaMA模型
model_path = "original_llama_7b"
tokenizer = AutoTokenizer.from_pretrained(model_path)
model = AutoModelForCausalLM.from_pretrained(model_path)
# 保存为Hugging Face格式
hf_path = "llama_7b_hf"
model.save_pretrained(hf_path)
tokenizer.save_pretrained(hf_path)

此外,为了更好地处理中文文本,还需要扩充中文词表。可以参考Chinese-LLaMA项目,它在原始词表的基础上新增了大量汉字token,从而让模型能够更好地理解和生成中文内容。

复制
from transformers import AddedToken
# 加载原始tokenizer
tokenizer = AutoTokenizer.from_pretrained("llama_7b_hf")
# 添加中文字符
new_tokens = ["中文", "中国", "人工智能"]  # 实际应用中需要更全面的词表
new_tokens = [AddedToken(token) for token in new_tokens]
# 扩充词表
tokenizer.add_tokens(new_tokens)
model.resize_token_embeddings(len(tokenizer))
# 保存扩充后的tokenizer
tokenizer.save_pretrained("llama_7b_zh_extended")

数据准备

数据是训练模型的关键。需要根据任务需求收集海量的中文文本数据。例如,这些数据可以来自中文维基百科、新闻文章、小说等多个领域。这样可以确保模型能够学习到丰富的知识。在收集数据之后,还需要对数据进行清洗和预处理,去除其中的噪声和无关内容,以保证数据的质量。

下面是一个简单的清晰流程实例:

复制
def clean_text(text):
    # 去除HTML标签
    text = re.sub(r'<[^>]+>', '', text)
    # 去除特殊字符和多余空格
    text = re.sub(r'\s+', ' ', text).strip()
    # 其他自定义清洗规则
    return text
# 假设我们有一个文本文件列表
text_files = ["data/wiki_zh.txt", "data/news_zh.txt"]
cleaned_data = []
for file in text_files:
    with open(file, 'r', encoding='utf-8') as f:
        for line in tqdm(f):
            cleaned = clean_text(line)
            if len(cleaned) > 10:  # 过滤过短文本
                cleaned_data.append(cleaned)
# 保存清洗后的数据
with open("cleaned_zh_data.txt", 'w', encoding='utf-8') as f:
    f.write('\n'.join(cleaned_data))

训练设置

为了降低计算资源的需求,可以使用LoRA(Low-Rank Adaptation)技术进行二次预训练。LoRA通过在模型中添加低秩矩阵来实现高效的微调,大大减少了需要训练的参数数量。例如,原本全参微调7B模型需要8卡A100,使用LoRA后,单卡3090就足够了。此外,还需要设置合适的超参数,如学习率、批次大小等。这些超参数可以根据实验结果进行调整,以达到更好的训练效果。

复制
from transformers import Trainer, TrainingArguments
from peft import LoraConfig, get_peft_model
# 配置LoRA
lora_config = LoraConfig(
    r=8,  # 低秩矩阵的维度
    lora_alpha=32,
    target_modules=["q_proj", "v_proj"],  # 对query和value矩阵进行适配
    lora_dropout=0.05,
    bias="none",
    task_type="CAUSAL_LM"
)
# 应用LoRA到模型
model = get_peft_model(model, lora_config)
model.print_trainable_parameters()  # 查看可训练参数数量
# 准备训练参数
training_args = TrainingArguments(
    output_dir="./output",
    overwrite_output_dir=True,
    num_train_epochs=3,
    per_device_train_batch_size=4,
    save_steps=10_000,
    save_total_limit=2,
    learning_rate=1e-4,
    fp16=True,
    logging_steps=100,
    evaluation_strategy="steps",
    eval_steps=5_000,
    load_best_model_at_end=True
)
# 创建数据集
from datasets import load_dataset
dataset = load_dataset("text", data_files={"train": "cleaned_zh_data.txt"})
# 开始训练
trainer = Trainer(
    model=model,
    args=training_args,
    train_dataset=dataset["train"],
    tokenizer=tokenizer
)
trainer.train()

2、第二阶段:指令微调

数据准备

在第一阶段的预训练之后,需要对模型进行指令微调,以使其能够更好地理解和执行指令。为此,需要构造指令微调数据集,这些数据集包括中文指令和对应的回答。可以参考Alpaca-CoT项目,它提供了丰富的指令数据集。如果模型需要应用于特定的领域,如金融领域,还可以收集相关的领域指令数据。

训练设置

在第一阶段的预训练模型基础上进行指令微调。同样可以使用LoRA技术,进一步降低计算成本。如果希望模型更好地理解下游任务信息,可以将指令微调数据集拼接成文档格式,放入第一阶段进行增量预训练。

训练过程

使用FT(Full-Tuning)+LoRA SFT(Sparse Fine-Tuning)的方式进行微调。在训练过程中,模型会学习如何更好地理解和执行指令。为了确保模型的性能,需要定期评估模型在指令微调数据集上的表现,并根据评估结果调整训练策略。

复制
from transformers import DataCollatorForLanguageModeling
# 加载预训练模型
model = AutoModelForCausalLM.from_pretrained("./output/checkpoint-final")
tokenizer = AutoTokenizer.from_pretrained("llama_7b_zh_extended")
# 准备数据集
def preprocess_function(examples):
    texts = []
    for inst in examples["text"]:
        try:
            data = json.loads(inst)
            text = f"指令:{data['instruction']}\n输入:{data['input']}\n输出:{data['output']}"
            texts.append(text)
        except:
            continue
    return tokenizer(texts, truncatinotallow=True, max_length=512)
dataset = load_dataset("json", data_files={"train": "instruction_data.json"})
tokenized_dataset = dataset.map(preprocess_function, batched=True)
# 数据收集器
data_collator = DataCollatorForLanguageModeling(
    tokenizer=tokenizer, 
    mlm=False
)
# 微调参数
training_args = TrainingArguments(
    output_dir="./sft_output",
    per_device_train_batch_size=4,
    num_train_epochs=5,
    learning_rate=5e-5,
    fp16=True,
    save_steps=10_000,
    logging_steps=100,
    evaluation_strategy="no",
)
# 开始微调
trainer = Trainer(
    model=model,
    args=training_args,
    train_dataset=tokenized_dataset["train"],
    data_collator=data_collator,
    tokenizer=tokenizer
)
trainer.train()

低成本方案

例如8-bit优化:

复制
from transformers import BitsAndBytesConfig
quantization_config = BitsAndBytesConfig(
    load_in_8bit=True,
    llm_int8_threshold=6.0
)
model = AutoModelForCausalLM.from_pretrained(
    "llama_7b_hf",
    quantization_cnotallow=quantization_config
)

3、注意事项

  • 数据质量:在实际应用中,数据清洗和预处理的逻辑可能需要根据具体数据进行调整。
  • 超参数调整:超参数(如学习率、批次大小、LoRA的秩等)需要根据实验结果进行调整。
  • 模型评估:在训练过程中,建议定期在验证集上评估模型性能,以确保模型没有过拟合。

相关资讯

AI算法 | 领域模型Continue PreTrain数据篇

在当今人工智能的浪潮中,领域模型的构建与发展正成为推动行业进步的关键力量。 从医疗诊断到金融风险预测,从自然语言处理到图像识别,领域模型以其精准的适应性和强大的性能,为各个专业领域带来了前所未有的机遇。 而在这背后,Continue Pretrain(持续预训练)技术更是为领域模型的成长提供了源源不断的动力。

AI算法 | SFT数据篇

1、SFT需要多少条数据SFT所需数据量一般任务:对于大多数常见的自然语言处理任务(如文本分类、情感分析、简单对话等),SFT的数据量通常在2k-10k之间。 这个范围的数据量既能保证模型学习到足够的领域知识,又不会因为数据量过大而导致训练成本过高。 复杂任务:对于复杂的任务,如数学推理、代码生成、多轮对话等,可能需要更多的数据来训练。

LLM核心损失函数深度剖析——KL散度与交叉熵损失

在深度学习和机器学习领域,损失函数是模型优化的核心工具之一。 它不仅决定了模型的训练方向,还直接影响模型的性能和泛化能力。 随着大语言模型(LLM)的兴起,对损失函数的理解和应用变得更加重要。