.NET(C#) コンソールアプリで、Phi-3 を実行する

2024/06/02
★★★

Phi-3 ラインナップ

Phi-3 は、Microsoft Research が開発した SLM(Small Language Model) と呼ばれるコンパクトな言語モデルです。最大の特徴としては、モデルが公開されており、PC レベルでのリソースでも動作するため、言語モデルをローカルで実行することができます。エッジへの言語モデルの組み込みが可能です。

現在(2024/06)、Phi-3 モデルのラインナップは、以下のようになっています。

No. モデル パラメータ数 モデル名 コンテキスト長
1 Phi-3-mini 3.8B Phi-3-Mini-128K-Instruc 128K
2 ^ ^ Phi-3-Mini-4K-Instruc 4K
3 Phi-3-small 7B Phi-3-Small-128K-Instruct 128K
4 ^ ^ Phi-3-Small-8K-Instruct 8K
5 Phi-3-medium 14B Phi-3-Medium-128K-Instruct 128K
6 ^ ^ Phi-3-Medium-4K-Instruct 4K
7 Phi-3-vision 4.2B Phi-3-Vision-128K-Instruct 128K

規模としては、GPT-2 のパラメータ数が、1.5B、GPT-3 が 175B なので、GPT-2 と GPT-3 の中間というところでしょうか。

これらのモデルは、Hugging Face で公開されており、これらをダウンロードして利用できます。

以降では、C# コンソールアプリケーションで、ONNX ランタイムを使用して Phi-3 を実行する方法を説明します。

ONNX ランタイム向けに最適化された ONNX 形式ファイルのダウンロード

Hugging Face には、Phi-3 モデルを ONNX ランタイム向けに最適化された ONNX 形式のファイルも公開されています。

以下は、Phi-3-mini-4k-instruct モデルの DirectML 用 ONNX 形式ファイルになります。

その他、CPU 用、CUDA 用の各 ONNX 形式ファイルが公開されています。

今回は、DirectML 用を使用します。microsoft/Phi-3-mini-4k-instruct-onnx/directml/directml-int4-awq-block-128 以下に公開されているすべてのファイルをダウンロードします。

ファイルを一つ一つダウンロードしても良いですが、huggingface-cli を使用することで、各ファイルをまとめてダウンロードできます。

huggingface-cli をインストールします。pip を使うので、Python のセットアップが必要です。

pip install -U "huggingface_hub[cli]"

huggingface-cli で、microsoft/Phi-3-mini-4k-instruct-onnx/directml 以下のファイルをダウンロードします。

huggingface-cli download microsoft/Phi-3-mini-4k-instruct-onnx --include directml/* --local-dir .

生成 AI 用 DirectML 向け ONNX ランタイムのインストール

Visual Studio 2022 で、コンソールアプリケーションを作成し、以下のパッケージを Nuget からインストールします。

このパッケージが、生成 AI 用の DirectML 向け ONNX ランタイムとなります。

モデルの配置

microsoft/Phi-3-mini-4k-instruct-onnx からダウンロードした各ファイルをプロジェクトにコピーします。

ここでは、.\models\directml\directml-int4-awq-block-128\ に各ファイルをコピーしています。

コピーしたすべてのファイルのプロパティ [出力ディレクトリにコピー] を [新しい場合はコピーする] に設定します。

モデルの配置とプロパティの設定

これで、ビルド時の出力ディレクトリに各ファイルがコピーされるようになります。

コード サンプル

以下のようにコードを書きます。

using Microsoft.ML.OnnxRuntimeGenAI;
using System.Diagnostics;

namespace Phi3ConsoleApp001
{
    internal class Program
    {
        static void Main(string[] args)
        {
            // システムプロンプト
            var systemPrompt = "あなたは和歌の名手です。与えられた句を丁寧に解説してください。さらに、より良い句にするための添削を行い、添削のポイントを丁寧に解説してください。";
            // ユーザープロンプト
            var userPrompt = "この世をば わが世とぞ思ふ 望月の 欠けたることも なしと思へば";

            // プロンプトのテンプレート
            var prompt = $@"<|system|>{systemPrompt}<|end|><|user|>{userPrompt}<|end|><|assistant|>";

            // モデルが格納されているパス
            string modelDir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"Models\directml\directml-int4-awq-block-128");
            
            var sw = Stopwatch.StartNew();
            // モデルのロード
            Model model = new(modelDir);
            Tokenizer tokenizer = new(model);            
            sw.Stop();

            Console.WriteLine($"Model loading took {sw.ElapsedMilliseconds} ms.");

            sw = Stopwatch.StartNew();
            
            // プロンプトをトークン化
            var sequences = tokenizer.Encode(prompt);

            // 各パラメータを設定
            GeneratorParams generatorParams = new(model);
            generatorParams.SetSearchOption("max_length", 2048);            
            generatorParams.TryGraphCaptureWithMaxBatchSize(1);
            generatorParams.SetInputSequences(sequences);

            using var tokenizerStream = tokenizer.CreateStream();
            // 応答の生成
            using var generator = new Generator(model, generatorParams);
            
            while (!generator.IsDone())
            {                
                try
                {                    
                    generator.ComputeLogits();
                    generator.GenerateNextToken();
                    
                    // トークンの取り出し
                    var outputTokens = generator.GetSequence(0)[^1];
                    // トークンのデコード
                    var output = tokenizerStream.Decode(outputTokens);

                    Console.Write(output);                    
                }
                catch (Exception ex)
                {
                    Debug.WriteLine(ex);
                    break;
                }
            }

            Console.WriteLine();

            sw.Stop();
            Console.WriteLine($"Response generation took {sw.ElapsedMilliseconds} ms.");            
        }
    }
}


実行結果

実行結果は、以下のようになります。

実行結果

Phi-3 を使うことで、これまで GPT-4, GPT-3.5 を使用していた場面での代替ができるかもしれません。もちろん、クラウドへのアクセスや使用料も必要ありません。タスクによっては、精度面での課題はあるかもしれませんが、言語モデルの選択肢が広がったのは間違いない事実だと考えます。

コメント (0)

コメントの投稿