7
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

自分を模倣するLLMを作成する方法

Last updated at Posted at 2023-12-10

はじめに

最近はChatGPTなどの大規模言語モデル(LLM)の発展がめざましく、自分で文章を考えなくても勝手にAIが書いてくれる世の中になりました

しかし、ChatGPTなどの既存のLLMに意見とかを述べさせると、中立的で一般的な意見しか述べず、明らかにAIが書いたんだろうな~という文章しか作れません。

そんなわけで、今回は自分の意見に近い文章を出力してくれるLLMを作成しようという試みを書きたいと思います!!

最初に

まずはベースとなるLLMを用意するところから始めます

ChatGPTやBIng AIは高性能なのですが、実際のモデルはダウンロード出来ないので自分好みにカスタマイズできないという欠点があります。

そこでダウンロード可能なChat型LLMであるLlama2をゲットしましょう!!

Llama2はMeta社が開発したオープンモデルでChatGPT3.5にいくつかの指標で勝つなど優秀なモデルです

Llama2のダウンロード

Llama2は他のモデルに比べると日本語の返答にあまり強くないという欠点があります。そこで今回はLlama2をベースとして日本語の追加学習を行った「ELYZA-japanese-Llama-2-7b」をベースのモデルとしてダウンロードします

import torch
from transformers import AutoModelForCausalLM, AutoTokenizer, PreTrainedTokenizer

model_name = "elyza/ELYZA-japanese-Llama-2-7b-instruct"
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForCausalLM.from_pretrained(model_name, torch_dtype="auto")

tokenizer.save_pretrained("tokenizer")
model.save_pretrained("ELYZA_chat_model")

これで自分用のLLMをダウンロードすることが出来ました

自分の好みにカスタマイズする

まず自分用のプロンプトと出力例を用意します

以下のフォーマットで自分用のデータをcsvにします。

system_prompt,timestanp,input_num,input_1,output_1,input_2,output_2,input_3,output_3,input_4,output_4,input_5,output_5,input_6,output_6,input_7,output_7,input_8,output_8,input_9,output_9,input_10,output_10
"",2023/12/08 12:00:00,1,"簡潔に自己紹介をして","こんにちは。\n私の名前は**です。趣味は**でよく**しています。","どうしてそれが趣味なのですか?","昔、**が**でそこから**を趣味として楽しむようになりました。",,,,,,,

次に訓練用のデータセットを作成します。

#プロンプト
NAME = "****" #あなたの名前
B_INST, E_INST = "[INST]", "[/INST]"
B_SYS, E_SYS = "<<SYS>>\n", "\n<</SYS>>\n\n"
DEFAULT_SYSTEM_PROMPT = "あなたは{name}という名前の日本人です。今は{time}です。以下の会話に{name}として答えてください"

dataset = pd.Series(["" for _ in range(len(data))])

#GPUを有効化
if torch.backends.mps.is_available():
    mps_device = torch.device("mps")
    model.to(mps_device)

#データセットを作成
for i in range(len(data)):
    if data.loc[i, "system_prompt"] == "":
        system = B_SYS + DEFAULT_SYSTEM_PROMPT.format(name=NAME, time=data.loc[i, "timestamp"]) + E_SYS
    else:
        system = data.loc[i, "system_prompt"]
    prompt = "{bos_token}{b_inst} {system}{prompt} {e_inst} {output} {eos_token}".format(
        bos_token=tokenizer.bos_token,
        b_inst=B_INST,
        system=system,
        prompt=data.loc[i, "input_1"],
        e_inst=E_INST,
        output=data.loc[i, "output_1"],
        eos_token=tokenizer.eos_token
    )
    for j in range(data.loc[i, "input_num"]-1):
        prompt += "{bos_token}{b_inst} {prompt} {e_inst} {output} {eos_token}".format(
            bos_token=tokenizer.bos_token,
            b_inst=B_INST,
            prompt=data.loc[i, f"input_{j+2}"],
            e_inst=E_INST,
            output=data.loc[i, f"output_{j+2}"]
            eos_token=tokenizer.eos_token
        )

    dataset[i] = prompt

データセットの作成方法は以下のサイトを参考にしてください。

今回はQLoRAと呼ばれる手法でモデルをファインチューニング(追加学習)させていきます。

QLoRAの理論を知りたい方は以下のサイトを参考にしてください。

訓練コード

compute_dtype = getattr(torch, "float16")

quant_config = BitsAndBytesConfig(
    load_in_4bit=True,
    bnb_4bit_quant_type="nf4",
    bnb_4bit_compute_dtype=compute_dtype,
    bnb_4bit_use_double_quant=False,
)

model = AutoModelForCausalLM.from_pretrained(
    os.path.join(base_dir, model_path),
    quantization_config=quant_config,
    device_map={"": 0}
)
model.config.use_cache = False
model.config.pretraining_tp = 1

tokenizer = AutoTokenizer.from_pretrained(os.path.join(base_dir, tokenizer_path), trust_remote_code=True)
tokenizer.pad_token = tokenizer.eos_token
tokenizer.padding_side = "right"

peft_params = LoraConfig(
    lora_alpha=16,
    lora_dropout=0.1,
    r=64,
    bias="none",
    task_type="CAUSAL_LM",
)

training_params = TrainingArguments(
    output_dir=os.path.join(base_dir, "trani_output"),
    num_train_epochs=1,
    per_device_train_batch_size=4,
    gradient_accumulation_steps=1,
    optim="paged_adamw_32bit",
    save_steps=25,
    logging_steps=25,
    learning_rate=2e-4,
    weight_decay=0.001,
    fp16=False,
    bf16=False,
    max_grad_norm=0.3,
    max_steps=-1,
    warmup_ratio=0.03,
    group_by_length=True,
    lr_scheduler_type="constant",
    report_to="tensorboard"
)

trainer = SFTTrainer(
    model=model,
    train_dataset=train_data,
    peft_config=peft_params,
    dataset_text_field="text",
    max_seq_length=None,
    tokenizer=tokenizer,
    args=training_params,
    packing=False,
)

trainer.train()

trainer.model.save_pretrained(os.path.join(base_dir, "chat_model"))
trainer.tokenizer.save_pretrained(os.path.join(base_dir, "tokenizer"))

参考とした記事は以下の記事です

終わりに

実際には自分がしそうな返答のデータセットを作るために、SNSからデータを引っ張る等の追加の処理が必要となります。

是非皆さんも自分のコピーAIを作ってみてください。

7
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?