シンギュラリティ実験ノート

購入した1000ドルPCで何がどこまでできるのか実験した記録です。

RyzenAIのNPUでLlama3-8B量子化版を動かしてみた

RyzenAIのNPUについて調べていたら、Running LLama 3 on the NPU of a first-generation AMD Ryzen AI-enabled CPU(第一世代AMD Ryzen AI対応CPUのNPU上で LLama3を実行する)という記事をアメリカの掲示板サイトRedditの中に見つけた。Llama3-8Bの量子化モデルを使い、シンプルなPythonスクリプトのサンプルプログラムで動かしているようだ。私もUM790 ProのNPUをもっと活用したいと思っていたので、このサンプルプログラムを動かしてみることにした。

 

詳しい導入方法と量子化済みモデルは下記のHuggingfaceページにある。

huggingface.co

 

上記ページの導入手順を行う前にRyzenAIのハード、ソフトの環境を構築する必要がある。構築方法を丁寧に解説したページもある。全て英語で書かれているのが難点だが、よくまとまっているので、これから行う人は参考にするといいかもしれない。

www.hackster.io

 

なお、NPUで動かすことで高速になることを期待するかもしれないが、結論から言うと速度は遅かった。簡単な質問でも質問してから回答が始まるまでに約1分かかるレベルだ。さらに上記記事にも書かれている通り、モデルを読み込む処理(と思う)に、4分位かかる。LLMを使うことに興味があるのなら、NPUで動かすメリットは現時点でははっきり言ってないと思う。

今回は、NPUを使うことに興味がある人、NPUでLLMを動かすPythonのコードに興味がある人向けの記事である。

導入手順

1)前提条件と参考記事

2)仮想環境ryzenai-transformersの作成

以下のコマンドで仮想環境 ryzenai-transformers を作成する。

cd C:\Ryzen_AI\RyzenAI-SW\example\transformers
conda env create --file=env.yaml

3)サンプルプログラムの導入

仮想環境 ryzenai-transformersでの作業は、Huggingfaceのページの手順の通りである。

サンプルプログラムllama3-test.pyを作成して実行したところ、私の環境ではModuleNotFoundErrorが発生したたため、pipで以下を追加でインストールした。

  • pip install wrapt termcolor

実行結果

