AI и DIY,  Статьи

Генерация картинок в 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.

    Сводный чек-лист по оптимизации домашнего ПК под ИИ-инференс:

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

    Добавить комментарий

    Ваш адрес email не будет опубликован. Обязательные поля помечены *