FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

Comparing leejet:master...unslothai:master · leejet/stable-diffusion.cpp · GitHub

Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: leejet/stable-diffusion.cpp
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: master
Choose a base ref
Could not load branches
Nothing to show
{{ refName }}
...
head repository: unslothai/stable-diffusion.cpp
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: master
Choose a head ref
Could not load branches
Nothing to show
{{ refName }}
Checking mergeability… Don’t worry, you can still create the pull request.
  • 15 commits
  • 10 files changed
  • 2 contributors

Commits on Jul 1, 2026

  1. CI: build + publish Unsloth CPU/Apple stable-diffusion.cpp prebuilts

    Add a GitHub Actions pipeline that builds sd-cli + sd-server for the platforms
    where the native engine beats diffusers (CPU on Linux/WSL/Windows, and Apple
    Metal), then publishes them as release assets named to match the Unsloth Studio
    installer's resolver. GPU hosts use diffusers/torch, so no CUDA/ROCm/Vulkan.
    
    unsloth-sd-prebuilt.yml: resolve (leejet tag, supply-chain aged, stamped source
    tarball) then build-unix (macOS arm64 Metal + x64, Linux x64 + arm64) plus
    build-windows (x64, MSVC/Ninja) then assemble (fingerprint gate, sha256 plus
    manifest, coverage gate, atomic draft to publish).
    
    scripts/unsloth: package_bundle.py (resolver-compatible zips), assemble_metadata.py
    (sha256 plus manifest), assert_macho_minos.sh (macOS load-floor gate).
    
    Builds with SD_SERVER_BUILD_FRONTEND, SD_WEBP and SD_WEBM off, so only the ggml
    submodule is needed.
    danielhanchen committed Jul 1, 2026
    Configuration menu
    Copy the full SHA
    83f117a View commit details
    Browse the repository at this point in the history

Commits on Jul 4, 2026

  1. Configuration menu
    Copy the full SHA
    317d4e1 View commit details
    Browse the repository at this point in the history
  2. Pass /bigobj to the Windows CPU prebuilt build

    stable-diffusion.cpp grew past MSVC's default object section limit on the
    newer upstream tags (fatal error C1128 in run 28701743849); upstream's own
    Windows CI passes -DCMAKE_CXX_FLAGS='/bigobj' for the same reason.
    danielhanchen committed Jul 4, 2026
    Configuration menu
    Copy the full SHA
    f7007b0 View commit details
    Browse the repository at this point in the history

Commits on Aug 7, 2026

  1. Configuration menu
    Copy the full SHA
    59bba6e View commit details
    Browse the repository at this point in the history

