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

日本語LLM「ELYZA-japanese-Llama-2-7b」を試してみた

    Metaの「Llama 2」を基にELYZAが開発した日本語言語モデルを試用してみた

    はじめに

    ELYZA社が開発した、Metaの「Llama 2」を基盤とする商用利用可能な日本語言語モデル「ELYZA-japanese-Llama-2-7b」が新たにリリースされました。本記事では、この新モデルを試用し、その感想と具体的な使用例を紹介していきます。

    バックグラウンド

    「ELYZA-japanese-Llama-2-7b」は、日本語の理解と生成に特化した最新の言語モデルです。このモデルはELYZA, Inc.によって開発され、前のバージョンよりも精度と自然さが向上しているとされています。公開されているベンチマークによれば、日本語モデルの中でもトップクラスの性能を誇っています。そして、何よりも商用利用が可能である点が大きな魅力となっています。

    ベンチマークの結果と実際に使ってみた感じは必ずしも一致しないことが多いので、早速試してみました。

    モデルに関する詳細はモデルの公開記事をご覧ください。

    コード

    今回のテストでは軽くどのようなアウトプットが出てくるのかが知りたかったため、適当に作ったプロンプトを何パターンか試していきます。そもそも言語モデルが苦手とされるプロンプトが多いので、少し意地悪な質問ばかりでしたが、悪しからず。

    Colab での実行

    まずは必要なライブラリをインポート。

    !pip install -q transformers accelerate sentencepiece bitsandbytes

    Colab で素早い実行を行うために、モデルをロード時に量子化(Quantize)してしまいます。(これによってアウトプットの質が下がってしまう可能性もあるかもしれません。)量子化しなくても `torch_dtype=torch.float16` で Colab 上でも動くかもしれません。もし試された方いらっしゃったら教えてください。

    import torch
    from transformers import AutoTokenizer, AutoModelForCausalLM, BitsAndBytesConfig
    
    model_name = 'elyza/ELYZA-japanese-Llama-2-7b-instruct'
    
    # 量子化する際のパラメーター
    quantization_config = BitsAndBytesConfig(
        load_in_4bit=True,
        bnb_4bit_compute_dtype=torch.bfloat16
    )
    
    tokenizer = AutoTokenizer.from_pretrained(model_name)
    model = AutoModelForCausalLM.from_pretrained(
        model_name,
        device_map="auto",
        quantization_config=quantization_config,
    )

    トークナイザーのサイズを見てみます。

    tokenizer.vocab_size

    本モデルは `32000` との事でした。

    トレーニング時に使ったインプットパターンに極力従えるよう、モデルカードに書いてあったパターンを使って見ます。

    B_INST, E_INST = "[INST]", "[/INST]"
    B_SYS, E_SYS = "<<SYS>>\n", "\n<</SYS>>\n\n"
    DEFAULT_SYSTEM_PROMPT = "あなたは誠実で優秀な日本人のアシスタントです。"
    
    def build_prompt(text:str, system_prompt:str | None = None) -> str:
        system_prompt = system_prompt or DEFAULT_SYSTEM_PROMPT
        prompt = "{bos_token}{b_inst} {system}{prompt} {e_inst} ".format(
            bos_token=tokenizer.bos_token,
            b_inst=B_INST,
            system=f"{B_SYS}{system_prompt}{E_SYS}",
            prompt=text,
            e_inst=E_INST,
        )
        return prompt
    
    build_prompt("1 + 1 は何ですか?")
    <s>[INST] <<SYS>>
    あなたは誠実で優秀な日本人のアシスタントです。
    <</SYS>>
    
    1 + 1 は何ですか? [/INST]

    プロンプトのパターンは独特です(他のを知らないだけかも・・) Llamaのフォーマットでした。

    何パターンかインプットしてみて、アウトプットをみていきたいと思います。

    text = """
    りんごが5つあります。そこから2つのりんごを取り除きました。残りのりんごの数は何個でしょう?
    """.strip()
    inputs = tokenizer(build_prompt(text), add_special_tokens=False, return_tensors='pt')
    
    with torch.no_grad():
        output_ids = model.generate(
            inputs['input_ids'].to(model.device),
            max_new_tokens=100,
            do_sample=True,
            temperature=0.1,
            top_p=0.9,
            pad_token_id=tokenizer.pad_token_id,
            bos_token_id=tokenizer.bos_token_id,
            eos_token_id=tokenizer.eos_token_id,
            repetition_penalty=1.1,
        )
    
    output = tokenizer.decode(output_ids.tolist()[0])
    print(output)
    <s> [INST] <<SYS>>
    あなたは誠実で優秀な日本人のアシスタントです。
    <</SYS>>
    
    りんごが5つあります。そこから2つのりんごを取り除きました。残りのりんごの数は何個でしょう? [/INST]  りんごが5つあるところから、2つのりんごを取り除いた場合、残ったりんごの数は3つです。</s>

    引き算がちゃんとできました。(実はこれ、出来ないモデルも結構多いです。)

    次にバットとボールの問題。

    text = """
    バットとボールの両方を買うと1100円です。バットはボールよりも1000円高いです。ボールはいくらでしょう?
    """.strip()
    inputs = tokenizer(build_prompt(text), add_special_tokens=False, return_tensors='pt')
    
    with torch.no_grad():
        output_ids = model.generate(
            inputs['input_ids'].to(model.device),
            max_new_tokens=256,
            do_sample=True,
            temperature=0.1,
            top_p=0.9,
            pad_token_id=tokenizer.pad_token_id,
            bos_token_id=tokenizer.bos_token_id,
            eos_token_id=tokenizer.eos_token_id,
            repetition_penalty=1.1,
        )
    
    output = tokenizer.decode(output_ids.tolist()[0])
    print(output)
    <s> [INST] <<SYS>>
    あなたは誠実で優秀な日本人のアシスタントです。
    <</SYS>>
    
    バットとボールの両方を買うと1100円です。バットはボールよりも1000円高いです。ボールはいくらでしょう? [/INST]  バットがボールよりも1000円高いところから考えます。
    
    バットとボールの合計金額は、1100円 - 1000円 = 100円です。
    
    よって、ボールは1100円-100=1000円です。</s>

    こちら、引っ掛け問題なので解けなくてもいいんです。ただ、ステップを踏んで頑張ってました。答えは 50 円です。

    次に、これまた全くトレーニングされていないであろうタスクについて聞いてみます。

    text = """
    引数kを取り、返り値としてフィボナッチ数列におけるk個目の値を返すPython関数を書いてください。
    """.strip()
    inputs = tokenizer(build_prompt(text), add_special_tokens=False, return_tensors='pt')
    
    with torch.no_grad():
        output_ids = model.generate(
            inputs['input_ids'].to(model.device),
            max_new_tokens=256,
            do_sample=True,
            temperature=0.01,
            top_p=0.9,
            pad_token_id=tokenizer.pad_token_id,
            bos_token_id=tokenizer.bos_token_id,
            eos_token_id=tokenizer.eos_token_id,
            repetition_penalty=1.1,
        )
    
    output = tokenizer.decode(output_ids.tolist()[0], )
    print(output)
    <s> [INST] <<SYS>>
    あなたは誠実で優秀な日本人のアシスタントです。
    <</SYS>>
    
    引数kを取り、返り値としてフィボナッチ数列におけるk個目の値を返すPython関数を書いてください。 [/INST]  承知しました。フィボナッチ数列におけるk個目の値を求めるPython関数を以下に記述します:
    
    ```python
    def fib_k(k):
        if k == 0 or k == 1:
            return k
        else:
            return fib_k(k-1) + fib_k(k-2)
    ```</s>

    こちらは Llama 2 時代のトレーニング時に教師データにあったのかもしれませんね。覚えていたのかもしれません。

    次に翻訳を試してみました。

    text = """
    次の英語を日本語に翻訳してください。
    English: There were 3 apples and 2 oranges. How many fruits were there in total?
    """.strip()
    inputs = tokenizer(build_prompt(text), add_special_tokens=False, return_tensors='pt')
    
    with torch.no_grad():
        output_ids = model.generate(
            inputs['input_ids'].to(model.device),
            max_new_tokens=256,
            do_sample=True,
            temperature=0.1,
            top_p=0.9,
            pad_token_id=tokenizer.pad_token_id,
            bos_token_id=tokenizer.bos_token_id,
            eos_token_id=tokenizer.eos_token_id,
            repetition_penalty=1.1,
        )
    
    output = tokenizer.decode(output_ids.tolist()[0])
    print(output)
    <s> [INST] <<SYS>>
    あなたは誠実で優秀な日本人のアシスタントです。
    <</SYS>>
    
    次の英語を日本語に翻訳してください。
    English: There were 3 apples and 2 oranges. How many fruits were there in total? [/INST]  承知しました。翻訳は以下のようになります。
    
    日本語: 3つのリンゴと2つのレモンがあった。そのものすべての果物の数は、どれくらいですか?</s>

    若干日本語が不自然になりました。フルーツも変わりましたね。

    いかがでしたでしょうか?

    意地悪な質問ばかりでしたね・・・。

    ELYZA-japanese-Llama-2-7b-fast-instruct というモデルも試したのですが、少しだけアウトプットの質自体は低下していた印象でした。本記事でのご紹介は割愛しますが、試されたい方はぜひ下記のColabをご活用ください。

    今回使ったColabはこちらです。よかったらコピーしてお使いください。
    https://colab.research.google.com/drive/1anxzKtRH38BmpXQvmCC4TXXxVZU4xLt1?usp=sharing

    結論

    全体として、最近触った日本語モデルの中でもトップクラスの質だったのは間違いなしです。Elyza, Inc.の高い技術力が明らかに現れている素晴らしいモデルでした。今後 Llama 2 の 13b と 70b を日本語にトレーニングしたモデルも準備中とのことで、本当に目が話せません。

    感想

    • 試してきた日本語モデルの中でも最高クラスのアウトプット。

    • Instruct モデルも商用利用可でファインチューニングにも最適。

    • 4bit Quantize すれば Colab の T4 程度の GPU でも爆速。

    • チームの技術力が光るモデルでした

    以上、お読みいただきありがとうございます。少しでも参考になればと思います。

    もし今回の記事が楽しんでいただけたのであれば、noteとTwitter でフォローしていただけると嬉しいです。

    https://twitter.com/alexweberk

    Llama 2ベースの日本語モデルで商用利用可能ということで試すのが楽しみ。トークン数も日本語用に増やしてるとのこと。

    「ELYZA-japanese-Llama-2-7b」を公開しました|ELYZA, Inc. #note https://t.co/bsUiwrosa9

    — alex @ very GPU-poor🥹 (@alexweberk) August 29, 2023

    参考文献

    [1] モデルの公開記事

     
     
    AI / 機械学習 / LLM 関連で学んだ内容やニュースに関して共有していければ思います!

    あなたへのおすすめ