Перейти до основного вмісту

Запуск моделей GenAI через PCIe

ПолеЗначення
КатегоріяСпівпроцесинг PCIe
СкладністьСередній
Орієнтовний час читання15 minutes
МіткиPCIe, GenAI, LLM, VLM, Whisper

Кожен приклад завантажує підготовлену теку моделі LLiMa на хості, виконує запит з обмеженнями та закриває модель. Спочатку запускайте приклади окремо. Вони використовують однакові параметри з’єднання, але різні вхідні дані.

Покроковий огляд​

Завантаження LLM​

Створіть pcie::genai::GenAIModel у C++ або pyneatpcie.genai.GenAIModel у Python. Конструктор завантажує модель на карту; build() і вибір черги не потрібні. Укажіть connection.card_id, щоб вибрати карту. Можна передавати абсолютний шлях моделі або шлях відносно поточної робочої теки.

pcie_host/tutorials/029_run_genai_over_pcie/run_llm.cpp
genai::GenAIModel model(args.model, args.connection);
if (!model.accepts_text() || model.task() == genai::GenAITask::ASR)
throw std::invalid_argument("choose a text-generation model directory");

Надсилання текстового запиту​

Задайте prompt і max_new_tokens, а потім викличте run(). Результат містить текст відповіді та метрики генерації. За замовчуванням приклади обмежують генерацію 128 токенами; змініть цей ліміт за допомогою --max-tokens.

pcie_host/tutorials/029_run_genai_over_pcie/run_llm.cpp
genai::GenerationRequest request;
request.prompt = args.prompt;
request.max_new_tokens = args.max_tokens;
if (!args.stream) {
const auto result = model.run(request);
std::cout << result.text << '\n';
std::cout << "Generated tokens: " << result.metrics.generated_tokens << '\n';
}

Потокове отримання відповіді​

Передайте --stream прикладу LLM, щоб натомість перебирати значення TokenSample. Виводьте кожен текстовий фрагмент одразу після отримання; фінальний зразок містить підсумкові метрики генерації. Для кожної моделі одночасно може бути активним лише один запит.

pcie_host/tutorials/029_run_genai_over_pcie/run_llm.cpp
auto stream = model.stream(request);
for (const auto& sample : stream) {
std::cout << sample.text << std::flush;
if (sample.is_final)
std::cout << "\nGenerated tokens: " << sample.metrics.generated_tokens << '\n';
}

Закриття моделі​

C++ явно викликає close() після інференсу, а якщо виняток перериває приклад, очищення виконує деструктор. Python використовує менеджер контексту, який закриває модель при виході з блоку, зокрема при помилках. Обидва тайм-аути з’єднання скінченні: 15 хвилин для запуску та 5 хвилин для запиту.

pcie_host/tutorials/029_run_genai_over_pcie/run_llm.cpp
model.close();

Підготовка RGB-зображення​

Приклад VLM читає зображення на хості через OpenCV, перетворює BGR на RGB і створює неперервні пікселі UInt8 із формою [H, W, 3]. C++ обгортає вектор, що володіє пікселями, у PCIe-тензор; Python передає масив NumPy. Не нормалізуйте пікселі та не підставляйте локальний шлях зображення на карті.

pcie_host/tutorials/029_run_genai_over_pcie/run_vlm.cpp
const auto bgr = cv::imread(args.media, cv::IMREAD_COLOR);
if (bgr.empty())
throw std::invalid_argument("cannot read image: " + args.media);
cv::Mat rgb;
cv::cvtColor(bgr, rgb, cv::COLOR_BGR2RGB);
if (!rgb.isContinuous())
rgb = rgb.clone();
auto image = pcie::Tensor::from_vector(
std::vector<std::uint8_t>(rgb.data, rgb.data + rgb.total() * rgb.elemSize()),
{rgb.rows, rgb.cols, 3}, "", pcie::PixelFormat::RGB);

Запит про зображення​

Завантажте VLM і додайте RGB-вхід до request.images разом із промптом. Модель сама виконує попередню обробку зображення. Повернений текст відповідає на запитання; PCIe-запит не має поля для файлу зображення.

pcie_host/tutorials/029_run_genai_over_pcie/run_vlm.cpp
genai::GenAIModel model(args.model, args.connection);
if (!model.accepts_image())
throw std::invalid_argument("choose a vision-language model directory");
genai::GenerationRequest request;
request.prompt = args.prompt;
request.images = {image};
request.max_new_tokens = args.max_tokens;
std::cout << model.run(request).text << '\n';
model.close();

Транскрибування мовлення за допомогою Whisper​

