takaisin

Intel B70 ja AMD 9070 XT

CachyOS, ComfyUI, llama.cpp, Krita AI, OneTrainer, AMD 9070 XT (ROCm/Vulkan), Intel B70 (XPU/SYCL)

Skriptidumppi. Tuskin toimii sellaisenaan omalla koneella. Pyydä LLM lukemaan tämä sivu ja muokkaamaan toimiva koodi, tai käytä jotain helpompaa valmista, kuten Stability Matrix tai Odysseus.

Ei lataa ~/ai/models tiedostoja.

kokoonpano
# B70 on oikeasti kakkoskortti hitaammassa PCIe-väylässä, mutta softat näyttää välillä näin päin
[hans@pcmr ~]$ inxi -GSD -mm
System:
  Host: pcmr Kernel: 7.2.0-1-cachyos arch: x86_64 bits: 64
  Desktop: KDE Plasma v: 6.7.4 Distro: CachyOS
Memory:
  System RAM: total: 64 GiB available: 62.71 GiB used: 8.7 GiB (13.9%)
  Array-1: capacity: 128 GiB slots: 4 modules: 4 EC: None
  Device-1: Channel-A DIMM 0 type: DDR4 size: 16 GiB speed: 3200 MT/s
  Device-2: Channel-A DIMM 1 type: DDR4 size: 16 GiB speed: 3200 MT/s
  Device-3: Channel-B DIMM 0 type: DDR4 size: 16 GiB speed: 3200 MT/s
  Device-4: Channel-B DIMM 1 type: DDR4 size: 16 GiB speed: 3200 MT/s
Graphics:
  Device-1: Intel Battlemage G31 [Arc Pro B70] driver: xe v: kernel
  Device-2: Advanced Micro Devices [AMD/ATI] Navi 48 [Radeon RX 9070/9070
    XT/9070 GRE] driver: amdgpu v: kernel
  Display: wayland server: X.org v: 1.21.1.24 with: Xwayland v: 24.1.13
    compositor: kwin_wayland driver: gpu: amdgpu resolution: 3840x2160~120Hz
  API: EGL v: 1.5 drivers: iris,radeonsi,swrast
    platforms: gbm,wayland,x11,surfaceless,device
  API: OpenGL v: 4.6 vendor: amd mesa v: 26.3.0-devel renderer: AMD Radeon
    RX 9070 XT (radeonsi gfx1201 ACO DRM 3.64 7.2.0-1-cachyos)
  API: Vulkan v: 1.4.357 drivers: radv,intel,llvmpipe surfaces: N/A
  Info: Tools: api: clinfo, eglinfo, glxinfo, vulkaninfo
    de: kscreen-console,kscreen-doctor gpu: amd-smi, amdgpu_top, gputop,
    intel_gpu_top, lsgpu, lact, nvidia-smi wl: wayland-info
    x11: xdpyinfo, xprop, xrandr
Drives:
  Local Storage: total: 8.19 TiB used: 4.77 TiB (58.2%)
  ID-1: /dev/nvme0n1 vendor: Samsung model: SSD 990 PRO with Heatsink 4TB
    size: 3.64 TiB
  ID-2: /dev/sda vendor: Western Digital model: WD50NDZW-11BCSS1
    size: 4.55 TiB type: USB
[hans@pcmr ~]$ cat /proc/cmdline 
nvme_core.default_ps_max_latency_us=0 nvme.poll_queues=8 hpet=disable amdgpu.freesync_video=1 amdgpu.wbrf=0 amdgpu.seamless=1 xe.force_probe=e223 pcie_aspm=off pci=noaer iommu=pt usbcore.autosuspend=-1 amdgpu.ppfeaturemask=0xffffffff mitigations=off nokaslr norandmaps split_lock_detect=off split_lock_mitigate=0 quiet rw rootflags=subvol=/@ root=UUID=REDACTED
hakemistorakenne
~/ai/cache

~/ai/input/lähdekuva.png

~/ai/models/audio_encoders
~/ai/models/checkpoints
~/ai/models/clip_vision
~/ai/models/configs
~/ai/models/controlnet
~/ai/models/diffusers
~/ai/models/diffusion_models
~/ai/models/inpaint
~/ai/models/ipadapter
~/ai/models/latent_upscale_models
~/ai/models/llm
~/ai/models/llm_aux
~/ai/models/llm_presets
~/ai/models/loras
~/ai/models/model_patches
~/ai/models/sams
~/ai/models/style_models
~/ai/models/text_encoders
~/ai/models/ultralytics
~/ai/models/upscale_models
~/ai/models/vae

~/ai/onetrainer

~/ai/output/generoitu_kuva.png
~/ai/output/video/generoitu_video.mp4

~/ai/rocm

~/ai/src

~/ai/training/datasets/onetrainer_lähdedata

~/ai/user/default/workflows/comfy_workflow.json

~/ai/xpu

Bash-skripti

updateai
#!/usr/bin/env bash
# ~/.local/bin/updateai
# updateai — CachyOS dual ComfyUI + llama.cpp + OneTrainer
#   rocm       : ComfyUI ROCm + llama.cpp Vulkan  → ${HOME}/ai/rocm
#   xpu        : ComfyUI XPU  + llama.cpp SYCL    → ${HOME}/ai/xpu
#   onetrainer : OneTrainer XPU (PR 1413)         → ${HOME}/ai/onetrainer
# Runtime: CachyOS, uv, no containers. Requires Bash 5+, uv, git, curl,
#          makepkg+sudo (ROCm), cmake, vulkan-headers, shaderc, spirv-headers,
#          Intel oneAPI Base Toolkit (SYCL). Optional: ccache, ninja.
set -euo pipefail

readonly BASEDIR="${HOME}/ai"
readonly CACHE_DIR="${BASEDIR}/cache"
readonly PYTHON_VER="3.13"
readonly UV_INSTALL_URL="https://astral.sh/uv/install.sh"
readonly ROCM_PATH="/opt/rocm"
readonly ROCM_NIGHTLY_INDEX="https://rocm.nightlies.amd.com/v2-staging/gfx120X-all/"
readonly ROCM_TARBALL_BASE="https://rocm.nightlies.amd.com/tarball-multi-arch"
readonly PYTORCH_XPU_INDEX="https://download.pytorch.org/whl/nightly/xpu"
readonly PYTORCH_XPU_STABLE_INDEX="https://download.pytorch.org/whl/xpu"
readonly ONETRAINER_REPO="https://github.com/Nerogar/OneTrainer.git"
readonly ONETRAINER_DIR="${BASEDIR}/onetrainer"
readonly ONETRAINER_PR="1413"
readonly ONETRAINER_DIFFUSERS_REF="1ffa423"
readonly ONETRAINER_MGDS_REF="3a6994a"
readonly ONETRAINER_MUON_REF="f90a42b"
readonly LLAMA_CPP_REPO="https://github.com/ggml-org/llama.cpp.git"
readonly LLAMA_SRC_DIR="${BASEDIR}/src/llama.cpp"
readonly ONEAPI_SETVARS="/opt/intel/oneapi/setvars.sh"
readonly UNIT_DIR="${HOME}/.config/systemd/user"
readonly APP_DIR="${HOME}/.local/share/applications"
readonly LLM_MODELS_DIR="${BASEDIR}/models/llm"
readonly LLM_AUX_DIR="${BASEDIR}/models/llm_aux"
readonly LLM_PRESETS_DIR="${BASEDIR}/models/llm_presets"
readonly LLM_PRESET_FILE_16GB="${LLM_PRESETS_DIR}/16gb.ini"
readonly LLM_PRESET_FILE_32GB="${LLM_PRESETS_DIR}/32gb.ini"
readonly LLM_PRESET_FILE_SYSTEM_PROMPT_EN="${LLM_PRESETS_DIR}/system_prompt_en.txt"
readonly LLM_PRESET_FILE_SYSTEM_PROMPT_FI="${LLM_PRESETS_DIR}/system_prompt_fi.txt"
readonly LLM_PRESET_FILE_ONETRAINER_APP="${APP_DIR}/OneTrainer.desktop"
readonly RADEON_ICD="/usr/share/vulkan/icd.d/radeon_icd.x86_64.json"

