悯拄等 发表于 2025-7-21 18:55:37

大模型预训练

1.分组

'1. 两种训练方法'
从零开始预训练:BV1xhYtewEum 4分30秒
二次特定预训练:BV1xhYtewEum2.创建LLM

'1. 创建模型核心流程'
(1)加载模型->(2)将模型放入显卡->(3)输入文本并分词->
(4)将分词放入显卡->(5)设置label->(6)模型输出->
(7)获取模型loss->(8)更新参数->(9)保存模型'2. 创建模型核心代码'
#加载模型
model_path = '/data04/llama3/Meta-Llama-3.1-8B-Instruct'
tokenizer = AutoTokenizer.from_pretrained(model_path)

#将模型放入显卡
model.to("cuda")
optimizer = torch.optim.AdamW(model.parameters())

#输入文本,文本分词
text = "今天天气不错。"
input = tokenizer(text, return_tensors="pt")
input = {k: v.to("cuda") for k, v in input.items()}

#设置labels和inputs一致
input["labels"] = input["input_ids"].clone()
output = model(**input)

#获取模型的loss
loss = output.loss
loss.backward()
optimizer.step()
optimizer.zero_grad()

#保存模型
model.save_pretrained("output_dir")'3. 大模型计算内部Loss'
step1. LLM获取“今天”,输出概率最高的词是“天气”
step2. LLM输出“天气”,根据“今天”、“天气”选择输出概率最高的“不错”
step3. LLM输出“不错”,根据“今天”、“天气”、“不错”选择输出概率最高的“。”
step4. LLM输出“。”,由于输入的内容已经学习完毕,LLM便丢弃最后一个预测'4. llama的loss计算'
#丢弃预测的最后一个token;
#logits是预测结果,形状为 (batch_size, seq_len, classes)
#labels是真实标签,形状为 (batch_size, seq_len)
shift_logits = logits[...,;-1,:].contiguous()
shift_labels = labels[...,1:].contiguous()

#创建交叉熵损失函数
loss_fct = nn.CroassEntropyLoss()

#调整形状
##logits原始形状:(batch_size, seq_len-1, vocab_size)
##logits目标形状:(batch_size*(seq_len-1), vocab_size)
shift_logits = shift_logits.view(-1,self.config.vocab_size)
##labels原始形状:(batch_size, seq_len-1)
##labels目标形状:(batch_size*(seq_len-1))
shift_labels = shift_labels.view(-1)

#确保 logits和 labels在同一设备计算
shift_labels = shift_labels.to(shift_logits.device)
#损失计算​
loss = loss_fct(shift_logits,shift_labels)'5. 缩小显存需求-量化加载'
# 4bit load
bnb_config = BitsAndBytesConfig(
    load_in_4bit=True,
    bnb_4bit_use_double_quant=True,
    bnb_4bit_quant_type="nf4",
    bnb_4bit_compute_dtype=torch.bfloat16
)'6. 缩小显存需求-LoRA'
# 4bit load
peft_config = LoraConfig(
      r=8,
      target_modules=["q_proj",
                        "v_proj",
                        "k_proj",
                        "o_proj",
                        "gate_proj",
                        "down_proj",
                        "up_proj"
                        ],
      task_type=TaskType.CAUSAL_LM,
      lora_alpha=16,
      lora_dropout=0.05
    )
model = get_peft_model(model, peft_config)
model.print_trainable_parameters()3.训练LLM

'1. 数据处理'
step1 将数据保存为txt文件
step2 在文件的各个节点添加<|begin_of_text|>、<|start_header_id|>、
      <|end_header_id|>、<|end_header_id|>

'2. 参数初始化'
根据需要选择“验证策略”、“优化器”、“学习率”等参数
# 定义一个参数类
@dataclass
class CustomArguments(transformers.TrainingArguments):
    # LoRA_r
    lora_r: int = field(default=8)
    # 数据处理时的并行进程数
    num_proc: int = field(default=1)
# 使用类
parser = transformers.HfArgumentParser(CustomArguments)
training_args, = parser.parse_args_into_dataclasses()'3. 处理输入数据'
# 加载数据
train_dataset = load_dataset("text", data_dir="/train_data", split="train")
eval_dataset = load_dataset("text", data_dir="/eval_data", split="train")
# 定义分词函数:对传入的数据分词处理
#example是数据集中单条样本的字典,必须包含text字段
def tokenization(example):
    return tokenizer(example["text"])
# 对所以样本进行分词
# main_process_first保证分布式训练只在主进程处理
with training_args.main_process_first(desc="dataset map tokenization"):
    train_dataset = train_dataset.map(tokenization, remove_columns=["text"], num_proc=training_args.num_proc)
    eval_dataset = eval_dataset.map(tokenization, remove_columns=["text"], num_proc=training_args.num_proc)'4. 分组函数'
# 定义分组函数
def group_texts(examples):
    # 拼接所有样本序列,首位相连
    concatenated_examples = {k: list(chain(*examples)) for k in examples.keys()}
    # 计算总长度
    total_length = len(concatenated_examples])
    # 确保总长度是max_seq_length的整数倍,剩余的丢弃
    total_length = (total_length // training_args.max_seq_length) * training_args.max_seq_length
    # 分块处理:将连续序列按固定长度切分
    result = {
      k: for i in range(0, total_length, training_args.max_seq_length)]
      for k, t in concatenated_examples.items()
    }
    # 标签对齐
    result["labels"] = result["input_ids"].copy()
    return result
