miyuki2026 commited on
Commit
4012cf3
·
1 Parent(s): 4733ac1
examples/tutorials/grpo/step_2_train_grpo_model_unsloth_ddp.py CHANGED
@@ -14,7 +14,11 @@ torchrun --nproc_per_node=4 step_2_train_grpo_model_unsloth_ddp.py
14
  --------------
15
 
16
 
17
- nohup torchrun --nproc_per_node=4 step_2_train_grpo_model_unsloth_ddp.py &
 
 
 
 
18
 
19
  kill -9 `ps -aef | grep 'step_2_train_grpo_model_unsloth_ddp.py' | grep -v grep | awk '{print $2}'`
20
 
@@ -104,7 +108,7 @@ def get_args():
104
  parser.add_argument("--dataset_process_dir",
105
  default=(temp_directory / "dataset_process_dir").as_posix(),type=str)
106
  # 训练参数
107
- parser.add_argument("--valid_dataset_size", default=2000, type=int)
108
  parser.add_argument("--max_seq_length", default=2048, type=int)
109
  parser.add_argument("--lora_rank", default=32, type=int),
110
 
@@ -375,7 +379,7 @@ def main():
375
  load_best_model_at_end=True,
376
  metric_for_best_model="reward", # 使用奖励作为评估指标
377
  greater_is_better=True,
378
- fp16=False,
379
  bf16=False,
380
  max_grad_norm=1.0,
381
  report_to="none", # 可根据需要改为"wandb"等
 
14
  --------------
15
 
16
 
17
+ nohup torchrun --nproc_per_node=4 step_2_train_grpo_model_unsloth_ddp.py \
18
+ --valid_dataset_size 500 \
19
+ --lora_rank 16 \
20
+ &
21
+
22
 
23
  kill -9 `ps -aef | grep 'step_2_train_grpo_model_unsloth_ddp.py' | grep -v grep | awk '{print $2}'`
24
 
 
108
  parser.add_argument("--dataset_process_dir",
109
  default=(temp_directory / "dataset_process_dir").as_posix(),type=str)
110
  # 训练参数
111
+ parser.add_argument("--valid_dataset_size", default=500, type=int)
112
  parser.add_argument("--max_seq_length", default=2048, type=int)
113
  parser.add_argument("--lora_rank", default=32, type=int),
114
 
 
379
  load_best_model_at_end=True,
380
  metric_for_best_model="reward", # 使用奖励作为评估指标
381
  greater_is_better=True,
382
+ fp16=True,
383
  bf16=False,
384
  max_grad_norm=1.0,
385
  report_to="none", # 可根据需要改为"wandb"等