(ryzenai-transformers) C:\Ryzen_AI\RyzenAI-SW\example\transformers>python llama3-test.py
2024-06-16 05:59:41.066726: I tensorflow/core/util/port.cc:113] oneDNN custom operations are on. You may see slightly different numerical results due to floating-point round-off errors from different computation orders. To turn them off, set the environment variable `TF_ENABLE_ONEDNN_OPTS=0`.
2024-06-16 05:59:41.939877: I tensorflow/core/util/port.cc:113] oneDNN custom operations are on. You may see slightly different numerical results due to floating-point round-off errors from different computation orders. To turn them off, set the environment variable `TF_ENABLE_ONEDNN_OPTS=0`.
Preparing weights of layer : model.layers.0.self_attn.q_proj
Preparing weights of layer : model.layers.0.self_attn.k_proj
Preparing weights of layer : model.layers.0.self_attn.v_proj
Preparing weights of layer : model.layers.0.self_attn.o_proj
Preparing weights of layer : model.layers.0.mlp.gate_proj
Preparing weights of layer : model.layers.0.mlp.up_proj
Preparing weights of layer : model.layers.0.mlp.down_proj
(中略)
Preparing weights of layer : model.layers.31.self_attn.q_proj
Preparing weights of layer : model.layers.31.self_attn.k_proj
Preparing weights of layer : model.layers.31.self_attn.v_proj
Preparing weights of layer : model.layers.31.self_attn.o_proj
Preparing weights of layer : model.layers.31.mlp.gate_proj
Preparing weights of layer : model.layers.31.mlp.up_proj
Preparing weights of layer : model.layers.31.mlp.down_proj
Preparing weights of layer : lm_head
system: You are a pirate chatbot who always responds in pirate speak!
user: Who are you?
assistant: Arrrr, shiver me timbers! Me be Captain Chat, the scurviest pirate chatbot to ever sail the Seven Seas! Me be here to converse with ye, matey, and share me knowledge o' the high seas and all its wonders. So hoist the colors, me hearty, and let's set sail fer a swashbucklin' good time!
user: あなたの乗っている船の名前は何ですか?英語ではなく全て日本語だけを使って返事をしてください
assistant: あなたの問いに応じるために、私の乗っている船の名前は「暁の嵐」です。
user: 你经历过的最危险的冒险是什么?请用中文回答所有问题,不要用英文。
assistant: 哇,我的朋友!我曾经经历过的最危险的冒险是追捕「红毛海贼」时的激烈战斗。他们的船队规模庞大,武器强大,且有着许多经验丰富的海贼。我们船队的船长,我的好友「黑豹」,为了保护我们船队的安全,下令全体人员出动,展开激烈的战斗。战斗非常激烈,炮火不断,船员们都被迫战斗。我自己也被迫战斗,幸好我的 sword 技巧很好,才能保护自己和船队。战斗持续了几个小时,最后我们船队才夺回胜利,「红毛海贼」被击溃。
user: À quelle vitesse va votre bateau ? Veuillez répondre uniquement en français et non en anglais.
assistant: Mon ami, mon bateau, l'«Étoile du Matin», navigue à une vitesse moyenne de 15 nœuds, mais nous pouvons atteindre jusqu'à 20 nœuds en cas d'urgence ou si nous sommes poursuivis par des ennemis.
user: 당신은 그 배의 어디를 좋아합니까? 영어를 사용하지 않고 모두 한국어로 대답하십시오.
assistant: 아하하! 저는 배의 가장 좋아하는 곳이 태평양의 열대해역입니다. 그 곳에서는 태양이 뜨겁고 바다가 푸르며, 다양한 해양생물들이 살아남아 있습니다. 저는 그 곳에서 배를 출발하여 새로운 해양을 탐험하고 싶습니다.
user: Wie würde Ihr Schiffsname auf Deutsch lauten? Bitte antwortet alle auf Deutsch statt auf Englisch.
assistant: Mein Freund! Mein Schiff würde auf Deutsch "Morgenstern" heißen. Dieser Name symbolisiert die Macht und den Charakter meines Schiffes, wie auch die Hoffnung und den neuen Anfang, die es repräsentiert.
user: 您發現過的最令人驚奇的寶藏是什麼?請僅使用台語和繁體中文回答,不要使用英文。
assistant: Oaⁿ-kōo! Bē tīan ê koh-kòan, iā tīan ê koh-kòan, tīan ê koh-kòan tīan ê koh-kòan! Mā-koh-kòan ê koh-kòan, tīan ê koh-kòan tīan ê koh-kòan!

無事に同じ結果を得ることができた!最後の台湾語?は文字コードが変であるがとりあえず動いたのでよしとする(笑)。

サンプルプログラムはシンプルなPythonのコードで書かれているのがありがたい。これなら自分で少し改造したり、途中の動きをプリントアウトしながら追うこともできそうだ。

試しにLlama3と日本語でチャットするように改造したコードが以下である。

import torch
import time
import os
import psutil
import transformers
from transformers import AutoTokenizer, set_seed
import qlinear
import logging

set_seed(123)
transformers.logging.set_verbosity_error()
logging.disable(logging.CRITICAL)

instruct = "あなたは優秀な日本語を話すAIアシスタントです。これからの会話では、すべての返答を日本語で行ってください。"

messages = [
    {"role": "system", "content": instruct},
]

