見出し画像

WSL2でEZO-Common-T2-2B-gemma-2-itを試してみる

「Gemma-2-2B-itをベースとして、複数のチューニング手法を採用のうえ、汎用的に性能を向上させたモデルです。日本語タスクに優れつつ、世界中の多様なニーズに応える設計となってい」るらしいEZO-Common-T2-2B-gemma-2-itを試してみます。

使用するPCはドスパラさんの「GALLERIA UL9C-R49」。スペックは
・CPU: Intel® Core™ i9-13900HX Processor
・Mem: 64 GB
・GPU: NVIDIA® GeForce RTX™ 4090 Laptop GPU(16GB)
・GPU: NVIDIA® GeForce RTX™ 4090 (24GB)
・OS: Ubuntu22.04 on WSL2(Windows 11)
です。


1. 準備

蝦夷。

python3 -m venv ezo
cd $_
source bin/activate

パッケージのインストール。local-gemmaを使って試します。

pip install local-gemma"[cuda]"

local-gemmaの記事はこちら。

2. 流し込むコード

以下の内容を/path/to/query4local-gemma.pyとして保存します。

import sys
import argparse
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer, TextStreamer
from local_gemma import LocalGemma2ForCausalLM
from typing import List, Dict
import time

# argv
parser = argparse.ArgumentParser()
parser.add_argument("--model-path", type=str, default=None)
parser.add_argument("--tokenizer-path", type=str, default=None)
parser.add_argument("--no-chat", action='store_true')
#parser.add_argument("--no-use-system-prompt", action='store_true')
parser.add_argument("--max-tokens", type=int, default=256)
parser.add_argument("--preset", type=str, default="auto")

args = parser.parse_args(sys.argv[1:])

model_id = args.model_path
if model_id == None:
    exit

is_chat = not args.no_chat
#use_system_prompt = not args.no_use_system_prompt
use_system_prompt = False
max_new_tokens = args.max_tokens
preset = args.preset

tokenizer_id = model_id
if args.tokenizer_path:
    tokenizer_id = args.tokenizer_path

# トークナイザーとモデルの準備
tokenizer = AutoTokenizer.from_pretrained(
    tokenizer_id,
    #trust_remote_code=True
)
model = LocalGemma2ForCausalLM.from_pretrained(
    model_id,
    #torch_dtype="auto",
    torch_dtype=torch.bfloat16,
    #device_map="cuda",
    device_map="auto",
    low_cpu_mem_usage=True,
    #trust_remote_code=True,
    preset=preset
)
#if torch.cuda.is_available():
#    model = model.to("cuda")

streamer = TextStreamer(
    tokenizer,
    skip_prompt=True,
    skip_special_tokens=True
)

DEFAULT_SYSTEM_PROMPT = "あなたは誠実で優秀な日本人のアシスタントです。"


def q(
    user_query: str,
    history: List[Dict[str, str]]=None
) -> List[Dict[str, str]]:
    # generation params
    generation_params = {
        "do_sample": True,
        "temperature": 0.8,
        "top_p": 0.95,
        "top_k": 40,
        "max_new_tokens": max_new_tokens,
        "repetition_penalty": 1.1,
    }
    #
    start = time.process_time()
    # messages
    messages = ""
    if is_chat:
        messages = []
        if use_system_prompt:
            messages = [
                {"role": "system", "content": DEFAULT_SYSTEM_PROMPT},
            ]
        user_messages = [
            {"role": "user", "content": user_query}
        ]
    else:
        user_messages = user_query
    if history:
        user_messages = history + user_messages
    messages += user_messages
    # generation prompts
    if is_chat:
        prompt = tokenizer.apply_chat_template(
            conversation=messages,
            add_generation_prompt=True,
            tokenize=False
        )
    else:
        prompt = messages
    input_ids = tokenizer.encode(
        prompt,
        add_special_tokens=True,
        return_tensors="pt"
    )
    print("--- prompt")
    print(prompt)
    print("--- output")
    # 推論
    output_ids = model.generate(
        input_ids.to(model.device),
        streamer=streamer,
        **generation_params
    )
    output = tokenizer.decode(
        output_ids[0][input_ids.size(1) :],
        skip_special_tokens=True
    )
    if is_chat:
        user_messages.append(
            {"role": "assistant", "content": output}
        )
    else:
        user_messages += output
    end = time.process_time()
    ##
    input_tokens = len(input_ids[0])
    output_tokens = len(output_ids[0][input_ids.size(1) :])
    total_time = end - start
    tps = output_tokens / total_time
    print(f"prompt tokens = {input_tokens:.7g}")
    print(f"output tokens = {output_tokens:.7g} ({tps:f} [tps])")
    print(f"   total time = {total_time:f} [s]")
    return user_messages