readonly REPOS=(
    "https://github.com/Acly/comfyui-inpaint-nodes comfyui_inpaint_nodes"
    "https://github.com/Acly/comfyui-tooling-nodes comfyui_tooling_nodes"
    "https://github.com/AIToldMeTo/comfyui-cache-cleaner comfyui_cache_cleaner"
    "https://github.com/alexopus/ComfyUI-Image-Saver comfyui_image_saver"
    "https://github.com/Azornes/Comfyui-Resolution-Master comfyui_resolution_master"
    "https://github.com/BadCafeCode/masquerade-nodes-comfyui masquerade_nodes_comfyui"
    "https://github.com/Billy024/comfyui-aspect-ratio-crop-node comfyui_aspect_ratio_crop_node"
    "https://github.com/chflame163/ComfyUI_LayerStyle comfyui_layerstyle"
    "https://github.com/chrisgoringe/cg-use-everywhere cg_use_everywhere"
    "https://github.com/city96/ComfyUI-GGUF comfyui_gguf"
    "https://github.com/ClownsharkBatwing/RES4LYF res4lyf"
    "https://github.com/crystian/ComfyUI-Crystools comfyui_crystools"
    "https://github.com/cubiq/ComfyUI_essentials comfyui_essentials"
    "https://github.com/cubiq/ComfyUI_IPAdapter_plus comfyui_ipadapter_plus"
    "https://github.com/DoctorDiffusion/ComfyUI-MediaMixer comfyui_mediamixer"
    "https://github.com/Fannovel16/comfyui_controlnet_aux comfyui_controlnet_aux"
    "https://github.com/Fannovel16/ComfyUI-Frame-Interpolation comfyui_frame_interpolation"
    "https://github.com/JPS-GER/ComfyUI_JPS-Nodes comfyui_jps_nodes"
    "https://github.com/kijai/ComfyUI-KJNodes comfyui_kjnodes"
    "https://github.com/kijai/ComfyUI-MelBandRoFormer comfyui_melbandroformer"
    "https://github.com/Kosinkadink/ComfyUI-VideoHelperSuite comfyui_videohelpersuite"
    "https://github.com/LAOGOU-666/Comfyui-Memory_Cleanup comfyui_memory_cleanup"
    "https://github.com/ltdrdata/ComfyUI-Impact-Pack comfyui_impact_pack"
    "https://github.com/ltdrdata/ComfyUI-Impact-Subpack comfyui_impact_subpack"
    "https://github.com/ltdrdata/ComfyUI-Manager comfyui_manager"
    "https://github.com/orssorbit/ComfyUI-wanBlockswap comfyui_wanblockswap"
    "https://github.com/pythongosssss/ComfyUI-Custom-Scripts comfyui_custom_scripts"
    "https://github.com/rgthree/rgthree-comfy rgthree_comfy"
    "https://github.com/SeanScripts/ComfyUI-Unload-Model comfyui_unload_model"
    "https://github.com/Smirnov75/ComfyUI-mxToolkit comfyui_mxtoolkit"
    "https://github.com/tritant/ComfyUI_Custom_Switch comfyui_custom_switch"
    "https://github.com/WASasquatch/was-node-suite-comfyui was_node_suite_comfyui"
    "https://github.com/yolain/ComfyUI-Easy-Use comfyui_easy_use"
)

start_time=${SECONDS}
CMAKE_GENERATOR_ARGS=()
NOTES=()

log() { printf '\n=== %s ===\n\n' "$*"; }
die() { printf 'ERROR: %s\n' "$*" >&2; exit 1; }
note() { NOTES+=("$1"); }
print_notes() {
    local n
    for n in "${NOTES[@]}"; do
        printf '\n%s\n' "$n"
    done
}

usage() {
    cat <<EOF
Usage: $(basename "$0") [rocm|xpu|onetrainer|all]
  rocm        ComfyUI ROCm + llama.cpp Vulkan   \${BASEDIR}/rocm
  xpu         ComfyUI XPU  + llama.cpp SYCL     \${BASEDIR}/xpu
  onetrainer  OneTrainer XPU (PR ${ONETRAINER_PR})
  all         rocm + xpu + onetrainer

Services:
  comfy-rocm.service     :8189
  llama-vulkan.service   :9932
  comfy-xpu.service      :8188
  llama-sycl.service     :9931
EOF
    exit 1
}

ensure_uv() {
    export PATH="${HOME}/.local/bin:${PATH}"
    if command -v uv >/dev/null 2>&1; then
        log "uv already installed ($(uv --version 2>/dev/null || echo unknown))"
        return 0
    fi
    log "Installing uv"
    curl -LsSf "${UV_INSTALL_URL}" | sh
    export PATH="${HOME}/.local/bin:${PATH}"
}

stop_service() {
    systemctl --user daemon-reload >/dev/null 2>&1 || true
    systemctl --user stop "$1" >/dev/null 2>&1 || true
}

enable_units() {
    mkdir -p "${UNIT_DIR}"
    systemctl --user daemon-reload
}

clean_base() {
    log "Completely reinstalling $1"
    rm -rf "$1"
    mkdir -p "$1"
}

ensure_shared_dirs() {
    local -a dirs=(
        "${BASEDIR}/input" "${BASEDIR}/output" "${BASEDIR}/user"
        "${BASEDIR}/models" "${LLM_MODELS_DIR}" "${LLM_AUX_DIR}" "${LLM_PRESETS_DIR}"
        "${CACHE_DIR}/tunableop" "${CACHE_DIR}/miopen" "${CACHE_DIR}/triton"
        "${CACHE_DIR}/sycl" "${CACHE_DIR}/torchinductor" "${UNIT_DIR}" "${APP_DIR}"
    )
    local d
    for d in "${dirs[@]}"; do
        mkdir -p "${d}"
    done
}

git_rev() {
    git -C "$1" rev-parse --short HEAD 2>/dev/null || echo unknown
}

write_manifest() {
    local dest=$1
    shift
    {
        printf 'updated=%s\n' "$(date -Iseconds)"
        printf 'llama_src=%s\n' "$(git_rev "${LLAMA_SRC_DIR}")"
        printf '%s\n' "$@"
    } > "${dest}"
}

# ---------------------------------------------------------------------------
# ComfyUI + venv
# ---------------------------------------------------------------------------
setup_venv_and_comfy() {
    local basedir=$1
    cd "${basedir}"
    log "Creating Python ${PYTHON_VER} venv and cloning ComfyUI"
    uv venv --python "${PYTHON_VER}" venv
    # shellcheck source=/dev/null
    source venv/bin/activate
    git clone --quiet --no-tags --depth 1 https://github.com/comfyanonymous/ComfyUI comfy
    cd comfy
}

install_custom_nodes() {
    log "Installing ComfyUI custom nodes (parallel)"
    mkdir -p custom_nodes
    cd custom_nodes
    printf '%s\n' "${REPOS[@]}" | xargs -P "$(nproc)" -L 1 sh -c '
        git clone --quiet --no-tags --depth 1 "$0" "$1" || { echo "FAIL $0" >&2; exit 1; }
    '
    cd ..
}

update_pip_and_requirements() {
    log "Upgrading pip and installing requirements"
    uv pip install --upgrade pip wheel wheel_stub
    local -a req_args=("-r" "requirements.txt")
    local req_file
    while IFS= read -r -d '' req_file; do
        [[ -s "${req_file}" ]] && req_args+=("-r" "${req_file}")
    done < <(find custom_nodes -name "requirements.txt" -type f -print0)
    uv pip install --upgrade "${req_args[@]}"
}

setup_extra_model_paths() {
    log "Configuring extra_model_paths.yaml"
    local -a modeldirs=(
        audio_encoders checkpoints clip_vision configs controlnet
        diffusion_models inpaint ipadapter latent_upscale_models
        loras model_patches sams style_models text_encoders
        llm llm_aux llm_presets ultralytics upscale_models vae
    )
    {
        printf 'my_models:\n  base_path: %s\n' "${BASEDIR}/models"
        local dir
        for dir in "${modeldirs[@]}"; do
            mkdir -p "${BASEDIR}/models/${dir}"
            printf '  %s: %s\n' "${dir}" "${dir}"
        done
    } > extra_model_paths.yaml
}

