見出し画像

WSL2でLlama 3.1 SwallowをvLLMと共に試してみる

「Llama 3.1の英語の能力を維持しながら、日本語の能力を強化した大規模言語モデル (8B, 70B)」らしいLlama 3.1 Swallowを試してみます。

今回は8Bモデルを試してみます。

使用する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 vllm
cd $_
source bin/activate

つづいて、パッケージのインストール。

pip install -U vllm

vLLMのインストール時にtorchやら依存関係必要なものは勝手にインストールされます。

2. 流し込むコード

こちらを/path/to/query4vllm.pyとして保存します。

import sys
import argparse
from vllm import LLM, SamplingParams
from typing import List, Dict
import time

# argv
parser = argparse.ArgumentParser()
parser.add_argument("--model-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-model-len", type=int, default=32768)
parser.add_argument("--tensor-parallel-size", type=int, default=1)
parser.add_argument("--gpu-memory-utilization", type=float, default=0.2)
parser.add_argument("--max-tokens", type=int, default=4096)

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
max_new_tokens = args.max_tokens
tensor_parallel_size = args.tensor_parallel_size
max_model_len = args.max_model_len
gpu_memory_utilization = args.gpu_memory_utilization

# トークナイザーとモデルの準備
model = LLM(
    model=model_id,
    dtype="auto",
    trust_remote_code=True,
    tensor_parallel_size=tensor_parallel_size,
    max_model_len=max_model_len,
    #quantization="awq",
    gpu_memory_utilization=gpu_memory_utilization
)
tokenizer = model.get_tokenizer()

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

def q(
    user_query: str,
    history: List[Dict[str, str]]=None
) -> List[Dict[str, str]]:
    # generation params
    generation_params = SamplingParams(
        temperature=0.8,
        top_p=0.95,
        top_k=40,
        max_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,
    )
    print("--- prompt")
    print(prompt)
    print("--- output")
    # 推論
    outputs = model.generate(
        sampling_params=generation_params,
        prompt_token_ids=[input_ids],
    )
    print(outputs)
    output = outputs[0]
    print(output.outputs[0].text)
    if is_chat:
        user_messages.append(
            {"role": "assistant", "content": output.outputs[0].text}
        )
    else:
        user_messages += output.outputs[0].text
    end = time.process_time()
    ##
    input_tokens = len(output.prompt_token_ids)
    output_tokens = len(output.outputs[0].token_ids)
    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. 試してみる

(1) Llama-3.1-Swallow-8B-v0.1

8Bベースモデルに聞いてみます。

CUDA_VISIBLE_DEVICES=0 python -i /path/to/query4vllm.py \
    --model-path tokyotech-llm/Llama-3.1-Swallow-8B-v0.1 \
    --max-model-len 8192 \
    --gpu-memory-utilization 0.99 \
    --no-chat

pythonプロンプトが表示されたら、聞きましょう。

>>> history = q("ドラえもんとはなにか")
--- prompt
ドラえもんとはなにか
--- output
Processed prompts: 100%|████████████████| 1/1 [01:11<00:00, 71.73s/it, est. speed input: 0.11 toks/s, output: 52.76 toks/s]

