Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
[reforge]: https://github.com/Panchovix/stable-diffusion-webui-reForge
[simplesdxl]: https://github.com/metercai/SimpleSDXL/
[fluxgym]: https://github.com/cocktailpeanut/fluxgym
[fizgig]: https://github.com/shootthesound/Fizgig
[cogvideo]: https://github.com/THUDM/CogVideo
[cogstudio]: https://github.com/pinokiofactory/cogstudio
[amdforge]: https://github.com/lshqqytiger/stable-diffusion-webui-amdgpu-forge
Expand Down Expand Up @@ -63,6 +64,7 @@ See the [documentation index](docs/README.md) for installation, package manageme
- [Kohya's GUI][kohya-ss]
- [OneTrainer][onetrainer]
- [FluxGym][fluxgym]
- [Fizgig][fizgig]
- [CogVideo][cogvideo] via [CogStudio][cogstudio]
- Manage plugins / extensions for supported packages ([Automatic1111][auto1111], [Comfy UI][comfy], [SD Web UI-UX][webui-ux], and [SD.Next][sdnext])
- Easily install or update Python dependencies for each package
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ private void OnRunningPackageStatusChanged(object? sender, RunningPackageStatusC

var packageTitle = args.CurrentPackagePair.BasePackage switch
{
Fizgig => "Fizgig",

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Totally optional and fine as is: this switch just repeats each package's DisplayName, so a _ => args.CurrentPackagePair.BasePackage.DisplayName default would remove the need for this arm (and fix packages like AI-Toolkit showing "Running Stable Diffusion"). Happy to leave that for a follow-up on our side.

FluxGym => "FluxGym",
Fooocus => "Fooocus",
Reforge => "SD WebUI reForge",
Expand Down
8 changes: 8 additions & 0 deletions StabilityMatrix.Core/Helper/Factory/PackageFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,14 @@ public BasePackage GetNewBasePackage(InstalledPackage installedPackage)
pyInstallationManager,
pipWheelService
),
"Fizgig" => new Fizgig(
githubApiCache,
settingsManager,
downloadService,
prerequisiteHelper,
pyInstallationManager,
pipWheelService
),
"ai-toolkit" => new AiToolkit(
githubApiCache,
settingsManager,
Expand Down
194 changes: 194 additions & 0 deletions StabilityMatrix.Core/Models/Packages/Fizgig.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
using Injectio.Attributes;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: tiny one, the file starts with a UTF-8 BOM. A few older package files have one too, but we're avoiding it in new files.

using StabilityMatrix.Core.Helper;
using StabilityMatrix.Core.Helper.Cache;
using StabilityMatrix.Core.Helper.HardwareInfo;
using StabilityMatrix.Core.Models.Progress;
using StabilityMatrix.Core.Processes;
using StabilityMatrix.Core.Python;
using StabilityMatrix.Core.Services;

namespace StabilityMatrix.Core.Models.Packages;

[RegisterSingleton<BasePackage, Fizgig>(Duplicate = DuplicateStrategy.Append)]
public class Fizgig(
IGithubApiCache githubApi,
ISettingsManager settingsManager,
IDownloadService downloadService,
IPrerequisiteHelper prerequisiteHelper,
IPyInstallationManager pyInstallationManager,
IPipWheelService pipWheelService
)
: BaseGitPackage(
githubApi,
settingsManager,
downloadService,
prerequisiteHelper,
pyInstallationManager,
pipWheelService
)
{
public override string Name => "Fizgig";
public override string DisplayName { get; set; } = "Fizgig";
public override string Author => "shootthesound";

public override string Blurb =>
"LoRA training studio for Flux 2 Klein 9B, Krea 2, MiniMax H3 and Qwen Image 2.1 — train, profile, repair and extract";

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: we keep em dashes out of user-facing copy. Maybe ...MiniMax H3 and Qwen Image 2.1. Train, profile, repair and extract?


// Shown in the install browser before the user commits to installing.
public override string Disclaimer =>
Compat.IsWindows
? "Visual Studio Build Tools for C++ Desktop Development will be installed system-wide if not already present (may require admin privileges). "
+ "They are shared with other software and remain installed after Fizgig is uninstalled."
: string.Empty;

public override string LicenseType => "Apache-2.0";
public override string LicenseUrl => "https://github.com/shootthesound/Fizgig/blob/master/LICENSE";

// NOT launch.pyw: that launcher re-spawns itself under venv/Scripts/pythonw.exe and exits,
// which would drop the process we track (no console output, no working Stop button) and
// leave the GUI orphaned. lora_trainer_gui.py has a standalone main() and is what upstream's
// run_fizgig.sh invokes directly.
public override string LaunchCommand => "lora_trainer_gui.py";

public override Uri PreviewImageUri =>
new("https://github.com/shootthesound/Fizgig/blob/master/icon.png?raw=true");

public override string MainBranch => "master";
public override PackageType PackageType => PackageType.SdTraining;
public override PackageDifficulty InstallerSortOrder => PackageDifficulty.Advanced;
public override bool OfferInOneClickInstaller => false;
public override bool IsCompatible => HardwareHelper.HasNvidiaGpu();
public override IEnumerable<TorchIndex> AvailableTorchIndices => [TorchIndex.Cuda];

public override TorchIndex GetRecommendedTorchVersion() => TorchIndex.Cuda;

public override PyVersion RecommendedPythonVersion => Python.PyInstallationManager.Python_3_12_10;

// Tkinter for the GUI itself; VcBuildTools for triton / torch.compile's inductor backend,
// which the Compile Blocks speedup needs on Windows.
public override IEnumerable<PackagePrerequisite> Prerequisites =>
base.Prerequisites.Concat([PackagePrerequisite.Tkinter, PackagePrerequisite.VcBuildTools]);

public override List<LaunchOptionDefinition> LaunchOptions => [LaunchOptionDefinition.Extras];

// Trained LoRAs, not images.
public override string OutputFolderName => string.Empty;
public override Dictionary<SharedOutputType, IReadOnlyList<string>>? SharedOutputFolders => null;

/// <summary>
/// Defaults to None, matching the other trainers. Opting in to Symlink (Package Manager ->
/// ... -> Shared Model Strategy) junctions output_loras into the shared Lora folder, so a
/// freshly trained LoRA is immediately visible to ComfyUI and friends.
/// </summary>
public override SharedFolderMethod RecommendedSharedFolderMethod => SharedFolderMethod.None;

public override IEnumerable<SharedFolderMethod> AvailableSharedFolderMethods =>
[SharedFolderMethod.None, SharedFolderMethod.Symlink];

/// <remarks>
/// Only output_loras is mapped. Fizgig's models/ directory deliberately flattens every
/// weight it downloads into one folder — DiTs, text encoders, VAEs, turbo LoRAs and training
/// adapters all land there as bare filenames (see src/fizgig/scripts/fetch_models.py) — and
/// junctions are directory-level, so there is no way to fan that single directory out to
/// DiffusionModels/TextEncoders/VAE without them colliding on the same target path.
/// </remarks>
public override SharedFolderLayout SharedFolderLayout =>
new()
{
Rules =
[
new SharedFolderLayoutRule
{
SourceTypes = [SharedFolderType.Lora],
TargetRelativePaths = ["output_loras"],

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Heads up: Fizgig writes more than finished LoRAs into output_loras. Sample images go to output_loras/sample (get_samples_dir() in lora_trainer_gui.py), and with save-state on, the resume state folders (optimizer + weights, often several GB) land there too via save_state_on_epoch_end / save_and_remove_state_stepwise.

With Symlink enabled, all of that ends up in the shared Models/Lora folder, so ComfyUI's LoRA list would show the state-dir weights and the Checkpoint Manager would scan them. Fizgig's own LoRA pickers would also open on the user's whole LoRA library.

I'd lean towards dropping Symlink for now (None only, like the other trainers). Fizgig already has an Output Directory field, so anyone who wants their LoRAs in the shared folder can point it there themselves.

},
],
};

public override async Task InstallPackage(
string installLocation,
InstalledPackage installedPackage,
InstallPackageOptions options,
IProgress<ProgressReport>? progress = null,
Action<ProcessOutput>? onConsoleOutput = null,
CancellationToken cancellationToken = default
)
{
progress?.Report(new ProgressReport(-1f, "Setting up venv", isIndeterminate: true));

await using var venvRunner = await SetupVenvPure(
installLocation,
pythonVersion: options.PythonOptions.PythonVersion
)
.ConfigureAwait(false);

// hqq ships as an sdist whose setup.py kicks off a CUDA kernel build during egg_info
// unless DISABLE_CUDA is set. Fizgig only uses its pure-PyTorch path, and its own
// requirements.txt warns never to install that line without this.
venvRunner.UpdateEnvironmentVariables(env => env.SetItem("DISABLE_CUDA", "1"));

const string torchVersion = "==2.10.0";

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since releases are tracked and upstream ships often, these hardcoded pins worry me a bit. The exclude pattern strips upstream's own torch== lines, so when upstream bumps torch, an SM update keeps installing 2.10.0 (and re-pins it via ExtraPipArgs) without any error.

The risky part is triton: upstream pins triton-windows>=3.5.1,<3.7 and says to bump it together with torch. After their next torch bump we'd pair a newer triton-windows with the old torch, which is the mismatch their requirements.txt notes as hanging Krea 2 previews inside torch.compile.

Could we read the torch / torchvision lines and the --extra-index-url out of requirements.txt instead (roughly what upstream's uv_install_deps._parse_requirements does), and keep the torch-first ordering? Then the pins follow upstream automatically.

const string torchvisionVersion = "==0.25.0";

var config = new PipInstallConfig
{
RequirementsFilePaths = ["requirements.txt"],
// Drop the torch pins and the cu128 index line from the file so the pre-install step
// below is the single source of truth for which build lands in the venv. The pattern
// is anchored against the whole entry by the caller, so the version specifier has to
// be matched too - the default pattern only catches bare, unpinned names.
RequirementsExcludePattern =
@"(--extra-index-url.*|(torch|torchvision|torchaudio|xformers)([=<>!~].*)?)",
// Install the cu128 build before the requirements. accelerate (and friends) depend on
// torch transitively, so installing it afterwards would let the requirements step
// pull a default PyPI build that then has to be force-reinstalled over.
// torch 2.10 pairs with cu128 here; SM's default cu130 has no matching wheels.
PrePipInstallArgs =
[
$"torch{torchVersion}",
$"torchvision{torchvisionVersion}",
"--extra-index-url",
"https://download.pytorch.org/whl/cu128",
"--force-reinstall",

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: on a fresh install this step runs first, so there's nothing to force over. The flag only kicks in on updates, where it reinstalls torch, torchvision and all the nvidia-* CUDA wheels every time even when 2.10.0+cu128 is already there. Without it, uv keeps a matching build and still replaces a mismatched one.

],
// Re-state the pins alongside the requirements: pip then treats the installed
// 2.10.0+cu128 as satisfying them instead of resolving its own torch from PyPI, and
// fails loudly rather than swapping it if anything conflicts.
ExtraPipArgs = [$"torch{torchVersion}", $"torchvision{torchvisionVersion}"],
SkipTorchInstall = true,
};

await StandardPipInstallProcessAsync(
venvRunner,
options,
installedPackage,
config,
onConsoleOutput,
progress,
cancellationToken
)
.ConfigureAwait(false);

venvRunner.UpdateEnvironmentVariables(env => env.Remove("DISABLE_CUDA"));

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: this venvRunner is local and disposed by the await using right after, and RunPackage builds a fresh one via SetupVenv, so DISABLE_CUDA can't leak anywhere. This line can just go.

}

public override async Task RunPackage(
string installLocation,
InstalledPackage installedPackage,
RunPackageOptions options,
Action<ProcessOutput>? onConsoleOutput = null,
CancellationToken cancellationToken = default
)
{
await SetupVenv(installLocation, pythonVersion: PyVersion.Parse(installedPackage.PythonVersion))
.ConfigureAwait(false);

// Desktop Tkinter app - there is no local URL to wait for, so startup is complete
// as soon as the process is up.
VenvRunner.RunDetached(
[Path.Combine(installLocation, options.Command ?? LaunchCommand), .. options.Arguments],
onConsoleOutput,
OnExit
);
}
}
2 changes: 1 addition & 1 deletion docs/advanced/hardware-support.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ The lists below describe what the code checks for. Because hardware detection wo
- **Caveats:**
- The `cu130` wheels require an NVIDIA driver of version 580 or newer. ComfyUI checks the installed driver on launch and warns if it is older than 580.x while `cu130` torch is installed, suggesting either a driver update or manually downgrading to an older torch index such as `cu128`.
- Turing (RTX 2000-series) or newer is the practical recommendation; older cards may still work but are treated as legacy.
- **Packages:** CUDA is the most broadly supported backend. Every inference package that lists a GPU backend supports CUDA, and CUDA-only packages include Fooocus, SimpleSDXL, ForgeClassic, FramePack, and the training tools (Kohya's GUI, OneTrainer, FluxGym, AI Toolkit).
- **Packages:** CUDA is the most broadly supported backend. Every inference package that lists a GPU backend supports CUDA, and CUDA-only packages include Fooocus, SimpleSDXL, ForgeClassic, FramePack, and the training tools (Kohya's GUI, OneTrainer, FluxGym, AI Toolkit, Fizgig).

## AMD on Windows

Expand Down
3 changes: 2 additions & 1 deletion docs/package-manager/supported-packages.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,9 @@ Training packages are used to fine-tune or train AI models such as LoRAs, checkp
|---|---|
| **AI-Toolkit** | An all-in-one training suite for diffusion models supporting LoRA, full fine-tune, and more. |
| **OneTrainer** | A comprehensive one-stop solution for Stable Diffusion model training with a graphical interface. |
| **kohya_ss** | A Windows-focused Gradio GUI wrapping Kohya's popular Stable Diffusion trainer scripts. Windows only.|
| **kohya_ss** | A Windows-focused Gradio GUI wrapping Kohya's popular Stable Diffusion trainer scripts. Windows only. |
| **FluxGym** | A simple, low-VRAM Flux LoRA training UI designed for quick fine-tuning workflows. |
| **Fizgig** | A LoRA training studio for Flux 2 Klein 9B, Krea 2, MiniMax H3 and Qwen Image 2.1, with block profiling, repair and extraction tools. NVIDIA only, on Windows and Linux. |

---

Expand Down
Loading