3. 試してみる

モデルEZO-Common-T2-2B-gemma-2-itを指定して、実行します。

CUDA_VISIBLE_DEVICES=0 python -i ~/scripts/query4local-gemma.py --model-path HODACHI/EZO-Common-T2-2B-gemma-2-it --preset memory_extreme

聞いてみます。

>>> history = q("ドラえもんとはなにか")
--- prompt
<bos><start_of_turn>user
ドラえもんとはなにか<end_of_turn>
<start_of_turn>model

--- output
ドラえもんは、日本の漫画・アニメ作品「ドラえもん」の主人公です。

彼は**「道具を持った、未来のキャラクター」**として知られています。

具体的に以下のような特徴があります。

* **作者:**  藤子・F säker (藤子プロダクション) の代表的なキャラクター
* **能力:**  様々な道具を使って問題解決や冒険を助けることができる。
* **性格:**  明るく、好奇心旺盛で、時には無邪気な子供のような一面も持ち合わせている。
* **Appearances:**  漫画、アニメ、映画など、幅広いメディアで登場
* **代表的な道具:**  「タイムマシン」「バリア・パーフェクト」など
* **社会的な役割:**  子供たちにとっての憧憬の対象であり、未来への希望や可能性を象徴する存在


ドラえもんは、長年にわたり多くの人々に愛されてきました。彼の魅力は、道具の多様性、明るい性格、そして未来への探求心を兼ね備えたキャラクターとして受け止められています。
prompt tokens = 15
output tokens = 220 (23.160321 [tps])
   total time = 9.499005 [s]
>>>

ドラえもんは、藤子・F・不二雄先生が考案した、日本の漫画およびアニメ作品に登場する架空のロボットキャラクターです。

**正式名称は「Doraemon」**(ドーラモン)で、**未来からやってきたロボット猫**として知られています。

主な特徴は以下のとおりです:

* **タイムマシン搭載**: ドラえもんは、タイムマシンを背中に装備しており、過去や未来へ簡単に移動することが可能です。
* **道具庫**: 腕の中に収納された様々な道具を用いて、現代社会の様々な問題を解決します。
* **優しい性格**: いつもポジティブで、子供たちを助け、時にはユーモラスな言動で、笑いを誘います。
* **愛想の良さ**: 親しみやすく、友達のような存在感を持ち合わせており、多くのファンに愛されています。

ドラえもんは単なるキャラクターではなく、**日本の文化や価値観を反映した象徴的な存在**として、世代を超えて愛され続けています。

以下に具体的な例を挙げることで、より深く理解できると思います:

* **教育**: ドラえもんの道具を通して、未来への期待や、問題解決能力を学ぶ機会を提供しています。
* **社会現象**: ドラえもんの登場により、子供たちが科学技術や倫理観に目を向けるきっかけを与え、社会的な変化を促す役割を果たしたとされています。
* **エンターテイメント**: ドラえもんのコミカルなキャラクター性や、ストーリー性の高さから、世代を超えた人気を誇ります。


また、「ドラえもん」は、単独のキャラクターだけでなく、**長年にわたって展開される様々なメディア作品** (漫画、アニメ、映画、ゲームなど) で、その世界観がさらに深まっています。

HODACHI/EZO-Common-T2-2B-gemma-2-it

「藤子・F・不二雄先生」と敬称ありなのでいいですね。
「ドーラモン」が正式名称らしく、背中にタイムマシンを装備しているらしく。なるほど。

4. パフォーマンスなど

VRAM

--preset memory_extremeでモデルをロードすると、2.8GBほどしかVRAM使いません。

local-gemma & --preset memory_extreme

ふつうにtransformersでロードした際は、5.6GBなので、半分ほどですね。

transformers

推論速度

local-gemmaでもtransformersでも、22 ~ 23 トークン/秒でございました。

参考

この記事が気に入ったらサポートをしてみませんか?