Hiro00099 commited on
Commit
988815b
1 Parent(s): e7b678c
Files changed (1) hide show
  1. README.md +394 -0
README.md CHANGED
@@ -82,3 +82,397 @@ output_ids = model.generate(input_ids, max_new_tokens=100)
82
  output = tokenizer.decode(output_ids[0], skip_special_tokens=True)
83
 
84
  print(output)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
82
  output = tokenizer.decode(output_ids[0], skip_special_tokens=True)
83
 
84
  print(output)
85
+
86
+
87
+
88
+
89
+
90
+ # Sample Use
91
+ # コンペ用Fine-Tuningテンプレート
92
+
93
+ こちらは、コンペにてFineーTuningを行いたい方に向けたテンプレートとなるFine-tuningコードです。
94
+ こちらを実行いただくだけでコンペの基準に達することができると思います。上手く活用してコンペ上位を目指しましょう!!
95
+
96
+ 本コードはOmnicampusで提供される演習環境での実行を想定しています。
97
+ それ以外の環境で実行される場合は適宜、修正して下さい。
98
+
99
+ # python 3.10.12
100
+ !pip install -U pip
101
+ !pip install -U transformers
102
+ !pip install -U bitsandbytes
103
+ !pip install -U accelerate
104
+ !pip install -U datasets
105
+ !pip install -U peft
106
+ !pip install -U trl
107
+ !pip install -U wandb
108
+ !pip install ipywidgets --upgrade
109
+
110
+ from transformers import (
111
+ AutoModelForCausalLM,
112
+ AutoTokenizer,
113
+ BitsAndBytesConfig,
114
+ TrainingArguments,
115
+ logging,
116
+ )
117
+ from peft import (
118
+ LoraConfig,
119
+ PeftModel,
120
+ get_peft_model,
121
+ )
122
+ import os, torch, gc
123
+ from datasets import load_dataset
124
+ import bitsandbytes as bnb
125
+ from trl import SFTTrainer
126
+
127
+ # Hugging Face Token
128
+ HF_TOKEN = "HFT"
129
+
130
+ # モデルを読み込み。
131
+ # llm-jp-3 1.8B, 3.7B, 13Bのsnapshotをダウンロード済みでmodelsディレクトリに格納してあります。
132
+ # base_model_idの値はomnicampusの環境におけるモデルのパスを表しており、それ以外の環境で実行する場合は変更の必要があります。
133
+ # その他のモデルは取得に承諾が必要なため、各自でダウンロードお願いします。
134
+ base_model_id = "models/models--llm-jp--llm-jp-3-13b/snapshots/cd3823f4c1fcbb0ad2e2af46036ab1b0ca13192a" #Fine-Tuningするベースモデル
135
+ # omnicampus以外の環境をご利用の方は以下をご利用ください。
136
+ # base_model_id = "llm-jp/llm-jp-3-13b"
137
+ new_model_id = "llm-jp-3-13b-finetune" #Fine-Tuningしたモデルにつけたい名前
138
+
139
+ """
140
+ bnb_config: 量子化の設定
141
+
142
+ - load_in_4bit:
143
+ - 4bit量子化形式でモデルをロード
144
+
145
+ - bnb_4bit_quant_type:
146
+ - 量子化の形式を指定
147
+
148
+ - bnb_4bit_compute_dtype:
149
+ - 量子化された重みを用いて計算する際のデータ型
150
+
151
+ """
152
+
153
+ bnb_config = BitsAndBytesConfig(
154
+ load_in_4bit=True,
155
+ bnb_4bit_quant_type="nf4", # nf4は通常のINT4より精度が高く、ニューラルネットワークの分布に最適です
156
+ bnb_4bit_compute_dtype=torch.bfloat16,
157
+ )
158
+
159
+ from huggingface_hub import login
160
+ login("HFT")
161
+
162
+ base_model_id = "llm-jp/llm-jp-3-13b"
163
+
164
+ from transformers import AutoModelForCausalLM, BitsAndBytesConfig, AutoTokenizer
165
+ from huggingface_hub import login
166
+
167
+ # Hugging Faceにログイン
168
+ login("HFT")
169
+
170
+ # 量子化設定
171
+ bnb_config = BitsAndBytesConfig(
172
+ load_in_4bit=True,
173
+ bnb_4bit_quant_type="nf4",
174
+ bnb_4bit_compute_dtype=torch.bfloat16
175
+ )
176
+
177
+ # モデル読み込み
178
+ base_model_id = "llm-jp/llm-jp-3-13b"
179
+ device_map = "auto"
180
+
181
+ model = AutoModelForCausalLM.from_pretrained(
182
+ base_model_id,
183
+ quantization_config=bnb_config,
184
+ device_map=device_map,
185
+ trust_remote_code=True
186
+ )
187
+
188
+ tokenizer = AutoTokenizer.from_pretrained(base_model_id, trust_remote_code=True)
189
+ print("モデルとトークナイザーが正常にロードされました")
190
+
191
+
192
+
193
+ """
194
+ find_all_linear_names: モデル内の4bit量子化線形層を探します。
195
+ """
196
+
197
+ def find_all_linear_names(model):
198
+ cls = bnb.nn.Linear4bit # 4bit量子化線形層クラスを指定
199
+ lora_module_names = set() # ここに取得した線形層を保持します。
200
+
201
+ # モデル内の全てのモジュールを探索します
202
+ for name, module in model.named_modules():
203
+ if isinstance(module, cls): # モジュールが4bit量子化線形層の場合
204
+ names = name.split('.') # モジュールの名前を分割 (ネストされてる際などに対処)
205
+ lora_module_names.add(names[0] if len(names) == 1 else names[-1]) # 最下層の名前をlora_module_namesに追加
206
+
207
+ # 'lm_head' は16ビット演算の際に除外する必要があるため、lora_module_namesから削除
208
+ if 'lm_head' in lora_module_names:
209
+ lora_module_names.remove('lm_head')
210
+
211
+ return list(lora_module_names) # lora_module_namesをリストに変換して返します。
212
+
213
+ modules = find_all_linear_names(model)
214
+
215
+ """
216
+ peft_config: PEFTの構成設定
217
+
218
+ - r
219
+ - LoRA のランク (4, 8, 16 ,32...)
220
+ - 増やすほど学習が捗るが, 過学習のリスクも高まるので注意
221
+
222
+ - lora_alpha
223
+ - LoRAのスケーリング係数
224
+
225
+ - lora_dropout
226
+ - ドロップアウト率(過学習を防ぐための割合)
227
+
228
+ - bias
229
+ - バイアス項の扱い ("none"の場合、LoRAはバイアスを学習しない)
230
+
231
+ - task_type
232
+ - タスクタイプ
233
+
234
+ - target_modules
235
+ - LoRAを適用するターゲットモジュール (前のコードで特定した層)
236
+ """
237
+
238
+ peft_config = LoraConfig(
239
+ r=16,
240
+ lora_alpha=32,
241
+ lora_dropout=0.05,
242
+ bias="none",
243
+ task_type="CAUSAL_LM",
244
+ target_modules=modules,
245
+ )
246
+
247
+ model = get_peft_model(model, peft_config)
248
+
249
+ """
250
+ 学習に用いるデータセットの指定
251
+ 今回はLLM-jp の公開している Ichikara Instruction を使います。データにアクセスするためには申請が必要ですので、使いたい方のみ申請をしてください。
252
+ Ichikara Instruciton を Hugging Face Hub にて公開することはお控えください。
253
+ また、CC-BY-NC-SAですのでモデルはライセンスを継承する前提でお使いください。
254
+
255
+ 下記のリンクから申請を終えた先に Google Drive があり、Distribution20241221_all というフォルダごとダウンロードしてください。
256
+ 今回は「ichikara-instruction-003-001-1.json」を使います。必要であれば展開(!unzip など)し、データセットのパスを適切に指定してください。
257
+ omnicampusの開発環境では取得したデータを左側にドラッグアンドドロップしてお使いください。
258
+
259
+ https://liat-aip.sakura.ne.jp/wp/llmのための日本語インストラクションデータ作成/llmのための日本語インストラクションデータ-公開/
260
+ 関根聡, 安藤まや, 後藤美知子, 鈴木久美, 河原大輔, 井之上直也, 乾健太郎. ichikara-instruction: LLMのための日本語インストラクションデータの構築. 言語処理学会第30回年次大会(2024)
261
+
262
+ """
263
+
264
+ dataset = load_dataset("json", data_files="./ichikara-instruction-003-001-1.json")
265
+ dataset
266
+
267
+ # 学習時のプロンプトフォーマットの定義
268
+ prompt = """### 指示
269
+ {}
270
+ ### 回答
271
+ {}"""
272
+
273
+
274
+ """
275
+ formatting_prompts_func: 各データをプロンプトに合わせた形式に合わせる
276
+ """
277
+ EOS_TOKEN = tokenizer.eos_token # トークナイザーのEOSトークン(文末トークン)
278
+ def formatting_prompts_func(examples):
279
+ input = examples["text"] # 入力データ
280
+ output = examples["output"] # 出力データ
281
+ text = prompt.format(input, output) + EOS_TOKEN # プロンプトの作成
282
+ return { "formatted_text" : text, } # 新しいフィールド "formatted_text" を返す
283
+ pass
284
+
285
+ # # 各データにフォーマットを適用
286
+ dataset = dataset.map(
287
+ formatting_prompts_func,
288
+ num_proc= 4, # 並列処理数を指定
289
+ )
290
+
291
+ dataset
292
+
293
+ # データを確認
294
+ print(dataset["train"]["formatted_text"][3])
295
+
296
+ # データをtrainデータとtestデータに分割 (test_sizeの比率に)
297
+ # dataset = dataset["train"].train_test_split(test_size=0.1)
298
+ # dataset
299
+
300
+ """
301
+ training_arguments: 学習の設定
302
+
303
+ - output_dir:
304
+ -トレーニング後のモデルを保存するディレクトリ
305
+
306
+ - per_device_train_batch_size:
307
+ - デバイスごとのトレーニングバッチサイズ
308
+
309
+ - per_device_
310
+ _batch_size:
311
+ - デバイスごとの評価バッチサイズ
312
+
313
+ - gradient_accumulation_steps:
314
+ - 勾配を更新する前にステップを積み重ねる回数
315
+
316
+ - optim:
317
+ - オプティマイザの設定
318
+
319
+ - num_train_epochs:
320
+ - エポック数
321
+
322
+ - eval_strategy:
323
+ - 評価の戦略 ("no"/"steps"/"epoch")
324
+
325
+ - eval_steps:
326
+ - eval_strategyが"steps"のとき、評価を行うstep間隔
327
+
328
+ - logging_strategy:
329
+ - ログ記録の戦略
330
+
331
+ - logging_steps:
332
+ - ログを出力するステップ間隔
333
+
334
+ - warmup_steps:
335
+ - 学習率のウォームアップステップ数
336
+
337
+ - save_steps:
338
+ - モデルを保存するステップ間隔
339
+
340
+ - save_total_limit:
341
+ - 保存しておくcheckpointの数
342
+
343
+ - max_steps:
344
+ - トレーニングの最大ステップ数
345
+
346
+ - learning_rate:
347
+ - 学習率
348
+
349
+ - fp16:
350
+ - 16bit浮動小数点の使用設定(第8回演習を参考にすると良いです)
351
+
352
+ - bf16:
353
+ - BFloat16の使用設定
354
+
355
+ - group_by_length:
356
+ - 入力シーケンスの長さによりバッチをグループ化 (トレーニングの効率化)
357
+
358
+ - report_to:
359
+ - ログの送信先 ("wandb"/"tensorboard"など)
360
+ """
361
+
362
+ training_arguments = TrainingArguments(
363
+ output_dir=new_model_id,
364
+ per_device_train_batch_size=1,
365
+ gradient_accumulation_steps=2,
366
+ optim="paged_adamw_32bit",
367
+ num_train_epochs=1,
368
+ logging_strategy="steps",
369
+ logging_steps=10,
370
+ warmup_steps=10,
371
+ save_steps=100,
372
+ save_total_limit = 2,
373
+ max_steps = -1,
374
+ learning_rate=5e-5,
375
+ fp16=False,
376
+ bf16=False,
377
+ seed = 3407,
378
+ group_by_length=True,
379
+ report_to="none"
380
+ )
381
+
382
+ # トークナイザーで事前処理
383
+ tokenized_datasets = dataset.map(
384
+ lambda example: tokenizer(
385
+ example["formatted_text"],
386
+ truncation=True,
387
+ max_length=512,
388
+ padding="max_length"
389
+ ),
390
+ batched=True
391
+ )
392
+
393
+ # SFTTrainerの呼び出し
394
+ trainer = SFTTrainer(
395
+ model=model,
396
+ train_dataset=tokenized_datasets["train"],
397
+ peft_config=peft_config,
398
+ args=training_arguments
399
+ )
400
+ trainer.train()
401
+
402
+
403
+
404
+ import os
405
+
406
+ file_path = "./elyza-tasks-100-TV_0.jsonl"
407
+ if os.path.exists(file_path):
408
+ print("File exists at:", os.path.abspath(file_path))
409
+ else:
410
+ print("File not found!")
411
+
412
+
413
+ import json
414
+
415
+ file_path = "/content/elyza-tasks-100-TV_0.jsonl" # 正しいファイルパス
416
+ datasets = []
417
+
418
+ with open(file_path, "r") as f:
419
+ item = ""
420
+ for line in f:
421
+ line = line.strip()
422
+ item += line
423
+ if item.endswith("}"):
424
+ datasets.append(json.loads(item))
425
+ item = ""
426
+
427
+ print("Loaded datasets:", datasets)
428
+
429
+
430
+ # モデルによるタスクの推論。
431
+ from tqdm import tqdm
432
+
433
+ results = []
434
+ for data in tqdm(datasets):
435
+
436
+ input = data["input"]
437
+
438
+ prompt = f"""### 指示
439
+ {input}
440
+ ### 回答
441
+ """
442
+
443
+ tokenized_input = tokenizer.encode(prompt, add_special_tokens=False, return_tensors="pt").to(model.device)
444
+ attention_mask = torch.ones_like(tokenized_input)
445
+
446
+ with torch.no_grad():
447
+ outputs = model.generate(
448
+ tokenized_input,
449
+ attention_mask=attention_mask,
450
+ max_new_tokens=100,
451
+ do_sample=False,
452
+ repetition_penalty=1.2,
453
+ pad_token_id=tokenizer.eos_token_id
454
+ )[0]
455
+ output = tokenizer.decode(outputs[tokenized_input.size(1):], skip_special_tokens=True)
456
+
457
+ results.append({"task_id": data["task_id"], "input": input, "output": output})
458
+
459
+ # こちらで生成されたjsolを提出してください。
460
+ # 本コードではinputとeval_aspectも含んでいますが、なくても問題ありません。
461
+ # 必須なのはtask_idとoutputとなります。
462
+ import re
463
+ jsonl_id = re.sub(".*/", "", new_model_id)
464
+ with open(f"./{jsonl_id}-outputs.jsonl", 'w', encoding='utf-8') as f:
465
+ for result in results:
466
+ json.dump(result, f, ensure_ascii=False) # ensure_ascii=False for handling non-ASCII characters
467
+ f.write('\n')
468
+
469
+ # モデルとトークナイザーをHugging Faceにアップロード
470
+ model.push_to_hub(new_model_id, token=HF_TOKEN, private=True) # Online saving
471
+ tokenizer.push_to_hub(new_model_id, token=HF_TOKEN, private=True) # Online saving
472
+
473
+ https://liat-aip.sakura.ne.jp/wp/llmのための日本語インストラクションデータ作成/llmのための日本語インストラクションデータ-公開/
474
+
475
+ 関根聡, 安藤まや, 後藤美知子, 鈴木久美, 河原大輔, 井之上直也, 乾健太郎. ichikara-instruction: LLMのための日本語インストラクションデータの構築. 言語処理学会第30回年次大会(2024)
476
+
477
+
478
+