Ismerkedés a Phi3 és más nyelvi modellekkel a Windows-alkalmazásban a ONNX Runtime Generative AI
Ez a cikk végigvezeti egy Olyan WinUI 3-alkalmazás létrehozásán, amely Phi3-modellt és ONNX Runtime Generative AI kódtárat használ egy egyszerű generatív AI-csevegőalkalmazás implementálásához. A nagyméretű nyelvi modellek (LLM-ek) lehetővé teszik, hogy szöveggenerálási, átalakítási, érvelési és fordítási képességeket adjanak az alkalmazáshoz. Az AI- és gépi tanulási modellek Windows-alkalmazásban való használatáról további információt a AI használatának első lépései a Windowscímű témakörben talál. További információ az ONNX futtatókörnyezetről és a generatív AI-ről: Generative AI és ONNX Runtime.
Az AI-funkciók használatakor javasoljuk, hogy tekintse át: A Felelős Generatív AI Alkalmazások és Szolgáltatások Fejlesztése Windows-on.
Mi az a ONNX Runtime
ONNX Runtime egy platformfüggetlen gépi tanulási modellgyorsító, amely rugalmas felülettel rendelkezik a hardverspecifikus kódtárak integrálásához. ONNX Runtime a PyTorch, a Tensorflow/Keras, a TFLite, a scikit-learnés más keretrendszerek modelljeihez használható. További információért lásd a ONNX Runtime webhelyet a https://onnxruntime.ai/docs/címen.
Előfeltételek
- Az eszköznek engedélyeznie kell a fejlesztői módot. További információ: Engedélyezze az eszközt a fejlesztéshez.
- Visual Studio 2022 vagy újabb verzió a .NET asztali fejlesztési számítási feladattal.
Új C# WinUI-alkalmazás létrehozása
Hozzon létre egy új projektet a Visual Studióban. Az Új projekt létrehozása párbeszédpanelen állítsa a nyelvi szűrőt "C#" értékre, a projekttípus-szűrőt pedig "winui" értékre, majd válassza a Üres alkalmazás, Csomagolva (WinUI3 asztali verzió) sablont. Nevezze el az új projektet "GenAIExample" néven.
Hivatkozás hozzáadása a ONNX Runtime Generative AI Nuget-csomaghoz
A Megoldáskezelőbenkattintson a jobb gombbal Függőségek elemre, és válassza NuGet-csomagok kezelése...lehetőséget. A NuGet-csomagkezelőben válassza a Tallózás lapot. Keressen rá a "Microsoft.ML.OnnxRuntimeGenAI.DirectML" kifejezésre, válassza ki a legújabb stabil verziót a Verzió legördülő listában, majd kattintson a Telepítéselemre.
Modell- és szókincsfájl hozzáadása a projekthez
A Megoldáskezelőbenkattintson a jobb gombbal a projektre, és válassza a Hozzáadás>Új mappalehetőséget. Nevezze el az új mappát a "Models" névvel. Ebben a példában a modellt fogjuk használni https://huggingface.co/microsoft/Phi-3-mini-4k-instruct-onnx/tree/main/directml/directml-int4-awq-block-128.
A modellek lekérésének számos különböző módja van. Ehhez az útmutatóhoz a Hugging Face parancssori felületet (CLI) fogjuk használni. Ha a modelleket egy másik módszerrel szerzi be, előfordulhat, hogy a példakódban módosítania kell a fájl elérési útját a modellhez. Az Hugging Face CLI telepítésével és a fiók beállításával kapcsolatos információkért lásd: Parancssori felület (CLI).
A parancssori felület telepítése után nyisson meg egy terminált, keresse meg a létrehozott Models
könyvtárat, és írja be a következő parancsot.
huggingface-cli download microsoft/Phi-3-mini-4k-instruct-onnx --include directml/* --local-dir .
Ha a művelet befejeződött, ellenőrizze, hogy a következő fájl létezik-e: [Project Directory]\Models\directml\directml-int4-awq-block-128\model.onnx
.
A Megoldáskezelőbontsa ki a "directml-int4-awq-block-128" mappát, és jelölje ki a mappában lévő összes fájlt. A Fájl tulajdonságai panelen állítsa a Másolás a kimeneti könyvtárba opciót "Másolás, ha újabb" értékre.
Egyszerű felhasználói felület hozzáadása a modell használatához
Ebben a példában egy nagyon egyszerű felhasználói felületet hozunk létre, amely TextBox- tartalmaz egy kérdés megadásához, egy gombot a kérés elküldéséhez, valamint egy TextBlock az állapotüzenetek és a modell válaszainak megjelenítéséhez. Cserélje le az alapértelmezett StackPanel elemet MainWindow.xaml
az alábbi XAML-ra.
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<StackPanel Orientation="Vertical" HorizontalAlignment="Center" VerticalAlignment="Center" Grid.Column ="0">
<TextBox x:Name="promptTextBox" Text="Compose a haiku about coding."/>
<Button x:Name="myButton" Click="myButton_Click">Submit prompt</Button>
</StackPanel>
<Border Grid.Column="1" Margin="20">
<TextBlock x:Name="responseTextBlock" TextWrapping="WrapWholeWords"/>
</Border>
</Grid>
A modell inicializálása
A MainWindow.xaml.cs
adjon hozzá egy, a Microsoft.ML.OnnxRuntimeGenAI névtérhez tartozó használatirányelvet.
using Microsoft.ML.OnnxRuntimeGenAI;
Deklarálja a tagváltozókat a MainPage osztálydefinícióján belül a Model és a Tokenizerszámára. Adja meg az előző lépésekben hozzáadott modellfájlok helyét.
private Model? model = null;
private Tokenizer? tokenizer = null;
private readonly string ModelDir =
Path.Combine(AppDomain.CurrentDomain.BaseDirectory,
@"Models\directml\directml-int4-awq-block-128");
Hozzon létre egy segédmetódust a modell aszinkron inicializálásához. Ez a metódus meghívja a Modell osztály konstruktorát, és átadja a modellkönyvtár elérési útját. Ezután létrehoz egy új Tokenizer a modellből.
public Task InitializeModelAsync()
{
DispatcherQueue.TryEnqueue(() =>
{
responseTextBlock.Text = "Loading model...";
});
return Task.Run(() =>
{
var sw = Stopwatch.StartNew();
model = new Model(ModelDir);
tokenizer = new Tokenizer(model);
sw.Stop();
DispatcherQueue.TryEnqueue(() =>
{
responseTextBlock.Text = $"Model loading took {sw.ElapsedMilliseconds} ms";
});
});
}
Ebben a példában a főablak aktiválásakor töltjük be a modellt. Frissítse a lapkonstruktort, hogy regisztráljon egy kezelőt az Aktivált eseményhez.
public MainWindow()
{
this.InitializeComponent();
this.Activated += MainWindow_Activated;
}
Az aktivált esemény többször is elindítható, ezért az eseménykezelőben ellenőrizze, hogy a modell null értékű-e az inicializálás előtt.
private async void MainWindow_Activated(object sender, WindowActivatedEventArgs args)
{
if (model == null)
{
await InitializeModelAsync();
}
}
A kérés elküldése a modellnek
Hozzon létre egy segédmetódust, amely a kérést elküldi a modellnek, majd aszinkron módon visszaküldi az eredményeket a hívónak egy IAsyncEnumerablesegítségével.
Ebben a módszerben a Generator osztályt egy ciklusban használják, amely mindegyik körben meghívja a GenerateNextToken-t, hogy lekérje a modell által előrejelzett következő néhány karaktert, azaz a tokent, amely a bemeneti kérésen alapul. A hurok addig fut, amíg a generátor IsDone metódus igaz értéket nem ad vissza, vagy amíg bármelyik a következő jogkivonatok közül megérkezik: "<|end|>", "<|system|>", vagy "<|user|>", ami azt jelzi, hogy leállíthatjuk a jogkivonatok generálását.
public async IAsyncEnumerable<string> InferStreaming(string prompt)
{
if (model == null || tokenizer == null)
{
throw new InvalidOperationException("Model is not ready");
}
var generatorParams = new GeneratorParams(model);
var sequences = tokenizer.Encode(prompt);
generatorParams.SetSearchOption("max_length", 2048);
generatorParams.SetInputSequences(sequences);
generatorParams.TryGraphCaptureWithMaxBatchSize(1);
using var tokenizerStream = tokenizer.CreateStream();
using var generator = new Generator(model, generatorParams);
StringBuilder stringBuilder = new();
while (!generator.IsDone())
{
string part;
try
{
await Task.Delay(10).ConfigureAwait(false);
generator.ComputeLogits();
generator.GenerateNextToken();
part = tokenizerStream.Decode(generator.GetSequence(0)[^1]);
stringBuilder.Append(part);
if (stringBuilder.ToString().Contains("<|end|>")
|| stringBuilder.ToString().Contains("<|user|>")
|| stringBuilder.ToString().Contains("<|system|>"))
{
break;
}
}
catch (Exception ex)
{
Debug.WriteLine(ex);
break;
}
yield return part;
}
}
Felhasználói felületi kód hozzáadása a kérés elküldéséhez és az eredmények megjelenítéséhez
A gomb kattintáskezelőben először ellenőrizze, hogy a modell nem null értékű-e. Hozzon létre egy utasításszöveget a rendszer és a felhasználó utasításaival, majd hívja meg a InferStreaming-t, frissítve a TextBlock-at a válasz minden részével.
Az ebben a példában használt modell a következő formátumban lett betanított kérések elfogadására, ahol systemPrompt
a modell viselkedésére vonatkozó utasítások, userPrompt
pedig a felhasználó kérdése.
<|system|>{systemPrompt}<|end|><|user|>{userPrompt}<|end|><|assistant|>
A modelleknek dokumentálniuk kell az utasítási konvencióikat. Ebben a modellben a formátum a Huggingface modellkártyánvan dokumentálva.
private async void myButton_Click(object sender, RoutedEventArgs e)
{
responseTextBlock.Text = "";
if(model != null)
{
var systemPrompt = "You are a helpful assistant.";
var userPrompt = promptTextBox.Text;
var prompt = $@"<|system|>{systemPrompt}<|end|><|user|>{userPrompt}<|end|><|assistant|>";
await foreach (var part in InferStreaming(prompt))
{
responseTextBlock.Text += part;
}
}
}
A példa futtatása
A Visual Studióban a Megoldásplatformok legördülő listában győződjön meg arról, hogy a célprocesszor x64 értékre van állítva. Az ONNXRuntime Generative AI-kódtár nem támogatja az x86-ot. Hozza létre és futtassa a projektet. Várja meg, amíg a TextBlock jelzi, hogy a modell be lett töltve. Írjon be egy parancssort a parancssor szövegmezőbe, és kattintson a Küldés gombra. Látnia kell, hogy az eredmények fokozatosan kitöltik a szövegblokkot.
Lásd még:
- AI használatának első lépései Windows
- Generatív mesterséges intelligencia ONNX Runtime