? という問いに対し、藤子・F・不二雄は「ぼくが自分で考えたものです」と答える。ただ、物語としての『ドラえもん』をより楽しく読み解くためには、その成立背景や意図について知っておくとよいかもしれない。
たとえば、『大長編ドラえもん』シリーズなどから感じられる冒険活劇風味は、藤本先生の少年期における思い出に由来することが明らかになっている。また、「空想科学小説」というタイトルこそ冠されているものの、実際にはSF的ガジェットがさほど重要視されてはいないこともわかるだろう。これらの作品群を理解するうえでは必須ともいえる情報である。
それゆえ、本稿では、これまで公表されたエピソードを引用しながら、『ドラえもん』の創造過程を追っていきたいと思う。なお、各エピソードでの発言は、私たちにとっても新鮮で興味深い話ばかりだが、あまり多くの事柄を記憶しているわけではないので、この文章を書きながら調査した内容も含んでいることをご了承頂ければ幸いだ。
まずはじめに、私たちは誰しも、子供時代の夢――大人になったら何をしたいか? 何になりたいか? などの質問を受けた経験があるはずだ。例外なく私はそうだった。特に幼少期は、漫画家、宇宙飛行士といったあたりを考えていた気がする。藤本先生も同様であったようで、以下のように述べている。
私の子供の頃はまだ戦時中でしたんで、食料もないし、学校へ行けるのも月2回ぐらいで、それでも毎日朝から晩まで勉強してね。それでいつも頭の中にあるのは将来、何になりますかってことばっかりなんですね。何にも食べるものがないのに、そんなこと考えているくらいだから、変わり者でしょう(笑)。(※1)
ここからは、いかにして藤本先生が漫画家になることに決めたのかを紹介しよう。そのきっかけとなったのは、学童疎開(※2)の際に遭遇した一件であった。
そのとき、私は小学3年生でした。その前の年に引越しましたんで、なかなか友達がいなかったんですけど、一番仲良くなったのが近所の子と、おばさんの家に引き取られた男の子で、そこのおばさんは、私よりももっと好きになってくれる人なんですが、彼女もお医者さんだったんですね。しかし戦争中じゃなかったら、彼だけではなくて、私もしょっちゅう遊びに行っていたと思います。ところが戦時中に突然疎開が始まったんです。そして、皆川君(※3)は私のいた場所まで送られて来たんです。(…中略…)すると彼は私を呼ぶんです。「僕のお母さんが死んだ!」と言ったんです。急いで駆けつけて、まぁびっくりしました。おばさんの家は病院なんですね。そこでベッドの上にお母さんが寝ていました。その前には沢山のお花が飾られているんですが、顔を見たら、すごかったです! あんな顔を今まで見たことはありません。目玉が飛び出すんじゃないかと思うほどでした。(…中略…)そこでそのまま帰ろうとしたんですけども、どうしても嫌だったんですね。今考えると、お金があったらどこかの保育園とかに入れたのかもしれませんけど、当時の状況ではありませんでした。そうしたら先生方から「今度また疎開させますから、今度はこっちに預けろ」みたいなことを言われてしまって、途方に暮れるんです。すると近所のお姉ちゃんが「お兄ちゃんがいてくれるならいいよ」と言ってくれて、やっと安心したんです。こんなふうにして私はひとりぼっちで家に残されました。(…中略…)そして4年の夏休みから5年の春先まで、ひたすら絵ばかり描いているんです。しかも自分の住んでいた街とか、その周辺の土地ばかり描いていたんです。ほんとに病気のような状態でした。そのとき思ったのが、こういうことをずっと続けていたら、大人になった時に絵で生活できるんじゃないか、と。このころの思いが、現在につながっているような気がします。(※4)
その後、小学校高学年になると手塚治虫のアニメ映画『西遊記』(※5)を見る機会があり、マンガやアニメーションへの憧れを持ちはじめる。具体的にマンガ家になる意思を固めたのは、中学生に上がってからのことだ。
中学一年生になってすぐの夏休みに、初めてペンネームをつけました。当時はまだフジオプロなんて名前もあるはずがありませんし、サインもしていませんでしたからね。最初に買った紙袋もその名残りです。本当のところ、私はマンガを描いていない間にちょっと苦労しています。いや、正確には本当に苦労していたんです。もうね、生きるか死ぬかみたいな(笑)。親父とおふくろは二人とも内職みたいなのをやってたんですが、向こうから逃げちゃったんです。だから、もう頼むところはないし、どこへ行ったらいいか分からないという状況でした。結局、高校三年間をアルバイトでしのぎました。(…中略…)大学は行けないと思ってましたし、行っても仕方ないなと思っ てました。それで何か商売をしようと思ったんです。でも私は田舎出身なんですね。あちらこちらで聞かされるのは「マンガ屋になれ」「マンガ家になれ」ばっかりで、そうなれば家族も喜ぶだろうし、自分自身が好きな仕事に就けるし…となると、漫画家以外は選択肢にありませんでした。そこで中学卒業と同時に、会社勤めをするために上京したんです。ちょうど東京都美術館で講習会をやるというので、石ノ森章太郎のアシスタントを募集していると聞いたからです。しかし参加した人は2000人以上いて、そのうち採用されたのはわずかに6人。私は最終選考に残った15人の一人だけでした。どうなることやら、と不安で胸がいっぱいだったことを覚えています。そこで色々試させてもらって、最後に石ノ森さんに「マンガ家に転進します」と伝えたんです。そのとき「それもいいんじゃない?」と言ってもらえました。結果的に私は漫画家という方向性に進んだわけですが、それはあのとき、チャンスを与えてくれた石ノ森さんのお陰なんだと思います。(※6)
藤本先生が描いた原案でデビュー作となる予定だったのは、『鉄人28号』のパロディである「ウルトラウーマン」(※7)。しかし、雑誌の連載企画において、アニメ制作とのタイアップという条件付きのオファーであったことで、後に失敗を招いてしまうことになる。
先生の漫画を読んでいない人が多いせいか、『鉄腕アトム』のアニメ化に関してはよく誤解されています。テレビ番組のスポンサーが欲しいから作られたように思われがちですが、そうではありません。元々は、手塚先生が東京新聞の社員だった昭和32年に、全国放送を視野に入れたテレビ漫画の製作委員会を作り、その第1弾として『鉄腕アトム』を作ったんです。つまり、まず手塚先生の意志により、放映権や原作権の一部を放棄してまで広告代理店が関われる形態にしたというわけです。それと共に、スポンサーを探し出したり、著作者の版権管理を行ったりする日本動画株式会社(ニッポンの動画)という企業も設立されました。私はその会社の社員兼アシスタントとし て働いていたんですが、週刊少年マガジンで漫画を連載するという話が出てきたんです。しかも、自分でネーム(下書き)を切らせてくれという話に。普通、出版社の担当編集者の言う通りに描くんじゃないですか。だけど、編集側は漫画家をコピー機扱いにするから、断ることもできなければ文句も言いづらく、ストレスが溜まるばかりでした。そこで独立すれば自由に活動できるし、収入だって増えるだろうと考えたんです。けれど、会社に所属していなかったら、他の人を雇えないじゃないですか。漫画の出版を依頼する場合、契約する前に原稿料の支払い方法を確認するのが常識です。出版社は前払い方式をとりますが、広告主であれば、CMの放映率によって報酬が変わ るというケースが一般的なのです。もしその条件が許容できないと判断したなら、即座に手を引かない限り、損害賠償請求や損益補填を要求される可能性があります。私は以前、別の出版社から無理難題を吹っ掛けられていたのですが、石ノ森先生の紹介で、新たな契約相手に出会えたのです。私は漫画家として、全く未経験なまま契約締結に向かっていました。当然の成り行きだと受け止められていたようです。ところが、その頃は日本動画株式会社の財務基盤が脆弱で、倒産の危機に瀕していたらしいんです。そういう事情も絡み合って、なぜか契約直後の翌日に、日本動画株式会社の代表取締役は辞任届を出しました。一体何があったのか全く分からず、とても悔しかった です。私は完全に騙されたわけですが、その場を取り繕うために、手塚先生に相談して、手塚プロダクションの一室をお借りすることにしました。そうでもしない限り、他の出版社と契約を交わせなくなっていたからです。手塚先生のご厚意で、部屋は無料提供されました。けれど、手塚先生の関係者に迷惑をかけていたとはいえ、私も同じ穴の狢(むじな)だったわけですし、非常に負い目を感じました。結論から申し上げますと、その後、私の漫画は一度も掲載されることなく終わってしまったのです。(※8)
藤本先生は、この失敗から教訓を得て、次に起用された『怪獣ブースカ』(※9)でも自らのアイディアを盛り込むなど、積極的に制作に参加することになる。そうした協力姿勢に応じる形で、原作のクレジットには、石ノ森先生の名前のみが表示されたのである。
さらに、1963(昭和38)年10月に発表された単独の原作作品「海底ハイキング」の存在も忘れてはならない。本作は、『天才バカボン』以降の短編ギャグマンガに見られる、「道具を使って人間の願望を叶えようとする」スタイルを既に示唆しており、後に「スモールライト」をはじめとする数多くの「秘密道具」を登場させるきっかけとなったのだ。
私はこの頃から、「未来の世界を舞台にしたドリトル博士の物語」という構想を持っていたのですが、ドリトル博士を主人公に据えたのは、私が20代半ばの頃でした。最初に書いたのは、単純に「タイムマシン」ものだったんです。時間旅行を可能にする秘密兵器を作りあげた人物を中心に展開する物語です。要するに、今回のドラえもんとの出会いのように、未来から現代に来るという設定です。けれど、よく考えてみるとこれじゃ、古典的なタイム・トリップものと変わらないじゃないですか。他の要素を組み合わせれば面白くなるだろうなと考えました。でも、私は歴史小説には詳しくないし、偉人の伝記や逸話なども知らず、架空のキャラクターを作るにも困難を極めま した。すると「それは良いアイディアだな」と褒めてくださったのが、当時一緒に仕事をしていた横山光輝先生でした。それで早速、新宿にあった喫茶店で打ち合わせをしたんですが、私はそれまで横山先生の『伊賀の影丸』しか読んだことがなくて、他の作品については殆ど知らなかったんです。だけど先生はとても優秀な方で、細かい説明をしなくても、すべてご存知でした。私は何も教えなくても、黙って聞いているだけでOKなんですね。(…中略…)で、先生は私の提案に同意してくださいました。それはとてもありがたく、嬉しかったです。先生からアイディアを授けていただいて、「これは使わせていただきます」と返事をしたら、先生は「ああ、良いですよ」と笑顔でおっしゃいました。あの瞬間のことを、今でもよく覚えております。ただ、横山先生が私に伝えてくださった言葉は「未来を舞台にした、地球征服物語」。つまり、昔のヒーローのようなイメージで、地球侵略軍と対峙するという設定だったんです。しかし私は「地球征服」なんて絶対にイヤですし、そもそも私は悪党っぽいタイプの方が好きじゃないんですよね。だから、私の思うところとは大きく異なっていました。そこで「悪の敵組織VS善良な主人公たちの物語」ではなくて、「奇妙な奴等が集団で行動する」というコンセプトに変更したんです。すると横山先生は「そういうのは僕が得意とするところだよ」と仰ってくれました。横山先生は『魔法使いサリー』(※11)を執筆した直後だったので、「ハチャメチャな連中が集まって何かをする」というアイディアを気に入ってくださったようです。(※12)
1970(昭和45)年3月16日発売の「ぼく、マリオネット」「黒騎士の物語」の2作品が、『テヅカくん』(※13)に寄稿された中短篇作品の最後となった。残念ながら両者とも人気を獲得するに至らなかったが、この経験が後の『ドラえもん』誕生に直接影響を及ぼしたことは疑いようがない。なぜなら、1970年4月27日の投稿原稿から、藤本先生は長期連載路線へと切り替え、『ドラえもん』という新たなステージへと駒を進めたからである。
「藤子不二雄ランド ドラえもん 名作選III」(中央公論新社,1998/07)p.40
「藤子・F・不二雄大全集 テヅカくん」(小学館,2011/02)p.119
「藤子・F・不二雄大全集 スーパー・テヅカくん」(小学館,2012/08)p.127
「藤子・F・不二雄大全集 ミノタウロスの皿」(小学館,2007/04)p.17-19
「藤子・F・不二雄大全集 タイムマシンにお願い!」(小学館,2010/05)p.14
「藤子・F・不二雄大全集 ザ・ドラえもんズスペシャル2」(小学館,2008/03)p.44-50
「藤子・F・不二雄大全集 少年 SF 短編集 3」(小学館,2010/09)p.30-35
「藤子・F・不二雄大全集 ポコニャン」(小学館,2009/06)p.34
「藤子・F・不二雄大全集 ウメ星デンカ」(小学館,2008/01)p.26
「藤子・F・不二雄大全集 新オバケのQ太郎 4」(小学館,2012/05)p.36
「藤子・F・不二雄大全集 大長編ドラえもん 15」(小学館,2011/01)p.21-22
「藤子・F・不二雄大全集 ドラえもん 43」(小学館,2011/04)p.84-85
「藤子・F・不二雄大全集 21エモン」(小学館,2009/12)p.25
「藤子・F・不二雄大全集 エスパー魔美 6」(小学館,2010/01)p.104
「藤子・F・不二雄大全集 小平博士とドラえもん」(小学館,2012/01)p.37-42