Завантажте теку Whisper та задайте в audio_file шлях до аудіо на хості. Використовуйте language="auto" для визначення мови або задайте вихідну мову через --language. За замовчуванням запит виконує транскрибування; --translate вибирає переклад англійською. Прочитайте транскрипт, мову та необов’язкову ймовірність відсутності мовлення. Не додавайте чат-промпт до ASR-запиту.

pcie_host/tutorials/029_run_genai_over_pcie/run_whisper.cpp
genai::GenAIModel model(args.model, args.connection);
if (model.task() != genai::GenAITask::ASR || !model.accepts_audio())
throw std::invalid_argument("choose a Whisper model directory");
genai::GenerationRequest request;
request.audio_file = args.media;
request.language = args.language;
request.asr_task = args.translate ? genai::ASRTask::Translate : genai::ASRTask::Transcribe;
const auto result = model.run(request);
std::cout << result.text << '\n';
std::cout << "Language: " << result.language << '\n';
if (result.no_speech_prob)
std::cout << "No-speech probability: " << *result.no_speech_prob << '\n';
model.close();

Запуск​

Виконайте встановлення PCIe на хості та підготовку до навчальних прикладів. Використовуйте сумісні пакети хоста й карти, що надають PCIe GenAI API. Усі наведені нижче команди запускайте на хості з кореневої теки розпакованого PCIe extras.

Завантаження підготовлених моделей​

Ці репозиторії SiMa.ai Model Zoo вже містять скомпільовані артефакти LLiMa: Qwen3, LFM2-VL та Whisper. Завантажуйте лише ті моделі, які плануєте запускати. Перегляньте картки моделей і використовуйте артефакти, сумісні зі встановленою платформою.

source ~/pyneatpcie/bin/activate
python -m pip install huggingface_hub opencv-python
mkdir -p models
hf download simaai/Qwen3-0.6B-Autoround-a16w4 \
--local-dir models/Qwen3-0.6B-Autoround-a16w4
hf download simaai/LFM2-VL-450M-Autoround-a16w4 \
--local-dir models/LFM2-VL-450M-Autoround-a16w4
hf download simaai/whisper-small-a16w8 \
--local-dir models/whisper-small-a16w8

Зберігайте кожну теку повністю, включно з токенізатором, конфігурацією та скомпільованими артефактами. Розпакування або ручне копіювання на карту не потрібне. Початковий контрольний знімок Hugging Face не є підготовленою текою LLiMa; для власних моделей спершу дотримуйтесь GenAI з LLiMa, а потім запускайте цей приклад.

Підготовка медіа​

Команди VLM використовують зображення вуличної сцени з комплекту. Для Whisper запишіть або підготуйте короткий фрагмент мовлення на хості. Якщо встановлено FFmpeg, перетворіть наявний запис на моно WAV із частотою 16 кГц:

ffmpeg -i recording.mp3 -ar 16000 -ac 1 -c:a pcm_s16le speech.wav

Не оцінюйте якість транскрибування за тишею. Приклади приймають інший шлях зображення або аудіо через --image чи --audio.

C++ (prebuilt):

./lib/sima-pcie-host/tutorials/tutorial_029_run_llm \
--model models/Qwen3-0.6B-Autoround-a16w4 --stream
./lib/sima-pcie-host/tutorials/tutorial_029_run_vlm \
--model models/LFM2-VL-450M-Autoround-a16w4 \
--image share/sima-pcie-host/tutorials/assets/street-scene.png
./lib/sima-pcie-host/tutorials/tutorial_029_run_whisper \
--model models/whisper-small-a16w8 --audio speech.wav

C++ (build from source):

./build.sh --target tutorial_029_run_llm
./build.sh --target tutorial_029_run_vlm
./build.sh --target tutorial_029_run_whisper
./build/tutorials-standalone/tutorial_029_run_llm \
--model models/Qwen3-0.6B-Autoround-a16w4 --stream
./build/tutorials-standalone/tutorial_029_run_vlm \
--model models/LFM2-VL-450M-Autoround-a16w4 \
--image share/sima-pcie-host/tutorials/assets/street-scene.png
./build/tutorials-standalone/tutorial_029_run_whisper \
--model models/whisper-small-a16w8 --audio speech.wav

Для збирання C++ з вихідного коду потрібні пакет розробки PCIe та файли розробки OpenCV. Усі приклади за замовчуванням використовують карту 0 і стандартного SSH-користувача з’єднання sima. Якщо ваше встановлення відрізняється, додайте --card N, --user USER, --ssh-key PATH або --card-host ADDRESS. Використовуйте налаштований SSH-акаунт; приклади не налаштовують доступ.

Очікуйте відповідь LLM, опис сцени або транскрипт, що відповідає записаному мовленню. Формулювання залежить від моделі та вхідних даних; сам успішний запуск не є перевіркою якості.

