ELYZAのggufをGPUで動かすまで

自分用メモです。

# 動機
ELYZA-japanese-Llama-2-13b-fast-instructをローカルで動かしたかった。

# 環境
Intel CPU
GTX3060
64GB RAM

# モデルダウンロード
## ファイルが1つなら
wget https://huggingface.co/mmnga/ELYZA-japanese-Llama-2-13b-fast-instruct-gguf/resolve/main/ELYZA-japanese-Llama-2-13b-fast-instruct-q4_K_M.gguf

## モデルが複数なら

``` download.py
    from huggingface_hub import snapshot_download

    model_name = "TheBloke/zephyr-7B-alpha-GPTQ" # モデル名
    download_path = snapshot_download(
    repo_id=model_name,
    local_dir=f"/models/{model_name}",
    local_dir_use_symlinks=False, 
)

print(download_path)
```

# Dockerimage
FROM nvidia/cuda:12.2.2-devel-ubuntu22.04

# llama-cpp-pythonインストール
CMAKE_ARGS="-DLLAMA_CUBLAS=on" pip install llama-cpp-python

# サンプル
```example.py
from llama_cpp import Llama

llm = Llama(
    model_path="/models/ELYZA-japanese-Llama-2-13b-fast-instruct-q8_0.gguf",
    n_ctx=2048,
# GPUを使うとき
# n_gpu_layers=30 # 多すぎるとOOM。以下のログの数値を参考に調整。
# llm_load_tensors: offloaded 0/41 layers to GPU
)
output = llm(
    # ゼロショット
    #   "Q: 太陽系の惑星の名前は? A: ",

    # クマベンチ
    #   "
 
あなたは誠実で優秀な日本人のアシスタントです。
クマが海辺に行ってアザラシと友達になり、最終的には家に帰るというプロットの短編小説を書いてください。 
",
    #       '''

    # oneショット回答生成
    #       

    #       
あなたは誠実で優秀な日本人のアシスタントです。
    #       以下の知識を元に回答してください。
    #       ------
    # 魔王を倒して王都に凱旋した勇者ヒンメル、僧侶ハイター、戦士アイゼン、魔法使いフリーレンら勇者パーティー4人は、10年間もの旅路を終えて感慨にふけっていたが、1000年は軽く生きる長命種のエルフであるフリーレンにとって、その旅はきわめて短いものであった。そして、50年に一度降るという「半世紀（エーラ）流星」を見た4人は、次回もそれを見る約束を交わしてパーティーを解散する。
    # 50年後、すっかり年老いたヒンメルと再会したフリーレンは、ハイターやアイゼンとも連れ立って再び流星群を観賞する。まもなくヒンメルは亡くなるが、彼の葬儀でフリーレンは自分がヒンメルについて何も知らず、知ろうともしなかったことに気付いて涙する。その悲しみに困惑したフリーレンは、人間を知るためと魔法収集のために旅に出る。
    # それから20年後、フリーレンは老い先短いハイターを訪ねる。ハイターは魔導書の解読と戦災孤児のフェルンを弟子にすることをフリーレンに依頼。その4年後、フリーレンは魔導書の解読を終え、フェルンは1人前の魔法使いとなる。ハイターの最期を看取った2人は諸国を巡る旅に出発する。
    # さらにその後、アイゼンの下を訪れたフリーレン達は、彼の協力によりフリーレンの師匠で伝説の大魔法使いフランメの手記を入手、死者の魂と対話できる場所・オレオールの存在を知る。その在処は大陸の北端エンデ。かつての魔王城の所在地だった。当ての無かった旅は、ヒンメルとの再会を目指す北への旅となる。そしてアイゼンの弟子シュタルクや僧侶ザインを仲間に加え、フリーレン達の旅は続く。
    #     

    #       フリーレンは何年以上生きるか
    #       
",
    #       ''',

    # 要約
    """
      

      
あなたは誠実で優秀な日本人のアシスタントです。
      以下の知識を元に回答してください。
      ------
魔王を倒して王都に凱旋した勇者ヒンメル、僧侶ハイター、戦士アイゼン、魔法使いフリーレンら勇者パーティー4人は、10年間もの旅路を終えて感慨にふけっていたが、1000年は軽く生きる長命種のエルフであるフリーレンにとって、その旅はきわめて短いものであった。そして、50年に一度降るという「半世紀（エーラ）流星」を見た4人は、次回もそれを見る約束を交わしてパーティーを解散する。
50年後、すっかり年老いたヒンメルと再会したフリーレンは、ハイターやアイゼンとも連れ立って再び流星群を観賞する。まもなくヒンメルは亡くなるが、彼の葬儀でフリーレンは自分がヒンメルについて何も知らず、知ろうともしなかったことに気付いて涙する。その悲しみに困惑したフリーレンは、人間を知るためと魔法収集のために旅に出る。
それから20年後、フリーレンは老い先短いハイターを訪ねる。ハイターは魔導書の解読と戦災孤児のフェルンを弟子にすることをフリーレンに依頼。その4年後、フリーレンは魔導書の解読を終え、フェルンは1人前の魔法使いとなる。ハイターの最期を看取った2人は諸国を巡る旅に出発する。
さらにその後、アイゼンの下を訪れたフリーレン達は、彼の協力によりフリーレンの師匠で伝説の大魔法使いフランメの手記を入手、死者の魂と対話できる場所・オレオールの存在を知る。その在処は大陸の北端エンデ。かつての魔王城の所在地だった。当ての無かった旅は、ヒンメルとの再会を目指す北への旅となる。そしてアイゼンの弟子シュタルクや僧侶ザインを仲間に加え、フリーレン達の旅は続く。      
    

      与えられた知識を100文字以内で要約してください 
      
",
      """,
    max_tokens=1024,  # 生成長
    #   stop=["Q:", "\n"], # ストップトークン
    echo=True,  # プロンプトを出力に含める
    temperature=0,
)
print(output)
```
# 実行結果
GPUありで6トークン/s程度。品質は良いと思う。
GPU RAMは11GB, RAMは16GB程度。
```
llama_print_timings:        load time =    3396.76 ms
llama_print_timings:      sample time =     138.23 ms /   266 runs   (    0.52 ms per token,  1924.33 tokens per second)
llama_print_timings: prompt eval time =    3396.42 ms /   466 tokens (    7.29 ms per token,   137.20 tokens per second)
llama_print_timings:        eval time =   44376.48 ms /   265 runs   (  167.46 ms per token,     5.97 tokens per second)
llama_print_timings:       total time =   48521.88 ms
{'id': 'cmpl-b366d6a3-5217-4f1c-935d-71b9eeb2762b', 'object': 'text_completion', 'created': 1703871460, 
'model': '/models/ELYZA-japanese-Llama-2-13b-fast-instruct-q8_0.gguf',
'choices': [{'text': '50年後、ヒンメルと再会した魔法使いフリーレ ンは、ハイターやアイゼンとも連れ立って流星群を観賞する。ヒンメルは亡くなるが、彼の葬儀でフリーレンは自分がヒンメルについて何も知らず、知ろうともしなかったことに気付いて涙する。フリーレンは人間を知るためと魔法収集のために旅に出る。\n20年後、フリーレンは老い先短いハイターを訪ねる。ハイターは魔導書の解読と戦災孤児のフェルンを弟子にすることをフリーレンに依頼。4 年後、フリーレンは魔導書の解読を終え、フェルンは1人前の魔法使いとなる。ハイターの最期を看取った2人は諸国を巡る旅に出発する。\nさらに後、アイゼンの下を訪れたフリーレン達は、彼の協力によりフリーレンの師匠で伝説の大魔法使いフランメの手記を入手し、死者の魂と対話できる場所・オレオールの存在を知る。その在処は大陸の北端エンデ。かつての魔王城の所在地だった。当ての無かった旅は、ヒンメルとの再会を目指す北への旅となる。そしてアイゼンの弟子シュタルクや僧侶ザインを仲間に加え、フリーレン達の旅は続く。', 'index': 0, 'logprobs': None, 'finish_reason': 'stop'}], 'usage': {'prompt_tokens': 466, 'completion_tokens': 265, 'total_tokens': 731}}
```