Llama 3.1 Swallow 8B より
prompt tokens = 8
output tokens = 3784 (52.589512 [tps])
   total time = 71.953510 [s]

想定していなかったまさかの長文出力。ツッコミどころが満載ではありますが、そういう読み物だとしたらよいんじゃないでしょうか。

(2) Llama-3.1-Swallow-8B-Instruct-v0.1

8B指示チューニングモデルに聞いてみます。

CUDA_VISIBLE_DEVICES=0 python -i /path/to/query4vllm.py \
    --model-path tokyotech-llm/Llama-3.1-Swallow-8B-Instruct-v0.1 \
    --max-model-len 8192 \
    --gpu-memory-utilization 0.99

pythonプロンプトが表示されたら、聞きましょう。

>>> history = q("ドラえもんとはなにか")
--- prompt
<|begin_of_text|><|start_header_id|>system<|end_header_id|>

あなたは誠実で優秀な日本人のアシスタントです。<|eot_id|><|start_header_id|>user<|end_header_id|>

ドラえもんとはなにか<|eot_id|><|start_header_id|>assistant<|end_header_id|>


--- output
Processed prompts: 100%|████████████████| 1/1 [00:04<00:00,  4.35s/it, est. speed input: 9.20 toks/s, output: 49.47 toks/s]

