IWAIYuma commited on
Commit
52229aa
·
verified ·
1 Parent(s): 25e66db

Update README.md

Browse files
Files changed (1) hide show
  1. README.md +382 -0
README.md CHANGED
@@ -20,3 +20,385 @@ language:
20
  This llama model was trained 2x faster with [Unsloth](https://github.com/unslothai/unsloth) and Huggingface's TRL library.
21
 
22
  [<img src="https://raw.githubusercontent.com/unslothai/unsloth/main/images/unsloth%20made%20with%20love.png" width="200"/>](https://github.com/unslothai/unsloth)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20
  This llama model was trained 2x faster with [Unsloth](https://github.com/unslothai/unsloth) and Huggingface's TRL library.
21
 
22
  [<img src="https://raw.githubusercontent.com/unslothai/unsloth/main/images/unsloth%20made%20with%20love.png" width="200"/>](https://github.com/unslothai/unsloth)
23
+
24
+ サンプルコードで作成したモデルを強化学習する。
25
+
26
+ 使用するデータセットは、『cyberagent/chatbot-arena-ja-calm2-7b-chat-experimental』のオープンソースを使用
27
+
28
+ https://huggingface.co/datasets/cyberagent/chatbot-arena-ja-calm2-7b-chat-experimental)
29
+
30
+ このソースは『このデータセットを用いてcalm2-7b-chatに対してDirect Preference Optimization (DPO)を行い、calm2-7b-chat-dpoを作成しました。 Instruction Tuningの評価用タスクであるELYZA-tasks-100とJapanese MT-Benchを用いてGPT-4による自動評価を行ったところ、どちらのデータセットでもcalm2-7b-chat-dpoの方がcalm2-7b-chatよりも高いスコアが得られました。』とあるため期待
31
+
32
+ ◯ 参考にしたコード『自作FT済みモデルからDPOするためのサンプルコード(Unsloth最新版 2024.12.2)』にある、藤越様のコードを参考にし、RLHFをしてみました。
33
+
34
+ https://matsuolab-geniac.notion.site/FT-DPO-Unsloth-2024-12-2-bac63c15586840b9ad118f5f5b27420a
35
+
36
+ '''python
37
+ # Google Colab の場合は上記の環境構築手順を行なわず、単にこのセルから実行していってください。
38
+ !pip uninstall unsloth -y
39
+ !pip install --upgrade --no-cache-dir "unsloth[colab-new] @ git+https://github.com/unslothai/unsloth.git"
40
+ # Google Colab のデフォルトで入っているパッケージをアップグレード(Moriyasu さんありがとうございます)
41
+ !pip install --upgrade torch
42
+ !pip install --upgrade xformers
43
+ # notebookでインタラクティブな表示を可能とする(ただし、うまく動かない場合あり)
44
+ !pip install ipywidgets --upgrade
45
+
46
+ # Install Flash Attention 2 for softcapping support
47
+ import torch
48
+ if torch.cuda.get_device_capability()[0] >= 8:
49
+ !pip install --no-deps packaging ninja einops "flash-attn>=2.6.3"
50
+ from google.colab import output
51
+ output.enable_custom_widget_manager()
52
+ # Hugging Face Token を指定
53
+
54
+ from huggingface_hub import login
55
+ from google.colab import userdata
56
+
57
+ hf_token = userdata.get('HF_TOKEN')
58
+ if hf_token:
59
+ login(token=hf_token)
60
+ print("Hugging Face token found and logged in.")
61
+ else:
62
+ print("Hugging Face token not found. Please set it using userdata.set('HF_TOKEN', '<your-token>')")
63
+ print(dataset['train'][0])
64
+ # 学習時のプロンプトフォーマットの定義
65
+ prompt = """### 指示
66
+ {}
67
+ ### 回答
68
+ {}"""
69
+
70
+
71
+
72
+ """
73
+ formatting_prompts_func: 各データをプロンプトに合わせた形式に合わせる
74
+ """
75
+ EOS_TOKEN = tokenizer.eos_token # トークナイザーのEOSトークン(文末トークン)
76
+ def formatting_prompts_func(examples):
77
+ input = examples["text"] # 入力データ
78
+ output = examples["output"] # 出力データ
79
+ text = prompt.format(input, output) + EOS_TOKEN # プロンプトの作成
80
+ return { "formatted_text" : text, } # 新しいフィールド "formatted_text" を返す
81
+ pass
82
+
83
+ # # 各データにフォーマットを適用
84
+ dataset = dataset.map(
85
+ formatting_prompts_func,
86
+ num_proc= 4, # 並列処理数を指定
87
+ )
88
+
89
+ dataset
90
+ """
91
+ training_arguments: 学習の設定
92
+
93
+ - output_dir:
94
+ -トレーニング後のモデルを保存するディレクトリ
95
+
96
+ - per_device_train_batch_size:
97
+ - デバイスごとのトレーニングバッチサイズ
98
+
99
+ - per_device_eval_batch_size:
100
+ - デバイスごとの評価バッチサイズ
101
+
102
+ - gradient_accumulation_steps:
103
+ - 勾配を更新する前にステップを積み重ねる回数
104
+
105
+ - optim:
106
+ - オプティマイザの設定
107
+
108
+ - num_train_epochs:
109
+ - エポック数
110
+
111
+ - eval_strategy:
112
+ - 評価の戦略 ("no"/"steps"/"epoch")
113
+
114
+ - eval_steps:
115
+ - eval_strategyが"steps"のとき、評価を行うstep間隔
116
+
117
+ - logging_strategy:
118
+ - ログ記録の戦略
119
+
120
+ - logging_steps:
121
+ - ログを出力するステップ間隔
122
+
123
+ - warmup_steps:
124
+ - 学習率のウォームアップステップ数
125
+
126
+ - save_steps:
127
+ - モデルを保存するステップ間隔
128
+
129
+ - save_total_limit:
130
+ - 保存しておくcheckpointの数
131
+
132
+ - max_steps:
133
+ - トレーニングの最大ステップ数
134
+
135
+ - learning_rate:
136
+ - 学習率
137
+
138
+ - fp16:
139
+ - 16bit浮動小数点の使用設定(第8回演習を参考にすると良いです)
140
+
141
+ - bf16:
142
+ - BFloat16の使用設定
143
+
144
+ - group_by_length:
145
+ - 入力シーケンスの長さによりバッチをグループ化 (トレーニングの効率化)
146
+
147
+ - report_to:
148
+ - ログの送信先 ("wandb"/"tensorboard"など)
149
+ """
150
+ from trl import SFTTrainer
151
+ from transformers import TrainingArguments
152
+ from unsloth import is_bfloat16_supported
153
+
154
+ trainer = SFTTrainer(
155
+ model = model,
156
+ tokenizer = tokenizer,
157
+ train_dataset=dataset["train"],
158
+ max_seq_length = max_seq_length,
159
+ dataset_text_field="formatted_text",
160
+ packing = False,
161
+ args = TrainingArguments(
162
+ per_device_train_batch_size = 2,
163
+ gradient_accumulation_steps = 4,
164
+ num_train_epochs = 1,
165
+ logging_steps = 10,
166
+ warmup_steps = 10,
167
+ save_steps=100,
168
+ save_total_limit=2,
169
+ max_steps=-1,
170
+ learning_rate = 2e-4,
171
+ fp16 = not is_bfloat16_supported(),
172
+ bf16 = is_bfloat16_supported(),
173
+ group_by_length=True,
174
+ seed = 3407,
175
+ output_dir = "outputs",
176
+ report_to = "none",
177
+ ),
178
+ )
179
+ #@title 学習実行
180
+ trainer_stats = trainer.train()
181
+ edataset = load_dataset("elyza/ELYZA-tasks-100")
182
+ edataset = edataset.remove_columns('eval_aspect')
183
+ edataset = edataset.rename_columns({'input':'text'})
184
+ print(edataset['test'][0])
185
+ # 学習時のプロンプトフォーマットの定義
186
+ prompt = """### 指示
187
+ {}
188
+ ### 回答
189
+ {}"""
190
+
191
+
192
+
193
+ """
194
+ formatting_prompts_func: 各データをプロンプトに合わせた形式に合わせる
195
+ """
196
+ EOS_TOKEN = tokenizer.eos_token # トークナイザーのEOSトークン(文末トークン)
197
+ def formatting_prompts_func(examples):
198
+ input = examples["text"] # 入力データ
199
+ output = examples["output"] # 出力データ
200
+ text = prompt.format(input, output) + EOS_TOKEN # プロンプトの作成
201
+ return { "formatted_text" : text, } # 新しいフィールド "formatted_text" を返す
202
+ pass
203
+
204
+ # # 各データにフォーマットを適用
205
+ edataset = edataset.map(
206
+ formatting_prompts_func,
207
+ num_proc= 4, # 並列処理数を指定
208
+ )
209
+
210
+ edataset
211
+
212
+ # データを確認
213
+ print(edataset["test"]["formatted_text"][3])
214
+ etrainer = SFTTrainer(
215
+ model = model,
216
+ tokenizer = tokenizer,
217
+ train_dataset=edataset["test"],
218
+ max_seq_length = max_seq_length,
219
+ dataset_text_field="formatted_text",
220
+ packing = False,
221
+ args = TrainingArguments(
222
+ per_device_train_batch_size = 2,
223
+ gradient_accumulation_steps = 4,
224
+ num_train_epochs = 1,
225
+ logging_steps = 10,
226
+ warmup_steps = 10,
227
+ save_steps=100,
228
+ save_total_limit=2,
229
+ max_steps=-1,
230
+ learning_rate = 2e-4,
231
+ fp16 = not is_bfloat16_supported(),
232
+ bf16 = is_bfloat16_supported(),
233
+ group_by_length=True,
234
+ seed = 3407,
235
+ output_dir = "outputs",
236
+ report_to = "none",
237
+ ),
238
+ )
239
+ #@title 学習実行
240
+ trainer_stats = etrainer.train()
241
+ # 強化学習
242
+ %%capture
243
+ !pip install unsloth
244
+ # Also get the latest nightly Unsloth!
245
+ !pip uninstall unsloth -y && pip install --upgrade --no-cache-dir --no-deps git+https://github.com/unslothai/unsloth.git
246
+ from huggingface_hub import login
247
+ from google.colab import userdata
248
+ # hugging faseにlog in
249
+
250
+ hf_token = userdata.get('HF_TOKEN')
251
+ if hf_token:
252
+ login(token=hf_token)
253
+ print("Hugging Face token found. Logged in to Hugging Face.")
254
+ else:
255
+ print("Hugging Face token not found. Please set it using userdata.set('HF_TOKEN', '<your-token>')")
256
+ from unsloth import PatchDPOTrainer
257
+ PatchDPOTrainer()
258
+ from unsloth import FastLanguageModel
259
+ import torch
260
+ max_seq_length = 2048 # Choose any! We auto support RoPE Scaling internally!
261
+ dtype = None # None for auto detection. Float16 for Tesla T4, V100, Bfloat16 for Ampere+
262
+ load_in_4bit = True # Use 4bit quantization to reduce memory usage. Can be False.
263
+ model, tokenizer = FastLanguageModel.from_pretrained(
264
+ model_name = "IWAIYuma/llm-jp-3-13b-it_v3", # 自分がUnslothを使ってFTして、loraだけアップロードしているモデル
265
+ max_seq_length = max_seq_length,
266
+ dtype = dtype,
267
+ load_in_4bit = load_in_4bit,
268
+ token = hf_token,
269
+ )
270
+ # cyberagent/chatbot-arena-ja-calm2-7b-chat-experimentalデータセットの読み込み
271
+ import json
272
+ import codecs
273
+ from pprint import pprint
274
+ from datasets import load_dataset
275
+ # データセットをロード
276
+ ds = load_dataset("cyberagent/chatbot-arena-ja-calm2-7b-chat-experimental")
277
+
278
+ # フィルタリング関数を定義
279
+ def filter_short_examples(example):
280
+ return (
281
+ len(example['prompt']) <= 2000 and
282
+ len(example['chosen']) <= 2000 and
283
+ len(example['rejected']) <= 2000
284
+ )
285
+
286
+ # トレーニングデータをフィルタリング
287
+ filtered_train = ds['train'].filter(filter_short_examples)
288
+
289
+ # データセットをトレーニング用と評価用に分割 (80%をトレーニング用、20%を評価用)
290
+ train_size = int(0.8 * len(filtered_train)) # トレーニングデータのサイズ
291
+ eval_size = len(filtered_train) - train_size # 評価データのサイズ
292
+
293
+ # インデックスを順序通りに生成 (ランダム性なし)
294
+ train_indices = list(range(train_size)) # トレーニング用インデックス
295
+ eval_indices = list(range(train_size, len(filtered_train))) # 評価用インデックス
296
+
297
+ # トレーニングデータと評価データを選択
298
+ train_dataset = filtered_train.select(train_indices)
299
+ eval_dataset = filtered_train.select(eval_indices)
300
+
301
+ # データセットのサイズを出力
302
+ print(f"トレーニングデータセットのサイズ: {len(train_dataset)}")
303
+ print(f"評価データセットのサイズ: {len(eval_dataset)}")
304
+ pprint(train_dataset[0])
305
+ print("\n")
306
+ pprint(eval_dataset[0])
307
+
308
+ # 一旦100までを学習
309
+ # 結果が良かったので修正
310
+ # use_dataset = train_dataset.select(range(100))
311
+ use_dataset = train_dataset
312
+ use_dataset
313
+
314
+ # One must patch the DPO Trainer first!
315
+ from unsloth import PatchDPOTrainer
316
+ PatchDPOTrainer()
317
+
318
+ from transformers import TrainingArguments
319
+ from trl import DPOTrainer, DPOConfig
320
+ from unsloth import is_bfloat16_supported
321
+
322
+ dpo_trainer = DPOTrainer(
323
+ model = model,
324
+ ref_model = None,
325
+ args = DPOConfig(
326
+ per_device_train_batch_size = 2,
327
+ gradient_accumulation_steps = 4,
328
+ warmup_ratio = 0.1,
329
+ num_train_epochs = 1,
330
+ learning_rate = 5e-6,
331
+ fp16 = not is_bfloat16_supported(),
332
+ bf16 = is_bfloat16_supported(),
333
+ logging_steps = 1,
334
+ optim = "adamw_8bit",
335
+ weight_decay = 0.0,
336
+ lr_scheduler_type = "linear",
337
+ seed = 42,
338
+ output_dir = "outputs",
339
+ report_to = "none", # Use this for WandB etc
340
+ ),
341
+ beta = 0.1,
342
+ train_dataset = use_dataset, #raw_datasets["train"],
343
+ # eval_dataset = raw_datasets["test"],
344
+ tokenizer = tokenizer,
345
+ max_length = 2048,
346
+ max_prompt_length = 1024,
347
+ )
348
+
349
+ # 学習の開始
350
+ dpo_trainer.train()
351
+
352
+ # ELYZA-tasks-100-TV データセットの読み込み。
353
+
354
+ import json
355
+ datasets = []
356
+ with open("/content/elyza-tasks-100-TV_0.jsonl", "r") as f:
357
+ item = ""
358
+ for line in f:
359
+ line = line.strip()
360
+ item += line
361
+ if item.endswith("}"):
362
+ datasets.append(json.loads(item))
363
+ item = ""
364
+
365
+ # 学習したモデルを用いてタスクを実行
366
+ from tqdm import tqdm
367
+
368
+ # 推論するためにモデルのモードを変更
369
+ FastLanguageModel.for_inference(model)
370
+
371
+ results = []
372
+ for dt in tqdm(datasets):
373
+ input = dt["input"]
374
+
375
+ prompt = f"""### 指示\n{input} 簡潔に回答してください \n### 回答\n"""
376
+
377
+ inputs = tokenizer([prompt], return_tensors = "pt").to(model.device)
378
+
379
+ outputs = model.generate(**inputs, max_new_tokens = 2048, use_cache = True, do_sample=False, repetition_penalty=1.2)
380
+ prediction = tokenizer.decode(outputs[0], skip_special_tokens=True).split('\n### 回答')[-1]
381
+
382
+ results.append({"task_id": dt["task_id"], "input": input, "output": prediction})
383
+
384
+ # jsonlで保存
385
+ new_model_id = "llm-jp-3-13b-it"
386
+ with open(f"{new_model_id}_output.jsonl", 'w', encoding='utf-8') as f:
387
+ for result in results:
388
+ json.dump(result, f, ensure_ascii=False)
389
+ f.write('\n')
390
+
391
+ #書き込みにログイン
392
+ whf_token = userdata.get('WHF_TOKEN')
393
+ if whf_token:
394
+ login(token=whf_token)
395
+ print("Hugging Face token found and logged in.")
396
+ else:
397
+ print("Hugging Face token not found. Please set it using userdata.set('HF_TOKEN', '<your-token>')")
398
+
399
+ # モデルとトークナイザーをHugging Faceにアップロード
400
+ new_model_id = "llm-jp-3-13b-it"
401
+ new_model_id = f"{new_model_id}_RLHFv3"
402
+ model.push_to_hub(new_model_id, token=whf_token, private=True)
403
+ tokenizer.push_to_hub(new_model_id, token=whf_token, private=True)
404
+ '''