大模型预训练
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]