Sakana.AIのTinySwallow-1.5Bをローカルで動かしたい

1月末にSakana.AIがTinySwallow-1.5Bという小規模日本語言語モデルを発表しました。ちょうど山梨県は甲府の企業で生成AI研修をやっている最中のことで、受講者の皆さんがワークをやっている間にWebブラウザ上で動作するチャットアプリをちょっと手元で試して、ご紹介したということがありました。

それまでGPT-4oとかをご紹介していたので、生成される内容自体は大したことないというか、ハルシネーションが盛大に含まれる様子はちょっと失笑といった感じだったのですが、それがクラウドで動作しているわけではなく、ブラウザ上だけでが動いているのだと説明したときに、驚きに変わったことを覚えています。

何より自分自身が感動していたのです。それまで、Let’s noteに外付けGPU Box(GeForce RTX3070)をつないで、LM Studioで言語生成して、あまりの生成速度の遅さに辟易した経験があるのです。それが、CPUだけで(しかもブラウザ上で)現実的といえる速度で日本語が生成されている。

小規模言語モデルゆえに知識が少ないから、ハルシネーションは起きるのですが、日本語としては破綻していない。ということは、RAGで知識を入れつつ回答を生成させれば、充分に使えるのではないか。これが衝撃だったのです。

TinySwallow-1.5Bをローカルで動かしたい

というわけで、この記事の本題なのですが、ローカルで動かしたいのです。いくつかの方法を試してみました。

環境構築

Python 3.11は動作しているものとして、仮想環境を作成し、CPUだけの環境で動作させるための環境構築を行います。

まず、PyTorchのCPU版をインストールします。

pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cpu

さらに、Transformersを導入します。

pip install transformers

HuggingFaceからモデルをダウンロードして生成する

まず、試してみたのがこんなコードです。きちんと動作します。
最初はHuggigFaceからモデルをダウンロードするので時間がかかりますが、ダウンロードしたモデルはキャッシュするようにしているので、2回目以降はそれほど遅くありません。

from transformers import AutoModelForCausalLM, AutoTokenizer

model_name = 'SakanaAI/TinySwallow-1.5B'
tokenizer = AutoTokenizer.from_pretrained(model_name, cache_dir='./cache')
model = AutoModelForCausalLM.from_pretrained(model_name, cache_dir='./cache')

input_text = 'こんにちは。'
inputs = tokenizer(input_text, return_tensors='pt')

outputs = model.generate(inputs['input_ids'], max_length=50, num_return_sequences=1)

generated_text = tokenizer.decode(outputs[0], skip_special_tokens=True)
print(generated_text)

26秒ほどかかって、このような文章が生成されました。急にSEOやアフィリエイトの話が始まりました。微妙・・・。

こんにちは。こんにちは。
今回は、アフィリエイトで稼ぐために欠かせない「SEO」について解説していきます。
アフィリエイトの基本知識については以下の記事を参考にしてくださいね。
Contents

Instructモデルを使う

このような言語生成で使用するには、Instructモデルの方が良いので、それもやってみます。質問文はuserロールのメッセージとしてセットします。

from transformers import AutoModelForCausalLM, AutoTokenizer

model_name = 'SakanaAI/TinySwallow-1.5B-Instruct'
tokenizer = AutoTokenizer.from_pretrained(model_name, cache_dir='./cache')
model = AutoModelForCausalLM.from_pretrained(model_name, cache_dir='./cache')
model.to('cpu')

text = '北九州市はどんなところ?'
messages = [{'role': 'user', 'content': text}]
input_ids = tokenizer.apply_chat_template(messages, add_generation_prompt=True, return_tensors='pt')

output_ids = model.generate(input_ids.to('cpu'), max_new_tokens=1024)

output_ids = output_ids[:, input_ids.shape[1]:]
generated_text = tokenizer.batch_decode(output_ids, skip_special_tokens=True)[0]
print(generated_text)

生成には1分54秒もかかってしまいましたが、文章としてはなかなかです。ただ、ハルシネーションはあり、橋本花火大会とか大門通商店街など、謎なキーワードが登場しています。ここはRAGでどうにかしてやりたいところです。

北九州市は福岡県の北部に位置する都市で、歴史と近代的な要素を併せ持つ魅力的な場所です。

**特徴:**

* **産業:** 北九州港を中心に製鉄や化学工業など、重工業が盛んです。
* **観光:** 橋本花火大会や小倉城などの伝統的な文化遺産だけでなく、新幹線「博多駅」からもアクセスしやすいことから、現代的なイベントや施設も多くあります。
* **食事:** 豊富な海の幸を利用した料理や、地元食材を使った創作料理などが楽しめます。特に、「水炊き」という鍋料理は有名です。
* **交通:** 新幹線、在来線、高速バスなど様々な交通手段があり、福岡市内へのアクセスが便利です。

