Views
No views yet

! python --version! nvidia-smi1# 必要なライブラリをインストール
2! pip install -U -q unsloth
3! pip install -U -q torch
4! pip install -U -q peft
5! pip install chromadb -U -q
6! pip install openpyxl -U -q1# 必要なライブラリを読み込み
2from unsloth import FastLanguageModel
3from peft import PeftModel
4import json
5from tqdm import tqdm
6import re
7import pandas as pd
8from datasets import load_dataset
9
10import os
11from dotenv import load_dotenv
12load_dotenv()
13
14import chromadb1from enum import Enum
2
3class TASK(Enum):
4 ELYZA_100_TV = "elyza100tv"
5 ELYZA_100 = "elyza100"
6
7
8class Prompt(Enum):
9 Defualt = "default"
10 ZeroShotCoT = "ZS-CoT"1collection_name = 'elyza100'
2
3persist_path = './outputs/rag/'
4
5chroma_client = chromadb.PersistentClient(path=persist_path)1try:
2 # 再現性のためにコレクションを削除して再作成
3 chroma_client.delete_collection(name=collection_name)
4except:
5 print('collection not found')
6collection = chroma_client.get_or_create_collection(collection_name)1def load_datasets(inference_task: TASK)->pd.DataFrame:
2 """
3 inference_taskに応じたデータセットを読み込む関数
4 """
5 # タスクとなるデータの読み込み。
6 # 事前にデータをアップロードしてください。
7 if inference_task == TASK.ELYZA_100_TV:
8 datasets = []
9 with open("./elyza-tasks-100-TV_0.jsonl", "r") as f:
10 item = ""
11 for line in f:
12 line = line.strip()
13 item += line
14 if item.endswith("}"):
15 datasets.append(json.loads(item))
16 item = ""
17 datasets = pd.DataFrame(datasets)
18 # Elyza100のタスクを解く場合
19 elif inference_task == TASK.ELYZA_100:
20 datasets_raw = load_dataset("elyza/ELYZA-tasks-100", revision="1.0.0")
21
22 datasets = datasets_raw["test"].to_pandas()
23
24 datasets["task_id"] = datasets.index.astype(str)
25 else:
26 raise ValueError("Invalid task")
27
28 return datasets1# elyza/ELYZA-tasks-100 データセットの読み込み
2
3elyza100_data = load_datasets(TASK.ELYZA_100)1collection.add(
2documents=elyza100_data["input"].to_list(),
3ids= elyza100_data.index.map(lambda x: str(x)).to_list(),)1def get_answer_from_result(idx, result):
2 """
3 RAGの検索結果からidxに応じた回答を取得する
4 """
5 return {
6 "id": result["ids"][0][idx],
7 "distance": round(result["distances"][0][idx], 2),
8 "document": result["documents"][0][idx][:100]
9 }
10def convert_result_to_df(result):
11 """
12 RAGの検索結果をDataFrameに変換する
13 """
14 df = []
15 for idx in range(len(result["ids"][0])):
16 df.append(get_answer_from_result(idx, result))
17 return pd.DataFrame(df)
18
19input = "仕事の熱意を取り戻すためのアイデアを5つ挙げてください。"
20result=collection.query(
21 query_texts=[input],
22 n_results=10,
23 )
24
25df = convert_result_to_df(result)
26df1# ベースとなるモデルと学習したLoRAのアダプタ(Hugging FaceのIDを指定)。
2model_id = "google/gemma-2-9b"
3adapter_id = "marimo2000/gemma-2-9b-elyza-100_x3_lora"
4
5model_local_path = f'content/{os.path.basename(model_id)}'
6
7HF_TOKEN = os.getenv("HF_TOKEN")
8
9COT_COEFF_TASK_ID_FILE_PATH = "outputs/elyza100/score/gemma-2-9b-elyza-100_x3_lora_diff_high_v1.csv"
10
11VERSION = "FINAL"1# すでにモデルが存在する場合は終了
2if os.path.exists(model_local_path):
3 print("Model already exists")
4else:
5 os.makedirs(model_local_path, exist_ok=True)
6 !huggingface-cli login --token {HF_TOKEN}
7 !huggingface-cli download {model_name} --local-dir={model_local_path}
8
9 !ls -lh {model_local_path}1# unslothのFastLanguageModelでLocalのモデルを読み込む
2dtype = None # Noneにしておけば自動で設定
3load_in_4bit = True # 今回は13Bモデルを扱うためTrue
4
5model, tokenizer = FastLanguageModel.from_pretrained(
6 model_name=model_local_path,
7 dtype=dtype,
8 load_in_4bit=load_in_4bit,
9 trust_remote_code=True,
10)1# 元のモデルにLoRAのアダプタを統合。
2model = PeftModel.from_pretrained(model, adapter_id, token = HF_TOKEN)1# モデルを用いてタスクの推論。
2
3# 推論するためにモデルのモードを変更
4FastLanguageModel.for_inference(model)1def load_cot_efficiency_task_ids(file_path: str)->list:
2 """
3 CoTの効率化が必要なタスクidを読み込む関数
4 """
5 df_cot_efficiency_task_ids = pd.read_csv(file_path)
6 cot_efficiency_task_ids = df_cot_efficiency_task_ids["task_id"].tolist()
7 cot_efficiency_task_ids.sort()
8 print(f"CoTの効率化が必要なタスクid: {cot_efficiency_task_ids}")
9 return cot_efficiency_task_ids
10
11def save_results(results, file_path):
12 """
13 結果を保存する関数
14 """
15 with open(file_path, "w", encoding='utf-8') as f:
16 for result in results:
17 json.dump(result, f, ensure_ascii=False)
18 f.write('\n')
19
20 print(f"結果を{file_path}に保存しました。")
21
22
23
24def do_task(model, adapter_id, tokenizer, collection, inference_task: TASK):
25 """
26 タスクを解く関数
27 """
28
29 print(f"推論するタスクは{inference_task.value}です。")
30
31 # ここではadapter_idを元にファイル名を決定しているが、ファイル名は任意で問題なし。
32 output_dir = f"outputs/{inference_task.value}"
33 json_file_id = re.sub(".*/", "", adapter_id)
34 results_file_path = f"{output_dir}/{json_file_id}_with_rag_output_v{VERSION}.jsonl"
35
36 print(f"結果は{results_file_path}に保存されます。")
37
38 # データセットの読み込み
39 datasets = load_datasets(inference_task)
40
41 # CoTの効率化が必要なタスクのidを読み込む
42 cot_efficiency_task_ids = load_cot_efficiency_task_ids(file_path=COT_COEFF_TASK_ID_FILE_PATH)
43
44 results = []
45 for _, dt in tqdm(datasets.iterrows(), total=len(datasets)):
46 input = dt["input"]
47
48 # CoTの効率化が必要なタスクの場合はプロンプトを変更
49 if is_cot_valid_question(input, collection, cot_efficiency_task_ids):
50 prompt = get_prompt(Prompt.ZeroShotCoT, input)
51 else:
52 prompt = get_prompt(Prompt.Defualt, input)
53
54 # LLMによる生成
55 inputs = tokenizer([prompt], return_tensors = "pt").to(model.device)
56 outputs = model.generate(**inputs, max_new_tokens = 512, use_cache = True, do_sample=False, repetition_penalty=1.2)
57 prediction = tokenizer.decode(outputs[0], skip_special_tokens=True).split('### 回答\n')[-1]
58
59 # 結果をListに追加
60 results.append({"task_id": dt["task_id"], "input": input, "output": prediction})
61
62 # 結果を保存
63 save_results(results, results_file_path)
64
65def get_prompt(prompt: Prompt, input: str):
66 """
67 prompのenumに応じたプロンプトを返す。
68 """
69 if prompt == Prompt.Defualt:
70 return f"""### 指示\n{input}\n### 回答\n"""
71 elif prompt == Prompt.ZeroShotCoT:
72 return f"""### 指示\n{input}\nLet's think step by step\n### 回答\n"""
73 else:
74 raise ValueError("Invalid prompt")
75
76def is_cot_valid_question(input, collection, cot_efficiency_task_ids: list):
77 """
78 CoTの効率化が必要なタスクかどうかを判定する。
79 """
80 results = collection.query(
81 query_texts=[input],
82 n_results=1,
83 )
84
85 #top1の中にcot_efficiency_task_idsが含まれているか
86
87 df = convert_result_to_df(results)
88 for idx, row in df.iterrows():
89 if int(row["id"]) in cot_efficiency_task_ids:
90 return True
91
92 return False
93cot_efficiency_task_ids = load_cot_efficiency_task_ids(file_path=COT_COEFF_TASK_ID_FILE_PATH)do_task(model, adapter_id, tokenizer, collection, TASK.ELYZA_100_TV)