Commits on Aug 8, 2026

  1. Spare 1-D norm weights from a blanket --type

    tensor_should_be_converted has no rule for 1-D weights, so a per-channel norm
    scale survives a blanket --type only by accident: when its length does not
    divide the quant block size (FLUX q_norm/k_norm are [128] and 128 % 256 != 0),
    or when one of the FLUX-era name rules happens to match it.
    
    MiniMax-H3's per-block norms are [5376], and 5376 % 256 == 0, so a blanket
    --type q4_K quantizes 105 of them. The result loads and renders a plausible
    video, so a "does it run" check passes it, but scored against a bf16 render of
    the same prompt and seed it is destroyed.
    
    A 1-D weight is a per-channel gain, never a matmul weight. Every channel of a
    block would share one scale and one min, and a gain vector has no reason to be
    locally smooth, so quantizing it buys almost nothing and costs a lot: on this
    model holding all 211 1-D tensors adds 0.77 MiB to a 10.60 GiB file, 0.007%.
    
    Measured on minimax_h3_fl2va_pruned, converted from the same bf16 checkpoint
    with a blanket --type q4_K and no --tensor-type-rules, rendered at 640x384,
    25 frames, 4 steps, cfg 1.0, seed 1234, --rng cpu, and scored against a bf16
    render of that same prompt and seed:
    
        1-D tensor types                          PSNR   SSIM   LPIPS
        before  F32 5, F16 51, BF16 106, Q4_K 105  9.87  0.074   0.981
        after   F32 5, F16 51, BF16 211           22.22  0.841   0.292
    
    SSIM 0.074 means the output is essentially uncorrelated with the reference.
    
    The 1-D rule alone is sufficient. A build made with
    --tensor-type-rules 'norm[0-9]*\.weight$=bf16,condition_proj\.weight$=bf16'
    produces the same 1-D layout and scores 21.52 / 0.838 / 0.299, so nothing here
    depends on also sparing condition_proj.weight, which is 2-D and a separate
    quality choice. Peak VRAM is unchanged at 16.83 GiB.
    danielhanchen committed Aug 8, 2026
    Configuration menu
    Copy the full SHA
    7a431ec View commit details
    Browse the repository at this point in the history
  2. Stop MiniMax-H3 aborting on default cfg-scale and on --vae-on-cpu

    Two independent SIGABRTs, both reachable from ordinary invocations.
    
    1. cfg-scale. H3 is distilled with guidance baked in and has no negative prompt
    semantics; its empty uncond prompt encodes to zero tokens, so building the uncond
    branch trips GGML_ASSERT(!ggml_is_transposed(a)) in ggml.c. sd.cpp defaults
    --cfg-scale to 7.0, so a bare `sd-cli --mode vid_gen` on H3 crashes rather than
    rendering. Measured: cfg 1.0 renders, cfg 1.5 and cfg 4.0 both abort, exit 134.
    
    There is no correct cfg > 1 behaviour to implement for a CFG-free model, so warn
    and clamp to 1.0 instead of asserting deep inside ggml.
    
    2. --vae-on-cpu. ggml_conv_1d and ggml_conv_1d_dw build an F16 im2col, and the
    CPU backend additionally requires the kernel itself to be F16;
    ggml_compute_forward_im2col_f16 asserts it. audio_conv_weight_type maps only
    BF16 to F16 and lets F32 through, so H3's F32 audio conv kernels abort with
    GGML_ASSERT(src0->type == GGML_TYPE_F16) as soon as the audio VAE decodes on the
    CPU. Converting the checkpoint to fp16 does not help: the type is imposed here,
    not by the file.
    
    Cast the kernel in-graph, and only when the runner is actually on a CPU backend,
    so GPU precision is untouched and no weight is degraded at load. All four
    conv_1d sites in this file need it, not just the module ones: the STFT
    forward_basis and the transposed-conv reversed_filter are computed F32 tensors
    that reach the same assert. depthwise_conv_transpose1d therefore takes the
    runner context rather than a bare ggml_context.
    
    Verified on minimax_h3_fl2va_pruned q4_K, 640x384, 25 frames, 4 steps, seed 1234:
    
        case                              before      after
        --cfg-scale 4.0                   exit 134    exit 0
        cfg omitted (default 7.0)         exit 134    exit 0
        --vae-on-cpu --audio-vae          exit 134    exit 0
        full low_vram flag set            exit 134    exit 0
        baseline                          exit 0      exit 0, byte-identical
        --offload-to-cpu                  exit 0      exit 0, byte-identical
    
    The two CPU-VAE cases differ from the baseline by 114 bytes, which is the
    expected consequence of their conv kernels now running F16 on the CPU.
    danielhanchen committed Aug 8, 2026
    Configuration menu
    Copy the full SHA
    1c0397a View commit details
    Browse the repository at this point in the history
  3. Fail with a message when MiniMax-H3 is run in img_gen mode

    H3 is video-only: the denoiser always splits the packed latent into a video and
    an audio half, and only generate_video computes the audio length. Reaching
    generate_image with an H3 checkpoint therefore hits
    GGML_ASSERT(!audio_input_cache.empty()) and core dumps, after the minutes it
    takes to load the weights and with nothing in the output naming the cause.
    Forgetting --mode vid_gen is easy since it is the one flag not implied by
    passing --audio-vae.
    
    Before: SIGABRT, exit 134, a ggml assert and a stack trace.
    After:  "MiniMax-H3 is a video model and cannot be run in img_gen mode; use
            --mode vid_gen", exit 1.
    
    The AnimateDiff branch routes vid_gen back through generate_image, but that is
    SD1.5 plus a motion module and never H3, so the guard cannot fire there.
    danielhanchen committed Aug 8, 2026
    Configuration menu
    Copy the full SHA
    6fd03c9 View commit details
    Browse the repository at this point in the history
  4. Apply the open H3 fixes to the prebuilts we publish

    The prebuilt pipeline builds leejet's source at an aged release tag, not this
    fork's master, so the three MiniMax-H3 fixes on master reach nobody: every
    Studio user installs a binary that still aborts on the default cfg-scale, still
    aborts on --vae-on-cpu, and still quantizes H3's 1-D norms into an output
    uncorrelated with its own bf16 reference.
    
    Building from master instead would throw away the reason the pipeline is shaped
    this way, which is that what we publish should be traceable to a specific
    upstream release. So keep the upstream tag as the base and carry the delta
    explicitly:
    
    - patches/ holds one file per fix, each with its upstream pull request in the
      header. All three are open on leejet: #1861, #1862, #1863.
    - resolve applies them to the checked-out tag, after running git apply --check
      over the whole set so a stale patch stops the run before the tree is half
      modified. That failure is the signal to delete the patch (upstream merged it)
      or refresh it (upstream moved the code).
    - a non-empty set moves the published tag to <upstream tag>-u<id>, where id is
      the sha256 prefix of the concatenated patches. The tag then says whether a box
      is stock, and a changed patch set republishes rather than matching an existing
      release and skipping.
    - the manifest and the release notes both record the applied list.
    
    An empty patches/ leaves the tag and every asset name exactly as they are today.
    
    Verified by running the resolve step against master-813-bfbef5b with gh stubbed:
    all three patches apply, the tag becomes master-813-bfbef5b-u<id>, and the
    stamped source tarball contains the fixes.
    danielhanchen committed Aug 8, 2026
    Configuration menu
    Copy the full SHA
    ef18136 View commit details
    Browse the repository at this point in the history
  5. CI: raise ROCm ccache to 2G, drop 1d eviction (#6)

    * CI: raise ROCm ccache to 2G, drop 1d eviction
    
    The Windows ROCm leg is getting a 4.13% ccache hit rate (16 of 387), which is
    the same signature we already fixed in llama.cpp. Two causes, both here:
    
    ccache-action defaults max-size to 500M when the input is unset. That truncates
    the cache at save, and a truncated cache is worse than none: it restores fine,
    then misses on everything that got dropped, so the hit rate collapses with
    nothing failing. Linux measured 0.4 GB of 0.5 and 73.65% hits; Windows 0.3 of
    0.5 and 4.13%.
    
    evict-old-files: 1d discards objects by age on top of that. Age eviction at a
    sub-daily build cadence throws away objects that are still being reused, and a
    local replay showed it costs hit rate rather than saving space. ccache's own
    LRU under a 2G ceiling covers the same ground.
    
    Both blocks match upstream leejet byte for byte, so this is a deliberate
    divergence and will show up on the next sync.
    
    * Fix the Windows ROCm cache miss at its actual cause
    
    My first pass had the Windows diagnosis wrong and the eviction change
    backwards. Four consecutive Windows runs disprove the truncation story:
    
      92812296767  0.2 / 0.5 (42.26%)   13 / 385 (3.38%)
      93021695452  0.2 / 0.5 (42.54%)   17 / 387 (4.39%)
      93045420552  0.3 / 0.5 (64.40%)   16 / 387 (4.13%)
      93056114309  0.3 / 0.5 (65.52%)   16 / 387 (4.13%)
    
    The cache never reached the 500M cap, so it was never truncated, and the hit
    rate is flat whether it is 42% or 65% full. Two runs restoring different caches
    produced identical hit counts, which is a restored cache contributing nothing.
    
    The real cause: every Windows run logs "Cache not found for input keys:
    rocm-wheels-7.14.0-Windows" and re-expands the devel tree, so clang gets a new
    mtime, and ccache's default compiler_check=mtime hashes mtime and size. Every
    object is keyed to a compiler hash that never recurs. Ubuntu never expands a
    devel tree and sits at 73.65%. Set CCACHE_COMPILERCHECK=content on the Windows
    job, which the ccache manual recommends for exactly this bootstrapping case.
    
    Restored evict-old-files: 1d on both. The manual defines --evict-older-than as
    removing files "used less recently than AGE" and notes ccache refreshes mtime
    on every hit, so it never discards objects still being reused. On Windows it is
    the only thing reaping objects that can never be hit again, and removing it
    alongside a 2G cap would have parked ~2 GB of dead objects per ref.
    
    max-size: 2G stays on Ubuntu only, where it is earned: that cache plateaus at
    the default (88.19% full, 142 misses per run). Windows keeps the default until
    the compiler hash is stable, which also avoids multiplying a repo already at
    10.39 GB of cache.
    
    * Apply the 2G cap to the Windows ROCm ccache too
    
    max-size is an upper bound, not a reservation: ccache stores only what it
    compiles, and GitHub bills actual bytes, so a cap the build never approaches
    costs nothing. Measured across llama.cpp's 38 build legs at 2G, total usage is
    10.69 GB, mean 0.28 GB, and no leg exceeds 0.9 GB.
    
    Windows was left at the default in the previous commit because it was not
    cap-bound and its objects were unusable. With CCACHE_COMPILERCHECK=content the
    objects become reusable, so the cache is worth letting grow, and
    evict-old-files: 1d still reaps anything untouched for a day. Uniform settings
    across both legs also mean one less thing to re-tune when a build grows.
    
    ---------
    
    Co-authored-by: danielhanchen <unslothshared@gmail.com>
    danielhanchen and danielhanchen authored Aug 8, 2026
    Configuration menu
    Copy the full SHA
    d9ad778 View commit details
    Browse the repository at this point in the history
  6. CI: run the GPU build legs on demand only (#7)

    Nothing this workflow builds ships. Our prebuilts come from
    unsloth-sd-prebuilt.yml, which is CPU and Apple only by design because GPU
    hosts run diffusers/torch. No release here has ever carried a CUDA, ROCm or
    Vulkan asset, and build.yml's own release job fails on every push with
    "Resource not accessible by integration", so it has never published anything.
    Even a forced native GPU load does not use these: install_sd_cpp_prebuilt.py
    falls back to leejet upstream when our mirror cannot serve the host.
    
    Measured on run 31238801839, the GPU legs are 561 of 658 minutes, 85% of the
    run, and they are the source of the multi-GB artifacts that were filling
    Actions storage.
    
    Gated to workflow_dispatch: ubuntu-latest-cmake-vulkan, windows-latest-rocm,
    ubuntu-latest-rocm, the container images job, and the cuda12 and vulkan entries
    of windows-latest-cmake. What still runs on push and PR is the compile smoke
    signal worth keeping: ubuntu-latest-cmake, macOS-latest-cmake and windows CPU,
    about 29 minutes.
    
    The matrix entries cannot take a job-level if, so that one uses a fromJSON
    ternary. Verified both branches parse back to the original entries with the
    defines byte-identical, and that the file is otherwise unchanged outside the
    five gates.
    
    Side effect worth knowing: release needs the gated jobs, so on a master push it
    now skips instead of failing. It has never succeeded here, so this removes a
    standing red X rather than losing a capability. Reverting any single gate
    restores the old behaviour for that leg.
    
    Co-authored-by: danielhanchen <unslothshared@gmail.com>
    danielhanchen and danielhanchen authored Aug 8, 2026
    Configuration menu
    Copy the full SHA
    22e2879 View commit details
    Browse the repository at this point in the history

Commits on Aug 9, 2026

  1. CI: build the prebuilts from this repository, not from a fetched tarb…

    …all (#8)
    
    * CI: build the prebuilts from this repository, not from a fetched tarball
    
    The pipeline resolved an upstream release tag, fetched that tree, applied
    the patch set in patches/, and built the result. That made every
    published binary depend on a foreign repository at build time and left
    three fixes living as diffs that had to be kept applying to a tree we do
    not control.
    
    All three are already commits here, merged as PRs 2, 3 and 4. So build
    this checkout. patches/ is deleted; there is nothing left to re-apply.
    
    The tag still names the upstream release the tree descends from, read
    from our own history rather than from an API, with the head sha as the
    -u suffix:
    
        master-813-bfbef5b-u22e2879
    
    Two details worth keeping.
    
    HIGHEST reachable release, not nearest. git describe answers "nearest",
    and on a merge-shaped history that is wrong: this tree reaches
    master-813 through a merge 73 commits back and master-811 on its own
    line 13 commits back, so describe names the build after 811 and
    understates what it contains.
    
    The -u suffix is now always present, which is what it should have been.
    Studio's installer treats a -u tag as mirror-only and goes straight to
    this repository's releases instead of trying an upstream download that
    is guaranteed to 404. A build of ours is never a stock upstream build,
    so it should never carry a bare upstream tag.
    
    Supply-chain aging is kept and re-pointed: it now guards the age of the
    upstream release the tree descends from rather than the moment a
    release appeared. Our own commits on top are reviewed here, so they are
    not what the delay is for.
    
    assemble_metadata keeps its --patches flag, always empty, so existing
    manifest readers do not have to change.
    
    * CI: carry pinned PRs into the prebuilts, like unslothai/llama.cpp does
    
    The prebuilts now build this tree, but that alone only ships what is
    already merged. The llama.cpp pipeline exists to ship a reviewed mix:
    an aged upstream base plus a set of pull requests pinned to exact
    commits, merged at build time. This adds the same mechanism here.
    
    scripts/unsloth/pr-set.json lists PRs to merge, each pinned to a
    40-hex commit copied from the PR's commits tab. Only that commit is
    built, so an author pushing more commits cannot change what the
    nightly ships. Non-open required pins fail the build rather than
    silently publishing without them, because dropping a pin changes the
    tag and would ship a quietly different binary under a new name.
    additive_merge.py, vendored from unslothai/llama.cpp, resolves the one
    conflict shape that is mechanical (both sides only added, at a place
    the merge base had nothing) and refuses to guess at anything else.
    
    One deliberate difference from llama.cpp. There the base is a pristine
    upstream release, so every Unsloth change has to stay pinned and open,
    and merging one into fork master drops it from the nightly. Here the
    base is our own tree, so a merged fix is simply in it and its pin is
    deleted. That is why the three MiniMax-H3 fixes need no pins.
    
    Only PRs in this repository may be pinned. To carry a fix that exists
    as an upstream pull request, vendor it here as a PR first and pin
    that. The build fetches from nowhere else.
    
    The tag suffix absorbs the set: with no pins it is the head sha, with
    pins it hashes the pinned number:sha pairs together with the head sha,
    so a repin or a reorder yields a new tag and a rebuild while an
    unchanged set still matches an existing release and skips. The
    existing -u shape is kept rather than llama.cpp's -mix-, because
    Studio's installer keys mirror-only resolution on it.
    
    Verified locally against this tree: the schema gate passes, an empty
    set yields master-813-bfbef5b-u692a7c8, a one-pin set yields a
    different suffix, and both match the installer's mirror-only pattern.
    
    * CI: publish a Linux CUDA prebuilt
    
    The CPU/Apple matrix rests on the assumption that a GPU host runs the
    diffusers path instead. MiniMax-H3 breaks that assumption: its diffusers
    path wants ~68.5 GB of VRAM, so every consumer card falls back to the
    GGUF engine, and on Linux that engine had no accelerated build to fall
    back to. Measured on one box, 65 s/step at 320x192 across 96 CPU
    threads, against 21.5 s/step at 960x544 from a local CUDA build of the
    same tag: four hours per clip versus eleven minutes.
    
    The new leg is continue-on-error and is not in the coverage gate, which
    still lists exactly the five CPU/Apple assets. assemble collects bundles
    by the sd-*-bin-* pattern, so the CUDA asset is published when it built
    and simply absent when it did not; a broken CUDA toolchain can never
    hold back the assets Studio falls back to.
    
    sm_75 through sm_120, which is the first toolkit able to emit sm_100 and
    sm_120 and covers everything from Turing up. The CUDA runtime libraries
    are copied in beside the binaries with an $ORIGIN rpath, because a host
    with an NVIDIA driver does not necessarily have a CUDA runtime installed
    and we must not lean on the copies torch keeps.
    
    package_bundle matched runtime libraries on Path.suffix, which reads
    ".12" for libcudart.so.12 and dropped it. It now matches the ".so."
    infix as well, so a versioned soname ships under the exact name
    DT_NEEDED spells.
    
    * CI: name the cuBLAS packages the way apt does
    
    cuda-toolkit installs sub-packages as cuda-<name>-12-8, and cuBLAS does not use
    that prefix, so apt could not find cuda-cublas-12-8 or cuda-cublas_dev-12-8 and
    the leg died before it compiled anything. They belong in non-cuda-sub-packages
    as libcublas and libcublas-dev. cudart-dev joins the list too, since cudart on
    its own is the runtime and carries no headers to compile against.
    
    The libcublas debs land in the system multiarch directory rather than under the
    toolkit root, so the bundling step now searches both.
    danielhanchen authored Aug 9, 2026
    Configuration menu
    Copy the full SHA
    13b9d92 View commit details
    Browse the repository at this point in the history

Commits on Aug 10, 2026

  1. CI: ccache the SD CUDA leg (#9)

    * CI: ccache the SD CUDA leg
    
    This leg rebuilt every object on every run. It took 3903 s of the 4121 s job on
    2026-08-09 and 4942 s on the run before it, with no speedup between the two,
    while every other job in the pipeline finished in under 8 minutes. The repo held
    no cache entry for it at all, only the ROCm ones build.yml writes.
    
    Key on the CUDA version and the architecture list, since both decide the
    objects, and set the CUDA compiler launcher as well as C and CXX: nvcc is nearly
    the whole build and Jimver installs it outside the default search. Save on
    always() so a failed or capped job keeps what it compiled.
    
    * CI: do not fail the CUDA build on a ccache stats call
    danielhanchen authored Aug 10, 2026
    Configuration menu
    Copy the full SHA
    ff6b225 View commit details
    Browse the repository at this point in the history

Commits on Aug 11, 2026

  1. Configuration menu
    Copy the full SHA
    2d2351f View commit details
    Browse the repository at this point in the history
  2. Configuration menu
    Copy the full SHA
    2869179 View commit details
    Browse the repository at this point in the history

Commits on Aug 25, 2026

  1. Pin the unsloth-sd-prebuilt actions to commit SHAs (#12)

    All 18 action references in unsloth-sd-prebuilt.yml resolved through a moving
    tag, including msvc-dev-cmd and cuda-toolkit, which run in the jobs that build
    and upload the prebuilt binaries.
    
    Each SHA is the commit the corresponding tag points at today, so nothing about
    what runs changes and no version is bumped. That includes the older majors this
    workflow pins deliberately, checkout v4, upload-artifact v4, download-artifact
    v4, setup-python v5 and cuda-toolkit v0.2.22, none of which are moved forward
    here.
    
    Upstream build.yml, close-inactive-issues.yml and stale-prs.yml are left alone
    so this costs nothing at the next upstream sync.
    danielhanchen authored Aug 25, 2026
    Configuration menu
    Copy the full SHA
    ea65600 View commit details
    Browse the repository at this point in the history
Loading

Back | FazBrowse Home | New Git URL