メインコンテンツへスキップ
見出し画像

Google Colab で Llama 3 のファインチューニングを試す

    「Google Colab」での「Llama 3」のファインチューニングを試したので、まとめました。

    【注意】Google Colab Pro/Pro+のA100で動作確認しています。

    1. Llama 3

    「Llama 3」は、Metaが開発したオープンモデルです。

    今回は、ござるデータセットで学習します。AIが「我、りんえもんは思う。◯◯でござる。知らんけど。」的な口調になります。

    2. 学習

    Colabでの学習手順は、次のとおりです。

    (1) Colabのノートブックを開き、メニュー「編集 → ノートブックの設定」で「GPU」の「A100」を選択。

    (2) パッケージのインストール。

    # パッケージのインストール
    !pip install -U transformers accelerate bitsandbytes
    !pip install trl peft wandb
    !git clone https://github.com/huggingface/trl
    %cd trl

    (3) 環境変数の準備。
    左端の鍵アイコンで「HF_TOKEN」(HuggingFaceのトークン)を設定し、有効化してからセルを実行してください。

    HuggingFace Hubにモデルをアップロードするには、「write」権限を持つAPIキーを選択する必要があります。

    (4) HuggingFaceへのログイン。
    指示に応じて、HugginFaceのAPIキーを入力します。

    # HuggingFaceへのログイン
    !huggingface-cli login

    (5) 「trl/examples/sft.py」の編集。
    「sft.py」の96行目のデータセットの読み込みを以下のように書き換えます。

        raw_datasets = load_dataset(args.dataset_name)
        train_dataset = raw_datasets["train"]
        eval_dataset = raw_datasets["test"]

       ↓

        # データセットの読み込み
        dataset = load_dataset("bbz662bbz/databricks-dolly-15k-ja-gozarinnemon", split="train")
        dataset = dataset.filter(lambda example: example["category"] == "open_qa")
    
        # プロンプトの生成
        def generate_prompt(example):
            messages = [
                {
                    'role': "system",
                    'content': "あなたは日本語で回答するAIアシスタントです。"
                },
                {
                    'role': "user",
                    'content': example["instruction"]
                },
                {
                    'role': "assistant",
                    'content': example["output"]
                }
            ]
            return tokenizer.apply_chat_template(messages, tokenize=False)
    
        # textカラムの追加
        def add_text(example):
            example["text"] = generate_prompt(example)
            return example
    
        dataset = dataset.map(add_text)
        dataset = dataset.remove_columns(["input", "category", "output", "index", "instruction"])
    
        # データセットの分割
        train_test_split = dataset.train_test_split(test_size=0.1)
        train_dataset = train_test_split["train"]
        eval_dataset = train_test_split["test"]

    (6) 学習。
    練習として500ステップだけ学習します。指示に応じて、wandbのAPIを入力してください。8分ほどで学習完了します。

    # 学習
    !python examples/scripts/sft.py \
        --model_name meta-llama/Meta-Llama-3-8B-Instruct \
        --dataset_name bbz662bbz/databricks-dolly-15k-ja-gozaru \
        --dataset_text_field text \
        --per_device_train_batch_size 2 \
        --gradient_accumulation_steps 1 \
        --learning_rate 2e-4 \
        --optim adamw_torch \
        --save_steps 50 \
        --logging_steps 50 \
        --max_steps 500 \
        --use_peft \
        --lora_r 64 \
        --lora_alpha 16 \
        --lora_dropout 0.1 \
        --load_in_4bit \
        --report_to wandb \
        --output_dir Llama-3-Gozaru-8B-Instruct
    {'loss': 1.9094, 'grad_norm': 1.3531537055969238, 'learning_rate': 0.00018, 'epoch': 0.03}
    {'loss': 1.354, 'grad_norm': 0.7856459617614746, 'learning_rate': 0.00016, 'epoch': 0.06}
    {'loss': 1.3859, 'grad_norm': 0.6068201661109924, 'learning_rate': 0.00014, 'epoch': 0.09}
    {'loss': 1.3009, 'grad_norm': 1.1571404933929443, 'learning_rate': 0.00012, 'epoch': 0.12}
    {'loss': 1.2169, 'grad_norm': 0.7323430776596069, 'learning_rate': 0.0001, 'epoch': 0.15}
    {'loss': 1.287, 'grad_norm': 0.7343457341194153, 'learning_rate': 8e-05, 'epoch': 0.18}
    {'loss': 1.31, 'grad_norm': 0.8455875515937805, 'learning_rate': 6e-05, 'epoch': 0.22}
    {'loss': 1.2687, 'grad_norm': 0.8726828694343567, 'learning_rate': 4e-05, 'epoch': 0.25}
    {'loss': 1.3166, 'grad_norm': 0.543333888053894, 'learning_rate': 2e-05, 'epoch': 0.28}
    {'loss': 1.3012, 'grad_norm': 0.7505847811698914, 'learning_rate': 0.0, 'epoch': 0.31}
    {'train_runtime': 542.2354, 'train_samples_per_second': 1.844, 'train_steps_per_second': 0.922, 'train_loss': 1.3650647735595702, 'epoch': 0.31}
    100% 500/500 [08:02<00:00,  1.04it/s]

    wandbのlossのグラフは、次のとおりです。

    画像

    メモリ消費量は、次のとおりです。

    画像

    3. 推論

    Colabでの推論手順は、次のとおりです。

    (1) トークナイザーとモデルの準備。

    from transformers import AutoTokenizer, AutoModelForCausalLM
    import torch
    
    # トークナイザーとモデルの準備
    tokenizer = AutoTokenizer.from_pretrained(
        "meta-llama/Meta-Llama-3-8B-Instruct"
    )
    model = AutoModelForCausalLM.from_pretrained(
        "./Llama-3-Gozaru-8B-Instruct",
        device_map="auto",
        torch_dtype="auto",
    )

    (2) 推論の実行。

    import torch
    
    # プロンプトの準備
    chat = [
        { "role": "system", "content": "あなたは日本語で回答するAIアシスタントです。" },
        { "role": "user", "content": "まどか☆マギカでは誰が一番かわいい?" },
    ]
    prompt = tokenizer.apply_chat_template(chat, tokenize=False, add_generation_prompt=True)
    
    # 推論の実行
    token_ids = tokenizer.encode(prompt, add_special_tokens=False, return_tensors="pt")
    with torch.no_grad():
        output_ids = model.generate(
            token_ids.to(model.device),
            do_sample=True,
            temperature=0.6,
            top_p=0.9,
            max_new_tokens=256,
            eos_token_id=[
                tokenizer.eos_token_id,
                tokenizer.convert_tokens_to_ids("<|eot_id|>")
            ],
        )
    output = tokenizer.decode(output_ids.tolist()[0][token_ids.size(1) :], skip_special_tokens=True)
    print(output)

    我、りんえもんは思う。 マミは一番かわいい。知らんけど。

    4. HuggingFace Hubへのアップロード

    モデルをHuggingFace Hubにアップロードする手順は、次のとおりです。

    (1) LoRAアダプタをベースモデルにマージ。

    import gc
    from peft import PeftModel
    
    # メモリ解放
    del model
    gc.collect()
    gc.collect()
    torch.cuda.empty_cache()
    
    # モデル名
    base_model = "meta-llama/Meta-Llama-3-8B-Instruct"
    new_model = "Llama-3-Gozaru-8B-Instruct"
    
    # トークナイザの準備
    tokenizer = AutoTokenizer.from_pretrained(base_model)
    
    # モデルの準備
    fp16_model = AutoModelForCausalLM.from_pretrained(
        base_model,
        low_cpu_mem_usage=True,
        return_dict=True,
        torch_dtype=torch.float16,
        device_map="auto",
    )
    
    # アダプタをベースモデルにマージ
    model = PeftModel.from_pretrained(fp16_model, new_model)
    model = model.merge_and_unload()

    (2) 「HuggingFace Hub」のメニュー「New Model」を選択。

    画像

    (3) HuggingFace Hubのリポジトリの作成。
    「Private」を選択することもできます。

    画像

    (4) HuggingFace Hubへのアップロード

    # HuggingFace Hubへのアップロード
    new_model = "Llama-3-Gozaru-8B-Instruct"
    model.push_to_hub(new_model, use_temp_dir=False)
    tokenizer.push_to_hub(new_model, use_temp_dir=False)

    関連



     
     

    npaka

     
     
    プログラマー。iPhone / Android / Unity / ROS / AI / AR / VR / RasPi / ロボット / ガジェット。年2冊ペースで技術書を執筆。アニソン / カラオケ / ギター / 猫 twitter : @npaka123

    あなたへのおすすめ