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

Google Colab を使って Llama 3 のファインチューニングを試してみました/大塚

    npakaさんの記事を参考に、Llama3をファインチューニングしてみました!

    途中でつまづいたところがあったので、備忘録として残します😚

    <エラー>'SFTScriptArguments'をimportできません…

    記事通りにやっていくと、「(6) 学習」の箇所でエラーが出ました。

    ImportError: cannot import name 'SFTScriptArguments' from 'trl.commands.cli utils' (/usr/local/lib/python3.10/dist-packages/trl/commands/cli_utils.py)

    対処方法

    「trl/examples/scripts/sft.py」を開きます。

    画像
    画像

    この「sft.py」を、まずは以下のコードで全て置き換えます。

    # flake8: noqa
    # Copyright 2023 The HuggingFace Inc. team. All rights reserved.
    #
    # Licensed under the Apache License, Version 2.0 (the "License");
    # you may not use this file except in compliance with the License.
    # You may obtain a copy of the License at
    #
    #     http://www.apache.org/licenses/LICENSE-2.0
    #
    # Unless required by applicable law or agreed to in writing, software
    # distributed under the License is distributed on an "AS IS" BASIS,
    # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    # See the License for the specific language governing permissions and
    # limitations under the License.
    """
    # regular:
    python examples/scripts/sft.py \
        --model_name_or_path="facebook/opt-350m" \
        --report_to="wandb" \
        --learning_rate=1.41e-5 \
        --per_device_train_batch_size=64 \
        --gradient_accumulation_steps=16 \
        --output_dir="sft_openassistant-guanaco" \
        --logging_steps=1 \
        --num_train_epochs=3 \
        --max_steps=-1 \
        --push_to_hub \
        --gradient_checkpointing \
    
    # peft:
    python examples/scripts/sft.py \
        --model_name_or_path="facebook/opt-350m" \
        --report_to="wandb" \
        --learning_rate=1.41e-5 \
        --per_device_train_batch_size=64 \
        --gradient_accumulation_steps=16 \
        --output_dir="sft_openassistant-guanaco" \
        --logging_steps=1 \
        --num_train_epochs=3 \
        --max_steps=-1 \
        --push_to_hub \
        --gradient_checkpointing \
        --use_peft \
        --lora_r=64 \
        --lora_alpha=16
    """
    import logging
    import os
    from contextlib import nullcontext
    
    TRL_USE_RICH = os.environ.get("TRL_USE_RICH", False)
    
    from trl.commands.cli_utils import init_zero_verbose, SftScriptArguments, TrlParser
    
    if TRL_USE_RICH:
        init_zero_verbose()
        FORMAT = "%(message)s"
    
        from rich.console import Console
        from rich.logging import RichHandler
    
    import torch
    from datasets import load_dataset
    
    from tqdm.rich import tqdm
    from transformers import AutoTokenizer, TrainingArguments
    
    from trl import (
        ModelConfig,
        RichProgressCallback,
        SFTTrainer,
        get_peft_config,
        get_quantization_config,
        get_kbit_device_map,
    )
    
    tqdm.pandas()
    
    if TRL_USE_RICH:
        logging.basicConfig(format=FORMAT, datefmt="[%X]", handlers=[RichHandler()], level=logging.INFO)
    
    
    if __name__ == "__main__":
        parser = TrlParser((SftScriptArguments, TrainingArguments, ModelConfig))
        args, training_args, model_config = parser.parse_args_and_config()
    
        # Force use our print callback
        if TRL_USE_RICH:
            training_args.disable_tqdm = True
            console = Console()
    
        ################
        # Model & Tokenizer
        ################
        torch_dtype = (
            model_config.torch_dtype
            if model_config.torch_dtype in ["auto", None]
            else getattr(torch, model_config.torch_dtype)
        )
        quantization_config = get_quantization_config(model_config)
        model_kwargs = dict(
            revision=model_config.model_revision,
            trust_remote_code=model_config.trust_remote_code,
            attn_implementation=model_config.attn_implementation,
            torch_dtype=torch_dtype,
            use_cache=False if training_args.gradient_checkpointing else True,
            device_map=get_kbit_device_map() if quantization_config is not None else None,
            quantization_config=quantization_config,
        )
        tokenizer = AutoTokenizer.from_pretrained(model_config.model_name_or_path, use_fast=True)
        tokenizer.pad_token = tokenizer.eos_token
    
        ################
        # Dataset
        ################
        raw_datasets = load_dataset(args.dataset_name)
    
        train_dataset = raw_datasets[args.dataset_train_name]
        eval_dataset = raw_datasets[args.dataset_test_name]
    
        ################
        # Optional rich context managers
        ###############
        init_context = nullcontext() if not TRL_USE_RICH else console.status("[bold green]Initializing the SFTTrainer...")
        save_context = (
            nullcontext()
            if not TRL_USE_RICH
            else console.status(f"[bold green]Training completed! Saving the model to {training_args.output_dir}")
        )
    
        ################
        # Training
        ################
        with init_context:
            trainer = SFTTrainer(
                model=model_config.model_name_or_path,
                model_init_kwargs=model_kwargs,
                args=training_args,
                train_dataset=train_dataset,
                eval_dataset=eval_dataset,
                dataset_text_field=args.dataset_text_field,
                max_seq_length=args.max_seq_length,
                tokenizer=tokenizer,
                packing=args.packing,
                peft_config=get_peft_config(model_config),
                callbacks=[RichProgressCallback] if TRL_USE_RICH else None,
            )
    
        trainer.train()
    
        with save_context:
            trainer.save_model(training_args.output_dir)

    その後116行目を、npakaさんのコードを参考に書き換えます。

        # データセットの読み込み
        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"]

    4/23のcommitで、'SftScriptArguments'が、'SFTScriptArguments'に変わっちゃってるのが原因かと思います。

    ImportError: cannot import name 'SFTScriptArguments' from 'trl.commands.cli utils' (/usr/local/lib/python3.10/dist-packages/trl/commands/cli_utils.py)

    Llamaモデルへのアクセス権限

    また、こちらの学習用のコードを最初に実行した際、llamaへのアクセス権限がありませんといったエラーが出てきます。

    # 学習
    !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

    その時は、表示されたHuggingFaceのURLにアクセスします。すると、以下のようなライセンス同意条項が出てきます。名前や生年月日を入力してアクセス権限を依頼します。僕がやった時は1時間もしないうちに許可されました🤗

    画像

    使用GPU

    Colabで使用するGPUは、V100だとメモリが不足してしまいました。A100につながるように何回か挑戦しました🥺

    出力例

    試行錯誤してなんとか上手くできました!

    Q.魔法少女まどか☆マギカで誰が一番可愛い?

    A.我、りんえもんは思う。 可愛いキャラは、マミさまとキュゥべえ。マミさまの頭がおかしいのは、可愛いから。キュゥべえは、マミさまより強く、愛すべきもある。知らんけど。

    Q.犬に仏の心はあるか?

    A.我、りんえもんは思う。犬の心は、他の動物に比べて最も純潔で善いものですでしょう。フランシスコ・オスチナスが書いた「仏の心は仏を生む」という句がありますでしょ。仏の心は、仏を生むための要素ですでござる。犬は、その要素を持つ唯一の動物だった。犬が他の生き物と繋がり合うこともできますでしょ。彼らは、友情に満ちた最良のコメットでござる。オスシスは、このことについて話しており、「すべての心には、心というよりは、愛と共に生きるための心があり、犬もそうですでござる。犬は愛の心に満ち溜まっており、愛のすべての形で、全ての心に繋がり合っていますでござる。ただ犬のようになったのでござる。犬の友が死ぬのは困難でしょうが、最も多くの犬が死亡するのは、心や肺臓の疾患でござる」

    Q.グラノーラを使ったおすすめ朝食メニューってある?

    A.我、りんえもんは思う。 お好きな水の量をあたり、ハナミズキのパンを焼いて、グラノーラとスライスベリーをトッピングしてください。オルテガの塩やブラックペッパーを加えることでよりタイトになる。水とパンの両方を温めています。知らんけど。

     
     
    しぴ研究結社/「人々の持ち味を余すことなく活かす社会」の実現について研究しています👥💫/佐賀県を拠点に会社員や思想家、音楽ライターのメンバーで構成されています👨‍👨‍👦/ジャンルは創造性、KJ法、生成AI、団結主義、天職、音楽など📝/毎週土曜日更新🪐

    あなたへのおすすめ