Repository navigation
Add Fizgig LoRA training studio package #1761
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
e-nord
wants to merge
10
commits into
LykosAI:main
Choose a base branch
from
e-nord:feat-fizgig-package
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
5e4d417
feat: add Fizgig LoRA training studio package
e-nord ed47e1f
fix(fizgig): install CUDA torch before requirements, disclose VS Buil…
e-nord 128e8e9
docs(fizgig): note Linux support for the NVIDIA/CUDA path
e-nord 7ef903e
Merge branch 'main' into feat-fizgig-package
e-nord 0b9f961
chore(fizgig): remove UTF-8 BOM from Fizgig.cs
e-nord d2444fc
fix(fizgig): remove em dash from package blurb
e-nord 9944d2c
refactor(fizgig): drop redundant DISABLE_CUDA cleanup
e-nord 0aa7e97
fix(fizgig): stop force-reinstalling torch on every update
e-nord 888fa30
fix(fizgig): drop Symlink shared folder option
e-nord 136e078
fix(fizgig): read torch pins and index from upstream requirements.txt
e-nord File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,214 @@ | ||
| using System.Text.RegularExpressions; | ||
| using Injectio.Attributes; | ||
| 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 partial 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"; | ||
|
|
||
| // 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; | ||
|
|
||
| /// <remarks> | ||
| /// None only, like the other trainers. output_loras also receives sample images and multi-GB | ||
| /// resume-state folders, so linking it into the shared Lora folder would leak those into other | ||
| /// packages. Users who want trained LoRAs there can point Fizgig's Output Directory at it. | ||
| /// models/ can't be shared either: Fizgig flattens every weight it downloads into that one | ||
| /// directory, which doesn't map onto the per-type shared folders. | ||
| /// </remarks> | ||
| public override SharedFolderMethod RecommendedSharedFolderMethod => SharedFolderMethod.None; | ||
|
|
||
| public override IEnumerable<SharedFolderMethod> AvailableSharedFolderMethods => [SharedFolderMethod.None]; | ||
|
|
||
| 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")); | ||
|
|
||
| // Mirrors upstream's uv_install_deps.py: torch goes in first from the CUDA index, then | ||
| // the rest of requirements.txt without that index. The torch pins stay in the second | ||
| // step so nothing can swap the CUDA build for a PyPI one. | ||
| var (extraIndexUrl, torchSpecs) = await ParseRequirementsAsync( | ||
| Path.Combine(installLocation, "requirements.txt"), | ||
| cancellationToken | ||
| ) | ||
| .ConfigureAwait(false); | ||
|
|
||
| var config = new PipInstallConfig | ||
| { | ||
| RequirementsFilePaths = ["requirements.txt"], | ||
| RequirementsExcludePattern = "--extra-index-url.*", | ||
| PrePipInstallArgs = | ||
| extraIndexUrl is not null && torchSpecs.Count > 0 | ||
| ? [.. torchSpecs, "--extra-index-url", extraIndexUrl] | ||
| : [], | ||
| SkipTorchInstall = true, | ||
| }; | ||
|
|
||
| await StandardPipInstallProcessAsync( | ||
| venvRunner, | ||
| options, | ||
| installedPackage, | ||
| config, | ||
| onConsoleOutput, | ||
| progress, | ||
| cancellationToken | ||
| ) | ||
| .ConfigureAwait(false); | ||
| } | ||
|
|
||
| private static readonly string[] TorchEcosystem = ["torch", "torchvision", "torchaudio"]; | ||
|
|
||
| /// <summary> | ||
| /// Port of _parse_requirements in upstream's uv_install_deps.py: returns the single | ||
| /// --extra-index-url and the torch-ecosystem requirement lines. | ||
| /// </summary> | ||
| private static async Task<(string? ExtraIndexUrl, List<string> TorchSpecs)> ParseRequirementsAsync( | ||
| string requirementsPath, | ||
| CancellationToken cancellationToken | ||
| ) | ||
| { | ||
| string? extraIndexUrl = null; | ||
| var torchSpecs = new List<string>(); | ||
|
|
||
| var lines = await File.ReadAllLinesAsync(requirementsPath, cancellationToken).ConfigureAwait(false); | ||
| foreach (var raw in lines) | ||
| { | ||
| var code = raw.Split('#', 2)[0].Trim(); | ||
| if (code.StartsWith("--extra-index-url", StringComparison.Ordinal)) | ||
| { | ||
| if (extraIndexUrl is not null) | ||
| { | ||
| throw new InvalidOperationException( | ||
| "Fizgig's requirements.txt declares more than one --extra-index-url" | ||
| ); | ||
| } | ||
|
|
||
| var parts = code.Split((char[]?)null, 2, StringSplitOptions.RemoveEmptyEntries); | ||
| if (parts.Length == 2) | ||
| { | ||
| extraIndexUrl = parts[1]; | ||
| } | ||
| continue; | ||
| } | ||
|
|
||
| if (code.Length > 0) | ||
| { | ||
| var pkg = RequirementNameEndRegex().Split(code, 2)[0]; | ||
| if (TorchEcosystem.Contains(pkg)) | ||
| { | ||
| torchSpecs.Add(code); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| return (extraIndexUrl, torchSpecs); | ||
| } | ||
|
|
||
| [GeneratedRegex(@"[=<>!~\s\[;]")] | ||
| private static partial Regex RequirementNameEndRegex(); | ||
|
|
||
| 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 | ||
| ); | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
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.DisplayNamedefault 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.