# ---------------------------------------------------------------------------
# llama.cpp
# ---------------------------------------------------------------------------
ensure_llm_preset() {
    log "Writing LLM preset: ${LLM_PRESET_FILE_16GB}"
    cat > "${LLM_PRESET_FILE_16GB}" <<PRESET_EOF
# 16 GiB VRAM (primary desktop GPU, single user)
# ${LLM_PRESET_FILE_16GB}
[*]
flash-attn = on
gpu-layers = all
parallel = 1
cache-type-k = q4_0
cache-type-v = q4_0
batch-size = 384
ubatch-size = 384
load-mode = mlock
spec-type = draft-mtp,ngram-mod
spec-draft-n-max = 2
spec-ngram-mod-n-match = 24
spec-ngram-mod-n-min = 24
spec-ngram-mod-n-max = 32
image-min-tokens = 1024
image-max-tokens = 2048

# KV cache VRAM
# Qwen3.8-27B: 16 attn layers × 4 KV heads × 256 dim × 2 (K+V)
# q4_0/q4_0: 0.5 B/elem → 16 KiB/token → GiB ≈ ctx / 65536
# https://datakeskus.io/files/qwen38-27b-kv-cache.txt
#ctx-size = 2048    # 0.03 GiB
#ctx-size = 4096    # 0.06 GiB
#ctx-size = 6144    # 0.09 GiB
#ctx-size = 8192    # 0.13 GiB
#ctx-size = 16384   # 0.25 GiB
#ctx-size = 32768   # 0.50 GiB
#ctx-size = 49152   # 0.75 GiB
#ctx-size = 65536   # 1.00 GiB
#ctx-size = 81920   # 1.25 GiB
#ctx-size = 98304   # 1.50 GiB
#ctx-size = 114688  # 1.75 GiB
#ctx-size = 131072  # 2.00 GiB
#ctx-size = 147456  # 2.25 GiB
#ctx-size = 163840  # 2.50 GiB
#ctx-size = 180224  # 2.75 GiB
#ctx-size = 196608  # 3.00 GiB
#ctx-size = 229376  # 3.50 GiB
#ctx-size = 245760  # 3.75 GiB
#ctx-size = 262144  # 4.00 GiB

# Model VRAM
# Qwen3.8-27B-ZB4.00-MIN-v3-IQ4_XS.gguf     12.7 GiB
# mmproj-Qwen3.8-27B-BF16.gguf              0.89 GiB
# https://huggingface.co/tooltd/Qwen3.8-27B-IQ4-XS-16GB-VRAM-GGUF
# https://huggingface.co/ggml-org/Qwen3.8-27B-GGUF

[Instruct]
ctx-size = 32768
temperature = 0.7
top-p = 0.8
top-k = 20
min-p = 0.0
presence-penalty = 1.5
repeat-penalty = 1.0
reasoning = off
chat-template-kwargs = {"enable_thinking": false}

[Instruct Vision CPU]
ctx-size = 32768
mmproj = ${LLM_AUX_DIR}/mmproj-Qwen3.8-27B-BF16.gguf
# saves VRAM; slower image/PDF/video analysis
no-mmproj-offload = on
temperature = 0.7
top-p = 0.8
top-k = 20
min-p = 0.0
presence-penalty = 1.5
repeat-penalty = 1.0
reasoning = off
chat-template-kwargs = {"enable_thinking": false}

[Instruct Vision GPU]
ctx-size = 32768
mmproj = ${LLM_AUX_DIR}/mmproj-Qwen3.8-27B-BF16.gguf
temperature = 0.7
top-p = 0.8
top-k = 20
min-p = 0.0
presence-penalty = 1.5
repeat-penalty = 1.0
reasoning = off
chat-template-kwargs = {"enable_thinking": false}

[Thinking]
ctx-size = 32768
m = ${LLM_MODELS_DIR}/Qwen3.8-27B-ZB4.00-MIN-v3-IQ4_XS.gguf
temperature = 1.0
top-p = 0.95
top-k = 20
min-p = 0.0
presence-penalty = 0.0
repeat-penalty = 1.0
reasoning-preserve = on
reasoning-effort = medium
chat-template-kwargs = {"reasoning_effort": "medium"}

[Thinking Vision CPU]
ctx-size = 32768
mmproj = ${LLM_AUX_DIR}/mmproj-Qwen3.8-27B-BF16.gguf
# saves VRAM; slower image/PDF/video analysis
no-mmproj-offload = on
temperature = 1.0
top-p = 0.95
top-k = 20
min-p = 0.0
presence-penalty = 0.0
repeat-penalty = 1.0
reasoning-preserve = on
reasoning-effort = medium
chat-template-kwargs = {"reasoning_effort": "medium"}

[Thinking Vision GPU]
ctx-size = 32768
mmproj = ${LLM_AUX_DIR}/mmproj-Qwen3.8-27B-BF16.gguf
temperature = 1.0
top-p = 0.95
top-k = 20
min-p = 0.0
presence-penalty = 0.0
repeat-penalty = 1.0
reasoning-preserve = on
reasoning-effort = medium
chat-template-kwargs = {"reasoning_effort": "medium"}
PRESET_EOF

    log "Writing LLM preset: ${LLM_PRESET_FILE_32GB}"
    cat > "${LLM_PRESET_FILE_32GB}" <<PRESET_EOF
# 32 GiB VRAM (dedicated AI GPU, single user)
# ${LLM_PRESET_FILE_32GB}
[*]
flash-attn = on
gpu-layers = all
parallel = 1
cache-type-k = q8_0
cache-type-v = q4_1
batch-size = 4096
ubatch-size = 2048
load-mode = none
spec-type = draft-mtp,ngram-mod
spec-draft-n-max = 3
spec-ngram-mod-n-match = 24
spec-ngram-mod-n-min = 24
spec-ngram-mod-n-max = 32
image-min-tokens = 1024
image-max-tokens = 2048

# KV cache VRAM
# Qwen3.8-27B: 16 attn layers × 4 KV heads × 256 dim × 2 (K+V)
# q8_0/q4_1 : ~0.75 B/elem → 24 KiB/token → GiB ≈ ctx / 43690
# https://datakeskus.io/files/qwen38-27b-kv-cache.txt
#ctx-size = 2048     # 0.05 GiB
#ctx-size = 4096     # 0.09 GiB
#ctx-size = 8192     # 0.19 GiB
#ctx-size = 16384    # 0.38 GiB
#ctx-size = 32768    # 0.75 GiB
#ctx-size = 49152    # 1.13 GiB
#ctx-size = 65536    # 1.50 GiB
#ctx-size = 87040    # 2.00 GiB
#ctx-size = 98304    # 2.25 GiB
#ctx-size = 131072   # 3.00 GiB
#ctx-size = 163840   # 3.75 GiB
#ctx-size = 196608   # 4.50 GiB
#ctx-size = 229376   # 5.25 GiB
#ctx-size = 262144   # 6.00 GiB

# Model VRAM
# Qwen3.8-27B-Uncensored-Q6_K.gguf          20.9 GiB
# mmproj-Qwen3.8-27B-Uncensored-f16.gguf    0.89 GiB
# https://huggingface.co/orcarouter/Qwen3.8-27B-Uncensored-GGUF
m = ${LLM_MODELS_DIR}/Qwen3.8-27B-Uncensored-Q6_K.gguf

[Instruct]
ctx-size = 98304
temperature = 0.7
top-p = 0.8
top-k = 20
min-p = 0.0
presence-penalty = 1.5
repeat-penalty = 1.0
reasoning = off
chat-template-kwargs = {"enable_thinking": false}

[Instruct Vision CPU]
ctx-size = 98304
mmproj = ${LLM_AUX_DIR}/mmproj-Qwen3.8-27B-Uncensored-f16.gguf
# saves VRAM; slower image/PDF/video analysis
no-mmproj-offload = on
temperature = 0.7
top-p = 0.8
top-k = 20
min-p = 0.0
presence-penalty = 1.5
repeat-penalty = 1.0
reasoning = off
chat-template-kwargs = {"enable_thinking": false}

[Instruct Vision GPU]
ctx-size = 98304
mmproj = ${LLM_AUX_DIR}/mmproj-Qwen3.8-27B-Uncensored-f16.gguf
temperature = 0.7
top-p = 0.8
top-k = 20
min-p = 0.0
presence-penalty = 1.5
repeat-penalty = 1.0
reasoning = off
chat-template-kwargs = {"enable_thinking": false}

[Thinking]
ctx-size = 98304
temperature = 1.0
top-p = 0.95
top-k = 20
min-p = 0.0
presence-penalty = 0.0
repeat-penalty = 1.0
reasoning-preserve = on
reasoning-effort = medium
chat-template-kwargs = {"reasoning_effort": "medium"}

[Thinking Vision CPU]
ctx-size = 98304
mmproj = ${LLM_AUX_DIR}/mmproj-Qwen3.8-27B-Uncensored-f16.gguf
# saves VRAM; slower image/PDF/video analysis
no-mmproj-offload = on
temperature = 1.0
top-p = 0.95
top-k = 20
min-p = 0.0
presence-penalty = 0.0
repeat-penalty = 1.0
reasoning-preserve = on
reasoning-effort = medium
chat-template-kwargs = {"reasoning_effort": "medium"}

[Thinking Vision GPU]
ctx-size = 98304
mmproj = ${LLM_AUX_DIR}/mmproj-Qwen3.8-27B-Uncensored-f16.gguf
temperature = 1.0
top-p = 0.95
top-k = 20
min-p = 0.0
presence-penalty = 0.0
repeat-penalty = 1.0
reasoning-preserve = on
reasoning-effort = medium
chat-template-kwargs = {"reasoning_effort": "medium"}
PRESET_EOF

    log "Writing system prompt: ${LLM_PRESET_FILE_SYSTEM_PROMPT_EN}"
    cat > "${LLM_PRESET_FILE_SYSTEM_PROMPT_EN}" <<'PRESET_EOF'
Role: Software engineer. Treat the user as a peer. No tutoring.

Language: Everything in English, unless requested otherwise.

Style: Direct, technically precise, concise. No pleasantries, flattery, or filler.

Constraints: No emojis. Do not end responses with a question. Stay on task; no unsolicited expansions.

Code and comments: Prefer simple, fast, compact, readable code. Do not overcomplicate. Comment only non-obvious logic.

Python: Google Python Style Guide, Black, reST function docstrings.

Bash 5+ on Linux only. Google Shell Style Guide, ShellCheck, shfmt. Use set -euo pipefail. No POSIX or cross-platform compatibility.
PRESET_EOF

    log "Writing system prompt: ${LLM_PRESET_FILE_SYSTEM_PROMPT_FI}"
    cat > "${LLM_PRESET_FILE_SYSTEM_PROMPT_FI}" <<'PRESET_EOF'
Role: Software engineer. Treat the user as a peer. No tutoring.

Language: Base text in Finnish. No colloquial speak (sä, sun, sulla, mä, mun, mulla), do not address formally, use regular Finnish (sinä, sinun, sinulla, minä, minun, minulla).

Style: Direct, technically precise, concise. No pleasantries, flattery, or filler.

Constraints: No emojis. Do not end responses with a question. Stay on task; no unsolicited expansions.

Code and comments in English. Prefer simple, fast, compact, readable code. Do not overcomplicate. Comment only non-obvious logic.

Python: Google Python Style Guide, Black, reST function docstrings.

Bash 5+ on Linux only. Google Shell Style Guide, ShellCheck, shfmt. Use set -euo pipefail. No POSIX or cross-platform compatibility.
PRESET_EOF

    log "Writing system prompt: ${LLM_PRESET_FILE_ONETRAINER_APP}"
    cat > "${LLM_PRESET_FILE_ONETRAINER_APP}" <<PRESET_EOF
# ${LLM_PRESET_FILE_ONETRAINER_APP}
[Desktop Entry]
Comment=
Exec=/usr/bin/bash -c 'cd ${ONETRAINER_DIR}; source venv/bin/activate; python scripts/train_ui_qt.py &>log.txt'
Icon=${ONETRAINER_DIR}/resources/icons/icon.png
Name=OneTrainer
NoDisplay=false
Path=
PrefersNonDefaultGPU=false
StartupNotify=true
Terminal=false
TerminalOptions=
Type=Application
X-KDE-SubstituteUID=false
X-KDE-Username=
PRESET_EOF
}

