はじめに
いまさらながらですが、Phi 3 を試してみるために、ローカルで実行してみるコンソールアプリを作ってみました。
リポジトリはこちらです。
github.com
モデルは Hugging Face から DL してください。
DL する cli のコマンドのサンプルは前回の記事を参照ください。
hiro128.hatenablog.jp
コード
以下のページを参考にコードを作成しました。
learn.microsoft.com
モデルをメモリに展開して、システムプロンプトとユーザープロンプトを投げて回答ストリーミングで表示するだけのシンプルなコードです
using Microsoft.Extensions.Configuration; using Microsoft.ML.OnnxRuntimeGenAI; using System.Diagnostics; using System.Text; var env = Environment.GetEnvironmentVariable("DOTNET_ENVIRONMENT") ?? string.Empty; var configuration = new ConfigurationBuilder() .SetBasePath(Directory.GetCurrentDirectory()) .AddJsonFile("appsettings.json") .AddJsonFile($"appsettings.{env}.json", true) .Build(); string modelPhi35Min128k = configuration["modelPhi35Min128k"] ?? throw new ArgumentNullException("modelPhi35Min128k is not found."); string modelPhi3Med4k = configuration["modelPhi3Med4k"] ?? throw new ArgumentNullException("modelPhi3Med4k is not found."); string modelPhi3Med128k = configuration["modelPhi3Med128k"] ?? throw new ArgumentNullException("modelPhi3Med128k is not found."); string modelPhi3Min4k = configuration["modelPhi3Min4k"] ?? throw new ArgumentNullException("modelPhi3Min4k is not found."); string modelPhi3Min128k = configuration["modelPhi3Min128k"] ?? throw new ArgumentNullException("modelPhi3Min128k is not found."); var systemPrompt = configuration["systemPrompt"] ?? throw new ArgumentNullException("systemPrompt is not found."); var userPrompt = configuration["userPrompt"] ?? throw new ArgumentNullException("userPrompt is not found."); using OgaHandle ogaHandle = new OgaHandle(); // モデルのセットアップ var modelPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, modelPhi3Med128k); var sw = Stopwatch.StartNew(); using Model model = new Model(modelPath); using Tokenizer tokenizer = new Tokenizer(model); sw.Stop(); Console.WriteLine($"\r\nModel loading time is {sw.Elapsed.Seconds:0.00} sec.\r\n"); // プロンプトのセットアップ Console.WriteLine($"\r\nシステムプロンプト:\r\n{systemPrompt}"); Console.WriteLine($"\r\nユーザープロンプト:\r\n{userPrompt}\r\n"); var sequences = tokenizer.Encode($@"<|system|>{systemPrompt}<|end|><|user|>{userPrompt}<|end|><|assistant|>"); // プロンプトを投げて回答を得る using GeneratorParams generatorParams = new GeneratorParams(model); generatorParams.SetSearchOption("min_length", 100); generatorParams.SetSearchOption("max_length", 2000); generatorParams.TryGraphCaptureWithMaxBatchSize(1); generatorParams.SetInputSequences(sequences); using var tokenizerStream = tokenizer.CreateStream(); using var generator = new Generator(model, generatorParams); StringBuilder stringBuilder = new(); Console.WriteLine("レスポンス:"); var totalTokens = 0; string part; sw = Stopwatch.StartNew(); while (!generator.IsDone()) { try { await Task.Delay(10).ConfigureAwait(false); generator.ComputeLogits(); generator.GenerateNextToken(); part = tokenizerStream.Decode(generator.GetSequence(0)[^1]); Console.Write(part); stringBuilder.Append(part); if (stringBuilder.ToString().Contains("<|end|>") || stringBuilder.ToString().Contains("<|user|>") || stringBuilder.ToString().Contains("<|system|>")) { break; } } catch (Exception ex) { Debug.WriteLine(ex); break; } } Console.WriteLine("\r\n"); sw.Stop(); totalTokens = generator.GetSequence(0).Length; Console.WriteLine($"Streaming Tokens: {totalTokens} - Time: {sw.Elapsed.Seconds:0.00} sec"); Console.WriteLine($"Tokens per second: {((double)totalTokens / sw.Elapsed.TotalSeconds):0.00} tokens");
実行環境
- CPU : Snapdragon X Elite
- RAM : 16GB
- CPU : Core Ultra7 155H
- RAM : 64GB
速度・精度
速度は3回試行し、真ん中の値ですのであくまでも参考程度とお考え下さい。
| Phi 3 | |||
|---|---|---|---|
| 速度 | 日本語精度 | 英語精度 | |
| Mini 4k | 23.19 tokens/sec. | X | ◯ |
| Mini 128k | 25.49 tokens/sec. | X | ◯ |
| Medium 4k | 5.95 tokens/sec. | △ | ◯ |
| Medium 128k | 6.24 tokens/sec. | △ | ◯ |
プロンプトとレスポンスの一例
Phi 3 Mini 128k(日本語)
回答の内容は不正確で破綻しています。
システムプロンプト: あなたは船舶と航海の歴史に詳しい歴史学者です。与えられた質問にあなたの船舶と航海の歴史の知識を最大限活用して解説してください。 ユーザープロンプト: タイタニック号の航海について最大300字以内で教えてください。 レスポンス: タイタニック号は、1929年に日本の船舶大手東洋販売社によって設計された、世界初の大型軽艘船です。彼らは、日本海外の貿易と 旅行に革新をもたらしました。タイタニック号は、特に東京からパリまでの航路で知られ、その長い航路は日本航天の航海史において重要な役割を果たしました。しかし、1954年の航海中に海底沖縄に墜落し、その後、多くの探検により、救助作戦として知られるようになりました。この船は、日本航天の歴史における重要な転機を象徴しており、その存在は日本航天の発展において不可欠な存在です。
Phi 3 Mini 128k(英語)
回答の内容は正確です。(Phi 3 は英語で精度が出るように調整されているので順当な結果ではありますが)
システムプロンプト: You are a historian with an intimate knowledge of the history of ships and navigation. Please use your knowledge of the history of ships and navigation to the best of your ability to explain the questions given. ユーザープロンプト: Please tell us about the voyage of the RMS Titanic in a maximum of 150 words. レスポンス: The RMS Titanic, a British luxury liner, embarked on its maiden voyage from Southampton, England, on April 10, 1912. Designed to be the pinnacle of maritime engineering, it was deemed "unsinkable." However, on its journey to New York City, it tragically struck an iceberg in the North Atlantic Ocean. Despite the distress signals, the Titanic sank on April 15, claiming over 1,500 lives. The disaster highlighted the ship's insufficient lifeboats and the crew's inadequate emergency response. The Titanic's sinking led to significant changes in maritime safety regulations, including the establishment of the International Convention for the Safety of Life at Sea (SOLAS) in 1914. The Titanic's story remains a poignant reminder of human vulnerability and the importance of safety in the face of nature's unpredictability.
Phi 3 Medium 128k(日本語)
回答の内容は一部が不正確ですが、おおむね合っています。
システムプロンプト: あなたは船舶と航海の歴史に詳しい歴史学者です。与えられた質問にあなたの船舶と航海の歴史の知識を最大限活用して解説してください。 ユーザープロンプト: タイタニック号の航海について最大300字以内で教えてください。 レスポンス: タイタニック号は、1912年4月10日にイギリスの南ウェールズのバーケンヘッドから出航し、ニューヨーク市へ向かった。この豪華客船は、白い巨人として知られ、当時世界最大の客船であった。しかし、4月14日の夜、北大西洋の氷山に衝突し、氷山の氷によって押し潰された。船はわずか2時間40分で沈没し、乗客乗員1,517人が犠牲になった。この悲劇は、船の設計上の欠陥、船長の誤った判断、氷山の警告を無視したことなど、複数の要因が組み合わさった結果であった。タイタニック号の沈没は、海事史上最も悲劇的な出来事の一つとして記憶されている。
Phi 3 Medium 128k(英語)
回答の内容は正確です。(Phi 3 は英語で精度が出るように調整されているので順当な結果ではありますが)
システムプロンプト: You are a historian with an intimate knowledge of the history of ships and navigation. Please use your knowledge of the history of ships and navigation to the best of your ability to explain the questions given. ユーザープロンプト: Please tell us about the voyage of the RMS Titanic in a maximum of 150 words. レスポンス: The RMS Titanic, a British luxury passenger liner, embarked on its maiden voyage from Southampton, England, to New York City, USA, on April 10, 1 vice-admiral of the Royal Navy, Edward Smith, as captain. The ship, deemed "unsinkable," carried 2,224 passengers and crew. On April 14, 1912, Titanic struck an iceberg in the North Atlantic Ocean, causing the ship to sink in less than three hours. Of the passengers and crew, only 710 survived, thanks to lifeboats and the Carpathia, a nearby ship that rescued survivors. The tragedy led to significant improvements in maritime safety, including the International Convention for the Safety of Life at Sea (SOLAS) and the establishment of the International Ice Patrol. The wreck of the Titanic was discovered in 1985, lying at a depth of about 12,500 feet.
速度と精度の両立を狙うための改善を考えてみる
- Phi 3 mini
- メモリ 16 GB でも実用的な速度は出る
- 日本語での回答精度は話にならないほど低い
- 英語での回答精度はかなり高い
- Phi 3 medium
- メモリ 16GB では空きメモリがほとんどゼロになるが、かろうじて待てるくらいの速度は出るが常用はかなりストレス
- メモリ 32GB であればメモリは足りるが、速度はあまり改善しない。
- 日本語での回答精度もかなり高い。
- 英語での回答精度はかなり高い
- 英語なら Phi 3 mini でもかなり精度が高いので、【日本語のプロンプト -> 英語に翻訳して投げる -> 英語のレスポンスを再度日本語に翻訳】という方法で速度と精度の両立を狙えないか検証してみたい(次の記事で検証)