Views
No views yet
1[
2[90/90 20:47, Epoch 4/5]
3## 10 / 0.713900
4## 20 / 0.683300
5## 30 / 0.322100
6## 40 / 0.180100
7## 50 / 0.052900
8## 60 / 0.017600
9## 70 / 0.004400
10## 80 / 0.003100
11## 90 / 0.000700
12
13]1# ベースモデルと学習したLoRAのアダプタの指定。
2base_model_id = "llm-jp/llm-jp-3-13b"
3adapter_id = "ayayana/llm-jp-3-13b-ayanatest_lora" #dpoするベースモデル (あなたがFine-Tuningしたモデル - 今回はアダプタのみを想定)
4new_model_id = "llm-jp-3-13b-dpo_ayana10" #dpoするモデルにつけたい名前
5
6
7##DPO学習用データセットの構築
8# データセットの準備
9print("Preparing dataset...")
10dataset = load_dataset("llm-jp/hh-rlhf-12k-ja")
11train_data = dataset["train"]
12
13
14# 140文字以上のデータをフィルタリング
15filtered_data = []
16for item in train_data:
17 chosen = item['chosen']
18 rejected = item['rejected']
19 # conversationsから最初の人間の発言を取得
20 conversations = item['conversations']
21 if conversations and len(conversations) > 0:
22 # 最初の人間からの発言を取得
23 first_human_msg = next((conv['value'] for conv in conversations if conv['from'] == 'human'), "")
24 prompt = first_human_msg
25 else:
26 prompt = ""
27
28
29 if 140 <= len(chosen) <= 1024 and 140 <= len(rejected) <= 1024:
30 filtered_data.append({
31 'prompt': prompt, # 人からの最初の発言をプロンプトとして使用
32 'chosen': chosen,
33 'rejected': rejected
34 })
35
36
37print(f"Original data size: {len(train_data)}")
38print(f"Filtered data size: {len(filtered_data)}")
39
40
41# データの例を表示して確認
42print("\nExample data:")
43print(f"Prompt: {filtered_data[0]['prompt']}")
44print(f"Chosen: {filtered_data[0]['chosen'][:210]}...")
45print(f"Rejected: {filtered_data[0]['rejected'][:210]}...")
46
47##データセット制作
48filtered_data = []
49for item in train_data:
50 chosen = item['chosen']
51 rejected = item['rejected']
52
53
54 # 会話の取得
55 conversations = item['conversations']
56 if conversations and len(conversations) > 0:
57 first_human_msg = next((conv['value'] for conv in conversations if conv['from'] == 'human'), "")
58 prompt = first_human_msg.strip()
59 else:
60 continue
61
62
63 # 内容の検証
64 if (140 <= len(chosen) <= 3000 and
65 140 <= len(rejected) <= 3000 and
66 len(prompt.strip()) > 0 and
67 chosen != rejected and
68 not all(c.isspace() for c in chosen) and
69 not all(c.isspace() for c in rejected)):
70
71
72 filtered_data.append({
73 'prompt': prompt,
74 'chosen': chosen.strip(),
75 'rejected': rejected.strip()
76 })
77
78
79# ループの外で一回だけデータ品質をチェック
80print("\nData quality check:")
81print(f"Total examples: {len(filtered_data)}")
82print(f"Empty prompts: {sum(1 for x in filtered_data if not x['prompt'])}")
83print(f"Average chosen length: {sum(len(x['chosen']) for x in filtered_data)/len(filtered_data)}")
84print(f"Average rejected length: {sum(len(x['rejected']) for x in filtered_data)/len(filtered_data)}")
85
86
87# サンプルデータの表示
88if filtered_data:
89 print("\nSample data:")
90 print(f"Prompt: {filtered_data[0]['prompt']}")
91 print(f"Chosen: {filtered_data[0]['chosen'][:120]}...")
92 print(f"Rejected: {filtered_data[0]['rejected'][:120]}...")
93
94
95# 300件をランダムサンプリング
96if len(filtered_data) > 300:
97 sampled_data = random.sample(filtered_data, 300)
98else:
99 sampled_data = filtered_data
100
101
102print(f"Final sampled data size: {len(sampled_data)}")
103
104
105# DPO用のデータ形式に変換
106dpo_datasets = []
107for item in sampled_data:
108 dpo_item = {
109 "prompt": item['prompt'], # 元のプロンプトを使用
110 "chosen": item['chosen'],
111 "rejected": item['rejected']
112 }
113 dpo_datasets.append(dpo_item)
114
115
116# データの例を表示して確認
117print("\nExample data:")
118print(f"Prompt: {dpo_datasets[0]['prompt']}")
119print(f"Chosen: {dpo_datasets[0]['chosen'][:200]}...")
120print(f"Rejected: {dpo_datasets[0]['rejected'][:200]}...")
121
122
123# JSONファイルに保存
124json_file_path = "dpo_dataset.json"
125with open(json_file_path, "w", encoding="utf-8") as f:
126 json.dump(dpo_datasets, f, indent=4, ensure_ascii=False)
127
128
129print(f"\nData saved to {json_file_path}")
130
131
132
133
134##DPO学習
135# データセットをHuggingFace Dataset形式に変換
136dpo_datasets = Dataset.from_list(dpo_datasets)
137
138
139# メモリクリア
140torch.cuda.empty_cache()
141gc.collect()
142if torch.cuda.is_available():
143 torch.cuda.synchronize() # GPU操作の完了を待つ
144 torch.cuda.empty_cache() # もう一度クリア
145
146
147# DPO training configuration
148training_args = DPOConfig(
149 output_dir=new_model_id,
150 per_device_train_batch_size=1,
151 # per_device_eval_batch_size=1,
152 per_device_eval_batch_size=2, #メモリ対策
153 # gradient_accumulation_steps=32,#メモリ対策
154 gradient_accumulation_steps=16, # 16から32へ増やす(要調整)
155 optim="paged_adamw_8bit",
156 num_train_epochs=5,
157 logging_steps=10,
158 save_steps=10,
159 save_total_limit=1,
160 max_steps=-1,
161 learning_rate=2e-4,
162 fp16=False,
163 bf16=True,
164 max_grad_norm=0.3,
165 dataloader_num_workers=0,
166 report_to="none",
167 gradient_checkpointing=True # 勾配チェックポイントを有効化
168)
169
170
171# Initialize DPO trainer
172dpo_trainer = DPOTrainer(
173 model,
174 args=training_args,
175 train_dataset=dpo_datasets,
176 tokenizer=tokenizer,
177 peft_config=peft_config,
178)
179
180
181# Start training
182model.config.use_cache = False
183dpo_trainer.train()
184
185
186# アダプター名を事前に定義
187adapter_model_id = new_model_id + "+lora_adp10"
188
189
190# LoRAアダプターとして保存
191model.save_pretrained(
192 adapter_model_id,
193 push_to_hub=True,
194 token=HF_TOKEN,
195 private=True
196)
197
1981results = []
2for data in tqdm(datasets):
3
4 input = data["input"]
5
6 prompt = f"""### 指示
7 {input} 簡潔に回答してください。
8 ### 回答
9 """
10
11 tokenized_input = tokenizer.encode(prompt, add_special_tokens=False, return_tensors="pt").to(model.device)
12 attention_mask = torch.ones_like(tokenized_input)
13 with torch.no_grad():
14 outputs = model.generate(
15 tokenized_input,
16 attention_mask=attention_mask,
17 max_new_tokens=1024,
18 do_sample=False,
19 repetition_penalty=1.2,
20 pad_token_id=tokenizer.eos_token_id
21 )[0]
22 output = tokenizer.decode(outputs[tokenized_input.size(1):], skip_special_tokens=True)
23
24 results.append({"task_id": data["task_id"], "input": input, "output": output})1import re
2jsonl_id = re.sub(".*/", "", adapter_id) #保存用のパス。任意に指定。
3with open(f"./{jsonl_id}-outputs.jsonl", 'w', encoding='utf-8') as f: #保存用のファイル名になります。任意に指定してください。
4 for result in results:
5 json.dump(result, f, ensure_ascii=False)
6 f.write('\n')
71import json
2import pandas as pd
3
4# JSONLファイルのパス
5jsonl_file_path = "/content/llm-jp-3-13b-ayana002_lora_output.jsonl"
6
7# JSONLファイルを読み込み
8with open(jsonl_file_path, "r", encoding="utf-8") as f:
9 results = [json.loads(line) for line in f]
10
11# DataFrameに変換
12df = pd.DataFrame(results)
13
14# Excelファイルに保存
15df.to_excel("output.xlsx", index=False, engine="openpyxl")
16
17print("Excelファイルが 'output.xlsx' として保存されました!")
18