- Extract model loading from generate()/edit() into VnAssetsSession class - Session eagerly loads SDXL + Qwen Image Edit at construction (28s, once) - Both models held in GPU memory across calls; generate()/edit() reuse them - generate.py and edit.py become thin wrappers (backwards compatible CLI) - Context manager (with VnAssetsSession(...) as vna:) for library use - Metadata backwards-compatible: all fields preserved including lora_load_s - load_time_s now reflects total session construction, amortized across calls - Add performance stats for edit path (Qwen Image Edit + Lightning LoRA) - Benchmark matmul fallback (86.8s) vs flash attention (53.3s, 1.63x speedup) - Session vs cold start comparison: 2 ops save one 28s load, 5 edits save 112s - Flash attention via TORCH_ROCM_AOTRITON_ENABLE_EXPERIMENTAL=1 documented
VNAsset
Fast CLI pipeline for visual novel image asset generation.
Drop-in replacement for the ComfyUI workflow loop: generate base character sprites with SDXL, then batch-edit variants (expressions, outfits) with Qwen Image Edit — all in one warm session, no node-graph overhead.
Hardware
Built for AMD Strix Halo (Ryzen AI Max 395 Pro, Radeon 8060S, 128 GB unified memory). Also works on discrete AMD GPUs with ROCm. NVIDIA support is untested but should work if you swap the torch backend.
Install
git clone <repo> vnassets
cd vnassets
# Create venv (Python 3.12 required for ROCm torch compatibility)
python3.12 -m venv .venv
source .venv/bin/activate
# Install ROCm PyTorch (adjust index URL for your ROCm version)
pip install torch --index-url https://download.pytorch.org/whl/rocm7.2
# Install the rest
pip install -e .
Models
Symlink your ComfyUI models into models/:
cd models
ln -s /path/to/ComfyUI/models/checkpoints/novaAnimeXL_ilV190.safetensors .
ln -s /path/to/ComfyUI/models/diffusion_models/qwen_image_edit_2509_fp8_e4m3fn.safetensors .
ln -s /path/to/ComfyUI/models/text_encoders/qwen_2.5_vl_7b_fp8_scaled.safetensors .
ln -s /path/to/ComfyUI/models/vae/qwen_image_vae.safetensors .
ln -s /path/to/ComfyUI/models/loras/Qwen-Image-Edit-2509-Lightning-4steps-V1.0-bf16.safetensors .
Or place the actual files there — the tool just reads whatever safetensors you point it at.
Usage
Generate (SDXL text-to-image)
vnasset generate \
--checkpoint models/novaAnimeXL_ilV190.safetensors \
--prompt "1girl, solo, red hair, glasses, blue eyes, white crop top, standing, portrait" \
--negative-prompt "deformed, ugly, bad quality, lowres" \
--steps 20 \
--seed 42 \
--output output/character_base.png
| Option | Default | Description |
|---|---|---|
--checkpoint |
(required) | Path to SDXL .safetensors |
--prompt |
(required) | Positive prompt |
--negative-prompt |
"" |
Negative prompt |
--width |
1024 |
Image width |
--height |
1024 |
Image height |
--steps |
20 |
Inference steps |
--cfg |
4.5 |
CFG scale |
--seed |
0 |
RNG seed (use random for random) |
--output |
output.png |
Output path |
--raw |
false |
Disable Compel prompt weighting (fall back to plain diffusers encoding) |
When --seed is random, a random seed is generated and recorded in the
metadata file.
Output
Each generation produces:
{output}.png— the image{output}.json— metadata (prompt, seed, model path, timing, resolution)
Directories in --output are created automatically.
Edit (Qwen Image Edit)
vnasset edit \
--model models/qwen_image_edit_2509_fp8_e4m3fn.safetensors \
--input character_base.png \
--prompt "make her smile happily" \
--steps 4 --cfg 1.0 \
--lora models/Qwen-Image-Edit-2509-Lightning-4steps-V1.0-bf16.safetensors \
--output character_happy.png
| Option | Default | Description |
|---|---|---|
--model |
(required) | Path to Qwen Image Edit .safetensors |
--input |
(required) | Input image to edit |
--prompt |
(required) | Edit instruction |
--steps |
20 |
Inference steps (4 with Lightning LoRA) |
--cfg |
4.0 |
CFG scale (1.0 with Lightning LoRA) |
--seed |
random |
RNG seed |
--lora |
(none) | Path to LoRA .safetensors |
--output |
output.png |
Output path |
Current State
| Command | Status |
|---|---|
vnasset generate |
✅ Working |
vnasset edit |
✅ Working |
vnasset pipeline |
🚧 Planned |
Performance
Generate (SDXL)
Radeon 8060S (Strix Halo iGPU), bfloat16, 1024×1024:
- ~1s per step
- ~20s for 20-step generation
Model loading adds ~5s cold-start overhead.
Edit (Qwen Image Edit)
Radeon 8060S, bfloat16:
- ~120s per step at 512×512
- ~23s model loading
Larger resolutions scale proportionally. The SDPA math fallback in the text encoder's visual branch and the transformer's attention blocks is the main bottleneck.
Turbo mode: Use the Lightning 4-step LoRA with --steps 4 --cfg 1.0 to
cut per-step time proportionally (4× fewer steps).
Technical Notes
bfloat16 required on RDNA 3.5
float16 causes GPU kernel crashes (segfault) on the Radeon 8060S. The tool
uses bfloat16 internally. This is transparent to the user.
Custom attention
The default PyTorch SDPA backends (flash attention, mem-efficient attention) are unstable on this AMD GPU. VNAsset uses a simple matmul-based attention implementation that avoids the SDPA dispatch entirely.
ROCm torch version
Tested with torch 2.11.0+rocm7.2. Newer ROCm nightlies (2.13+, 2.14+) may
cause GPU crashes. If you encounter segfaults, try matching this version.
Documentation
- SDXL Generation — checkpoint loading, attention patches, prompt encoding, and generation pipeline details
- ComfyUI Prompt Style Support — prompt weighting and BREAK syntax specification
Prompt Syntax
VNAsset supports ComfyUI-style prompt weighting via the compel library.
Weighting
| Syntax | Effect |
|---|---|
(word) |
Boost ×1.1 |
(word:1.5) |
Boost ×1.5 |
(word:0.6) |
De-emphasize ×0.6 |
[word] |
De-emphasize ×0.9 (shorthand) |
\(word\) |
Literal parentheses (escaped) |
vnasset generate \
--checkpoint models/novaAnimeXL_ilV190.safetensors \
--prompt "(masterpiece:1.2), 1girl, (red hair:1.3), blue eyes, [glasses]" \
--negative-prompt "(bad quality, worst quality:1.4)" \
--steps 20 --seed 42
BREAK (condition chunking)
Split the prompt into independent conditioning chunks with BREAK:
vnasset generate \
--prompt "1girl, red hair, standing BREAK blue sky, cherry blossoms" \
--steps 20 --seed 42
Use --raw to bypass weighting and fall back to plain diffusers encoding.
Future Improvements
- Persistent model session — keep models loaded between commands to
eliminate the ~5s cold-start overhead per generation. A
vnasset servedaemon orvnasset batchcommand. torch.compileon UNet — the UNet forward is identical each step; ROCm'storch.compilesupport is maturing and could cut per-step time in half.- Self-contained torch wheel — bundle the known-working torch wheel file in
the project (
wheels/torch-2.11.0+rocm7.2-cp312-cp312-linux_x86_64.whl) so the install is reproducible without depending on PyTorch's nightly index availability or a ComfyUI installation. - Qwen Image Edit support —
vnasset editandvnasset pipelinefor batch expression/outfit variant editing.