**見どころ:**
- **北九州市立美術館:** 近代美術や工芸品などを展示しています。
- **小倉城:** 16世紀に築かれた天守閣が現存しており、国の重要文化財に指定されています。
- **大門通商店街:** 昔ながらの雰囲気を感じられる商店街です。
- **六連島公園:** 海辺の散策路や遊歩道があり、美しい景色を楽しみながらリラックスできます。

**その他:**
- 都市部にはショッピングセンターや飲食店が多く集まっています。
- 子育て支援にも力を入れており、子供向けの施設やサービスもあります。

以上のように、北九州市は自然豊かな環境と活気に満ちた都市であり、多くの魅力を持った場所と言えます。

llama.cppを使ってみる

生成精度はひとまず良いとして、生成時間をもっと短縮したいところです。TinySwallow-1.5BではGGUFバージョンも提供されています。GGUFは量子化に対応した軽量化と高速化を目的に最適化されたモデルフォーマットであり、llama.cppやggmlベースのエンジンで使用することができます。

llama-cpp-pythonの導入

llama.cppはその名のとおりC++で実装されていますが、そのPythonバインディングが提供されており、pipで導入できるパッケージもあるので、それで導入します。

pip install llama-cpp-python

GGUFファイルのダウンロード

こちらのサイトからGGUFファイルをダウンロードできます。

Q8とQ5の2つのバージョンが提供されています。Q8の方がより正確ですがやや遅く、Q5はQ8より精度が落ちますがより速く動作します。

今回は、tinyswallow-1.5b-instruct-q5_k_m.ggufをダウンロードしました。1.1GBほどあります。

llama-cpp-pythonで言語生成

このようなプログラムで言語生成できます。

from llama_cpp import Llama

llm = Llama(
    model_path='./tinyswallow-1.5b-instruct-q5_k_m.gguf',
)

output = llm('USER: 北九州はどんなところ?100文字以内で回答してください。 ASSISTANT: ', max_tokens=100)
print(output['choices'][0]['text'])

100文字以内という指示をしているため10秒程度で、このような文章が生成されました。佐賀県とは隣接していません・・・。

九州の北端に位置し、福岡県、佐賀県と隣接しています。また、周辺地域との交通の便が良く、歴史的な観光スポットや自然豊かな場所もあります。

langchainで使ってみる

llama-cpp-pythonで動けば、langchainでも使用できます。

pip install langchain langchain-community

langchainで動くとなれば、テンプレートも使用できますし、RAGでもAIエージェントでもチャットでも使えるので、これが一番実用的ですね。。

from langchain_core.prompts import ChatPromptTemplate
from langchain_community.chat_models.llamacpp import ChatLlamaCpp

model = ChatLlamaCpp(
    model_path='./tinyswallow-1.5b-instruct-q5_k_m.gguf',
)

prompt = ChatPromptTemplate.from_messages([
    ('system', 'あなたは冗談を言うプロです。200文字程度で日本の文化をよく知っていて軽妙なジョークを言うことができます。'),
    ('user', '{place}の{season}をテーマに、何か冗談を言ってください。')
])

chain = prompt | model

chain.invoke({'place': '北九州', 'season': '夏'})

46秒ほどで、このようなAIMessageのレスポンスが返ってきました。ちょっと遅いかなぁ。

AIMessage(content='北九州の夏と言えば、熱気と湿気が交わる季節ですよね。\n\nそんな暑い日には「冷やし中華」を食べるのが一番!\n\nでもちょっと待って! 「冷やし中華」という言葉は、実は中国では使われないんです。\n\nもしかしたら、「冷やしうどん」や「冷やしつけめ」の方が正しいのかもしれませんね。 \n\n\n\n', additional_kwargs={}, response_metadata={'finish_reason': 'stop'}, id='run-0e975e50-0384-4500-90be-9307241614dc-0')

ということで、これでもCPUだけでここまで動くというのは立派です。今後、活用方法を探っていきたいと思っています。

この記事を書いた人

井上 研一

株式会社ビビンコ代表取締役、ITエンジニア/経済産業省推進資格ITコーディネータ。AIに強いITコーディネータとして活動。2018年、株式会社ビビンコを北九州市に創業。生成AIを業務に組み込むためのサービス「Gen2Go」を開発し、北九州発!新商品創出事業の認定を受ける。近著に「使ってわかった AWSのAI」、「ワトソンで体感する人工知能」。日本全国でセミナー・研修講師としての登壇も多数。