ensure_llama_src() {
    mkdir -p "$(dirname "${LLAMA_SRC_DIR}")"
    if [[ -d "${LLAMA_SRC_DIR}/.git" ]]; then
        log "Updating llama.cpp source"
        git -C "${LLAMA_SRC_DIR}" fetch --depth 1 origin
        git -C "${LLAMA_SRC_DIR}" reset --hard origin/HEAD
    else
        log "Cloning llama.cpp → ${LLAMA_SRC_DIR}"
        rm -rf "${LLAMA_SRC_DIR}"
        git clone --quiet --no-tags --depth 1 "${LLAMA_CPP_REPO}" "${LLAMA_SRC_DIR}"
    fi
}

setup_build_env() {
    if command -v ccache >/dev/null 2>&1; then
        export CMAKE_C_COMPILER_LAUNCHER=ccache
        export CMAKE_CXX_COMPILER_LAUNCHER=ccache
        export CCACHE_COMPILERCHECK=content
        log "ccache enabled"
    fi
    if command -v ninja >/dev/null 2>&1; then
        CMAKE_GENERATOR_ARGS=(-G Ninja)
        log "Ninja generator enabled"
    else
        CMAKE_GENERATOR_ARGS=()
    fi
}

install_llama_artifacts() {
    local build_bin=$1 dest=$2
    mkdir -p "${dest}"
    cp -a "${build_bin}"/llama-* "${dest}/"
    if compgen -G "${build_bin}/*.so*" >/dev/null; then
        cp -a "${build_bin}"/*.so* "${dest}/"
    fi
    chmod +x "${dest}"/llama-*
}

build_llama_vulkan() {
    local basedir=$1
    local build_dir="${LLAMA_SRC_DIR}/build-vulkan"
    ensure_llama_src
    setup_build_env
    log "Building llama.cpp (Vulkan)"
    cd "${LLAMA_SRC_DIR}"
    cmake -B "${build_dir}" \
        "${CMAKE_GENERATOR_ARGS[@]}" \
        -DGGML_VULKAN=ON \
        -DCMAKE_BUILD_TYPE=Release
    cmake --build "${build_dir}" --config Release -j"$(nproc)"
    install_llama_artifacts "${build_dir}/bin" "${basedir}/venv/bin"
}

source_oneapi() {
    [[ -f "${ONEAPI_SETVARS}" ]] || die "oneAPI not found at ${ONEAPI_SETVARS}"
    if [[ -n "${ONEAPI_ROOT:-}" ]]; then
        return 0
    fi
    set +u
    set --
    # shellcheck source=/dev/null
    source "${ONEAPI_SETVARS}"
    set -u
}

build_llama_sycl() {
    local basedir=$1
    local build_dir="${LLAMA_SRC_DIR}/build-sycl"
    log "Sourcing oneAPI environment"
    source_oneapi
    ensure_llama_src
    setup_build_env
    log "Building llama.cpp (SYCL + F16 + oneDNN graphs)"
    cd "${LLAMA_SRC_DIR}"
    cmake -B "${build_dir}" \
        "${CMAKE_GENERATOR_ARGS[@]}" \
        -DGGML_SYCL=ON \
        -DGGML_SYCL_F16=ON \
        -DGGML_SYCL_DNN=ON \
        -DGGML_SYCL_TARGET=INTEL \
        -DGGML_SYCL_DEVICE_ARCH=bmg_g21 \
        -DCMAKE_C_COMPILER=icx \
        -DCMAKE_CXX_COMPILER=icpx \
        -DCMAKE_BUILD_TYPE=Release \
        -DCMAKE_C_FLAGS_RELEASE="-O3 -DNDEBUG" \
        -DCMAKE_CXX_FLAGS_RELEASE="-O3 -DNDEBUG"
    cmake --build "${build_dir}" --config Release -j"$(nproc)"
    install_llama_artifacts "${build_dir}/bin" "${basedir}/venv/bin"
}

# ---------------------------------------------------------------------------
# ROCm + Vulkan
# ---------------------------------------------------------------------------
create_comfy_rocm_service() {
    local basedir_rocm=$1
    log "Writing comfy-rocm.service"
    cat > "${UNIT_DIR}/comfy-rocm.service" <<EOF
# ${UNIT_DIR}/comfy-rocm.service
[Unit]
Description=ComfyUI ROCm
After=network.target

[Service]
WorkingDirectory=${basedir_rocm}/comfy
Type=simple
Restart=always
RestartSec=10
TimeoutStopSec=10
OOMScoreAdjust=-500

Environment=ROCM_PATH=${ROCM_PATH}
Environment=ROCM_HOME=${ROCM_PATH}
Environment=HIP_PATH=${ROCM_PATH}
Environment=HIP_PLATFORM=amd
Environment=PYTORCH_TUNABLEOP_ENABLED=1
Environment=PYTORCH_TUNABLEOP_TUNING=0
Environment=PYTORCH_TUNABLEOP_FILENAME=${CACHE_DIR}/tunableop/results.csv
Environment=COMFYUI_ENABLE_MIOPEN=1
Environment=MIOPEN_FIND_MODE=FAST
Environment=PYTORCH_MIOPEN_SUGGEST_NHWC=0
Environment=PYTORCH_HIP_ALLOC_CONF=expandable_segments:True
Environment=TORCH_BLAS_PREFER_HIPBLASLT=1
Environment=HSA_ENABLE_SDMA=0
Environment=FLASH_ATTENTION_TRITON_AMD_ENABLE=TRUE
Environment=MIOPEN_USER_DB_PATH=${CACHE_DIR}/miopen
Environment=MIOPEN_CUSTOM_CACHE_DIR=${CACHE_DIR}/miopen
Environment=TRITON_CACHE_DIR=${CACHE_DIR}/triton
Environment=TORCHINDUCTOR_CACHE_DIR=${CACHE_DIR}/torchinductor

ExecStart=/bin/bash -c 'source ${basedir_rocm}/venv/bin/activate && \\
    export PATH=${ROCM_PATH}/bin:\$PATH && \\
    export LD_LIBRARY_PATH=${ROCM_PATH}/lib:${basedir_rocm}/venv/lib:\${LD_LIBRARY_PATH:-} && \\
    python main.py \\
    --input-directory ${BASEDIR}/input \\
    --output-directory ${BASEDIR}/output \\
    --user-directory ${BASEDIR}/user \\
    --port 8189 \\
    --disable-cuda-malloc \\
    --enable-dynamic-vram \\
    --use-pytorch-cross-attention \\
    --reserve-vram 2 \\
    --fast'

[Install]
WantedBy=default.target
EOF
}

create_vulkan_service() {
    local basedir_rocm=$1
    log "Writing llama-vulkan.service"
    cat > "${UNIT_DIR}/llama-vulkan.service" <<EOF
# ${UNIT_DIR}/llama-vulkan.service
[Unit]
Description=llama.cpp Vulkan
After=network.target

[Service]
WorkingDirectory=${basedir_rocm}
Type=simple
Restart=on-failure
RestartSec=5
TimeoutStopSec=15
OOMScoreAdjust=-500

Environment=VK_ICD_FILENAMES=${RADEON_ICD}
Environment=RADV_PERFTEST=transfer_queue

ExecStart=/bin/bash -c 'export LD_LIBRARY_PATH=${basedir_rocm}/venv/bin:\${LD_LIBRARY_PATH:-} && \\
    exec ${basedir_rocm}/venv/bin/llama-server \\
    --host 127.0.0.1 \\
    --port 9932 \\
    --models-max 1 \\
    --tools all \\
    --models-preset ${LLM_PRESET_FILE_16GB}'

[Install]
WantedBy=default.target
EOF
}

latest_rocm_tarball() {
    curl -sL "${ROCM_TARBALL_BASE}/" \
        | grep -oE 'therock-dist-linux-gfx120X-all-[0-9.]+a[0-9]{8}\.tar\.gz' \
        | sort -V | tail -1
}

install_rocm_nightly() {
    local basedir_rocm=$1
    local latest_tarball latest_pkgver installed
    latest_tarball=$(latest_rocm_tarball)
    [[ -n "${latest_tarball}" ]] || die "Could not determine latest ROCm tarball"
    latest_pkgver="${latest_tarball#therock-dist-linux-gfx120X-all-}"
    latest_pkgver="${latest_pkgver%.tar.gz}"
    installed=$(pacman -Q rocm-nightly 2>/dev/null | awk '{print $2}' || true)
    if [[ "${installed}" == "${latest_pkgver}-"* ]]; then
        log "ROCm nightly ${latest_pkgver} already installed, skipping makepkg"
        return 0
    fi

    log "Building ROCm nightly ${latest_pkgver}"
    local rocm_dir="${basedir_rocm}/rocm-nightly"
    mkdir -p "${rocm_dir}"
    cd "${rocm_dir}"

    cat > PKGBUILD <<PKGBUILD_EOF
pkgname="rocm-nightly"
pkgver=${latest_pkgver}
pkgrel=1
pkgdesc="ROCm nightly (RDNA4 gfx120X) — monolithic"
arch=('x86_64')
url="https://rocm.nightlies.amd.com"
license=('MIT' 'custom:LicenseRef-ROCm-EULA')
depends=('glibc' 'gcc-libs' 'python-pyelftools' 'python')
_rocm_packages=(
    hip-runtime-amd amdsmi composable-kernel
    rocm-core rocm-cmake rocm-llvm rocm-device-libs
    hsa-rocr hsakmt-roct hsa-amd-aqlprofile
    comgr rocminfo rocwmma rocprofiler-register
    rocm-smi-lib rocm-gdb rocm-dbgapi rocprofiler roctracer
    rocm-opencl-runtime rocm-opencl-sdk
    hipblas hipblas-common hipblaslt rocblas
    hipfft rocfft hipdnn hiprand rocrand hipsolver rocsolver
    hipsparse hipsparselt rocsparse
    rccl rocalution rocprim rocthrust hipcub
    hipify-clang miopen-hip
    rocm-hip-sdk rocm-hip-libraries rocm-hip-runtime rocm-ml-sdk
)
provides=("\${_rocm_packages[@]}" opencl-driver "rocm=${latest_pkgver}")
conflicts=("\${_rocm_packages[@]}" rocm)
options=('!strip' '!debug')
source=("${ROCM_TARBALL_BASE}/${latest_tarball}")
sha256sums=('SKIP')
noextract=("${latest_tarball}")

package() {
    install -d "\${pkgdir}${ROCM_PATH}"
    tar xzf "${latest_tarball}" -C "\${pkgdir}${ROCM_PATH}"
    install -Dm644 /dev/stdin "\${pkgdir}/etc/ld.so.conf.d/rocm-nightly-gfx120X-all.conf" <<CONF
${ROCM_PATH}/lib
${ROCM_PATH}/lib64
CONF
    install -Dm644 /dev/stdin "\${pkgdir}/etc/OpenCL/vendors/amdocl64.icd" <<ICD
${ROCM_PATH}/lib/opencl/libamdocl64.so
ICD
    install -d "\${pkgdir}/usr/share/licenses/\${pkgname}"
    if [[ -f "\${pkgdir}${ROCM_PATH}/share/doc/NOTICES.txt" ]]; then
        ln -s "${ROCM_PATH}/share/doc/NOTICES.txt" \\
            "\${pkgdir}/usr/share/licenses/\${pkgname}/NOTICES.txt"
    fi
}
PKGBUILD_EOF

    if [[ ! -f "${latest_tarball}" ]]; then
        curl -LO "${ROCM_TARBALL_BASE}/${latest_tarball}"
    fi
    makepkg --skipchecksums -si --noconfirm
    rm -f "${latest_tarball}"
    sudo ldconfig
    cd "${basedir_rocm}"
    rm -rf "${rocm_dir}"
}

purge_cuda_pypi() {
    local -a pkgs
    mapfile -t pkgs < <(uv pip freeze | awk -F== 'BEGIN{IGNORECASE=1}
        /^(nvidia-|cuda-|pynvml|onnxruntime-gpu)/ {print $1}')
    if ((${#pkgs[@]})); then
        log "Removing CUDA PyPI leftovers"
        uv pip uninstall -y "${pkgs[@]}" >/dev/null
    fi
}

install_torch_rocm() {
    log "Installing ROCm PyTorch stack"
    uv pip install --upgrade --force-reinstall \
        --extra-index-url "${ROCM_NIGHTLY_INDEX}" \
        torch torchaudio torchvision triton \
        filelock fsspec jinja2 markupsafe mpmath networkx numpy pillow \
        setuptools sympy typing-extensions apex cxxfilt sageattention soundfile
    uv pip install "kornia>=0.7.0,<0.8.0" --no-deps --force-reinstall
    purge_cuda_pypi
}

smoke_rocm() {
    local basedir_rocm=$1
    log "ROCm smoke test"
    # shellcheck source=/dev/null
    source "${basedir_rocm}/venv/bin/activate"
    export ROCM_PATH
    export HIP_PATH="${ROCM_PATH}"
    export HIP_PLATFORM=amd
    export PATH="${ROCM_PATH}/bin:${PATH}"
    export LD_LIBRARY_PATH="${ROCM_PATH}/lib:${basedir_rocm}/venv/lib:${LD_LIBRARY_PATH:-}"
    python - <<'PY'
import torch
print("torch", torch.__version__, "hip", getattr(torch.version, "hip", None))
if not torch.cuda.is_available():
    raise SystemExit("ROCm HIP device not available")
print("device", torch.cuda.get_device_name(0))
PY
    [[ -x "${basedir_rocm}/venv/bin/llama-server" ]] || die "llama-server missing"
    deactivate
}

setup_rocm() {
    local basedir_rocm="${BASEDIR}/rocm"
    stop_service comfy-rocm
    stop_service llama-vulkan
    ensure_shared_dirs
    ensure_llm_preset
    clean_base "${basedir_rocm}"
    setup_venv_and_comfy "${basedir_rocm}"
    create_comfy_rocm_service "${basedir_rocm}"
    create_vulkan_service "${basedir_rocm}"
    install_custom_nodes
    update_pip_and_requirements
    install_rocm_nightly "${basedir_rocm}"
    cd "${basedir_rocm}/comfy"
    install_torch_rocm
    setup_extra_model_paths
    build_llama_vulkan "${basedir_rocm}"
    write_manifest "${basedir_rocm}/.updateai-manifest" \
        "comfy=$(git_rev "${basedir_rocm}/comfy")" \
        "torch=$(python -c 'import torch; print(torch.__version__)')" \
        "rocm=$(pacman -Q rocm-nightly 2>/dev/null || echo missing)"
    deactivate
    smoke_rocm "${basedir_rocm}"
    enable_units comfy-rocm.service llama-vulkan.service
    note "ROCm stack: ${basedir_rocm}
  comfy-rocm.service     http://127.0.0.1:8189/
  llama-vulkan.service   http://127.0.0.1:9932/
Restart: systemctl --user restart comfy-rocm llama-vulkan"
}

# ---------------------------------------------------------------------------
# XPU + SYCL
# ---------------------------------------------------------------------------
create_comfy_xpu_service() {
    local basedir_xpu=$1
    log "Writing comfy-xpu.service"
    cat > "${UNIT_DIR}/comfy-xpu.service" <<EOF
# ${UNIT_DIR}/comfy-xpu.service
[Unit]
Description=ComfyUI XPU
After=network.target

[Service]
WorkingDirectory=${basedir_xpu}/comfy
Type=simple
Restart=always
RestartSec=10
TimeoutStopSec=10
OOMScoreAdjust=-500

Environment=ONEAPI_DEVICE_SELECTOR=level_zero:0
#Environment=SYCL_CACHE_PERSISTENT=1
#Environment=SYCL_CACHE_DIR=${CACHE_DIR}/sycl
Environment=TRITON_CACHE_DIR=${CACHE_DIR}/triton
Environment=TORCHINDUCTOR_CACHE_DIR=${CACHE_DIR}/torchinductor

ExecStart=/bin/bash -c 'source ${basedir_xpu}/venv/bin/activate && \\
    export LD_LIBRARY_PATH=${basedir_xpu}/venv/lib:\${LD_LIBRARY_PATH:-} && \\
    set +u && source ${ONEAPI_SETVARS} && set -u && \\
    python main.py \\
    --input-directory ${BASEDIR}/input \\
    --output-directory ${BASEDIR}/output \\
    --user-directory ${BASEDIR}/user \\
    --port 8188 \\
    --oneapi-device-selector level_zero:0'

[Install]
WantedBy=default.target
EOF
}

create_sycl_service() {
    local basedir_xpu=$1
    log "Writing llama-sycl.service"
    cat > "${UNIT_DIR}/llama-sycl.service" <<EOF
# ${UNIT_DIR}/llama-sycl.service
[Unit]
Description=llama.cpp SYCL
After=network.target

[Service]
WorkingDirectory=${basedir_xpu}
Type=simple
Restart=on-failure
RestartSec=5
TimeoutStopSec=15
OOMScoreAdjust=-500

Environment=ONEAPI_DEVICE_SELECTOR=level_zero:0
#Environment=SYCL_CACHE_PERSISTENT=1
#Environment=SYCL_CACHE_DIR=${CACHE_DIR}/sycl

ExecStart=/bin/bash -c 'set +u && source ${ONEAPI_SETVARS} && set -u && \\
    export LD_LIBRARY_PATH=${basedir_xpu}/venv/bin:\${LD_LIBRARY_PATH:-} && \\
    exec ${basedir_xpu}/venv/bin/llama-server \\
    --host 127.0.0.1 \\
    --port 9931 \\
    --models-max 1 \\
    --tools all \\
    --models-preset ${LLM_PRESET_FILE_32GB}'

[Install]
WantedBy=default.target
EOF
}

install_torch_xpu() {
    log "Installing PyTorch XPU nightly"
    uv pip install --pre --upgrade --force-reinstall \
        --index-url "${PYTORCH_XPU_INDEX}" \
        torch torchvision torchaudio
    uv pip install --force-reinstall 'numpy<2.5'
    purge_cuda_pypi
}

smoke_xpu() {
    local basedir_xpu=$1
    log "XPU smoke test"
    # shellcheck source=/dev/null
    source "${basedir_xpu}/venv/bin/activate"
    source_oneapi
    export ONEAPI_DEVICE_SELECTOR=level_zero:0
    python - <<'PY'
import torch
print("torch", torch.__version__)
print("xpu", torch.xpu.is_available(), "count", torch.xpu.device_count())
if not torch.xpu.is_available():
    raise SystemExit("XPU not available")
print("device", torch.xpu.get_device_name(0))
PY
    [[ -x "${basedir_xpu}/venv/bin/llama-server" ]] || die "llama-server missing"
    deactivate
}

setup_xpu() {
    local basedir_xpu="${BASEDIR}/xpu"
    stop_service comfy-xpu
    stop_service llama-sycl
    ensure_shared_dirs
    ensure_llm_preset
    clean_base "${basedir_xpu}"
    setup_venv_and_comfy "${basedir_xpu}"
    create_comfy_xpu_service "${basedir_xpu}"
    create_sycl_service "${basedir_xpu}"
    install_custom_nodes
    update_pip_and_requirements
    install_torch_xpu
    setup_extra_model_paths
    build_llama_sycl "${basedir_xpu}"
    write_manifest "${basedir_xpu}/.updateai-manifest" \
        "comfy=$(git_rev "${basedir_xpu}/comfy")" \
        "torch=$(python -c 'import torch; print(torch.__version__)')"
    deactivate
    smoke_xpu "${basedir_xpu}"
    enable_units comfy-xpu.service llama-sycl.service
    note "XPU stack: ${basedir_xpu}
  comfy-xpu.service      http://127.0.0.1:8188/
  llama-sycl.service     http://127.0.0.1:9931/
Restart: systemctl --user restart comfy-xpu llama-sycl"
}

# ---------------------------------------------------------------------------
# OneTrainer XPU
# ---------------------------------------------------------------------------
onetrainer_uv() { UV_NO_PROJECT=1 uv "$@"; }

sync_onetrainer_src() {
    local ot=$1
    mkdir -p "$(dirname "${ot}")"
    if [[ -d "${ot}/.git" ]]; then
        log "Updating OneTrainer source"
        git -C "${ot}" fetch --prune origin
        git -C "${ot}" checkout --force master
        git -C "${ot}" reset --hard origin/master
        git -C "${ot}" clean -fd \
            --exclude=venv \
            --exclude=training_concepts \
            --exclude=training_configs \
            --exclude=training_samples \
            --exclude=workspace \
            --exclude=workspace-cache
    else
        log "Cloning OneTrainer → ${ot}"
        rm -rf "${ot}"
        git clone --quiet --no-tags --depth 1 "${ONETRAINER_REPO}" "${ot}"
    fi
    log "Merging PR ${ONETRAINER_PR}"
    git -C "${ot}" fetch origin "pull/${ONETRAINER_PR}/head:pr-${ONETRAINER_PR}"
    git -C "${ot}" merge "pr-${ONETRAINER_PR}" --no-edit || true
    if [[ -f "${ot}/.git/MERGE_HEAD" ]]; then
        if git -C "${ot}" diff --name-only --diff-filter=U | grep -qx 'scripts/train_ui.py'; then
            git -C "${ot}" checkout --ours scripts/train_ui.py
            git -C "${ot}" add scripts/train_ui.py
        fi
        if git -C "${ot}" diff --name-only --diff-filter=U | grep -q .; then
            die "Unresolved OneTrainer merge conflicts remain"
        fi
        git -C "${ot}" add -u
        git -C "${ot}" commit --no-edit
    fi
}

patch_onetrainer_xpu() {
    local ot=$1
    log "Applying XPU patches"
    python - <<PY
from pathlib import Path
import re

root = Path("${ot}")

p = root / "scripts/util/import_util.py"
text = p.read_text()
if "ipex_init" not in text:
    p.write_text(text.rstrip() + """

    import torch

    if hasattr(torch, "xpu") and torch.xpu.is_available():
        from ipex_to_cuda import ipex_init

        ipex_init()
        print("CUDA -> XPU hijacking active")
""")
    print("import_util.py: ipex hook added")
else:
    print("import_util.py: ipex hook already present")

tu = root / "modules/util/torch_util.py"
kept = []
removed = 0
for line in tu.read_text().splitlines(keepends=True):
    if 'print ("true")' in line or 'print("true")' in line:
        removed += 1
        continue
    kept.append(line)
if removed:
    tu.write_text("".join(kept))
    print(f"torch_util.py: removed {removed} debug print(s)")
else:
    print("torch_util.py: no debug print")

zluda = root / "modules/zluda/ZLUDA.py"
ztext = zluda.read_text()
new_fn = '''def is_zluda(device):
    try:
        if isinstance(device, str):
            if device.lower() == "cpu":
                return False
            if device.lower().startswith("cuda"):
                parts = device.split(":")
                device = int(parts[1]) if len(parts) > 1 else 0
        return str(torch.cuda.get_device_name(device)).endswith("[ZLUDA]")
    except Exception:
        return False
'''
ztext2, n = re.subn(
    r"def is_zluda\([\s\S]*?(?=\ndef |\Z)",
    new_fn + "\n",
    ztext,
    count=1,
)
if n != 1:
    raise SystemExit(f"ZLUDA is_zluda replace count={n}")
zluda.write_text(ztext2)
print("ZLUDA.py: is_zluda patched")
PY
    python -m py_compile \
        "${ot}/scripts/util/import_util.py" \
        "${ot}/modules/util/torch_util.py" \
        "${ot}/modules/zluda/ZLUDA.py"
}

install_onetrainer_python() {
    local ot=$1
    log "Creating OneTrainer Python ${PYTHON_VER} venv"
    rm -rf "${ot}/venv"
    onetrainer_uv venv "${ot}/venv" --python "${PYTHON_VER}"
    # shellcheck source=/dev/null
    source "${ot}/venv/bin/activate"
    log "Installing torch XPU stable + ipex_to_cuda"
    onetrainer_uv pip install torch torchvision torchaudio \
        --index-url "${PYTORCH_XPU_STABLE_INDEX}"
    onetrainer_uv pip install "git+https://github.com/Disty0/ipex_to_cuda.git"
    onetrainer_uv pip install \
        "git+https://github.com/huggingface/diffusers.git@${ONETRAINER_DIFFUSERS_REF}" \
        "git+https://github.com/Nerogar/mgds.git@${ONETRAINER_MGDS_REF}" \
        "git+https://github.com/KellerJordan/Muon.git@${ONETRAINER_MUON_REF}"
    grep -vE '^\-e |^numpy==' "${ot}/requirements-global.txt" \
        | onetrainer_uv pip install -r -
    onetrainer_uv pip install onnxruntime
    python - <<'PY'
import torch
print(torch.__version__)
print("xpu", torch.xpu.is_available(), torch.xpu.device_count())
if not torch.xpu.is_available():
    raise SystemExit("XPU not available in OneTrainer venv")
PY
    deactivate
}

setup_onetrainer() {
    local ot="${ONETRAINER_DIR}"
    log "Installing OneTrainer XPU stack → ${ot}"
    ensure_shared_dirs
    sync_onetrainer_src "${ot}"
    patch_onetrainer_xpu "${ot}"
    install_onetrainer_python "${ot}"
    write_manifest "${ot}/.updateai-manifest" \
        "onetrainer=$(git_rev "${ot}")"
    note "OneTrainer XPU: ${ot}
  Launch: source ${ot}/venv/bin/activate && python ${ot}/scripts/train_ui_qt.py
  Device: xpu
  Kept:   ${ot}/training_concepts
          ${ot}/training_configs
          ${ot}/training_samples
          ${ot}/workspace
          ${ot}/workspace-cache"
}

# ---------------------------------------------------------------------------
# Main
# ---------------------------------------------------------------------------
main() {
    [[ $# -eq 1 ]] || usage
    local target=$1
    case "${target}" in
        rocm|xpu|onetrainer|all) ;;
        *) usage ;;
    esac

    log "Starting updateai (${target})"
    ensure_uv
    ensure_shared_dirs

    case "${target}" in
        rocm) setup_rocm ;;
        xpu) setup_xpu ;;
        onetrainer) setup_onetrainer ;;
        all)
            setup_rocm
            setup_xpu
            setup_onetrainer
            ;;
    esac

    print_notes
    local elapsed=$((SECONDS - start_time))
    if (( elapsed >= 60 )); then
        printf '\n=== READY (%d minutes %d seconds) ===\n\n' \
            "$((elapsed / 60))" "$((elapsed % 60))"
    else
        printf '\n=== READY (%d seconds) ===\n\n' "${elapsed}"
    fi
}

main "$@"

Skripti generoi

32gb.ini (llama.cpp 32 GB VRAM)
# 32 GiB VRAM (dedicated AI GPU, single user)
# /home/hans/ai/models/llm_presets/32gb.ini
[*]
flash-attn = on
gpu-layers = all
parallel = 1
cache-type-k = q8_0
cache-type-v = q4_1
batch-size = 4096
ubatch-size = 2048
load-mode = none
spec-type = draft-mtp,ngram-mod
spec-draft-n-max = 3
spec-ngram-mod-n-match = 24
spec-ngram-mod-n-min = 24
spec-ngram-mod-n-max = 32
image-min-tokens = 1024
image-max-tokens = 2048

# KV cache VRAM
# Qwen3.8-27B: 16 attn layers × 4 KV heads × 256 dim × 2 (K+V)
# q8_0/q4_1 : ~0.75 B/elem → 24 KiB/token → GiB ≈ ctx / 43690
# https://datakeskus.io/files/qwen38-27b-kv-cache.txt
#ctx-size = 2048     # 0.05 GiB
#ctx-size = 4096     # 0.09 GiB
#ctx-size = 8192     # 0.19 GiB
#ctx-size = 16384    # 0.38 GiB
#ctx-size = 32768    # 0.75 GiB
#ctx-size = 49152    # 1.13 GiB
#ctx-size = 65536    # 1.50 GiB
#ctx-size = 87040    # 2.00 GiB
#ctx-size = 98304    # 2.25 GiB
#ctx-size = 131072   # 3.00 GiB
#ctx-size = 163840   # 3.75 GiB
#ctx-size = 196608   # 4.50 GiB
#ctx-size = 229376   # 5.25 GiB
#ctx-size = 262144   # 6.00 GiB

# Model VRAM
# Qwen3.8-27B-Uncensored-Q6_K.gguf          20.9 GiB
# mmproj-Qwen3.8-27B-Uncensored-f16.gguf    0.89 GiB
# https://huggingface.co/orcarouter/Qwen3.8-27B-Uncensored-GGUF
m = /home/hans/ai/models/llm/Qwen3.8-27B-Uncensored-Q6_K.gguf

[Instruct]
ctx-size = 65536
temperature = 0.7
top-p = 0.8
top-k = 20
min-p = 0.0
presence-penalty = 1.5
repeat-penalty = 1.0
reasoning = off
chat-template-kwargs = {"enable_thinking": false}

[Instruct Vision CPU]
ctx-size = 65536
mmproj = /home/hans/ai/models/llm_aux/mmproj-Qwen3.8-27B-Uncensored-f16.gguf
# saves VRAM; slower image/PDF/video analysis
no-mmproj-offload = on
temperature = 0.7
top-p = 0.8
top-k = 20
min-p = 0.0
presence-penalty = 1.5
repeat-penalty = 1.0
reasoning = off
chat-template-kwargs = {"enable_thinking": false}

[Instruct Vision GPU]
ctx-size = 65536
mmproj = /home/hans/ai/models/llm_aux/mmproj-Qwen3.8-27B-Uncensored-f16.gguf
temperature = 0.7
top-p = 0.8
top-k = 20
min-p = 0.0
presence-penalty = 1.5
repeat-penalty = 1.0
reasoning = off
chat-template-kwargs = {"enable_thinking": false}

[Thinking]
ctx-size = 65536
temperature = 1.0
top-p = 0.95
top-k = 20
min-p = 0.0
presence-penalty = 0.0
repeat-penalty = 1.0
reasoning-preserve = on
reasoning-effort = medium
chat-template-kwargs = {"reasoning_effort": "medium"}

[Thinking Vision CPU]
ctx-size = 65536
mmproj = /home/hans/ai/models/llm_aux/mmproj-Qwen3.8-27B-Uncensored-f16.gguf
# saves VRAM; slower image/PDF/video analysis
no-mmproj-offload = on
temperature = 1.0
top-p = 0.95
top-k = 20
min-p = 0.0
presence-penalty = 0.0
repeat-penalty = 1.0
reasoning-preserve = on
reasoning-effort = medium
chat-template-kwargs = {"reasoning_effort": "medium"}

[Thinking Vision GPU]
ctx-size = 32768
mmproj = /home/hans/ai/models/llm_aux/mmproj-Qwen3.8-27B-Uncensored-f16.gguf
temperature = 1.0
top-p = 0.95
top-k = 20
min-p = 0.0
presence-penalty = 0.0
repeat-penalty = 1.0
reasoning-preserve = on
reasoning-effort = medium
chat-template-kwargs = {"reasoning_effort": "medium"}

16gb.ini (llama.cpp 16 GB VRAM)
# 16 GiB VRAM (primary desktop GPU, single user)
# /home/hans/ai/models/llm_presets/16gb.ini
[*]
flash-attn = on
gpu-layers = all
parallel = 1
cache-type-k = q4_0
cache-type-v = q4_0
batch-size = 384
ubatch-size = 384
load-mode = mlock
spec-type = draft-mtp,ngram-mod
spec-draft-n-max = 2
spec-ngram-mod-n-match = 24
spec-ngram-mod-n-min = 24
spec-ngram-mod-n-max = 32
image-min-tokens = 1024
image-max-tokens = 2048

# KV cache VRAM
# Qwen3.8-27B: 16 attn layers × 4 KV heads × 256 dim × 2 (K+V)
# q4_0/q4_0: 0.5 B/elem → 16 KiB/token → GiB ≈ ctx / 65536
# https://datakeskus.io/files/qwen38-27b-kv-cache.txt
#ctx-size = 2048    # 0.03 GiB
#ctx-size = 4096    # 0.06 GiB
#ctx-size = 6144    # 0.09 GiB
#ctx-size = 8192    # 0.13 GiB
#ctx-size = 16384   # 0.25 GiB
#ctx-size = 32768   # 0.50 GiB
#ctx-size = 49152   # 0.75 GiB
#ctx-size = 65536   # 1.00 GiB
#ctx-size = 81920   # 1.25 GiB
#ctx-size = 98304   # 1.50 GiB
#ctx-size = 114688  # 1.75 GiB
#ctx-size = 131072  # 2.00 GiB
#ctx-size = 147456  # 2.25 GiB
#ctx-size = 163840  # 2.50 GiB
#ctx-size = 180224  # 2.75 GiB
#ctx-size = 196608  # 3.00 GiB
#ctx-size = 229376  # 3.50 GiB
#ctx-size = 245760  # 3.75 GiB
#ctx-size = 262144  # 4.00 GiB

# Model VRAM
# Qwen3.8-27B-ZB4.00-MIN-v3-IQ4_XS.gguf     12.7 GiB
# mmproj-Qwen3.8-27B-BF16.gguf              0.89 GiB
# https://huggingface.co/tooltd/Qwen3.8-27B-IQ4-XS-16GB-VRAM-GGUF
# https://huggingface.co/ggml-org/Qwen3.8-27B-GGUF

[Instruct]
ctx-size = 32768
temperature = 0.7
top-p = 0.8
top-k = 20
min-p = 0.0
presence-penalty = 1.5
repeat-penalty = 1.0
reasoning = off
chat-template-kwargs = {"enable_thinking": false}

[Instruct Vision CPU]
ctx-size = 32768
mmproj = /home/hans/ai/models/llm_aux/mmproj-Qwen3.8-27B-BF16.gguf
# saves VRAM; slower image/PDF/video analysis
no-mmproj-offload = on
temperature = 0.7
top-p = 0.8
top-k = 20
min-p = 0.0
presence-penalty = 1.5
repeat-penalty = 1.0
reasoning = off
chat-template-kwargs = {"enable_thinking": false}

[Instruct Vision GPU]
ctx-size = 32768
mmproj = /home/hans/ai/models/llm_aux/mmproj-Qwen3.8-27B-BF16.gguf
temperature = 0.7
top-p = 0.8
top-k = 20
min-p = 0.0
presence-penalty = 1.5
repeat-penalty = 1.0
reasoning = off
chat-template-kwargs = {"enable_thinking": false}

[Thinking]
ctx-size = 32768
m = /home/hans/ai/models/llm/Qwen3.8-27B-ZB4.00-MIN-v3-IQ4_XS.gguf
temperature = 1.0
top-p = 0.95
top-k = 20
min-p = 0.0
presence-penalty = 0.0
repeat-penalty = 1.0
reasoning-preserve = on
reasoning-effort = medium
chat-template-kwargs = {"reasoning_effort": "medium"}

[Thinking Vision CPU]
ctx-size = 32768
mmproj = /home/hans/ai/models/llm_aux/mmproj-Qwen3.8-27B-BF16.gguf
# saves VRAM; slower image/PDF/video analysis
no-mmproj-offload = on
temperature = 1.0
top-p = 0.95
top-k = 20
min-p = 0.0
presence-penalty = 0.0
repeat-penalty = 1.0
reasoning-preserve = on
reasoning-effort = medium
chat-template-kwargs = {"reasoning_effort": "medium"}

[Thinking Vision GPU]
ctx-size = 32768
mmproj = /home/hans/ai/models/llm_aux/mmproj-Qwen3.8-27B-BF16.gguf
temperature = 1.0
top-p = 0.95
top-k = 20
min-p = 0.0
presence-penalty = 0.0
repeat-penalty = 1.0
reasoning-preserve = on
reasoning-effort = medium
chat-template-kwargs = {"reasoning_effort": "medium"}

comfy-rocm.service (ComfyUI AMD ROCm)
# /home/hans/.config/systemd/user/comfy-rocm.service
[Unit]
Description=ComfyUI ROCm
After=network.target

[Service]
WorkingDirectory=/home/hans/ai/rocm/comfy
Type=simple
Restart=always
RestartSec=10
TimeoutStopSec=10
OOMScoreAdjust=-500

Environment=ROCM_PATH=/opt/rocm
Environment=ROCM_HOME=/opt/rocm
Environment=HIP_PATH=/opt/rocm
Environment=HIP_PLATFORM=amd
Environment=PYTORCH_TUNABLEOP_ENABLED=1
Environment=PYTORCH_TUNABLEOP_TUNING=0
Environment=PYTORCH_TUNABLEOP_FILENAME=/home/hans/ai/cache/tunableop/results.csv
Environment=COMFYUI_ENABLE_MIOPEN=1
Environment=MIOPEN_FIND_MODE=FAST
Environment=PYTORCH_MIOPEN_SUGGEST_NHWC=0
Environment=PYTORCH_HIP_ALLOC_CONF=expandable_segments:True
Environment=TORCH_BLAS_PREFER_HIPBLASLT=1
Environment=HSA_ENABLE_SDMA=0
Environment=FLASH_ATTENTION_TRITON_AMD_ENABLE=TRUE
Environment=MIOPEN_USER_DB_PATH=/home/hans/ai/cache/miopen
Environment=MIOPEN_CUSTOM_CACHE_DIR=/home/hans/ai/cache/miopen
Environment=TRITON_CACHE_DIR=/home/hans/ai/cache/triton
Environment=TORCHINDUCTOR_CACHE_DIR=/home/hans/ai/cache/torchinductor

ExecStart=/bin/bash -c 'source /home/hans/ai/rocm/venv/bin/activate && \
    export PATH=/opt/rocm/bin:$PATH && \
    export LD_LIBRARY_PATH=/opt/rocm/lib:/home/hans/ai/rocm/venv/lib:${LD_LIBRARY_PATH:-} && \
    python main.py \
    --input-directory /home/hans/ai/input \
    --output-directory /home/hans/ai/output \
    --user-directory /home/hans/ai/user \
    --port 8189 \
    --disable-cuda-malloc \
    --enable-dynamic-vram \
    --use-pytorch-cross-attention \
    --reserve-vram 2 \
    --fast'

[Install]
WantedBy=default.target

comfy-xpu.service (ComfyUI Intel XPU)
# /home/hans/.config/systemd/user/comfy-xpu.service
[Unit]
Description=ComfyUI XPU
After=network.target

[Service]
WorkingDirectory=/home/hans/ai/xpu/comfy
Type=simple
Restart=always
RestartSec=10
TimeoutStopSec=10
OOMScoreAdjust=-500

Environment=ONEAPI_DEVICE_SELECTOR=level_zero:0
#Environment=SYCL_CACHE_PERSISTENT=1
#Environment=SYCL_CACHE_DIR=/home/hans/ai/cache/sycl
Environment=TRITON_CACHE_DIR=/home/hans/ai/cache/triton
Environment=TORCHINDUCTOR_CACHE_DIR=/home/hans/ai/cache/torchinductor

ExecStart=/bin/bash -c 'source /home/hans/ai/xpu/venv/bin/activate && \
    export LD_LIBRARY_PATH=/home/hans/ai/xpu/venv/lib:${LD_LIBRARY_PATH:-} && \
    set +u && source /opt/intel/oneapi/setvars.sh && set -u && \
    python main.py \
    --input-directory /home/hans/ai/input \
    --output-directory /home/hans/ai/output \
    --user-directory /home/hans/ai/user \
    --port 8188 \
    --oneapi-device-selector level_zero:0'

[Install]
WantedBy=default.target

llama-sycl.service (llama.cpp server Intel SYCL)
# /home/hans/.config/systemd/user/llama-sycl.service
[Unit]
Description=llama.cpp SYCL
After=network.target

[Service]
WorkingDirectory=/home/hans/ai/xpu
Type=simple
Restart=on-failure
RestartSec=5
TimeoutStopSec=15
OOMScoreAdjust=-500

Environment=ONEAPI_DEVICE_SELECTOR=level_zero:0
#Environment=SYCL_CACHE_PERSISTENT=1
#Environment=SYCL_CACHE_DIR=/home/hans/ai/cache/sycl

ExecStart=/bin/bash -c 'set +u && source /opt/intel/oneapi/setvars.sh && set -u && \
    export LD_LIBRARY_PATH=/home/hans/ai/xpu/venv/bin:${LD_LIBRARY_PATH:-} && \
    exec /home/hans/ai/xpu/venv/bin/llama-server \
    --host 127.0.0.1 \
    --port 9931 \
    --models-max 1 \
    --tools all \
    --models-preset /home/hans/ai/models/llm_presets/32gb.ini'

[Install]
WantedBy=default.target

llama-vulkan.service (llama.cpp server AMD Vulkan)
# /home/hans/.config/systemd/user/llama-vulkan.service
[Unit]
Description=llama.cpp Vulkan
After=network.target

[Service]
WorkingDirectory=/home/hans/ai/rocm
Type=simple
Restart=on-failure
RestartSec=5
TimeoutStopSec=15
OOMScoreAdjust=-500

Environment=VK_ICD_FILENAMES=/usr/share/vulkan/icd.d/radeon_icd.x86_64.json
Environment=RADV_PERFTEST=transfer_queue

ExecStart=/bin/bash -c 'export LD_LIBRARY_PATH=/home/hans/ai/rocm/venv/bin:${LD_LIBRARY_PATH:-} && \
    exec /home/hans/ai/rocm/venv/bin/llama-server \
    --host 127.0.0.1 \
    --port 9932 \
    --models-max 1 \
    --tools all \
    --models-preset /home/hans/ai/models/llm_presets/16gb.ini'

[Install]
WantedBy=default.target

OneTrainer.desktop (OneTrainer LoRA treenaus)
# /home/hans/.local/share/applications/OneTrainer.desktop
[Desktop Entry]
Comment=
Exec=/usr/bin/bash -c 'cd /home/hans/ai/onetrainer; source venv/bin/activate; python scripts/train_ui_qt.py &>log.txt'
Icon=/home/hans/ai/onetrainer/resources/icons/icon.png
Name=OneTrainer
NoDisplay=false
Path=
PrefersNonDefaultGPU=false
StartupNotify=true
Terminal=false
TerminalOptions=
Type=Application
X-KDE-SubstituteUID=false
X-KDE-Username=

päivitetty 5.9.2026 | lähdekoodi