# 使用分组函数
with training_args.main_process_first(desc="dataset map tokenization"):
    train_dataset = train_dataset.map(group_texts, num_proc=training_args.num_proc, batched=True)
    eval_dataset = eval_dataset.map(group_texts, num_proc=training_args.num_proc, batched=True)4.完整代码

from accelerate import PartialState
from datasets import load_dataset
from peft import TaskType, LoraConfig, get_peft_model
from transformers import Trainer
from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig
from dataclasses import dataclass, field
import transformers
from itertools import chain
import torch
import warnings

warnings.filterwarnings("ignore")


@dataclass
class CustomArguments(transformers.TrainingArguments):
    # LoRA_r
    lora_r: int = field(default=8)
    # 数据处理时的并行进程数
    num_proc: int = field(default=1)
    # 最大序列长度
    max_seq_length: int = field(default=32)
    # 验证策略,如不想进行验证,可以设置为 ‘no’
    eval_strategy: str = field(default="steps")
    # 每多少步进行一次验证
    eval_steps: int = field(default=100)
    # 随机种子
    seed: int = field(default=0)
    # 优化器
    optim: str = field(default="adamw_torch")
    # 训练epoch数
    num_train_epochs: int = field(default=2)
    # 每个设备上的批量大小
    per_device_train_batch_size: int = field(default=1)

    # 学习率
    learning_rate: float = field(default=5e-5)
    # 权重衰减
    weight_decay: float = field(default=0)
    # 预热步数
    warmup_steps: int = field(default=10)
    # 学习率规划期类型
    lr_scheduler_type: str = field(default="linear")
    # 是否使用梯度检查点
    gradient_checkpointing: bool = field(default=False)
    # 是否使用bf16作为混合精度训练类型
    bf16: bool = field(default=True)
    # 梯度累加步数
    gradient_accumulation_steps: int = field(default=1)

    # 日志记录的步长频率
    logging_steps: int = field(default=3)
    # checkpoint保存策略
    save_strategy: str = field(default="steps")
    # checkpoint保存的步长频率
    save_steps: int = field(default=3)
    # 总的保存checkpoint的数量
    save_total_limit: int = field(default=2)

# 使用CustomArguments
parser = transformers.HfArgumentParser(CustomArguments)
training_args, = parser.parse_args_into_dataclasses()

# 导入模型参数
model_path = '/data04/llama3/Meta-Llama-3.1-8B-Instruct'

# 4b量化加载
bnb_config = BitsAndBytesConfig(
    load_in_4bit=True,
    bnb_4bit_use_double_quant=True,
    bnb_4bit_quant_type="nf4",
    bnb_4bit_compute_dtype=torch.bfloat16
)

tokenizer = AutoTokenizer.from_pretrained(model_path)
# 创建模型
model = AutoModelForCausalLM.from_pretrained(
    model_path,
    low_cpu_mem_usage=True,
    quantization_config=bnb_config,
    device_map={"": PartialState().process_index}
)

# 将模型导入Lora中
peft_config = LoraConfig(
    r=training_args.lora_r,
    target_modules=["q_proj",
                  "v_proj",
                  "k_proj",
                  "o_proj",
                  "gate_proj",
                  "down_proj",
                  "up_proj"
                  ],
    task_type=TaskType.CAUSAL_LM,
    lora_alpha=16,
    lora_dropout=0.05
)
# 微调模型
model = get_peft_model(model, peft_config)
# 计算模型中的可训练参数数量
model.print_trainable_parameters()

# 加载数据
train_dataset = load_dataset("text", data_dir="/home/xuepeng/pretrain_test/train_data", split="train")
eval_dataset = load_dataset("text", data_dir="/home/xuepeng/pretrain_test/eval_data", split="train")

# 输入数据分词
def tokenization(example):
    return tokenizer(example["text"])
with training_args.main_process_first(desc="dataset map tokenization"):
    train_dataset = train_dataset.map(tokenization, remove_columns=["text"], num_proc=training_args.num_proc)
    eval_dataset = eval_dataset.map(tokenization, remove_columns=["text"], num_proc=training_args.num_proc)

# 输入数据分组
def group_texts(examples):
    # 将数据相连
    concatenated_examples = {k: list(chain(*examples)) for k in examples.keys()}
    # 计算总长度
    total_length = len(concatenated_examples])
    # 按定义最大长度分组,剩余token舍弃
    total_length = (total_length // training_args.max_seq_length) * training_args.max_seq_length
   # 分块
    result = {
      k: for i in range(0, total_length, training_args.max_seq_length)]
      for k, t in concatenated_examples.items()
    }
    # 标签对齐
    result["labels"] = result["input_ids"].copy()
    return result
with training_args.main_process_first(desc="dataset map tokenization"):
    train_dataset = train_dataset.map(group_texts, num_proc=training_args.num_proc, batched=True)
    eval_dataset = eval_dataset.map(group_texts, num_proc=training_args.num_proc, batched=True)

# 利用transformers包里面的Trainer做训练
if __name__ == '__main__':
    trainer = Trainer(
      model=model,
      args=training_args,
      train_dataset=train_dataset,
      eval_dataset=eval_dataset
    )
    trainer.train()
    trainer.save_model("/data04/xuepeng/test_train")学习视频:【大模型预训练看这个视频就够了】 https://www.bilibili.com/video/BV1xhYtewEum/?share_source=copy_web&vd_source=050ab764db52d186ab224170392c4055

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
页: [1]
查看完整版本: 大模型预训练