На практиці​

Для незалежних моделей використовуйте окремі дескриптори з урахуванням пам’яті й обчислювальних ресурсів карти. Для чату передавайте історію через messages, а не prompt; незалежні виклики не пам’ятають попередніх реплік. Для скасування потоку викличте cancel() і дочитайте до фінального зразка перед повторним використанням моделі.

Огляд API наведено в PCIe GenAI API. Навчальні приклади автономного GenAI використовують інший простір імен і локальне виконання моделей; не підставляйте їхні дескриптори моделей тут.

Повний початковий код​

Показати повні програми

Llm​

pcie_host/tutorials/029_run_genai_over_pcie/run_llm.cpp
// Run one text request, optionally streaming the answer, from the host over PCIe.
#include "tutorial_args.h"

namespace genai = simaai::neat::pcie::genai;

int main(int argc, char** argv) {
try {
const auto args = tutorial::parse_args(argc, argv, "llm");

genai::GenAIModel model(args.model, args.connection);
if (!model.accepts_text() || model.task() == genai::GenAITask::ASR)
throw std::invalid_argument("choose a text-generation model directory");

genai::GenerationRequest request;
request.prompt = args.prompt;
request.max_new_tokens = args.max_tokens;
if (!args.stream) {
const auto result = model.run(request);
std::cout << result.text << '\n';
std::cout << "Generated tokens: " << result.metrics.generated_tokens << '\n';
}
else {
auto stream = model.stream(request);
for (const auto& sample : stream) {
std::cout << sample.text << std::flush;
if (sample.is_final)
std::cout << "\nGenerated tokens: " << sample.metrics.generated_tokens << '\n';
}
}
model.close();
return 0;
} catch (const std::exception& error) {
std::cerr << "LLM tutorial: " << error.what() << '\n';
return 1;
}
}

Vlm​

pcie_host/tutorials/029_run_genai_over_pcie/run_vlm.cpp
// Load an image on the host and send RGB pixels with a question over PCIe.
#include "tutorial_args.h"

#include <opencv2/imgcodecs.hpp>
#include <opencv2/imgproc.hpp>

#include <cstdint>
#include <vector>

namespace genai = simaai::neat::pcie::genai;
namespace pcie = simaai::neat::pcie;

int main(int argc, char** argv) {
try {
const auto args = tutorial::parse_args(argc, argv, "vlm");

const auto bgr = cv::imread(args.media, cv::IMREAD_COLOR);
if (bgr.empty())
throw std::invalid_argument("cannot read image: " + args.media);
cv::Mat rgb;
cv::cvtColor(bgr, rgb, cv::COLOR_BGR2RGB);
if (!rgb.isContinuous())
rgb = rgb.clone();
auto image = pcie::Tensor::from_vector(
std::vector<std::uint8_t>(rgb.data, rgb.data + rgb.total() * rgb.elemSize()),
{rgb.rows, rgb.cols, 3}, "", pcie::PixelFormat::RGB);

genai::GenAIModel model(args.model, args.connection);
if (!model.accepts_image())
throw std::invalid_argument("choose a vision-language model directory");
genai::GenerationRequest request;
request.prompt = args.prompt;
request.images = {image};
request.max_new_tokens = args.max_tokens;
std::cout << model.run(request).text << '\n';
model.close();
return 0;
} catch (const std::exception& error) {
std::cerr << "VLM tutorial: " << error.what() << '\n';
return 1;
}
}

Whisper​

pcie_host/tutorials/029_run_genai_over_pcie/run_whisper.cpp
// Transcribe a host audio file on the card, or translate its speech into English.
#include "tutorial_args.h"

#include <filesystem>

namespace genai = simaai::neat::pcie::genai;

int main(int argc, char** argv) {
try {
const auto args = tutorial::parse_args(argc, argv, "whisper");
if (!std::filesystem::is_regular_file(args.media))
throw std::invalid_argument("audio file does not exist: " + args.media);

genai::GenAIModel model(args.model, args.connection);
if (model.task() != genai::GenAITask::ASR || !model.accepts_audio())
throw std::invalid_argument("choose a Whisper model directory");
genai::GenerationRequest request;
request.audio_file = args.media;
request.language = args.language;
request.asr_task = args.translate ? genai::ASRTask::Translate : genai::ASRTask::Transcribe;
const auto result = model.run(request);
std::cout << result.text << '\n';
std::cout << "Language: " << result.language << '\n';
if (result.no_speech_prob)
std::cout << "No-speech probability: " << *result.no_speech_prob << '\n';
model.close();
return 0;
} catch (const std::exception& error) {
std::cerr << "Whisper tutorial: " << error.what() << '\n';
return 1;
}
}

Джерело​