Bagikan melalui


Mulai menggunakan Phi3 dan model bahasa lain di aplikasi Windows Anda dengan ONNX Runtime Generative AI

Artikel ini memancang Anda membuat aplikasi WinUI 3 yang menggunakan model Phi3 dan ONNX Runtime Generative AI pustaka untuk mengimplementasikan aplikasi obrolan AI generatif sederhana. Model bahasa besar (LLM) memungkinkan Anda menambahkan kemampuan pembuatan teks, transformasi, penalaran, dan terjemahan ke aplikasi Anda. Untuk informasi selengkapnya tentang menggunakan model AI dan pembelajaran mesin di aplikasi windows Anda, lihat Mulai menggunakan model AI dan Pembelajaran Mesin di aplikasi Windows Anda. Untuk informasi selengkapnya tentang runtime ONNX dan AI generatif, lihat AI Generatif dengan ONNX Runtime.

Apa itu ONNX Runtime

ONNX Runtime adalah akselerator model pembelajaran mesin lintas platform, dengan antarmuka fleksibel untuk mengintegrasikan pustaka khusus perangkat keras. ONNX Runtime dapat digunakan dengan model dari PyTorch, Tensorflow/Keras, TFLite, scikit-learn, dan kerangka kerja lainnya. Untuk informasi selengkapnya, lihat ONNX Runtime situs web di https://onnxruntime.ai/docs/.

Prasyarat

Membuat aplikasi C# WinUI baru

Di Visual Studio, buat proyek baru. Dalam dialog Buat proyek baru, atur filter bahasa ke "C#" dan filter jenis proyek ke "winui", lalu pilih templat Aplikasi kosong, Dipaketkan (WinUI3 di Desktop). Beri nama proyek baru "GenAIExample".

Menambahkan referensi ke ONNX Runtime Generative AI paket Nuget

Di Penjelajah Solusi, klik kanan Dependensi dan pilih Kelola paket NuGet.... Di manajer paket NuGet, pilih tab Telusuri. Cari "Microsoft.ML.OnnxRuntimeGenAI.DirectML", pilih versi stabil terbaru di menu drop-down Versi lalu klik Instal.

Menambahkan model dan file kosakata ke proyek Anda

Di Penjelajah Solusi, klik kanan proyek Anda dan pilih Tambahkan> Folder Baru. Beri nama folder baru "Model". Untuk contoh ini, kita akan menggunakan model dari https://huggingface.co/microsoft/Phi-3-mini-4k-instruct-onnx/tree/main/directml/directml-int4-awq-block-128.

Ada beberapa cara berbeda untuk mengambil model. Untuk panduan ini, kita akan menggunakan Hugging Face Command Line Interface (CLI). Jika Anda mendapatkan model menggunakan metode lain, Anda mungkin harus menyesuaikan jalur file ke model dalam kode contoh. Untuk informasi tentang menginstal Hugging Face CLI dan menyiapkan akun Anda untuk menggunakannya, lihat Antarmuka Baris Perintah (CLI).

Setelah menginstal CLI, buka terminal, navigasikan ke direktori yang Models Anda buat, dan ketik perintah berikut.

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

Ketika operasi selesai verifikasi bahwa file berikut ada: [Project Directory]\Models\directml\directml-int4-awq-block-128\model.onnx.

Di Penjelajah Solusi, perluas folder "directml-int4-awq-block-128" dan pilih semua file dalam folder. Di panel Properti File, atur Salin ke Direktori Output ke "Salin jika lebih baru".

Menambahkan antarmuka pengguna sederhana untuk berinteraksi dengan model

Untuk contoh ini kita akan membuat UI yang sangat sederhana yang memiliki TextBox untuk menentukan perintah, Tombol untuk mengirimkan perintah, dan TextBlock untuk menampilkan pesan status dan respons dari model. Ganti elemen StackPanel default dengan MainWindow.xaml XAML berikut.

<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>

Menginisialisasi model

Di MainWindow.xaml.cs, tambahkan direktif penggunaan untuk namespace Microsoft.ML.OnnxRuntimeGenAI .

using Microsoft.ML.OnnxRuntimeGenAI;

Deklarasikan variabel anggota di dalam definisi kelas MainPage untuk Model dan Tokenizer. Atur lokasi untuk file model yang kami tambahkan di langkah-langkah sebelumnya.

private Model? model = null;
private Tokenizer? tokenizer = null;
private readonly string ModelDir = 
    Path.Combine(AppDomain.CurrentDomain.BaseDirectory,
        @"Models\directml\directml-int4-awq-block-128");

Buat metode pembantu untuk menginisialisasi model secara asinkron. Metode ini memanggil konstruktor untuk kelas Model , meneruskan jalur ke direktori model. Selanjutnya membuat Tokenizer baru dari model.

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";
        });
    });
}

Untuk contoh ini, kita akan memuat model ketika jendela utama diaktifkan. Perbarui konstruktor halaman untuk mendaftarkan handler untuk peristiwa Diaktifkan .

public MainWindow()
{
    this.InitializeComponent();
    this.Activated += MainWindow_Activated;
}

Peristiwa Diaktifkan dapat dinaikkan beberapa kali, jadi di penanganan aktivitas, periksa untuk memastikan model null sebelum menginisialisasinya.

private async void MainWindow_Activated(object sender, WindowActivatedEventArgs args)
{
    if (model == null)
    {
        await InitializeModelAsync();
    }
}

Mengirimkan perintah ke model

Buat metode pembantu yang mengirimkan permintaan ke model dan kemudian secara asinkron mengembalikan hasilnya ke pemanggil dengan IAsyncEnumerable.

Dalam metode ini, kelas Generator digunakan dalam perulangan, memanggil GenerateNextToken di setiap pass untuk mengambil apa yang model memprediksi beberapa karakter berikutnya, yang disebut token, harus didasarkan pada perintah input. Perulangan berjalan hingga metode IsDone generator mengembalikan true atau hingga salah satu token "<|end|>", "<|system|>", atau "<|user|>" diterima, yang memberi sinyal bahwa kami dapat berhenti menghasilkan token.

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;
    }
}

Tambahkan kode antarmuka pengguna untuk mengirimkan perintah dan menampilkan hasilnya

Di handler Klik tombol, pertama-tama verifikasi bahwa model tidak null. Buat string perintah dengan sistem dan permintaan pengguna dan panggil InferStreaming, perbarui TextBlock dengan setiap bagian respons.

Model yang digunakan dalam contoh ini telah dilatih untuk menerima perintah dalam format berikut, di mana systemPrompt adalah instruksi tentang bagaimana model harus beresiko, dan userPrompt merupakan pertanyaan dari pengguna.

<|system|>{systemPrompt}<|end|><|user|>{userPrompt}<|end|><|assistant|>

Model harus mendokumen konvensi permintaan mereka. Untuk model ini, format didokumenkan pada kartu model Huggingface.

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;
        }
    }
}

Jalankan contoh

Di Visual Studio, di menu drop-down Platform Solusi, pastikan bahwa prosesor target diatur ke x64. Pustaka AI Generatif ONNXRuntime tidak mendukung x86. Buat dan jalankan proyek. Tunggu TextBlock menunjukkan bahwa model telah dimuat. Ketik perintah ke dalam kotak teks perintah dan klik tombol kirim. Anda akan melihat hasilnya secara bertahap mengisi blok teks.

Lihat juga