ドラえもんとは、藤子・F・不二雄による漫画作品、およびその主人公の名前です。

ドラえもんは、22世紀から現代にやって来たネコ型ロボットで、のび太という少年と一緒にさまざまな冒険を繰り広げます。ドラえもんは、いつでもどこでも「四次元ポケット」から様々な道具を取り出して、のび太を助けたり困難を解決したりします。

ドラえもんは、1980年代にテレビアニメ化され、日本国内外で大ヒットしました。現在も世界中で愛されており、多くの国で翻訳版が出版されています。また、映画やゲームなども制作されています。

ドラえもんの特徴的な台詞は、「なんでもできるぞ!」「はいっ!」(「はいっ!」は、英語では「Yes, yes!」と表記されることが多い)です。

Llama 3.1 Swallow 8B Instructより

「なんでもできる」は言い換えると「なんにもできない」という意味ですから、はい…。

prompt tokens = 40
output tokens = 215 (49.413776 [tps])
   total time = 4.351013 [s]

2024/10/13追記

よく見ると、

`rope_scaling`'s original_max_position_embeddings field must be less than max_position_embeddings, got 8192 and max_position_embeddings=8192

というエラーが出力されている。config.json を見ると、確かにmax_position_embeddingsとoriginal_max_position_embeddingsが同じで、max_position_embeddings > original_max_position_embeddingsとはなってない。

  "max_position_embeddings": 8192,
(snip)
  "rope_scaling": {
    "factor": 8.0,
    "high_freq_factor": 4.0,
    "low_freq_factor": 1.0,
    "original_max_position_embeddings": 8192,
    "rope_type": "llama3"
  },

ちなみに、Llama 3.1のconfig.json は 131,072 > 8,192 となっている。

  "max_position_embeddings": 131072,
(snip)
  "rope_scaling": {
    "factor": 8.0,
    "low_freq_factor": 1.0,
    "high_freq_factor": 4.0,
    "original_max_position_embeddings": 8192,
    "rope_type": "llama3"
  },

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