1.分组
- '1. 两种训练方法'
- 从零开始预训练:BV1xhYtewEum 4分30秒
- 二次特定预训练:BV1xhYtewEum
复制代码 2.创建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[k])) for k in examples.keys()}
- # 计算总长度
- total_length = len(concatenated_examples[list(examples.keys())[0]])
- # 确保总长度是max_seq_length的整数倍,剩余的丢弃
- total_length = (total_length // training_args.max_seq_length) * training_args.max_seq_length
- # 分块处理:将连续序列按固定长度切分
- result = {
- k: [t[i: i + training_args.max_seq_length] 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[k])) for k in examples.keys()}
- # 计算总长度
- total_length = len(concatenated_examples[list(examples.keys())[0]])
- # 按定义最大长度分组,剩余token舍弃
- total_length = (total_length // training_args.max_seq_length) * training_args.max_seq_length
- # 分块
- result = {
- k: [t[i: i + training_args.max_seq_length] 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
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |