
Генерация картинок в zimage-turbo на 6GB видеокарте
В предыдущей статье «stable-diffusion.cpp — отличная альтернатива ComfyUI» подробно рассматривались особенности компиляции, тонкой настройки и развёртывания проекта sd.cpp в среде Linux на примере дистиллированной DiT-модели Z-Image-Turbo и гибридной связки из серверного ускорителя Nvidia Tesla V100 и бытовой видеокарты GeForce GTX 1660 Ti.
Настоящий материал развивает эту тему и призван ответить на практический вопрос: насколько эффективно современный инференс-движок на базе библиотеки GGML справляется с генерацией изображений на аппаратных конфигурациях начального уровня, лишённых специализированных тензорных ядер (Tensor Cores).
В качестве основного вычислительного узла в статье рассматривается та же Nvidia GeForce GTX 1660 Ti с 6GB VRAM (архитектура Turing). Физический объём её видеопамяти накладывает жёсткие ограничения: в него способны уместиться лишь легковесные квантованные профили диффузионных моделей классов Q4–Q5 (объёмом 4.3-5.2 ГБ) совместно с базовым VAE-автоэнкодером ae.safetensors. Тяжёлый сопутствующий текстовый энкодер Qwen3-4B-Q8_0.gguf (требующий ещё около 4 ГБ) в локальную VRAM одиночной карты физически не помещается.
Для обхода этого аппаратного тупика в stable-diffusion.cpp можно использовать агрессивный оффлоад, при котором матрицы диффузии и сэмплирования обрабатываются на GPU, а текстовый энкодер полностью выгружается в системную оперативную память хоста (RAM) для обработки силами центрального процессора (CPU).
Важным инженерным условием для извлечения максимальной вычислительной отдачи из дискретной видеокарты с малым объёмом памяти является полное переключение вывода графической оболочки операционной системы (X-сервера) на встроенное видеоядро процессора (iGPU). Этот шаг позволяет полностью очистить целевой GPU от задач рендеринга десктопа и высвободить до 500–800 МБ критически важной VRAM (выделяемой под кадровый буфер монитора и контекст отрисовки окон). В условиях работы «на грани» эти сэкономленные мегабайты приобретают решающее значение: их можно использовать под размещение вычислительных графов (cuMemCreate), дополнительных слоёв LoRA или вспомогательных модулей генерации.
В случае необходимости (игры, 3D-рендеринг и т.д.) видеокарту Nvidia можно задействовать, используя утилиту prime-run, для этого в linux создаем файл /usr/local/bin/prime-run:
sudo nano /usr/local/bin/prime-run
вставляем в него следующий системный синтаксис:
#!/bin/bash
export __NV_PRIME_RENDER_OFFLOAD=1
export __NV_PRIME_RENDER_OFFLOAD_PROVIDER=NVIDIA-G0
export __VK_LAYER_NV_optimus=NVIDIA_only
exec "$@"
Точное название NV_PRIME_RENDER_OFFLOAD_PROVIDER (в данном случае NVIDIA-G0) можно узнать командой:
xrandr --listproviders
Пример вывода xrandr —listproviders на компьютере с двумя видеокартами Nvidia с выводом на дисплей через встройку Intel:
Providers: number : 3
Provider 0: id: 0x43 cap: 0xf, Source Output, Sink Output, Source Offload, Sink Offload crtcs: 3 outputs: 2 associated providers: 2 name:modesetting
Provider 1: id: 0x3ad cap: 0x2, Sink Output crtcs: 4 outputs: 4 associated providers: 1 name:NVIDIA-G1
Provider 2: id: 0x20d cap: 0x2, Sink Output crtcs: 4 outputs: 4 associated providers: 1 name:NVIDIA-G0
Сохраняем файл и делаем его исполняемым:
sudo chmod +x /usr/local/bin/prime-run
Теперь, если нужно запустить программу с ускорением на Nvidia, нужно просто добавить слово prime-run перед ней, например:
prime-run blender
При использовании для AI-вычислений видеокарт без тензорных ядер, таких, как Nvidia GTX 1650-1660 разных модификаций, нужно учитывать их особенности.
Специфика архитектуры видеокарт Nvidia Turing без Tensor Cores
Линейка видеокарт GTX 1650 / 1660 / Ti / SUPER построена на архитектуре Turing, однако в данных чипах (в отличие от серии RTX) аппаратно вырезаны тензорные ядра. При стандартном CUDA-инференсе квантованных моделей это приводит к катастрофическому падению производительности из-за накладных расходов на деквантование матриц «на лету».
Для решения этой проблемы в stable-diffusion.cpp интегрирована низкоуровневая оптимизация -DGGML_CUDA_FORCE_MMQ=ON. Данный флаг принудительно активирует высокопроизводительные CUDA-ядра алгоритма Multi-Matrix-Quantization, изначально созданные для архитектур Pascal. Это позволяет картам семейства GTX 16xx осуществлять деквантование весов на полной скорости графического чипа, давая чистый прирост производительности до 40–50%.
Ниже приведён материал по компиляции, конфигурационные скрипты и примеры практической реализации по генерации изображений на старом, но еще вполне работоспособном десктопном железе: ПК на базе процессора Intel Core i7-7700 (4 ядра, 8 потоков, Kaby Lake), чипсет Intel Z270, 16GB RAM DDR4 2400MHz в Gentoo Linux (OpenRC, XFCE).
Вывод интерфейса операционной системы и аппаратное декодирование видео полностью возложены на встроенное видеоядро Intel HD Graphics 630 (драйвер Gallium Iris / iHD). Дискретная графика подключена в слоты PCI-E x16, но при установке двух карт работает в симметричном режиме x8 Gen3 (пропускная способность снижена до 7.88 ГБ/с на каждую карту), чего достаточно для неконфликтного обмена тензорами. В данной статье изложена первая часть накопленного материала, связанная с генерацией изображений в stable-diffusion.cpp в zimage-turbo лишь на одной видеокарте.
Сборка stable-diffusion.cpp для видеокарт Nvidia GeForce GTX 16xx
На компьютере предварительно развернуты необходимые зависимости: GCC 15.3.0, инструментарий CUDA Toolkit 13.3.73 (dev-util/nvidia-cuda-toolkit из оверлея stuff) и системная библиотека NCCL.
Сборка stable-diffusion.cpp из исходников:
git clone --recursive https://github.com/leejet/stable-diffusion.cpp && cd stable-diffusion.cpp
cmake -B build \
-DCMAKE_BUILD_TYPE=Release \
-DGGML_CUDA=ON \
-DGGML_RPC=ON \
-DGGML_NCCL=ON \
-DGGML_CCACHE=OFF \
-DGGML_CUDA_FORCE_MMQ=ON \
-DCMAKE_CUDA_ARCHITECTURES=75 \
-DCMAKE_C_FLAGS="-O3 -march=native -pipe" \
-DCMAKE_CXX_FLAGS="-O3 -march=native -pipe" \
-DCMAKE_CUDA_FLAGS="-O3" \
&& cmake --build build -j$(nproc)
Вывод конфигуратора и успешного завершения линковки бинарников stable-diffusion.cpp:
-- The C compiler identification is GNU 15.3.0
...
-- stable-diffusion.cpp version master-778-c00a9e9-1-ga8a91b2
-- stable-diffusion.cpp commit a8a91b2
...
-- Found OpenMP_C: -fopenmp (found version "4.5")
...
-- Adding CPU backend variant ggml-cpu: -march=native
...
-- The CUDA compiler identification is NVIDIA 13.3.73 with host compiler GNU 15.3.0
...
-- Using CMAKE_CUDA_ARCHITECTURES=75 CMAKE_CUDA_ARCHITECTURES_NATIVE=75-real
-- Found NCCL: /usr/local/lib/libnccl.so
-- CUDA host compiler is GNU 15.3.0
-- Including CUDA backend
-- Using RPC backend
-- RDMA transport disabled
-- Including RPC backend
-- ggml version: 0.15.3
-- ggml commit: eced84c8
...
[ 98%] Linking CXX executable ../../bin/sd-cli
[ 98%] Built target sd-cli
[100%] Linking CXX executable ../../bin/sd-server
[100%] Built target sd-server
Рыбалка со спинингом на тихом озере, художник zimage-turbo_Q4, кисть GTX 1660Ti:

Практическое тестирование пайплайнов
Для исследования лимитов VRAM и поиска оптимального баланса скорости сэмплирования тестировались AI-модели z_image_turbo Q4 и Q5 (от Вагнер Бруна, репозиторий wbruna/Z-Image-Turbo-sdcpp-GGUF на huggingface):
- Сценарий 1 (Базовый Flow-Matching DiT): Дистиллированная модель z_image_turbo-Q5_K_S.gguf (4.95GB) развёрнута в VRAM на GPU. Тяжёлый стандартный автоэнкодер ae.safetensors (160MB в контексте сервера) и текстовый энкодер Qwen3-4B-Q8_0.gguf (4.07GB) выгружены в ОЗУ хоста для обработки силами CPU.
- Сценарий 2 (Flow-Matching DiT с микро-декодером): Модель z_image_turbo-Q5_K_S.gguf (4.95GB) на GPU. Проблемный и тяжелый VAE полностью исключен, вместо него задействован ультра-легкий декодер taef1_decoder.safetensors (~9.4MB) локально в VRAM на GPU. Текстовый энкодер Qwen3-4B-Q8_0.gguf (4.07GB) обрабатывается на CPU.
- Сценарий 3 (Flow-Matching DiT с микро-декодером + lora + upscaler): Модель меньшего размера z_image_turbo-Q4_1.gguf (3.86GB) на GPU c декодером taef1_decoder.safetensors (~9.4MB) на GPU плюс zimage_lora.safetensors (325GB) и upscaler на том же GPU. Текстовый энкодер Qwen3-4B-Q8_0.gguf (4.07GB) — на CPU.
Рыбалка в стиле киберпанк на планете в созвездии Андромеда, художник z_image_turbo-Q4_1.gguf:

Практическая генерация изображений на видеокарте Nvidia GeForce GTX 1660 Ti в связке с Z-Image-Turbo
Перед написанием конфигурационных скриптов необходимо точно определить аппаратные идентификаторы доступных вычислительных устройств. Для этого запускаем серверную утилиту с флагом опроса топологии:
./sd-server --list-devices
Вывод команды предоставляет подробную информацию о распределении видеопамяти и архитектурных ограничениях текущей системы:
ggml_cuda_init: found 2 CUDA devices (Total VRAM: 11514 MiB):
Device 0: NVIDIA GeForce GTX 1660 Ti, compute capability 7.5, VMM: yes, VRAM: 5757 MiB
Device 1: NVIDIA GeForce GTX 1660 SUPER, compute capability 7.5, VMM: yes, VRAM: 5757 MiB
The following devices will have suboptimal performance due to a lack of tensor cores:
Device 0: NVIDIA GeForce GTX 1660 Ti
Device 1: NVIDIA GeForce GTX 1660 SUPER
Consider compiling with CMAKE_CUDA_ARCHITECTURES=61-virtual;80-virtual and DGGML_CUDA_FORCE_MMQ to force the use of the Pascal code for Turing.
CUDA0 NVIDIA GeForce GTX 1660 Ti
CUDA1 NVIDIA GeForce GTX 1660 SUPER
CPU Intel(R) Core(TM) i7-7700 CPU @ 3.60GHz
Несмотря на предупреждение компилятора о снижении производительности из-за отсутствия Tensor Cores, благодаря флагу FORCE_MMQ развертываются быстрые CUDA-ядра деквантования. Программа выдает точные системные алиасы бэкендов заглавными буквами: CUDA0, CUDA1 и CPU.
Ниже представлен рабочий скрипт запуска базового тяжелого конвейера (модель z_image_turbo-Q5_K_S.gguf + текстовый энкодер Qwen3-4B-Q8_0.gguf + автоэнкодер ae.safetensors) для сценария №1. Он оптимизирован для работы на одиночной видеокарте Nvidia GeForce GTX 1660 Ti с предварительным аппаратным оверлокингом подсистемы памяти и фиксацией лимита мощности.
#!/bin/bash
export CUDA_MODULE_LOADING=LAZY
# Включаем режим постоянного управления (Persistence Mode)
sudo nvidia-smi -pm 1
# ИСПРАВЛЕНО: Безопасный лимит мощности (карта не перегреется и удержит разгон)
sudo nvidia-smi -i 0 -pl 80
# Настройка охлаждения и разгона первой карты (index 0)
sudo nvidia-settings -a '[gpu:0]/GPUFanControlState=1'
sudo nvidia-settings -a '[fan:0]/GPUTargetFanSpeed=75'
sudo nvidia-settings -a '[gpu:0]/GPUMemoryTransferRateOffset[4]=800'
sudo nvidia-settings -a '[gpu:0]/GPUGraphicsClockOffset[4]=110'
sudo nvidia-settings -a '[gpu:0]/GPUPowerMizerMode=1'
./sd-server \
--listen-ip 127.0.0.1 \
--listen-port 1234 \
--diffusion-model "/home/intel42/Рабочий стол/AI_Models/Z-Image-Turbo/z_image_turbo-Q5_K_S.gguf" \
--vae "/home/intel42/Рабочий стол/AI_Models/Z-Image-Turbo/ae.safetensors" \
--llm "/home/intel42/Рабочий стол/AI_Models/Z-Image-Turbo/Qwen3-4B-Q8_0.gguf" \
--fa \
--color \
--threads 8 \
--eager-load \
--mmap \
--backend diffusion=CUDA0 \
--backend te=CPU \
--backend vae=CPU \
--steps 8 \
--cfg-scale 1 \
--sampling-method euler \
--scheduler sgm_uniform \
--width 896 \
--height 896 \
--vae-tiling \
--vae-relative-tile-size 0.25 \
--diffusion-conv-direct \
--vae-conv-direct
В данном сценарии разрешение генерации было намеренно снижено с целевых 1024×1024 до 896×896 пикселей. Это продиктовано тем, что при расчете геометрии тензоров Flow-Matching алгоритма в максимальном разрешении пиковый рабочий буфер cuMemCreate запрашивает около 690 MiB свободной памяти, что приводит к критической ошибке out of memory и аварийному останову на одиночной карте объемом 6GB. Снижение разрешения до 896×896 уменьшает вычислительный граф на ~25%, позволяя модели уложиться в локальные физические лимиты VRAM.
Генерация по промпту «Романтический отдых на пляже острова Таити на закате», скриншот интерфейса stable-diffusion.cpp в браузере:

Анализ логов инференса и временных затрат
При генерации изображения по промпту «Романтический отдых на пляже острова Таити на закате» сервер вывел в консоль следующие диагностические данные:
[INFO ] stable-diffusion.cpp:847 - Version: Z-Image
[INFO ] stable-diffusion.cpp:902 - Weight type stat: f32: 634 | q8_0: 253 | q5_K: 180 | bf16: 28
[INFO ] stable-diffusion.cpp:903 - Conditioner weight type stat: f32: 145 | q8_0: 253
[INFO ] stable-diffusion.cpp:904 - Diffusion model weight type stat: f32: 245 | q5_K: 180 | bf16: 28
[INFO ] stable-diffusion.cpp:905 - VAE weight type stat: f32: 244
[INFO ] model_loader.cpp:861 - using mmap for '/home/intel42/Рабочий стол/AI_Models/Z-Image-Turbo/z_image_turbo-Q5_K_S.gguf'
[INFO ] model_loader.cpp:861 - using mmap for '/home/intel42/Рабочий стол/AI_Models/Z-Image-Turbo/Qwen3-4B-Q8_0.gguf'
[INFO ] model_loader.cpp:861 - using mmap for '/home/intel42/Рабочий стол/AI_Models/Z-Image-Turbo/ae.safetensors'
[INFO ] stable-diffusion.cpp:1359 - using VAE for encoding / decoding
[INFO ] auto_encoder_kl.hpp:527 - vae decoder: ch = 128
[INFO ] stable-diffusion.cpp:1395 - Using Conv2d direct in the vae model
[INFO ] stable-diffusion.cpp:1463 - Using flash attention
[INFO ] stable-diffusion.cpp:1477 - Using flash attention in the diffusion model
[INFO ] model_loader.cpp:960 - memory-mapped 572 tensors in 2 files (4076.68 MB), taking 0.00s
|##################### | 453/1095 - 2.84GB/s
|####################################### | 851/1095 - 2.54GB/s
|##################################################| 1095/1095 - 2.44GB/s
[INFO ] model_loader.cpp:1272 - loading tensors completed, taking 2.11s (read: 0.75s, memcpy: 0.00s, convert: 0.06s, copy_to_backend: 0.48s)
[INFO ] stable-diffusion.cpp:1583 - total params memory size = 9187.26MB (VRAM 4950.83MB, RAM 4236.43MB): text_encoders 4076.43MB(RAM), diffusion_model 4950.83MB(VRAM), vae 160.00MB(RAM), controlnet 0.00MB(N/A), extensions 0.00MB(N/A)
[INFO ] stable-diffusion.cpp:1693 - running in FLOW mode
[INFO ] main.cpp:148 - listening on: http://127.0.0.1:1234
[INFO ] stable-diffusion.cpp:5258 - generate_image 896x896
[INFO ] stable-diffusion.cpp:2909 - Using 'z_image_omni' preset for reference images
[INFO ] denoiser.hpp:1050 - get_sigmas with SGM Uniform scheduler
[INFO ] stable-diffusion.cpp:4103 - sampling using Euler method
[INFO ] stable-diffusion.cpp:4938 - get_learned_condition completed, taking 53.17s
[INFO ] stable-diffusion.cpp:5309 - generating image: 1/1 - seed 42
|==================================================| 8/8 - 19.47s/it
[INFO ] stable-diffusion.cpp:5341 - sampling completed, taking 158.56s
[INFO ] stable-diffusion.cpp:5353 - generating 1 latent images completed, taking 158.56s
[INFO ] stable-diffusion.cpp:4963 - decoding 1 latents
|==================================================| 49/49 - 6.19s/it
[INFO ] stable-diffusion.cpp:5029 - latent 1 decoded, taking 305.82s
[INFO ] stable-diffusion.cpp:5033 - decode_first_stage completed, taking 305.82s
[INFO ] stable-diffusion.cpp:5491 - generate_image completed in 517.62s
Анализ лога выявляет серьезную проблему на этапе финальной сборки изображения. В строке распределения параметров total params memory size = 9187.26MB (VRAM 4950.83MB, RAM 4236.43MB) видно, что блок диффузии diffusion_model объемом 4950.83MB успешно занял видеопамять, текстовый энкодер ушел в ОЗУ, но из-за синтаксического сброса тяжелый модуль vae (160.00MB) также остался в системной оперативной памяти процессора (RAM).
Сэмплирование 8 шагов методом Эйлера на чистых CUDA-ядрах GTX 1660 Ti прошло с приемлемой скоростью 19.47 секунды на итерацию (суммарно 158.56с на фазу диффузии). Однако этап декодирования латентов (decoding 1 latents) силами центрального процессора i7-7700 занял катастрофические 305.82 секунды при скорости 6.19s/it. Общее время генерации одного кадра растянулось на 517.62 секунды, что делает использование стандартного VAE на CPU абсолютно нерентабельным.
Для исправления этого «бутылочного горлышка» и возврата этапа декодирования на аппаратную сторону GPU без риска переполнения памяти необходимо полностью исключить тяжелый VAE и задействовать микро-декодер семейства TAESD (taef1_decoder).
Генерация картинки с промтом «Романтический отдых на пляже острова Таити на закате» на видеокарте Nvidia GeForce GTX 1660 Ti (z_image_turbo-Q5_K_S.gguf + ae.safetensors + Qwen3-4B-Q8_0.gguf), 517.62s:

Для улучшения качества изображения в процесс генерации была добавлена lora размером 325GB:
./sd-server \
--listen-ip 127.0.0.1 \
--listen-port 1234 \
--diffusion-model "/home/intel42/Рабочий стол/AI_Models/Z-Image-Turbo/z_image_turbo-Q5_K_S.gguf" \
--llm "/home/intel42/Рабочий стол/AI_Models/Z-Image-Turbo/Qwen3-4B-Q8_0.gguf" \
--taesd "/home/intel42/Рабочий стол/AI_Models/taef1_decoder.safetensors" \
--lora-model-dir "/home/intel42/Рабочий стол/AI_Models/lora" \
--lora-apply-mode immediately \
--fa \
--color \
--threads 8 \
--eager-load \
--mmap \
--backend diffusion=CUDA0 \
--backend te=CPU \
--backend vae=CUDA0 \
--steps 8 \
--cfg-scale 1 \
--sampling-method euler \
--scheduler sgm_uniform \
--width 896 \
--height 896 \
--vae-tiling \
--vae-relative-tile-size 0.25 \
--diffusion-conv-direct \
--vae-conv-direct
В результате была получена картинка, соответствующая промту, но не учитывающая добавленной lora.
Изображение, полученное при генерации с промтом «Купальщица на пляже острова Таити на рассвете» на Nvidia GeForce GTX1660Ti 6GB (z_image_turbo-Q5_K_S.gguf + taef1_decoder.safetensors + Qwen3-4B-Q8_0.gguf) с подключенной, но неработающей lora, 225 секунд:

Логи генерации:
...
[INFO ] model_loader.cpp:242 - load /home/intel42/Рабочий стол/AI_Models/lora/zimage_lora_v1.safetensors using safetensors format
[INFO ] lora.hpp:45 - loading LoRA from '/home/intel42/Рабочий стол/AI_Models/lora/zimage_lora_v1.safetensors'
|##################################################| 480/480 - 0.00MB/s
[INFO ] model_loader.cpp:1272 - loading tensors completed, taking 0.20s (read: 0.00s, memcpy: 0.00s, convert: 0.00s, copy_to_backend: 0.00s)
|##################################################| 480/480 - 64.81MB/s
[INFO ] model_loader.cpp:1272 - loading tensors completed, taking 5.01s (read: 4.88s, memcpy: 0.00s, convert: 0.00s, copy_to_backend: 0.00s)
[INFO ] lora.hpp:891 - (0 / 480) LoRA tensors have been applied, lora_file_path = /home/intel42/Рабочий стол/AI_Models/lora/zimage_lora_v1.safetensors
[INFO ] stable-diffusion.cpp:4938 - get_learned_condition completed, taking 53.01s
[INFO ] stable-diffusion.cpp:5309 - generating image: 1/1 - seed 42
|##################################################| 452/452 - 641.44MB/s
[INFO ] model_loader.cpp:1272 - loading tensors completed, taking 7.72s (read: 2.10s, memcpy: 0.00s, convert: 0.00s, copy_to_backend: 0.15s)
[INFO ] model_loader.cpp:242 - load /home/intel42/Рабочий стол/AI_Models/lora/zimage_lora_v1.safetensors using safetensors format
[INFO ] lora.hpp:45 - loading LoRA from '/home/intel42/Рабочий стол/AI_Models/lora/zimage_lora_v1.safetensors'
|##################################################| 480/480 - 0.00MB/s
[INFO ] model_loader.cpp:1272 - loading tensors completed, taking 0.20s (read: 0.00s, memcpy: 0.00s, convert: 0.00s, copy_to_backend: 0.00s)
|##################################################| 480/480 - 54.01MB/s
[INFO ] model_loader.cpp:1272 - loading tensors completed, taking 6.01s (read: 5.80s, memcpy: 0.00s, convert: 0.00s, copy_to_backend: 0.03s)
[ERROR] ggml_extend.hpp:72 - ggml_backend_cuda_buffer_type_alloc_buffer: allocating 621.56 MiB on device 0: cudaMalloc failed: out of memory
[ERROR] ggml_extend.hpp:72 - ggml_gallocr_reserve_n_impl: failed to allocate CUDA0 buffer of size 651756032
[ERROR] ggml_extend.hpp:2166 - lora: failed to allocate the compute buffer
[ERROR] ggml_extend.hpp:2732 - lora alloc compute buffer failed
[INFO ] lora.hpp:891 - (480 / 480) LoRA tensors have been applied, lora_file_path = /home/intel42/Рабочий стол/AI_Models/lora/zimage_lora_v1.safetensors
|==================================================| 8/8 - 19.47s/it
[INFO ] stable-diffusion.cpp:5341 - sampling completed, taking 175.47s
[INFO ] stable-diffusion.cpp:5353 - generating 1 latent images completed, taking 175.47s
[INFO ] stable-diffusion.cpp:4963 - decoding 1 latents
|##################################################| 67/67 - 23.33MB/s
[INFO ] model_loader.cpp:1272 - loading tensors completed, taking 0.20s (read: 0.00s, memcpy: 0.00s, convert: 0.00s, copy_to_backend: 0.01s)
[INFO ] model_loader.cpp:242 - load /home/intel42/Рабочий стол/AI_Models/lora/zimage_lora_v1.safetensors using safetensors format
[INFO ] lora.hpp:45 - loading LoRA from '/home/intel42/Рабочий стол/AI_Models/lora/zimage_lora_v1.safetensors'
|##################################################| 480/480 - 0.00MB/s
[INFO ] model_loader.cpp:1272 - loading tensors completed, taking 0.20s (read: 0.00s, memcpy: 0.00s, convert: 0.00s, copy_to_backend: 0.00s)
|##################################################| 480/480 - 59.44MB/s
[INFO ] model_loader.cpp:1272 - loading tensors completed, taking 5.46s (read: 5.40s, memcpy: 0.00s, convert: 0.00s, copy_to_backend: 0.03s)
[INFO ] lora.hpp:891 - (0 / 480) LoRA tensors have been applied, lora_file_path = /home/intel42/Рабочий стол/AI_Models/lora/zimage_lora_v1.safetensors
|==================================================| 49/49 - 7.75it/s
[INFO ] stable-diffusion.cpp:5029 - latent 1 decoded, taking 12.79s
[INFO ] stable-diffusion.cpp:5033 - decode_first_stage completed, taking 12.79s
[INFO ] stable-diffusion.cpp:5491 - generate_image completed in 241.32s
Анализ лога:
1. Строка-индикатор: (0 / 480) LoRA tensors have been applied… При старте сервера в режиме immediately движок попытался задействовать LoRA. При этом ядро сервера на первом этапе заблокировало статическое впекание из-за несовместимости типов весов (о чем честно говорит 0 / 480).
На этапе сэмплирования движок перешел к генерации, и ему пришлось применить адаптер динамически. По логу видно, что файл zimage_lora_v1.safetensors весом в 480 тензоров считывался и обрабатывался три раза подряд. Каждая такая итерация создавала теневые буферы в памяти, поэтому в пиковый момент третьего прохода драйвер выдал ошибку:
allocating 621.56 MiB on device 0: cudaMalloc failed: out of memory
Движок sd.cpp перенаправил сбойный кусок вычислений на CPU в системную оперативную память хоста, но lora реально не приценилась, о чем свидетельствует строка:
stable-diffusion.cpp:1964 - apply_loras completed, taking 0.00s
Время работы 0.00 секунд означает, что сервер просто пропустил этот этап при запросе.
Для обеспечения полной функциональности LoRA и апскейлеров был уменьшен размер используемой модели путем перехода на z-image-turbo-q4_k_s.gguf размером ~ 4GB (на 0.8GB меньше). Благодаря этому освободилась память и появилась возможность практического использования lora и апскейлеров. Запуск с lora:
./sd-server \
--listen-ip 127.0.0.1 \
--listen-port 1234 \
--diffusion-model "/home/intel42/Рабочий стол/AI_Models/Z-Image-Turbo/z_image_turbo-Q4_1.gguf" \
--llm "/home/intel42/Рабочий стол/AI_Models/Z-Image-Turbo/Qwen3-4B-Q8_0.gguf" \
--taesd "/home/intel42/Рабочий стол/AI_Models/taef1_decoder.safetensors" \
--lora-model-dir "/home/intel42/Рабочий стол/AI_Models/lora" \
--fa \
--color \
--threads 8 \
--eager-load \
--mmap \
--backend diffusion=CUDA0 \
--backend te=CPU \
--backend vae=CUDA0 \
--steps 8 \
--cfg-scale 1 \
--sampling-method euler \
--scheduler sgm_uniform \
--width 896 \
--height 896 \
--vae-tiling \
--vae-relative-tile-size 0.25 \
--diffusion-conv-direct \
--vae-conv-direct
Генерация в z-image-turbo-q4_k_s.gguf + taef1_decoder + lora на GPU + Qwen3-4B-Q8_0.gguf на CPU:

Благодаря переходу на максимально оптимизированный профиль базовой модели, физический вес диффузионного ядра в VRAM был снижен до 3678.41 MB, что высвободило более 2.3 ГБ VRAM. Благодаря этому, при запуске сервера в штатном режиме автоматического рантайм-наложения, диагностические логи зафиксировали успешную генерацию:
[INFO ] stable-diffusion.cpp:1349 - using TAE for encoding / decoding
[INFO ] stable-diffusion.cpp:1964 - apply_loras completed, taking 4.93s
...
|==================================================| 8/8 - 21.41s/it
[INFO ] stable-diffusion.cpp:5341 - sampling completed, taking 171.34s
[INFO ] stable-diffusion.cpp:5029 - latent 1 decoded, taking 6.30s (7.75it/s)
[INFO ] lora.hpp:891 - (480 / 480) LoRA tensors have been applied
[INFO ] stable-diffusion.cpp:5491 - generate_image completed in 183.73s
Созданный запас памяти позволяет полностью локализовать тяжелые рантайм-буферы адаптера lora внутри видеопамяти без сброса вычислений на CPU. Исключение пограничного дефицита VRAM защищает математику CUDA от микро-округлений и предотвращает появление критических неопределенностей. Конвейер успешно удерживает Loss-стабильность, выдавая на выходе изображение с наложением стилистики LoRA. Время сэмплирования на чистых CUDA-ядрах Turing без Tensor Cores составило 21.4 секунды на итерацию (с учетом рантайм-оверхеда адаптера). Фаза декодирования латентов через TAESD заняла 6.3 секунды. Общий цикл генерации «под ключ» уложился в 183 секунды (чуть более 3 минут).
Учитывая наличие свободной видеопамяти, можно увеличить размер генерируемой картинки, добавив 4xupscaler:
./sd-server \
--listen-ip 127.0.0.1 \
--listen-port 1234 \
--diffusion-model "/home/intel42/Рабочий стол/AI_Models/Z-Image-Turbo/z_image_turbo-Q4_1.gguf" \
--llm "/home/intel42/Рабочий стол/AI_Models/Z-Image-Turbo/Qwen3-4B-Q8_0.gguf" \
--taesd "/home/intel42/Рабочий стол/AI_Models/taef1_decoder.safetensors" \
--upscale-model "/home/intel42/Рабочий стол/AI_Models/Z-Image-Turbo/RealESRGAN_x4plus.pth" \
--fa \
--color \
--threads 8 \
--eager-load \
--mmap \
--backend diffusion=CUDA0 \
--backend te=CPU \
--backend vae=CPU \
--steps 8 \
--cfg-scale 1 \
--sampling-method euler \
--scheduler sgm_uniform \
--width 512 \
--height 512 \
--vae-tiling \
--vae-relative-tile-size 0.25 \
--diffusion-conv-direct \
--vae-conv-direct \
--hires
Генерация по развернутому промту «A cinematic highly detailed book illustration of a mystical ancient Slavic fairy tale. In the center, a large, intelligent black and silver siberian cat with glowing emerald eyes, holding a giant vintage leather-bound book, walking majestically on a massive, heavy shimmering golden chain. The golden chain is wrapped around a colossal, ancient gnarled oak tree with deep textured bark and lush, vibrant green leaves. The setting is Lukomorye, a magical dark fantasy forest at twilight, with ethereal glowing mushrooms, mossy roots, and a distant mystical foggy sea coast with incoming waves. Enchanted atmosphere, rich oil painting style with hyper-realistic textures, volumetric golden sunset lighting filtering through the branches, cinematic composition, depth of field, masterpiece, 8k resolution, folklore art»:

Заключение и некоторые советы по генерации картинок на домашних компьютерах
На компьютере с небольшим объемом оперативной памяти браузер со множеством открытых вкладок может привести к переполнению ОЗУ и переходу в «режим торможения» из-за активации файла подкачки.
Чтобы максимально освободить память, можно закрыть браузер, генерируя картинки из консоли.
Для освобождения ресурсов можно использовать более агрессивную квантизацию моделей, но это приведет к неизбежной потере качества, правда, не столь заметной.
Если процессор имеет интегрированное видеоядро (iGPU), обязательно подключите монитор к материнской плате, а не к дискретной видеокарте. Перенос отрисовки рабочего стола и браузера на встроенную графику (например, Intel HD Graphics через драйвер Iris) очистит до 500–800 МБ критически важной видеопамяти (VRAM), защитив ИИ-конвейер от вылетов по ошибке cudaMalloc.
При генерации желательно отключать стандартный автоэнкодер (VAE) весом в сотни мегабайт и использовать микро-декодеры семейства TAESD (например, flux_taesd.gguf или taef1_decoder.safetensors). Они сжимают блок сборки картинок в памяти до единиц мегабайт, что не только экономит VRAM, но и ускоряет фазу финального декодирования кадра на GPU в десятки раз (с минут до долей секунды).
Во время генерации диффузии CUDA-ядра видеокарты загружаются на 100%, что приводит к резкому нагреву видеокарты. Чтобы избежать сброса частот из-за перегрева (термотроттлинга), нужно принудительно зажимать лимит мощности карты через nvidia-smi -pl. Ограничение потребления (например, до 75–80W для карт серии GTX 1660) снижает производительность всего на 1–2%, но удерживает чип в холодном и стабильном состоянии без просадок по частоте.
При генерации желательно активировать в инференс-движках низкоуровневые оптимизации diffusion-conv-direct и fa (Flash Attention). Прямой обсчет сверточных слоев в CUDA-ядрах (в обход промежуточных трансформаций в памяти) дает чистый прирост скорости генерации шагов до 15–20% на видеокартах без тензорных ядер.
Если параллельно тестируется несколько тяжелых ИИ-моделей подряд, Linux-ядро начинает кэшировать гигабайты прочитанных данных в оперативную память. Перед каждым новым запуском сервера нужно очищать кэш ядра командой
echo 3 | sudo tee /proc/sys/vm/drop_caches
чтобы вернуть операционной системе весь объем чистой RAM и вернуть отзывчивость интерфейса.
Для систем с 16GB оперативной памяти неоценимую поддержку окажет активация планировщика сжатия одинаковых страниц памяти в ядре (uksm или ksm). Поскольку текстовые энкодеры уровня Qwen-4B или T5-XXL занимают много места, дедупликация страниц памяти позволяет «выжать» дополнительно до 1.5–2 ГБ свободного пространства в RAM хоста под нужды системы. Для этого нужно использовать соответствующее ядро linux.

Сводный чек-лист по оптимизации домашнего ПК под ИИ-инференс:
- Консольный режим: Закрывайте тяжелые браузеры во время генерации. Запуск sd-server напрямую из терминала предотвращает уход системы в swap.
- Разумное квантование: Переходите на 4-битные или 5-битные кванты (Q4_K_S / Q5_K_S). Потеря художественного качества при этом практически незаметна глазу, но вес модели падает на гигабайты.
- Разгрузка VRAM через iGPU: Выводите рабочий стол на встроенную графику процессора.
- Отказ от классического VAE: Используйте исключительно специализированные под вашу архитектуру микро-декодеры TAESD.
- Тепловой контроль: Зажимайте Power Limit видеокарты и принудительно поднимайте обороты кулеров перед стартом генерации.


