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``` ```
12
13```python
14from transformers import (
15 AutoModelForCausalLM,
16 AutoTokenizer,
17 BitsAndBytesConfig,
18 TrainingArguments,
19 logging,
20)
21from peft import (
22 LoraConfig,
23 PeftModel,
24 get_peft_model,
25)
26import os, torch, gc
27from datasets import load_datasetデータセットからインポートload_dataset
28import bitsandbytes as bnb
29from trl import SFTTrainer1# Hugging Face Token
2HF_TOKEN = "write権限のあるトークン"1base_model_id = "llm-jp/llm-jp-3-13b"
2new_model_id = "llm-jp-3-13b-finetune" #Fine-Tuningしたモデルにつけたい名前1bnb_config = BitsAndBytesConfig(
2 load_in_4bit=True,
3 bnb_4bit_quant_type="nf4", # nf4は通常のINT4より精度が高く、ニューラルネットワークの分布に最適です
4 bnb_4bit_compute_dtype=torch.bfloat16,1model = AutoModelForCausalLM.from_pretrained(
2 base_model_id,
3 quantization_config=bnb_config,quantization_config=bnb_config、
4 device_map="auto"
5)
6
7tokenizer = AutoTokenizer.from_pretrained(base_model_id, trust_remote_code=True)1def find_all_linear_names(model):
2 cls = bnb.nn.Linear4bit # 4bit量子化線形層クラスを指定
3 lora_module_names = set() # ここに取得した線形層を保持します。
4
5 # モデル内の全てのモジュールを探索します
6 for name, module in model.named_modules():
7 if isinstance(module, cls): # モジュールが4bit量子化線形層の場合
8 names = name.split('.') # モジュールの名前を分割 (ネストされてる際などに対処)
9 lora_module_names.add(names[0] if len(names) == 1 else names[-1]) # 最下層の名前をlora_module_namesに追加
10
11 # 'lm_head' は16ビット演算の際に除外する必要があるため、lora_module_namesから削除
12 if 'lm_head' in lora_module_names:
13 lora_module_names.remove('lm_head')
14
15 return list(lora_module_names) # lora_module_namesをリストに変換して返します。
16
17modules = find_all_linear_names(model)
181-PEFTの構成設定
2
3peft_config = LoraConfig(
4 r=16,
5 lora_alpha=32,
6 lora_dropout=0.05,
7 bias="none",
8 task_type="CAUSAL_LM",
9 target_modules=modules,
10)
11
12model = get_peft_model(model, peft_config)
131dataset = load_dataset("json", data_files="./ichikara-instruction-003-001-1.json")dataset =load_dataset("json", data_files="./ichikara-instruction-003-001-1.json")
2datasetデータセット1prompt = """### 指示
2{}
3### 回答
4{}"""
5
6
7"""
8formatting_prompts_func: 各データをプロンプトに合わせた形式に合わせるformatting_prompts_func: 各データをプロンプトに合わせた形式に合わせる
9"""
10EOS_TOKEN = tokenizer.eos_token # トークナイザーのEOSトークン(文末トークン)
11def formatting_prompts_func(examples):
12 input = examples["text"] # 入力データ
13 output = examples["output"] # 出力データ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
24dataset1# データを確認
2print(dataset["train"]["formatted_text"][3])1# データをtrainデータとtestデータに分割 (test_sizeの比率に)
2dataset = dataset["train"].train_test_split(test_size=0.1)
3dataset
41training_arguments = TrainingArguments(
2 output_dir=new_model_id,
3 per_device_train_batch_size=1,
4 gradient_accumulation_steps=2,
5 optim="paged_adamw_32bit",
6 num_train_epochs=1,num_train_epochs=1、
7 logging_strategy="steps",
8 logging_steps=10,
9 warmup_steps=10,
10 save_steps=100,
11 save_total_limit = 2,save_total_limit = 2、
12 max_steps = -1,
13 learning_rate=5e-5,
14 fp16=False,
15 bf16=False,
16 seed = 3407,
17 group_by_length=True,
18 report_to="none"レポート先 = "なし"
19)1trainer = SFTTrainer(
2 model=model,
3 train_dataset=dataset["train"],
4 peft_config=peft_config,
5 max_seq_length= 512,
6 dataset_text_field="formatted_text",
7 tokenizer=tokenizer,
8 args=training_arguments,
9 packing= False,
10))
11
12model.config.use_cache = False # キャッシュ機能を無効化
13trainer.train() # トレーニングを実行trainer.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})results.append({"タスクID": データ["タスクID"], "入力": 入力, "出力": 出力})1import re
2jsonl_id = re.sub(".*/", "", new_model_id)jsonl_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')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