Views
No views yet
1# python 3.10.12
2!pip install -U pip
3!pip install -U transformers
4!pip install -U bitsandbytes
5!pip install -U accelerate
6!pip install -U datasets
7!pip install -U peft
8!pip install -U trl
9!pip install -U wandb
10!pip install ipywidgets --upgrade
11
12from transformers import (
13 AutoModelForCausalLM,
14 AutoTokenizer,
15 BitsAndBytesConfig,
16 TrainingArguments,
17 logging,
18)
19from peft import (
20 LoraConfig,
21 PeftModel,
22 get_peft_model,
23)
24import os, torch, gc
25from datasets import load_dataset
26import bitsandbytes as bnb
27from trl import SFTTrainerHF_TOKEN = "***"1base_model_id = "models/models--llm-jp--llm-jp-3-13b/snapshots/cd3823f4c1fcbb0ad2e2af46036ab1b0ca13192a" #Fine-Tuningするベースモデル
2# omnicampus以外の環境をご利用の方は以下をご利用ください。
3# base_model_id = "llm-jp/llm-jp-3-13b"
4
5new_model_id = "llm-jp-3-13b-finetune" #Fine-Tuningしたモデルにつけたい名前1"""
2bnb_config: 量子化の設定
3
4 - load_in_4bit:
5 - 4bit量子化形式でモデルをロード
6
7 - bnb_4bit_quant_type:
8 - 量子化の形式を指定
9
10 - bnb_4bit_compute_dtype:
11 - 量子化された重みを用いて計算する際のデータ型
12
13"""
14
15bnb_config = BitsAndBytesConfig(
16 load_in_4bit=True,
17 bnb_4bit_quant_type="nf4", # nf4は通常のINT4より精度が高く、ニューラルネットワークの分布に最適
18 bnb_4bit_compute_dtype=torch.bfloat16,
19)1"""
2model: モデル
3
4 - base_model:
5 - 読み込むベースモデル (事前に定義したもの)
6
7 - quantization_config:
8 - bnb_configで設定した量子化設定
9
10 - device_map:
11 - モデルを割り当てるデバイス (CPU/GPU) "auto"で自動に割り当てられます。
12
13tokenizer: トークナイザー
14
15 - base_model:
16 - 読み込むベースモデル (事前に定義したもの)
17
18 - trust_remote_code:
19 - リモートコードの実行を許可 (カスタムモデルなど)
20"""
21model = AutoModelForCausalLM.from_pretrained(
22 base_model_id,
23 quantization_config=bnb_config,
24 device_map="auto"
25)
26
27tokenizer = AutoTokenizer.from_pretrained(base_model_id, trust_remote_code=True)1"""
2find_all_linear_names: モデル内の4bit量子化線形層を探します。
3"""
4
5def find_all_linear_names(model):
6 cls = bnb.nn.Linear4bit # 4bit量子化線形層クラスを指定
7 lora_module_names = set() # ここに取得した線形層を保持します。
8
9 # モデル内の全てのモジュールを探索します
10 for name, module in model.named_modules():
11 if isinstance(module, cls): # モジュールが4bit量子化線形層の場合
12 names = name.split('.') # モジュールの名前を分割 (ネストされてる際などに対処)
13 lora_module_names.add(names[0] if len(names) == 1 else names[-1]) # 最下層の名前をlora_module_namesに追加
14
15 # 'lm_head' は16ビット演算の際に除外する必要があるため、lora_module_namesから削除
16 if 'lm_head' in lora_module_names:
17 lora_module_names.remove('lm_head')
18
19 return list(lora_module_names) # lora_module_namesをリストに変換して返します。
20
21modules = find_all_linear_names(model)1"""
2peft_config: PEFTの構成設定
3
4 - r
5 - LoRA のランク (4, 8, 16 ,32...)
6 - 増やすほど学習が捗るが, 過学習のリスクも高まるので注意
7
8 - lora_alpha
9 - LoRAのスケーリング係数
10
11 - lora_dropout
12 - ドロップアウト率(過学習を防ぐための割合)
13
14 - bias
15 - バイアス項の扱い ("none"の場合、LoRAはバイアスを学習しない)
16
17 - task_type
18 - タスクタイプ
19
20 - target_modules
21 - LoRAを適用するターゲットモジュール (前のコードで特定した層)
22"""
23
24peft_config = LoraConfig(
25 r=16,
26 lora_alpha=32,
27 lora_dropout=0.05,
28 bias="none",
29 task_type="CAUSAL_LM",
30 target_modules=modules,
31)
32
33model = get_peft_model(model, peft_config)1"""
2学習に用いるデータセットの指定
3
41. megagonlabs/instruction_ja (ライセンス MIT:コピー、変更、マージ、公開、配布に制限のないライセンス)
5
6https://github.com/megagonlabs/instruction_ja
7
82. 感想付きニュース雑談対話コーパス V3ファイル (ライセンス MIT:コピー、変更、マージ、公開、配布に制限のないライセンス)
9
10https://github.com/fukanarita/newschat-with-impression
11
121.と2.のデータセットを「質問」と「回答」の形式に加工してマージした megagonlabs_instruction_ja_V3.json を作成し、データセットとした。)。
13"""
14
15dataset = load_dataset("json", data_files="./megagonlabs_instruction_ja_V3.json")
16dataset1prompt = """### 指示
2{}
3### 回答
4{}"""
5
6
7"""
8formatting_prompts_func: 各データをプロンプトに合わせた形式に合わせる
9"""
10EOS_TOKEN = tokenizer.eos_token # トークナイザーのEOSトークン(文末トークン)
11def formatting_prompts_func(examples):
12 input = examples["text"] # 入力データ
13 output = examples["output"] # 出力データ
14 text = prompt.format(input, output) + EOS_TOKEN # プロンプトの作成
15 return { "formatted_text" : text, } # 新しいフィールド "formatted_text" を返す
16pass
17
18# # 各データにフォーマットを適用
19dataset = dataset.map(
20 formatting_prompts_func,
21 num_proc= 4, # 並列処理数を指定
22)
23
24datasetprint(dataset["train"]["formatted_text"][3])1"""
2training_arguments: 学習の設定
3
4 - output_dir:
5 -トレーニング後のモデルを保存するディレクトリ
6
7 - per_device_train_batch_size:
8 - デバイスごとのトレーニングバッチサイズ
9
10 - per_device_
11 _batch_size:
12 - デバイスごとの評価バッチサイズ
13
14 - gradient_accumulation_steps:
15 - 勾配を更新する前にステップを積み重ねる回数
16
17 - optim:
18 - オプティマイザの設定
19
20 - num_train_epochs:
21 - エポック数
22
23 - eval_strategy:
24 - 評価の戦略 ("no"/"steps"/"epoch")
25
26 - eval_steps:
27 - eval_strategyが"steps"のとき、評価を行うstep間隔
28
29 - logging_strategy:
30 - ログ記録の戦略
31
32 - logging_steps:
33 - ログを出力するステップ間隔
34
35 - warmup_steps:
36 - 学習率のウォームアップステップ数
37
38 - save_steps:
39 - モデルを保存するステップ間隔
40
41 - save_total_limit:
42 - 保存しておくcheckpointの数
43
44 - max_steps:
45 - トレーニングの最大ステップ数
46
47 - learning_rate:
48 - 学習率
49
50 - fp16:
51 - 16bit浮動小数点の使用設定(第8回演習を参考にすると良いです)
52
53 - bf16:
54 - BFloat16の使用設定
55
56 - group_by_length:
57 - 入力シーケンスの長さによりバッチをグループ化 (トレーニングの効率化)
58
59 - report_to:
60 - ログの送信先 ("wandb"/"tensorboard"など)
61"""
62
63training_arguments = TrainingArguments(
64 output_dir=new_model_id,
65 per_device_train_batch_size=1,
66 gradient_accumulation_steps=2,
67 optim="paged_adamw_32bit",
68 num_train_epochs=4,
69 logging_strategy="steps",
70 logging_steps=10,
71 warmup_steps=10,
72 save_steps=100,
73 save_total_limit = 2,
74 max_steps = -1,
75 learning_rate=1e-6,
76 fp16=False,
77 bf16=False,
78 seed = 1000,
79 group_by_length=True,
80 report_to="none"
81)1"""
2SFTTrainer: Supervised Fine-Tuningに関する設定
3
4 - model:
5 - 読み込んだベースのモデル
6
7 - train_dataset:
8 - トレーニングに使用するデータセット
9
10 - eval_dataset:
11 - 評価に使用するデータセット
12
13 - peft_config:
14 - PEFT(Parameter-Efficient Fine-Tuning)の設定(LoRAを利用する場合に指定)
15
16 - max_seq_length:
17 - モデルに入力されるシーケンスの最大トークン長
18
19 - dataset_text_field:
20 - データセット内の学習に使うテキストを含むフィールド名
21
22 - tokenizer:
23 - モデルに対応するトークナイザー
24
25 - args:
26 - トレーニングに使用するハイパーパラメータ(TrainingArgumentsの設定を指定)
27
28 - packing:
29 - 入力シーケンスのパッキングを行うかどうかの設定 (False に設定することで、各入力を独立して扱う)
30"""
31trainer = SFTTrainer(
32 model=model,
33 train_dataset=dataset["train"],
34 peft_config=peft_config,
35 max_seq_length= 512,
36 dataset_text_field="formatted_text",
37 tokenizer=tokenizer,
38 args=training_arguments,
39 packing= False,
40)
41
42model.config.use_cache = False # キャッシュ機能を無効化
43trainer.train() # トレーニングを実行1import json
2datasets = []
3with open("./elyza-tasks-100-TV_0.jsonl", "r") as f:
4 item = ""
5 for line in f:
6 line = line.strip()
7 item += line
8 if item.endswith("}"):
9 datasets.append(json.loads(item))
10 item = ""1from tqdm import tqdm
2
3results = []
4for data in tqdm(datasets):
5
6 input = data["input"]
7
8 prompt = f"""### 指示
9 {input}
10 ### 回答
11 """
12
13 tokenized_input = tokenizer.encode(prompt, add_special_tokens=False, return_tensors="pt").to(model.device)
14 attention_mask = torch.ones_like(tokenized_input)
15
16 with torch.no_grad():
17 outputs = model.generate(
18 tokenized_input,
19 attention_mask=attention_mask,
20 max_new_tokens=100,
21 do_sample=False,
22 repetition_penalty=1.2,
23 pad_token_id=tokenizer.eos_token_id
24 )[0]
25 output = tokenizer.decode(outputs[tokenized_input.size(1):], skip_special_tokens=True)
26
27 results.append({"task_id": data["task_id"], "input": input, "output": output})1import re
2jsonl_id = re.sub(".*/", "", new_model_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) # ensure_ascii=False for handling non-ASCII characters
6 f.write('\n')1model.push_to_hub(new_model_id, token=HF_TOKEN, private=True) # Online saving
2tokenizer.push_to_hub(new_model_id, token=HF_TOKEN, private=True) # Online saving