# プロンプトについて
- 100文字以内というと400くらい出す。25文字以内というと100文字くらいになる。トークン数で数えている？
- 以下は25文字以内での場合の例。生成速度は変化ないが、生成量に比例して処理時間は長くなる。
    - ヒンメルと再会したフリーレンは、ハイターや アイゼンとも連れ立って流星群を観賞する。ヒンメルは亡くなるが、彼の葬儀でフリーレンは自分がヒンメルについて何も知らず、知ろうともしなかったことに気付いて涙する。
- 50文字の例
    - ヒンメル、ハイター、アイゼン、魔法使いフリ ーレンらは勇者パーティーとして魔王を倒し、10年後の旅の末に再会を果たす。しかし、半世紀 (エーラ) 流星を見ようとしていた矢先、ヒンメルは亡くなる。フリーレンは人間を知るためと魔法収集のために旅に出る。その後、ハイターやフェルンを弟子にしたフリーレンは魔導書の解読を終え、アイゼンの協力によりフランメの手記を入手する。フリーレン達は北への旅を続ける。
    - かわいそうなヒンメル…流星見れなかったことにされてます。

# 参考

https://www.wasp.co.jp/blog/350

https://huggingface.co/mmnga/ELYZA-japanese-Llama-2-13b-fast-instruct-gguf

https://qiita.com/yagisawa/items/b212460d440e4b240fc3

https://github.com/abetlen/llama-cpp-python?tab=readme-ov-file

https://pypi.org/project/llama-cpp-python/

https://note.com/npaka/n/n9eda56d3a463

https://ja.wikipedia.org/wiki/%E8%91%AC%E9%80%81%E3%81%AE%E3%83%95%E3%83%AA%E3%83%BC%E3%83%AC%E3%83%B3