examples/tutorials/sft_for_function_call/step_2_train_model.py ADDED
@@ -0,0 +1,160 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/python3
2
+ # -*- coding: utf-8 -*-
3
+ """
4
+ https://huggingface.co/datasets/Team-ACE/ToolACE/viewer/default/train?row=0
5
+ """
6
+
7
+ import dataset
8
+ from transformers import AutoTokenizer
9
+ import torch
10
+
11
+ # 选择一个基础模型,这里以 Qwen2.5-7B-Instruct 为例
12
+ model_name = "Qwen/Qwen2.5-7B-Instruct"
13
+ tokenizer = AutoTokenizer.from_pretrained(model_name)
14
+ # 确保设置有填充token,通常用eos_token
15
+ if tokenizer.pad_token is None:
16
+ tokenizer.pad_token = tokenizer.eos_token
17
+
18
+
19
+ def format_toolace_for_sft(example):
20
+ """
21
+ 将ToolACE数据集的一个样本格式化为模型输入,并生成损失掩码。
22
+ """
23
+ # 1. 提取系统提示(包含工具定义)
24
+ system_prompt = example.get('system', '')
25
+ # 将工具定义也作为系统消息的一部分
26
+ # 有些样本可能没有独立的system字段,需要根据实际情况调整
27
+ messages = []
28
+ if system_prompt:
29
+ messages.append({"role": "system", "content": system_prompt})
30
+
31
+ # 2. 处理多轮对话
32
+ conversations = example['conversations']
33
+ # 假设conversations的格式是 [{"from": "human", "value": "..."}, {"from": "gpt", "value": "..."}, ...]
34
+ # 我们需要将其转换为 {"role": "user"/"assistant", "content": "..."} 格式
35
+ for turn in conversations:
36
+ if turn['from'] == 'human':
37
+ messages.append({"role": "user", "content": turn['value']})
38
+ elif turn['from'] == 'gpt':
39
+ # 这里,助手的回复value可能包含工具调用和普通文本
40
+ # 我们将其作为普通assistant消息处理,SFTTrainer会监督整个回复
41
+ messages.append({"role": "assistant", "content": turn['value']})
42
+ else:
43
+ # 处理其他角色,如工具执行结果(observation)
44
+ # 通常工具执行结果会以另一个角色出现,例如 'tool' 或 'observation'
45
+ # 这里为了简化,我们先忽略,或作为tool角色添加
46
+ if turn['from'] == 'tool':
47
+ messages.append({"role": "tool", "content": turn['value'], "name": turn.get('name', 'tool')})
48
+
49
+ # 3. 应用聊天模板生成文本
50
+ # tokenize=False 返回字符串,方便查看
51
+ formatted_text = tokenizer.apply_chat_template(
52
+ messages,
53
+ tokenize=False,
54
+ add_generation_prompt=False # 训练时不添加生成提示
55
+ )
56
+
57
+ # 4. 创建损失掩码
58
+ # 我们需要标记出哪些部分是"assistant"的回复,只有这些部分的token才计算损失。
59
+ # 这里采用一种简单但有效的方法:对模板化后的完整文本进行tokenize,
60
+ # 并标记出属于assistant回复的部分。
61
+
62
+ # 首先,对完整对话进行tokenize
63
+ tokenized_full = tokenizer(
64
+ formatted_text,
65
+ truncation=True,
66
+ max_length=2048, # 设置一个最大长度
67
+ return_tensors="pt",
68
+ return_offsets_mapping=True # 返回偏移映射,用于精确定位
69
+ )
70
+
71
+ # 为了简化,我们使用一个更通用的方法:对每个消息分别tokenize,并构建标签。
72
+ # 这是SFTTrainer内部常用的方式,我们也可以自己实现,但这里演示核心逻辑。
73
+ # 实际上,SFTTrainer可以通过DataCollatorForCompletionOnlyLM自动完成此操作。
74
+
75
+ # 但为了清晰展示,我们返回必要的字段,让SFTTrainer处理掩码。
76
+ # 我们只需要返回包含了最终文本的字段即可。SFTTrainer会处理剩下的。
77
+
78
+ return {"text": formatted_text}
79
+
80
+
81
+ # 应用格式化函数到数据集
82
+ formatted_dataset = dataset.map(format_toolace_for_sft)
83
+ print("格式化后的第一个样本文本预览:\n")
84
+ print(formatted_dataset[0]['text'][:1000]) # 打印前1000个字符看看
85
+
86
+
87
+
88
+ from trl import SFTTrainer
89
+ from transformers import TrainingArguments, AutoModelForCausalLM, BitsAndBytesConfig
90
+ from peft import LoraConfig, get_peft_model
91
+ import torch
92
+
93
+ # 1. 配置量化 (QLoRA) 以节省显存
94
+ bnb_config = BitsAndBytesConfig(
95
+ load_in_4bit=True,
96
+ bnb_4bit_quant_type="nf4",
97
+ bnb_4bit_compute_dtype=torch.bfloat16,
98
+ bnb_4bit_use_double_quant=True,
99
+ )
100
+
101
+ # 2. 加载模型
102
+ model = AutoModelForCausalLM.from_pretrained(
103
+ model_name,
104
+ quantization_config=bnb_config,
105
+ device_map="auto",
106
+ trust_remote_code=True,
107
+ torch_dtype=torch.bfloat16,
108
+ )
109
+
110
+ # 3. 配置 LoRA
111
+ peft_config = LoraConfig(
112
+ r=16, # 秩
113
+ lora_alpha=32, # 缩放参数
114
+ target_modules=["q_proj", "k_proj", "v_proj", "o_proj", "gate_proj", "up_proj", "down_proj"], # 常见目标模块
115
+ lora_dropout=0.05,
116
+ bias="none",
117
+ task_type="CAUSAL_LM",
118
+ )
119
+
120
+ # 4. 配置训练参数
121
+ training_args = TrainingArguments(
122
+ output_dir="./qwen2.5-toolace-lora", # 模型保存路径
123
+ num_train_epochs=3, # 训练轮数
124
+ per_device_train_batch_size=2, # 根据显存调整
125
+ gradient_accumulation_steps=4, # 梯度累积,模拟更大batch
126
+ warmup_steps=100, # 预热步数
127
+ logging_steps=10, # 日志记录步数
128
+ save_strategy="epoch", # 每轮保存一次
129
+ learning_rate=2e-4, # 学习率
130
+ bf16=True, # 使用bfloat16
131
+ save_total_limit=2, # 最多保存2个checkpoint
132
+ remove_unused_columns=False, # 保留数据集中的原始列
133
+ report_to="none", # 不报告到外部工具
134
+ )
135
+
136
+ # 5. 初始化 SFTTrainer
137
+ # 关键点:通过 formatting_func 返回 'text' 字段,SFTTrainer会自动处理
138
+ # 并且可以通过 response_template 来指定只计算助手回复部分的损失
139
+ trainer = SFTTrainer(
140
+ model=model,
141
+ args=training_args,
142
+ train_dataset=formatted_dataset,
143
+ tokenizer=tokenizer,
144
+ peft_config=peft_config,
145
+ max_seq_length=2048, # 最大序列长度
146
+ dataset_text_field="text", # 指定包含训练文本的字段
147
+ )
148
+
149
+ # 6. 开始训练
150
+ trainer.train()
151
+
152
+ # 7. 保存最终的LoRA权重
153
+ trainer.save_model("./qwen2.5-toolace-lora-final")
154
+
155
+
156
+
157
+
158
+
159
+ if __name__ == "__main__":
160
+ pass