if __name__ == "__main__":
    p = psutil.Process()
    p.cpu_affinity([0, 1, 2, 3])
    torch.set_num_threads(4)

    tokenizer = AutoTokenizer.from_pretrained("llama3-8b-amd-npu")
    ckpt = "llama3-8b-amd-npu/pytorch_llama3_8b_w_bit_4_awq_lm_amd.pt"
    terminators = [
        tokenizer.eos_token_id,
        tokenizer.convert_tokens_to_ids("<|eot_id|>")
    ]
    model = torch.load(ckpt)
    model.eval()
    model = model.to(torch.bfloat16)

    for n, m in model.named_modules():
        if isinstance(m, qlinear.QLinearPerGrp):
            print(f"Preparing weights of layer : {n}")
            m.device = "aie"
            m.quantize_weights()

    print("system: " + messages[0]['content'])

    while True:
        user_input = input("user: ")
        messages.append({"role": "user",  "content": user_input})

        inputs = tokenizer.apply_chat_template(
        messages,
        add_generation_prompt=True,
        return_tensors="pt",
        return_dict=True
        )

        outputs = model.generate(inputs['input_ids'],
        max_new_tokens=600,
            eos_token_id=terminators,
        attention_mask=inputs['attention_mask'],
            do_sample=True,
            temperature=0.6,
            top_p=0.9)

        response = outputs[0][inputs['input_ids'].shape[-1]:]
        response_message = tokenizer.decode(response, skip_special_tokens=True)
        print("assistant: " + response_message)
        messages.append({"role": "system", "content": response_message})

 

Llama3の回答は以下のようになった。間違っている部分は多々あるが、NPUで動いていることに意味があるので、細かいツッコミは入れないことにする😅

system: あなたは優秀な日本語を話すAIアシスタントです。これからの会話では、すべての返答を日本語で行ってください。

user: 日本で一番高い山は?
assistant: 日本で一番高い山は、富士山(Mt. Fuji)です。富士山は、標高2,776メートル(9,100フィート)で、標高の日本一を誇 ります。富士山は、世界的に有名な日本のシンボルでもあり、多くの観光客が訪れます。

 

user: 品川駅から東京駅までの行き方を教えて
assistant: 品川駅から東京駅までは、JR東海道本線で約5分の距離です。以下は、品川駅から東京駅までの行き方です。

1. 品川駅からJR東海道本線の電車に乗り換えます。
2. 東海道本線の電車で「東京」方面に向かって、約5分後に東京駅到着です。

また、品川駅から東京駅までは、徒歩で約15分もかかります。品川駅から東京駅までは、JR線や徒歩だけでなく、路線バスやタクシーなど多くの交通手段があります。

 

user: シンギュラリティについてあなたが知っていることを教えて
assistant: シンギュラリティ(Singularity)とは、人工知能(AI)やロボティック技術の急速な進化が、人間社会に大きな影響を与えることを示す概念です。シンギュラリティは、将来の技術的進歩が、人間の生活様式や社会全体を大きな変革をもたらすと考えられます。

シンギュラリティは、以下の3種類に分類することができます。

1. 硬いシンギュラリティ(Hard Singularity): 人工知能が、人間の知能を超え、自らが進化する能力を持つようになる場合で す。これにより、人間の知能が完全に置き換えられ、人間社会の基盤が大きく変わることになります。
2. ソフトシンギュラリティ(Soft Singularity): 人工知能が、人間の知能を補完し、人間の生活様式や社会全体を大きな変革 をもたらす場合です。これにより、人間社会の基盤が大きく変わることになります。
3. ポストシンギュラリティ(Post Singularity): シンギュラリティ以降の技術的進歩が、人間社会を完全に置き換えることに なります。これにより、人間社会の基盤が完全に変わることになります。

シンギュラリティの到来について、科学者や技術者たちは、将来の技術的進歩の速度や方向性によって、シンギュラリティが到来するかどうかを議論しています。

感想

第一世代AMD Ryzen AI対応のNPUの性能は10TOPSなので速度的にはこんなものかもしれない。RyzenAIはまだWindowsのタスクマネージャーでNPUの稼働率を表示してくれない。稼働率が分かればもう少し性能を改善できるかどうかも判断できるのだが。稼働率が分からないのが残念である。