mirror of
https://github.com/DarthAffe/StableDiffusion.NET.git
synced 2025-12-12 21:38:45 +00:00
commit
4d6bc12b33
@ -11,10 +11,13 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="HPPH.System.Drawing" Version="1.0.0" />
|
||||
<PackageReference Include="StableDiffusion.NET" Version="2.0.0" />
|
||||
<PackageReference Include="StableDiffusion.NET.Backend.Cpu" Version="2.0.0" />
|
||||
<PackageReference Include="StableDiffusion.NET.Backend.Cuda" Version="2.0.0" />
|
||||
<PackageReference Include="StableDiffusion.NET.Backend.Rocm" Version="2.0.0" />
|
||||
<PackageReference Include="StableDiffusion.NET.Backend.Cpu" Version="3.0.0" />
|
||||
<PackageReference Include="StableDiffusion.NET.Backend.Cuda" Version="3.0.0" />
|
||||
<PackageReference Include="StableDiffusion.NET.Backend.Rocm" Version="3.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\StableDiffusion.NET\StableDiffusion.NET.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@ -8,7 +8,7 @@
|
||||
xmlns:sys="clr-namespace:System;assembly=System.Runtime"
|
||||
xmlns:sd="clr-namespace:StableDiffusion.NET;assembly=StableDiffusion.NET"
|
||||
mc:Ignorable="d"
|
||||
Title="StableDiffusion.NET" Width="1280" Height="800">
|
||||
Title="StableDiffusion.NET" Width="1706" Height="960">
|
||||
<Window.DataContext>
|
||||
<local:MainWindowViewModel />
|
||||
</Window.DataContext>
|
||||
@ -42,81 +42,112 @@
|
||||
<ColumnDefinition Width="400" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<StackPanel Margin="4,0" Orientation="Vertical">
|
||||
<TextBlock Margin="8" Text="This is just an example - inputs are not validated! Make sure everything is correct before pressing 'Create Image'." />
|
||||
<ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled">
|
||||
<StackPanel Margin="4,0" Orientation="Vertical">
|
||||
<TextBlock Margin="8" Text="This is just an example - inputs are not validated! Make sure everything is correct before pressing 'Create Image'." />
|
||||
|
||||
<Separator />
|
||||
<Separator />
|
||||
|
||||
<Label Content="Model-Path" />
|
||||
<DockPanel>
|
||||
<Button DockPanel.Dock="Right" Width="24" Margin="2,0,0,0" Content="..." Command="{Binding SelectModelCommand}" IsEnabled="{Binding IsReady}" />
|
||||
<TextBox Text="{Binding ModelPath}" />
|
||||
</DockPanel>
|
||||
|
||||
<Label Content="Vae-Path (Optional)" />
|
||||
<DockPanel>
|
||||
<Button DockPanel.Dock="Right" Width="24" Margin="2,0,0,0" Content="..." Command="{Binding SelectVaeCommand}" IsEnabled="{Binding IsReady}" />
|
||||
<TextBox Text="{Binding VaePath}" />
|
||||
</DockPanel>
|
||||
|
||||
<Label Content="Schedule" />
|
||||
<ComboBox ItemsSource="{Binding Source={StaticResource ScheduleDataSource}}" SelectedItem="{Binding Schedule}" />
|
||||
|
||||
<Button Margin="0,8" Content="Load Model" Command="{Binding LoadModelCommand}" IsEnabled="{Binding IsReady}" />
|
||||
|
||||
<Separator />
|
||||
|
||||
<Label Margin="0,8,0,0" Content="Prompt" />
|
||||
<TextBox Height="80" TextWrapping="Wrap" Text="{Binding Prompt}" />
|
||||
|
||||
<Label Content="AntiPrompt" />
|
||||
<TextBox Height="80" TextWrapping="Wrap" Text="{Binding AntiPrompt}" />
|
||||
|
||||
<DockPanel LastChildFill="True">
|
||||
<StackPanel DockPanel.Dock="Left">
|
||||
<StackPanel DockPanel.Dock="Top" Orientation="Horizontal" Margin="0,8,0,0">
|
||||
<Label Width="50" Content="Width" />
|
||||
<TextBox HorizontalAlignment="Left" Width="60" Text="{Binding Width}" />
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel DockPanel.Dock="Top" Orientation="Horizontal" Margin="0,8,0,0">
|
||||
<Label Width="50" Content="Height" />
|
||||
<TextBox HorizontalAlignment="Left" Width="60" Text="{Binding Height}" />
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel DockPanel.Dock="Top" Orientation="Horizontal" Margin="0,8,0,0">
|
||||
<Label Width="50" Content="Cfg" />
|
||||
<TextBox HorizontalAlignment="Left" Width="60" Text="{Binding Cfg}" />
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel DockPanel.Dock="Top" Orientation="Horizontal" Margin="0,8,0,0">
|
||||
<Label Width="50" Content="Steps" />
|
||||
<TextBox HorizontalAlignment="Left" Width="60" Text="{Binding Steps}" />
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel DockPanel.Dock="Top" Orientation="Horizontal" Margin="0,8,0,0">
|
||||
<Label Width="50" Content="Seed" />
|
||||
<TextBox HorizontalAlignment="Left" Width="60" Text="{Binding Seed}" />
|
||||
</StackPanel>
|
||||
<Label Content="Model-Type" />
|
||||
<StackPanel Orientation="Horizontal" Margin="4,0,0,0">
|
||||
<RadioButton Content="Stable Diffusion" IsChecked="{Binding IsStableDiffusionSelected}" GroupName="ModelType" />
|
||||
<RadioButton Margin="16,0,0,0" Content="Flux" IsChecked="{Binding IsFluxSelected}" GroupName="ModelType" />
|
||||
</StackPanel>
|
||||
|
||||
<DockPanel Margin="16,0,0,0" LastChildFill="True">
|
||||
<Label DockPanel.Dock="Top" Content="Image2Image Source" />
|
||||
<DockPanel DockPanel.Dock="Top" >
|
||||
<Button DockPanel.Dock="Right" Width="24" Margin="2,0,0,0" Content="..." Command="{Binding SelectImage2ImageSourceCommand}" IsEnabled="{Binding IsReady}" />
|
||||
<TextBox Text="{Binding Image2ImageSourcePath}" />
|
||||
<StackPanel Orientation="Vertical" IsEnabled="{Binding IsStableDiffusionSelected}">
|
||||
<Label Content="Model-Path" />
|
||||
<DockPanel>
|
||||
<Button DockPanel.Dock="Right" Width="24" Margin="2,0,0,0" Content="..." Command="{Binding SelectModelCommand}" IsEnabled="{Binding IsReady}" />
|
||||
<TextBox Text="{Binding ModelPath}" />
|
||||
</DockPanel>
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Orientation="Vertical" IsEnabled="{Binding IsFluxSelected}">
|
||||
<Label Content="DiffusionModel-Path" />
|
||||
<DockPanel>
|
||||
<Button DockPanel.Dock="Right" Width="24" Margin="2,0,0,0" Content="..." Command="{Binding SelectDiffusionModelCommand}" IsEnabled="{Binding IsReady}" />
|
||||
<TextBox Text="{Binding DiffusionModelPath}" />
|
||||
</DockPanel>
|
||||
|
||||
<Image Source="{Binding Image2ImageSource, Converter={StaticResource ImageToImageSourceConverter}}" />
|
||||
<Label Content="ClipL-Path" />
|
||||
<DockPanel>
|
||||
<Button DockPanel.Dock="Right" Width="24" Margin="2,0,0,0" Content="..." Command="{Binding SelectClipLCommand}" IsEnabled="{Binding IsReady}" />
|
||||
<TextBox Text="{Binding ClipLPath}" />
|
||||
</DockPanel>
|
||||
|
||||
<Label Content="T5xxl-Path" />
|
||||
<DockPanel>
|
||||
<Button DockPanel.Dock="Right" Width="24" Margin="2,0,0,0" Content="..." Command="{Binding SelectT5xxlCommand}" IsEnabled="{Binding IsReady}" />
|
||||
<TextBox Text="{Binding T5xxlPath}" />
|
||||
</DockPanel>
|
||||
</StackPanel>
|
||||
|
||||
<Label Content="Vae-Path (Optional)" />
|
||||
<DockPanel>
|
||||
<Button DockPanel.Dock="Right" Width="24" Margin="2,0,0,0" Content="..." Command="{Binding SelectVaeCommand}" IsEnabled="{Binding IsReady}" />
|
||||
<TextBox Text="{Binding VaePath}" />
|
||||
</DockPanel>
|
||||
</DockPanel>
|
||||
|
||||
<Label Content="Sample-Method" />
|
||||
<ComboBox ItemsSource="{Binding Source={StaticResource SamplerDataSource}}" SelectedItem="{Binding SampleMethod}" />
|
||||
<Label Content="Schedule" />
|
||||
<ComboBox ItemsSource="{Binding Source={StaticResource ScheduleDataSource}}" SelectedItem="{Binding Schedule}" />
|
||||
|
||||
<Button Margin="0,16,0,0" Content="Create Image" Command="{Binding CreateImageCommand}" IsEnabled="{Binding IsReady}" />
|
||||
<Button Margin="0,16,0,0" Content="Save Image" Command="{Binding SaveImageCommand}" IsEnabled="{Binding IsReady}" />
|
||||
</StackPanel>
|
||||
<Button Margin="0,8" Content="Load Model" Command="{Binding LoadModelCommand}" IsEnabled="{Binding IsReady}" />
|
||||
|
||||
<Separator />
|
||||
|
||||
<Label Margin="0,8,0,0" Content="Prompt" />
|
||||
<TextBox Height="80" TextWrapping="Wrap" Text="{Binding Prompt}" />
|
||||
|
||||
<Label Content="AntiPrompt" />
|
||||
<TextBox Height="60" TextWrapping="Wrap" Text="{Binding AntiPrompt}" />
|
||||
|
||||
<DockPanel LastChildFill="True">
|
||||
<StackPanel DockPanel.Dock="Left">
|
||||
<StackPanel DockPanel.Dock="Top" Orientation="Horizontal" Margin="0,8,0,0">
|
||||
<Label Width="50" Content="Width" />
|
||||
<TextBox HorizontalAlignment="Left" Width="60" Text="{Binding Width}" />
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel DockPanel.Dock="Top" Orientation="Horizontal" Margin="0,8,0,0">
|
||||
<Label Width="50" Content="Height" />
|
||||
<TextBox HorizontalAlignment="Left" Width="60" Text="{Binding Height}" />
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel DockPanel.Dock="Top" Orientation="Horizontal" Margin="0,8,0,0">
|
||||
<Label Width="50" Content="Cfg" />
|
||||
<TextBox HorizontalAlignment="Left" Width="60" Text="{Binding Cfg}" />
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel DockPanel.Dock="Top" Orientation="Horizontal" Margin="0,8,0,0">
|
||||
<Label Width="50" Content="Steps" />
|
||||
<TextBox HorizontalAlignment="Left" Width="60" Text="{Binding Steps}" />
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel DockPanel.Dock="Top" Orientation="Horizontal" Margin="0,8,0,0">
|
||||
<Label Width="50" Content="Seed" />
|
||||
<TextBox HorizontalAlignment="Left" Width="60" Text="{Binding Seed}" />
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
|
||||
<DockPanel Margin="16,0,0,0" LastChildFill="True">
|
||||
<Label DockPanel.Dock="Top" Content="Image2Image Source" />
|
||||
<DockPanel DockPanel.Dock="Top" >
|
||||
<Button DockPanel.Dock="Right" Width="24" Margin="2,0,0,0" Content="..." Command="{Binding SelectImage2ImageSourceCommand}" IsEnabled="{Binding IsReady}" />
|
||||
<TextBox Text="{Binding Image2ImageSourcePath}" />
|
||||
</DockPanel>
|
||||
|
||||
<Image Source="{Binding Image2ImageSource, Converter={StaticResource ImageToImageSourceConverter}}" />
|
||||
</DockPanel>
|
||||
</DockPanel>
|
||||
|
||||
<Label Content="Sample-Method" />
|
||||
<ComboBox ItemsSource="{Binding Source={StaticResource SamplerDataSource}}" SelectedItem="{Binding SampleMethod}" />
|
||||
|
||||
<Button Margin="0,16,0,0" Content="Create Image" Command="{Binding CreateImageCommand}" IsEnabled="{Binding IsReady}" />
|
||||
<Button Margin="0,16,0,0" Content="Save Image" Command="{Binding SaveImageCommand}" IsEnabled="{Binding IsReady}" />
|
||||
</StackPanel>
|
||||
|
||||
</ScrollViewer>
|
||||
|
||||
<GridSplitter Grid.Column="1" Margin="2,0" Width="2" Background="DimGray" VerticalAlignment="Stretch" HorizontalAlignment="Center" />
|
||||
|
||||
|
||||
@ -13,7 +13,21 @@ public class MainWindowViewModel : INotifyPropertyChanged
|
||||
{
|
||||
#region Properties & Fields
|
||||
|
||||
private StableDiffusionModel? _model;
|
||||
private DiffusionModel? _model;
|
||||
|
||||
private bool _isStableDiffusionSelected = true;
|
||||
public bool IsStableDiffusionSelected
|
||||
{
|
||||
get => _isStableDiffusionSelected;
|
||||
set => SetProperty(ref _isStableDiffusionSelected, value);
|
||||
}
|
||||
|
||||
private bool _isFluxSelected;
|
||||
public bool IsFluxSelected
|
||||
{
|
||||
get => _isFluxSelected;
|
||||
set => SetProperty(ref _isFluxSelected, value);
|
||||
}
|
||||
|
||||
private string _modelPath = string.Empty;
|
||||
public string ModelPath
|
||||
@ -22,6 +36,27 @@ public class MainWindowViewModel : INotifyPropertyChanged
|
||||
set => SetProperty(ref _modelPath, value);
|
||||
}
|
||||
|
||||
private string _clipLPath;
|
||||
public string ClipLPath
|
||||
{
|
||||
get => _clipLPath;
|
||||
set => SetProperty(ref _clipLPath, value);
|
||||
}
|
||||
|
||||
private string _t5xxlPath;
|
||||
public string T5xxlPath
|
||||
{
|
||||
get => _t5xxlPath;
|
||||
set => SetProperty(ref _t5xxlPath, value);
|
||||
}
|
||||
|
||||
private string _diffusionModelPath;
|
||||
public string DiffusionModelPath
|
||||
{
|
||||
get => _diffusionModelPath;
|
||||
set => SetProperty(ref _diffusionModelPath, value);
|
||||
}
|
||||
|
||||
private string _vaePath = string.Empty;
|
||||
public string VaePath
|
||||
{
|
||||
@ -78,8 +113,8 @@ public class MainWindowViewModel : INotifyPropertyChanged
|
||||
set => SetProperty(ref _steps, value);
|
||||
}
|
||||
|
||||
private int _seed = -1;
|
||||
public int Seed
|
||||
private long _seed = -1;
|
||||
public long Seed
|
||||
{
|
||||
get => _seed;
|
||||
set => SetProperty(ref _seed, value);
|
||||
@ -156,6 +191,15 @@ public class MainWindowViewModel : INotifyPropertyChanged
|
||||
private ActionCommand? _selectModelCommand;
|
||||
public ActionCommand SelectModelCommand => _selectModelCommand ??= new ActionCommand(SelectModel);
|
||||
|
||||
private ActionCommand? _selectDiffusionModelCommand;
|
||||
public ActionCommand SelectDiffusionModelCommand => _selectDiffusionModelCommand ??= new ActionCommand(SelectDiffusionModel);
|
||||
|
||||
private ActionCommand? _selectClipLCommand;
|
||||
public ActionCommand SelectClipLCommand => _selectClipLCommand ??= new ActionCommand(SelectClipL);
|
||||
|
||||
private ActionCommand? _selectT5xxlCommand;
|
||||
public ActionCommand SelectT5xxlCommand => _selectT5xxlCommand ??= new ActionCommand(SelectT5xxl);
|
||||
|
||||
private ActionCommand? _selectVaeCommand;
|
||||
public ActionCommand SelectVaeCommand => _selectVaeCommand ??= new ActionCommand(SelectVae);
|
||||
|
||||
@ -170,8 +214,8 @@ public class MainWindowViewModel : INotifyPropertyChanged
|
||||
{
|
||||
try
|
||||
{
|
||||
StableDiffusionModel.Log += (_, args) => LogLine($"LOG [{args.Level}]: {args.Text}", false);
|
||||
StableDiffusionModel.Progress += (_, args) => LogLine($"PROGRESS {args.Step} / {args.Steps} ({(args.Progress * 100):N2} %) {args.IterationsPerSecond:N2} it/s ({args.Time})");
|
||||
StableDiffusionCpp.Log += (_, args) => LogLine($"LOG [{args.Level}]: {args.Text}", false);
|
||||
StableDiffusionCpp.Progress += (_, args) => LogLine($"PROGRESS {args.Step} / {args.Steps} ({(args.Progress * 100):N2} %) {args.IterationsPerSecond:N2} it/s ({args.Time})");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@ -191,8 +235,38 @@ public class MainWindowViewModel : INotifyPropertyChanged
|
||||
|
||||
_model?.Dispose();
|
||||
|
||||
LogLine($"Loading model '{ModelPath}'");
|
||||
_model = await Task.Run(() => new StableDiffusionModel(ModelPath, new ModelParameter { VaePath = VaePath, Schedule = Schedule }));
|
||||
bool restoreDefaultParameters = false;
|
||||
|
||||
if (IsStableDiffusionSelected)
|
||||
{
|
||||
restoreDefaultParameters = _model?.ModelParameter.DiffusionModelType != DiffusionModelType.StableDiffusion;
|
||||
|
||||
LogLine($"Loading stable diffusion-model '{ModelPath}'");
|
||||
_model = await Task.Run(() => ModelBuilder.StableDiffusion(ModelPath).WithMultithreading().WithVae(VaePath).WithSchedule(Schedule).Build());
|
||||
}
|
||||
else if (IsFluxSelected)
|
||||
{
|
||||
restoreDefaultParameters = _model?.ModelParameter.DiffusionModelType != DiffusionModelType.Flux;
|
||||
|
||||
LogLine($"Loading flux-model '{DiffusionModelPath}'");
|
||||
_model = await Task.Run(() => ModelBuilder.Flux(DiffusionModelPath, ClipLPath, T5xxlPath, VaePath).WithMultithreading().WithSchedule(Schedule).Build());
|
||||
}
|
||||
else
|
||||
{
|
||||
LogLine("No model-type selected :(");
|
||||
}
|
||||
|
||||
if (restoreDefaultParameters && (_model != null))
|
||||
{
|
||||
DiffusionParameter parameter = _model.GetDefaultParameter();
|
||||
AntiPrompt = parameter.NegativePrompt;
|
||||
Width = parameter.Width;
|
||||
Height = parameter.Height;
|
||||
Steps = parameter.SampleSteps;
|
||||
Seed = parameter.Seed;
|
||||
SampleMethod = parameter.SampleMethod;
|
||||
Cfg = _model.ModelParameter.DiffusionModelType == DiffusionModelType.Flux ? parameter.Guidance : parameter.CfgScale;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@ -206,37 +280,32 @@ public class MainWindowViewModel : INotifyPropertyChanged
|
||||
|
||||
private async void CreateImage()
|
||||
{
|
||||
if (_model == null) return;
|
||||
|
||||
try
|
||||
{
|
||||
IsReady = false;
|
||||
|
||||
DiffusionParameter parameter = _model.GetDefaultParameter()
|
||||
.WithNegativePrompt(AntiPrompt)
|
||||
.WithSize(Width, Height)
|
||||
.WithSteps(Steps)
|
||||
.WithSeed(Seed)
|
||||
.WithSampler(SampleMethod);
|
||||
if (_model.ModelParameter.DiffusionModelType == DiffusionModelType.StableDiffusion)
|
||||
parameter = parameter.WithCfg(Cfg);
|
||||
else if (_model.ModelParameter.DiffusionModelType == DiffusionModelType.Flux)
|
||||
parameter = parameter.WithGuidance(Cfg);
|
||||
|
||||
if (Image2ImageSource == null)
|
||||
{
|
||||
LogLine("Creating image ...");
|
||||
Image = await Task.Run(() => _model?.TextToImage(Prompt, new StableDiffusionParameter
|
||||
{
|
||||
NegativePrompt = AntiPrompt,
|
||||
Width = Width,
|
||||
Height = Height,
|
||||
CfgScale = Cfg,
|
||||
SampleSteps = Steps,
|
||||
Seed = Seed,
|
||||
SampleMethod = SampleMethod
|
||||
}));
|
||||
Image = await Task.Run(() => _model?.TextToImage(Prompt, parameter));
|
||||
}
|
||||
else
|
||||
{
|
||||
LogLine("Manipulating image ...");
|
||||
Image = await Task.Run(() => _model?.ImageToImage(Prompt, Image2ImageSource, new StableDiffusionParameter
|
||||
{
|
||||
NegativePrompt = AntiPrompt,
|
||||
Width = Width,
|
||||
Height = Height,
|
||||
CfgScale = Cfg,
|
||||
SampleSteps = Steps,
|
||||
Seed = Seed,
|
||||
SampleMethod = SampleMethod
|
||||
}));
|
||||
Image = await Task.Run(() => _model?.ImageToImage(Prompt, Image2ImageSource, parameter));
|
||||
}
|
||||
|
||||
LogLine("done!");
|
||||
@ -277,9 +346,30 @@ public class MainWindowViewModel : INotifyPropertyChanged
|
||||
ModelPath = openFileDialog.FileName;
|
||||
}
|
||||
|
||||
private void SelectDiffusionModel()
|
||||
{
|
||||
OpenFileDialog openFileDialog = new() { Filter = "Diffusion Model|*.*" };
|
||||
if (openFileDialog.ShowDialog() == true)
|
||||
DiffusionModelPath = openFileDialog.FileName;
|
||||
}
|
||||
|
||||
private void SelectClipL()
|
||||
{
|
||||
OpenFileDialog openFileDialog = new() { Filter = "ClipL|*.*" };
|
||||
if (openFileDialog.ShowDialog() == true)
|
||||
ClipLPath = openFileDialog.FileName;
|
||||
}
|
||||
|
||||
private void SelectT5xxl()
|
||||
{
|
||||
OpenFileDialog openFileDialog = new() { Filter = "T5xxl|*.*" };
|
||||
if (openFileDialog.ShowDialog() == true)
|
||||
T5xxlPath = openFileDialog.FileName;
|
||||
}
|
||||
|
||||
private void SelectVae()
|
||||
{
|
||||
OpenFileDialog openFileDialog = new() { Filter = "Stable Diffusion VAE|*.*" };
|
||||
OpenFileDialog openFileDialog = new() { Filter = "VAE|*.*" };
|
||||
if (openFileDialog.ShowDialog() == true)
|
||||
VaePath = openFileDialog.FileName;
|
||||
}
|
||||
|
||||
8
StableDiffusion.NET/Enums/DiffusionModelType.cs
Normal file
8
StableDiffusion.NET/Enums/DiffusionModelType.cs
Normal file
@ -0,0 +1,8 @@
|
||||
namespace StableDiffusion.NET;
|
||||
|
||||
public enum DiffusionModelType
|
||||
{
|
||||
None = 0,
|
||||
StableDiffusion = 1,
|
||||
Flux = 2
|
||||
}
|
||||
@ -37,4 +37,6 @@ public enum Quantization
|
||||
Q4_0_4_4 = 31,
|
||||
Q4_0_4_8 = 32,
|
||||
Q4_0_8_8 = 33,
|
||||
|
||||
Unspecified
|
||||
}
|
||||
@ -6,65 +6,87 @@ namespace StableDiffusion.NET;
|
||||
|
||||
public static class ParameterExtension
|
||||
{
|
||||
public static void Validate(this StableDiffusionParameter parameter)
|
||||
public static void Validate(this UpscaleModelParameter parameter)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(parameter, nameof(parameter));
|
||||
ArgumentNullException.ThrowIfNull(parameter.ControlNet, nameof(StableDiffusionParameter.ControlNet));
|
||||
ArgumentNullException.ThrowIfNull(parameter.PhotoMaker, nameof(StableDiffusionParameter.PhotoMaker));
|
||||
ArgumentNullException.ThrowIfNull(parameter.NegativePrompt, nameof(StableDiffusionParameter.NegativePrompt));
|
||||
ArgumentNullException.ThrowIfNull(parameter.ModelPath, nameof(UpscaleModelParameter.ModelPath));
|
||||
|
||||
ArgumentOutOfRangeException.ThrowIfNegativeOrZero(parameter.Width, nameof(StableDiffusionParameter.Width));
|
||||
ArgumentOutOfRangeException.ThrowIfNegativeOrZero(parameter.Height, nameof(StableDiffusionParameter.Height));
|
||||
ArgumentOutOfRangeException.ThrowIfNegativeOrZero(parameter.SampleSteps, nameof(StableDiffusionParameter.SampleSteps));
|
||||
if (!Enum.IsDefined(parameter.Quantization)) throw new ArgumentOutOfRangeException(nameof(UpscaleModelParameter.Quantization));
|
||||
}
|
||||
|
||||
ArgumentOutOfRangeException.ThrowIfNegative(parameter.CfgScale, nameof(StableDiffusionParameter.CfgScale));
|
||||
ArgumentOutOfRangeException.ThrowIfNegative(parameter.Strength, nameof(StableDiffusionParameter.Strength));
|
||||
public static void Validate(this DiffusionModelParameter parameter)
|
||||
{
|
||||
((IQuantizedModelParameter)parameter).Validate();
|
||||
((IDiffusionModelParameter)parameter).Validate();
|
||||
((IPhotomakerModelParameter)parameter).Validate();
|
||||
}
|
||||
|
||||
if (!Enum.IsDefined(parameter.SampleMethod)) throw new ArgumentOutOfRangeException(nameof(StableDiffusionParameter.SampleMethod));
|
||||
public static void Validate(this IQuantizedModelParameter parameter)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(parameter, nameof(parameter));
|
||||
ArgumentOutOfRangeException.ThrowIfNegativeOrZero(parameter.ThreadCount, nameof(IQuantizedModelParameter.ThreadCount));
|
||||
|
||||
if (!Enum.IsDefined(parameter.Quantization)) throw new ArgumentOutOfRangeException(nameof(IQuantizedModelParameter.Quantization));
|
||||
}
|
||||
|
||||
public static void Validate(this IPhotomakerModelParameter parameter)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(parameter, nameof(parameter));
|
||||
ArgumentNullException.ThrowIfNull(parameter.StackedIdEmbeddingsDirectory, nameof(IPhotomakerModelParameter.StackedIdEmbeddingsDirectory));
|
||||
}
|
||||
|
||||
public static void Validate(this IDiffusionModelParameter parameter)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(parameter, nameof(parameter));
|
||||
ArgumentNullException.ThrowIfNull(parameter.VaePath, nameof(IDiffusionModelParameter.VaePath));
|
||||
ArgumentNullException.ThrowIfNull(parameter.TaesdPath, nameof(IDiffusionModelParameter.TaesdPath));
|
||||
ArgumentNullException.ThrowIfNull(parameter.LoraModelDirectory, nameof(IDiffusionModelParameter.LoraModelDirectory));
|
||||
ArgumentNullException.ThrowIfNull(parameter.ControlNetPath, nameof(IDiffusionModelParameter.ControlNetPath));
|
||||
ArgumentNullException.ThrowIfNull(parameter.EmbeddingsDirectory, nameof(IDiffusionModelParameter.EmbeddingsDirectory));
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(parameter.VaePath) && !string.IsNullOrWhiteSpace(parameter.TaesdPath)) throw new ArgumentException("VAE and TAESD are mutually exclusive.");
|
||||
|
||||
if (!Enum.IsDefined(parameter.RngType)) throw new ArgumentOutOfRangeException(nameof(IDiffusionModelParameter.RngType));
|
||||
if (!Enum.IsDefined(parameter.Schedule)) throw new ArgumentOutOfRangeException(nameof(IDiffusionModelParameter.Schedule));
|
||||
}
|
||||
|
||||
public static void Validate(this DiffusionParameter parameter)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(parameter, nameof(parameter));
|
||||
ArgumentNullException.ThrowIfNull(parameter.ControlNet, nameof(DiffusionParameter.ControlNet));
|
||||
ArgumentNullException.ThrowIfNull(parameter.PhotoMaker, nameof(DiffusionParameter.PhotoMaker));
|
||||
ArgumentNullException.ThrowIfNull(parameter.NegativePrompt, nameof(DiffusionParameter.NegativePrompt));
|
||||
|
||||
ArgumentOutOfRangeException.ThrowIfNegativeOrZero(parameter.Width, nameof(DiffusionParameter.Width));
|
||||
ArgumentOutOfRangeException.ThrowIfNegativeOrZero(parameter.Height, nameof(DiffusionParameter.Height));
|
||||
ArgumentOutOfRangeException.ThrowIfNegativeOrZero(parameter.SampleSteps, nameof(DiffusionParameter.SampleSteps));
|
||||
|
||||
ArgumentOutOfRangeException.ThrowIfNegative(parameter.CfgScale, nameof(DiffusionParameter.CfgScale));
|
||||
ArgumentOutOfRangeException.ThrowIfNegative(parameter.Guidance, nameof(DiffusionParameter.Guidance));
|
||||
ArgumentOutOfRangeException.ThrowIfNegative(parameter.Strength, nameof(DiffusionParameter.Strength));
|
||||
|
||||
if (!Enum.IsDefined(parameter.SampleMethod)) throw new ArgumentOutOfRangeException(nameof(DiffusionParameter.SampleMethod));
|
||||
|
||||
parameter.ControlNet.Validate();
|
||||
parameter.PhotoMaker.Validate();
|
||||
}
|
||||
|
||||
public static void Validate(this StableDiffusionControlNetParameter parameter)
|
||||
public static void Validate(this ControlNetParameter parameter)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(parameter, nameof(StableDiffusionParameter.ControlNet));
|
||||
ArgumentNullException.ThrowIfNull(parameter, nameof(DiffusionParameter.ControlNet));
|
||||
|
||||
ArgumentOutOfRangeException.ThrowIfNegative(parameter.Strength, nameof(StableDiffusionControlNetParameter.Strength));
|
||||
ArgumentOutOfRangeException.ThrowIfNegative(parameter.CannyHighThreshold, nameof(StableDiffusionControlNetParameter.CannyHighThreshold));
|
||||
ArgumentOutOfRangeException.ThrowIfNegative(parameter.CannyLowThreshold, nameof(StableDiffusionControlNetParameter.CannyLowThreshold));
|
||||
ArgumentOutOfRangeException.ThrowIfNegative(parameter.CannyWeak, nameof(StableDiffusionControlNetParameter.CannyWeak));
|
||||
ArgumentOutOfRangeException.ThrowIfNegative(parameter.CannyStrong, nameof(StableDiffusionControlNetParameter.CannyStrong));
|
||||
ArgumentOutOfRangeException.ThrowIfNegative(parameter.Strength, nameof(ControlNetParameter.Strength));
|
||||
ArgumentOutOfRangeException.ThrowIfNegative(parameter.CannyHighThreshold, nameof(ControlNetParameter.CannyHighThreshold));
|
||||
ArgumentOutOfRangeException.ThrowIfNegative(parameter.CannyLowThreshold, nameof(ControlNetParameter.CannyLowThreshold));
|
||||
ArgumentOutOfRangeException.ThrowIfNegative(parameter.CannyWeak, nameof(ControlNetParameter.CannyWeak));
|
||||
ArgumentOutOfRangeException.ThrowIfNegative(parameter.CannyStrong, nameof(ControlNetParameter.CannyStrong));
|
||||
}
|
||||
|
||||
public static void Validate(this PhotoMakerParameter parameter)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(parameter, nameof(StableDiffusionParameter.PhotoMaker));
|
||||
ArgumentNullException.ThrowIfNull(parameter, nameof(DiffusionParameter.PhotoMaker));
|
||||
ArgumentNullException.ThrowIfNull(parameter.InputIdImageDirectory, nameof(PhotoMakerParameter.InputIdImageDirectory));
|
||||
|
||||
ArgumentOutOfRangeException.ThrowIfNegative(parameter.StyleRatio, nameof(PhotoMakerParameter.StyleRatio));
|
||||
}
|
||||
|
||||
public static void Validate(this ModelParameter parameter)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(parameter, nameof(parameter));
|
||||
ArgumentNullException.ThrowIfNull(parameter.TaesdPath, nameof(ModelParameter.TaesdPath));
|
||||
ArgumentNullException.ThrowIfNull(parameter.LoraModelDir, nameof(ModelParameter.LoraModelDir));
|
||||
ArgumentNullException.ThrowIfNull(parameter.VaePath, nameof(ModelParameter.VaePath));
|
||||
ArgumentNullException.ThrowIfNull(parameter.ControlNetPath, nameof(ModelParameter.ControlNetPath));
|
||||
ArgumentNullException.ThrowIfNull(parameter.EmbeddingsDirectory, nameof(ModelParameter.EmbeddingsDirectory));
|
||||
ArgumentNullException.ThrowIfNull(parameter.StackedIdEmbeddingsDirectory, nameof(ModelParameter.StackedIdEmbeddingsDirectory));
|
||||
|
||||
if (!Enum.IsDefined(parameter.RngType)) throw new ArgumentOutOfRangeException(nameof(ModelParameter.RngType));
|
||||
if (!Enum.IsDefined(parameter.Quantization)) throw new ArgumentOutOfRangeException(nameof(ModelParameter.Quantization));
|
||||
if (!Enum.IsDefined(parameter.Schedule)) throw new ArgumentOutOfRangeException(nameof(ModelParameter.Schedule));
|
||||
}
|
||||
|
||||
public static void Validate(this UpscalerModelParameter parameter)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(parameter, nameof(parameter));
|
||||
ArgumentNullException.ThrowIfNull(parameter.ESRGANPath, nameof(UpscalerModelParameter.ESRGANPath));
|
||||
|
||||
if (!Enum.IsDefined(parameter.Quantization)) throw new ArgumentOutOfRangeException(nameof(ModelParameter.Quantization));
|
||||
}
|
||||
}
|
||||
29
StableDiffusion.NET/Models/Builder/ESRGANModelBuilder.cs
Normal file
29
StableDiffusion.NET/Models/Builder/ESRGANModelBuilder.cs
Normal file
@ -0,0 +1,29 @@
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace StableDiffusion.NET;
|
||||
|
||||
[PublicAPI]
|
||||
public sealed class ESRGANModelBuilder : IQuantizedModelBuilder
|
||||
{
|
||||
#region Properties & Fields
|
||||
|
||||
public UpscaleModelParameter Parameter { get; }
|
||||
IQuantizedModelParameter IQuantizedModelBuilder.Parameter => Parameter;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public ESRGANModelBuilder(string modelPath)
|
||||
{
|
||||
Parameter = new UpscaleModelParameter { ModelPath = modelPath };
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
public UpscaleModel Build() => new(Parameter);
|
||||
|
||||
#endregion
|
||||
}
|
||||
@ -0,0 +1,122 @@
|
||||
using System;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace StableDiffusion.NET;
|
||||
|
||||
[PublicAPI]
|
||||
public static class DiffusionModelBuilderExtension
|
||||
{
|
||||
public static T WithVae<T>(this T builder, string vaePath)
|
||||
where T : IDiffusionModelBuilder
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(vaePath);
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(builder.Parameter.TaesdPath)) throw new ArgumentException("TAESD is already enabled. VAE and TAESD are mutually exclusive.", nameof(vaePath));
|
||||
|
||||
builder.Parameter.VaePath = vaePath;
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
public static T WithTaesd<T>(this T builder, string taesdPath)
|
||||
where T : IDiffusionModelBuilder
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(taesdPath);
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(builder.Parameter.VaePath)) throw new ArgumentException("VAE is already enabled. TAESD and VAE are mutually exclusive.", nameof(taesdPath));
|
||||
|
||||
builder.Parameter.TaesdPath = taesdPath;
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
public static T WithLoraSupport<T>(this T builder, string loraModelDirectory)
|
||||
where T : IDiffusionModelBuilder
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(loraModelDirectory);
|
||||
|
||||
builder.Parameter.LoraModelDirectory = loraModelDirectory;
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
public static T WithEmbeddingSupport<T>(this T builder, string embeddingsDirectory)
|
||||
where T : IDiffusionModelBuilder
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(embeddingsDirectory);
|
||||
|
||||
builder.Parameter.EmbeddingsDirectory = embeddingsDirectory;
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
public static T WithControlNet<T>(this T builder, string controlNetPath)
|
||||
where T : IDiffusionModelBuilder
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(controlNetPath);
|
||||
|
||||
builder.Parameter.ControlNetPath = controlNetPath;
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
public static T WithVaeDecodeOnly<T>(this T builder, bool vaeDecodeOnly = true)
|
||||
where T : IDiffusionModelBuilder
|
||||
{
|
||||
builder.Parameter.VaeDecodeOnly = vaeDecodeOnly;
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
public static T WithVaeTiling<T>(this T builder, bool vaeTiling = true)
|
||||
where T : IDiffusionModelBuilder
|
||||
{
|
||||
builder.Parameter.VaeTiling = vaeTiling;
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
public static T KeepVaeOnCpu<T>(this T builder, bool keepVaeOnCpu = true)
|
||||
where T : IDiffusionModelBuilder
|
||||
{
|
||||
builder.Parameter.KeepVaeOnCPU = keepVaeOnCpu;
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
public static T KeepClipNetOnCpu<T>(this T builder, bool keepClipNetOnCpu = true)
|
||||
where T : IDiffusionModelBuilder
|
||||
{
|
||||
builder.Parameter.KeepClipOnCPU = keepClipNetOnCpu;
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
public static T KeepControlNetOnCpu<T>(this T builder, bool keepControlNetOnCpu = true)
|
||||
where T : IDiffusionModelBuilder
|
||||
{
|
||||
builder.Parameter.KeepControlNetOnCPU = keepControlNetOnCpu;
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
public static T WithRngType<T>(this T builder, RngType rngType)
|
||||
where T : IDiffusionModelBuilder
|
||||
{
|
||||
if (!Enum.IsDefined(rngType)) throw new ArgumentOutOfRangeException(nameof(rngType));
|
||||
|
||||
builder.Parameter.RngType = rngType;
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
public static T WithSchedule<T>(this T builder, Schedule schedule)
|
||||
where T : IDiffusionModelBuilder
|
||||
{
|
||||
if (!Enum.IsDefined(schedule)) throw new ArgumentOutOfRangeException(nameof(schedule));
|
||||
|
||||
builder.Parameter.Schedule = schedule;
|
||||
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,18 @@
|
||||
using System;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace StableDiffusion.NET;
|
||||
|
||||
[PublicAPI]
|
||||
public static class PhotomakerModelBuilderExtension
|
||||
{
|
||||
public static T WithPhotomaker<T>(this T builder, string stackedIdEmbeddingsDirectory)
|
||||
where T : IPhotomakerModelBuilder
|
||||
{
|
||||
ArgumentException.ThrowIfNullOrWhiteSpace(stackedIdEmbeddingsDirectory, nameof(stackedIdEmbeddingsDirectory));
|
||||
|
||||
builder.Parameter.StackedIdEmbeddingsDirectory = stackedIdEmbeddingsDirectory;
|
||||
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,36 @@
|
||||
using System;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace StableDiffusion.NET;
|
||||
|
||||
[PublicAPI]
|
||||
public static class QuantizedModelBuilderExtension
|
||||
{
|
||||
public static T WithoutMultithreading<T>(this T builder)
|
||||
where T : IQuantizedModelBuilder
|
||||
{
|
||||
builder.Parameter.ThreadCount = 1;
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
public static T WithMultithreading<T>(this T builder, int threadCount = 0)
|
||||
where T : IQuantizedModelBuilder
|
||||
{
|
||||
ArgumentOutOfRangeException.ThrowIfLessThan(threadCount, 0, nameof(threadCount));
|
||||
|
||||
if (threadCount == 0) threadCount = Environment.ProcessorCount;
|
||||
|
||||
builder.Parameter.ThreadCount = threadCount;
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
public static T WithQuantization<T>(this T builder, Quantization quantization)
|
||||
where T : IQuantizedModelBuilder
|
||||
{
|
||||
builder.Parameter.Quantization = quantization;
|
||||
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
30
StableDiffusion.NET/Models/Builder/FluxModelBuilder.cs
Normal file
30
StableDiffusion.NET/Models/Builder/FluxModelBuilder.cs
Normal file
@ -0,0 +1,30 @@
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace StableDiffusion.NET;
|
||||
|
||||
[PublicAPI]
|
||||
public sealed class FluxModelBuilder : IDiffusionModelBuilder, IQuantizedModelBuilder
|
||||
{
|
||||
#region Properties & Fields
|
||||
|
||||
public DiffusionModelParameter Parameter { get; }
|
||||
IDiffusionModelParameter IDiffusionModelBuilder.Parameter => Parameter;
|
||||
IQuantizedModelParameter IQuantizedModelBuilder.Parameter => Parameter;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public FluxModelBuilder(string diffusionModelPath, string clipLPath, string t5xxlPath, string vaePath)
|
||||
{
|
||||
Parameter = new DiffusionModelParameter { DiffusionModelType = DiffusionModelType.Flux, DiffusionModelPath = diffusionModelPath, ClipLPath = clipLPath, T5xxlPath = t5xxlPath, VaePath = vaePath };
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
public DiffusionModel Build() => new(Parameter);
|
||||
|
||||
#endregion
|
||||
}
|
||||
@ -0,0 +1,6 @@
|
||||
namespace StableDiffusion.NET;
|
||||
|
||||
public interface IDiffusionModelBuilder
|
||||
{
|
||||
IDiffusionModelParameter Parameter { get; }
|
||||
}
|
||||
@ -0,0 +1,6 @@
|
||||
namespace StableDiffusion.NET;
|
||||
|
||||
public interface IPhotomakerModelBuilder
|
||||
{
|
||||
IPhotomakerModelParameter Parameter { get; }
|
||||
}
|
||||
@ -0,0 +1,6 @@
|
||||
namespace StableDiffusion.NET;
|
||||
|
||||
public interface IQuantizedModelBuilder
|
||||
{
|
||||
IQuantizedModelParameter Parameter { get; }
|
||||
}
|
||||
11
StableDiffusion.NET/Models/Builder/ModelBuilder.cs
Normal file
11
StableDiffusion.NET/Models/Builder/ModelBuilder.cs
Normal file
@ -0,0 +1,11 @@
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace StableDiffusion.NET;
|
||||
|
||||
[PublicAPI]
|
||||
public static class ModelBuilder
|
||||
{
|
||||
public static StableDiffusionModelBuilder StableDiffusion(string modelPath) => new(modelPath);
|
||||
public static FluxModelBuilder Flux(string diffusionModelPath, string clipLPath, string t5xxlPath, string vaePath) => new(diffusionModelPath, clipLPath, t5xxlPath, vaePath);
|
||||
public static ESRGANModelBuilder ESRGAN(string modelPath) => new(modelPath);
|
||||
}
|
||||
@ -0,0 +1,31 @@
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace StableDiffusion.NET;
|
||||
|
||||
[PublicAPI]
|
||||
public sealed class StableDiffusionModelBuilder : IDiffusionModelBuilder, IQuantizedModelBuilder, IPhotomakerModelBuilder
|
||||
{
|
||||
#region Properties & Fields
|
||||
|
||||
public DiffusionModelParameter Parameter { get; }
|
||||
IDiffusionModelParameter IDiffusionModelBuilder.Parameter => Parameter;
|
||||
IQuantizedModelParameter IQuantizedModelBuilder.Parameter => Parameter;
|
||||
IPhotomakerModelParameter IPhotomakerModelBuilder.Parameter => Parameter;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public StableDiffusionModelBuilder(string modelPath)
|
||||
{
|
||||
Parameter = new DiffusionModelParameter { DiffusionModelType = DiffusionModelType.StableDiffusion, ModelPath = modelPath };
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
public DiffusionModel Build() => new(Parameter);
|
||||
|
||||
#endregion
|
||||
}
|
||||
@ -1,61 +1,37 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using HPPH;
|
||||
using System.Runtime.InteropServices;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace StableDiffusion.NET;
|
||||
|
||||
[PublicAPI]
|
||||
public sealed unsafe class StableDiffusionModel : IDisposable
|
||||
public sealed unsafe class DiffusionModel : IDisposable
|
||||
{
|
||||
#region Properties & Fields
|
||||
|
||||
// ReSharper disable NotAccessedField.Local - They are important, the delegate can be collected if it's not stored!
|
||||
private static readonly Native.sd_log_cb_t LOG_CALLBACK;
|
||||
private static readonly Native.sd_progress_cb_t PROGRESS_CALLBACK;
|
||||
// ReSharper restore NotAccessedField.Local
|
||||
|
||||
private bool _disposed;
|
||||
|
||||
private readonly string _modelPath;
|
||||
private readonly ModelParameter _parameter;
|
||||
private readonly UpscalerModelParameter? _upscalerParameter;
|
||||
public DiffusionModelParameter ModelParameter { get; }
|
||||
|
||||
private Native.sd_ctx_t* _ctx;
|
||||
private Native.upscaler_ctx_t* _upscalerCtx;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Events
|
||||
|
||||
public static event EventHandler<StableDiffusionLogEventArgs>? Log;
|
||||
public static event EventHandler<StableDiffusionProgressEventArgs>? Progress;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
static StableDiffusionModel()
|
||||
public DiffusionModel(DiffusionModelParameter modelParameter)
|
||||
{
|
||||
Native.sd_set_log_callback(LOG_CALLBACK = OnNativeLog, null);
|
||||
Native.sd_set_progress_callback(PROGRESS_CALLBACK = OnNativeProgress, null);
|
||||
}
|
||||
ArgumentNullException.ThrowIfNull(modelParameter, nameof(modelParameter));
|
||||
|
||||
public StableDiffusionModel(string modelPath, ModelParameter parameter, UpscalerModelParameter? upscalerParameter = null)
|
||||
{
|
||||
ArgumentException.ThrowIfNullOrWhiteSpace(modelPath, nameof(modelPath));
|
||||
modelParameter.Validate();
|
||||
|
||||
parameter.Validate();
|
||||
upscalerParameter?.Validate();
|
||||
|
||||
this._modelPath = modelPath;
|
||||
this._parameter = parameter;
|
||||
this._upscalerParameter = upscalerParameter;
|
||||
this.ModelParameter = modelParameter;
|
||||
|
||||
Initialize();
|
||||
}
|
||||
|
||||
~StableDiffusionModel() => Dispose();
|
||||
~DiffusionModel() => Dispose();
|
||||
|
||||
#endregion
|
||||
|
||||
@ -63,45 +39,42 @@ public sealed unsafe class StableDiffusionModel : IDisposable
|
||||
|
||||
private void Initialize()
|
||||
{
|
||||
_ctx = Native.new_sd_ctx(_modelPath,
|
||||
_parameter.VaePath,
|
||||
_parameter.TaesdPath,
|
||||
_parameter.ControlNetPath,
|
||||
_parameter.LoraModelDir,
|
||||
_parameter.EmbeddingsDirectory,
|
||||
_parameter.StackedIdEmbeddingsDirectory,
|
||||
_parameter.VaeDecodeOnly,
|
||||
_parameter.VaeTiling,
|
||||
false,
|
||||
_parameter.ThreadCount,
|
||||
_parameter.Quantization,
|
||||
_parameter.RngType,
|
||||
_parameter.Schedule,
|
||||
_parameter.KeepClipOnCPU,
|
||||
_parameter.KeepControlNetOnCPU,
|
||||
_parameter.KeepVaeOnCPU);
|
||||
if (_ctx == null) throw new NullReferenceException("Failed to initialize Stable Diffusion");
|
||||
_ctx = Native.new_sd_ctx(ModelParameter.ModelPath,
|
||||
ModelParameter.ClipLPath,
|
||||
ModelParameter.T5xxlPath,
|
||||
ModelParameter.DiffusionModelPath,
|
||||
ModelParameter.VaePath,
|
||||
ModelParameter.TaesdPath,
|
||||
ModelParameter.ControlNetPath,
|
||||
ModelParameter.LoraModelDirectory,
|
||||
ModelParameter.EmbeddingsDirectory,
|
||||
ModelParameter.StackedIdEmbeddingsDirectory,
|
||||
ModelParameter.VaeDecodeOnly,
|
||||
ModelParameter.VaeTiling,
|
||||
false,
|
||||
ModelParameter.ThreadCount,
|
||||
ModelParameter.Quantization,
|
||||
ModelParameter.RngType,
|
||||
ModelParameter.Schedule,
|
||||
ModelParameter.KeepClipOnCPU,
|
||||
ModelParameter.KeepControlNetOnCPU,
|
||||
ModelParameter.KeepVaeOnCPU);
|
||||
|
||||
if (_upscalerParameter != null)
|
||||
{
|
||||
_upscalerCtx = Native.new_upscaler_ctx(_upscalerParameter.ESRGANPath,
|
||||
_upscalerParameter.ThreadCount,
|
||||
_upscalerParameter.Quantization);
|
||||
if (_upscalerCtx == null) throw new NullReferenceException("Failed to initialize Stable Diffusion");
|
||||
}
|
||||
if (_ctx == null) throw new NullReferenceException("Failed to initialize diffusion-model.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Manually load the native stable diffusion library.
|
||||
/// Once set, it will continue to be used for all instances.
|
||||
/// </summary>
|
||||
/// <param name="libraryPath">Path to the stable diffusion library.</param>
|
||||
/// <returns>Bool if the library loaded.</returns>
|
||||
public static bool LoadNativeLibrary(string libraryPath)
|
||||
=> Native.LoadNativeLibrary(libraryPath);
|
||||
|
||||
public IImage<ColorRGB> TextToImage(string prompt, StableDiffusionParameter parameter)
|
||||
public DiffusionParameter GetDefaultParameter() => ModelParameter.DiffusionModelType switch
|
||||
{
|
||||
DiffusionModelType.None => new DiffusionParameter(),
|
||||
DiffusionModelType.StableDiffusion => DiffusionParameter.SDXLDefault,
|
||||
DiffusionModelType.Flux => DiffusionParameter.FluxDefault,
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
};
|
||||
|
||||
public IImage<ColorRGB> TextToImage(string prompt, DiffusionParameter? parameter = null)
|
||||
{
|
||||
parameter ??= GetDefaultParameter();
|
||||
|
||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||
ArgumentNullException.ThrowIfNull(prompt);
|
||||
|
||||
@ -110,15 +83,18 @@ public sealed unsafe class StableDiffusionModel : IDisposable
|
||||
Native.sd_image_t* result;
|
||||
if (parameter.ControlNet.IsEnabled)
|
||||
{
|
||||
fixed (byte* imagePtr = parameter.ControlNet.Image!.ToRawArray())
|
||||
if (parameter.ControlNet.Image is not IImage<ColorRGB> controlNetImage)
|
||||
controlNetImage = parameter.ControlNet.Image!.ConvertTo<ColorRGB>();
|
||||
|
||||
fixed (byte* imagePtr = controlNetImage.ToRawArray())
|
||||
{
|
||||
if (parameter.ControlNet.CannyPreprocess)
|
||||
{
|
||||
Native.sd_image_t controlNetImage = new()
|
||||
Native.sd_image_t nativeControlNetImage = new()
|
||||
{
|
||||
width = (uint)parameter.ControlNet.Image.Width,
|
||||
height = (uint)parameter.ControlNet.Image.Height,
|
||||
channel = (uint)parameter.ControlNet.Image.ColorFormat.BytesPerPixel,
|
||||
width = (uint)controlNetImage.Width,
|
||||
height = (uint)controlNetImage.Height,
|
||||
channel = (uint)controlNetImage.ColorFormat.BytesPerPixel,
|
||||
data = Native.preprocess_canny(imagePtr,
|
||||
parameter.Width,
|
||||
parameter.Height,
|
||||
@ -134,27 +110,28 @@ public sealed unsafe class StableDiffusionModel : IDisposable
|
||||
parameter.NegativePrompt,
|
||||
parameter.ClipSkip,
|
||||
parameter.CfgScale,
|
||||
parameter.Guidance,
|
||||
parameter.Width,
|
||||
parameter.Height,
|
||||
parameter.SampleMethod,
|
||||
parameter.SampleSteps,
|
||||
parameter.Seed,
|
||||
1,
|
||||
&controlNetImage,
|
||||
&nativeControlNetImage,
|
||||
parameter.ControlNet.Strength,
|
||||
parameter.PhotoMaker.StyleRatio,
|
||||
parameter.PhotoMaker.NormalizeInput,
|
||||
parameter.PhotoMaker.InputIdImageDirectory);
|
||||
|
||||
Marshal.FreeHGlobal((nint)controlNetImage.data);
|
||||
Marshal.FreeHGlobal((nint)nativeControlNetImage.data);
|
||||
}
|
||||
else
|
||||
{
|
||||
Native.sd_image_t controlNetImage = new()
|
||||
Native.sd_image_t nativeControlNetImage = new()
|
||||
{
|
||||
width = (uint)parameter.ControlNet.Image.Width,
|
||||
height = (uint)parameter.ControlNet.Image.Height,
|
||||
channel = (uint)parameter.ControlNet.Image.ColorFormat.BytesPerPixel,
|
||||
width = (uint)controlNetImage.Width,
|
||||
height = (uint)controlNetImage.Height,
|
||||
channel = (uint)controlNetImage.ColorFormat.BytesPerPixel,
|
||||
data = imagePtr
|
||||
};
|
||||
|
||||
@ -163,13 +140,14 @@ public sealed unsafe class StableDiffusionModel : IDisposable
|
||||
parameter.NegativePrompt,
|
||||
parameter.ClipSkip,
|
||||
parameter.CfgScale,
|
||||
parameter.Guidance,
|
||||
parameter.Width,
|
||||
parameter.Height,
|
||||
parameter.SampleMethod,
|
||||
parameter.SampleSteps,
|
||||
parameter.Seed,
|
||||
1,
|
||||
&controlNetImage,
|
||||
&nativeControlNetImage,
|
||||
parameter.ControlNet.Strength,
|
||||
parameter.PhotoMaker.StyleRatio,
|
||||
parameter.PhotoMaker.NormalizeInput,
|
||||
@ -184,6 +162,7 @@ public sealed unsafe class StableDiffusionModel : IDisposable
|
||||
parameter.NegativePrompt,
|
||||
parameter.ClipSkip,
|
||||
parameter.CfgScale,
|
||||
parameter.Guidance,
|
||||
parameter.Width,
|
||||
parameter.Height,
|
||||
parameter.SampleMethod,
|
||||
@ -200,18 +179,23 @@ public sealed unsafe class StableDiffusionModel : IDisposable
|
||||
return ImageHelper.ToImage(result);
|
||||
}
|
||||
|
||||
public IImage<ColorRGB> ImageToImage(string prompt, IImage<ColorRGB> image, StableDiffusionParameter parameter)
|
||||
public IImage<ColorRGB> ImageToImage(string prompt, IImage image, DiffusionParameter? parameter = null)
|
||||
{
|
||||
parameter ??= GetDefaultParameter();
|
||||
|
||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||
ArgumentNullException.ThrowIfNull(prompt);
|
||||
|
||||
parameter.Validate();
|
||||
|
||||
fixed (byte* imagePtr = image.AsRefImage())
|
||||
return ImageToImage(prompt, image.ToSdImage(imagePtr), parameter);
|
||||
if (image is not IImage<ColorRGB> refImage)
|
||||
refImage = image.ConvertTo<ColorRGB>();
|
||||
|
||||
fixed (byte* imagePtr = refImage.AsRefImage())
|
||||
return ImageToImage(prompt, refImage.ToSdImage(imagePtr), parameter);
|
||||
}
|
||||
|
||||
private IImage<ColorRGB> ImageToImage(string prompt, Native.sd_image_t image, StableDiffusionParameter parameter)
|
||||
private IImage<ColorRGB> ImageToImage(string prompt, Native.sd_image_t image, DiffusionParameter parameter)
|
||||
{
|
||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||
ArgumentNullException.ThrowIfNull(prompt);
|
||||
@ -221,15 +205,18 @@ public sealed unsafe class StableDiffusionModel : IDisposable
|
||||
Native.sd_image_t* result;
|
||||
if (parameter.ControlNet.IsEnabled)
|
||||
{
|
||||
fixed (byte* imagePtr = parameter.ControlNet.Image!.ToRawArray())
|
||||
if (parameter.ControlNet.Image is not IImage<ColorRGB> controlNetImage)
|
||||
controlNetImage = parameter.ControlNet.Image!.ConvertTo<ColorRGB>();
|
||||
|
||||
fixed (byte* imagePtr = controlNetImage.ToRawArray())
|
||||
{
|
||||
if (parameter.ControlNet.CannyPreprocess)
|
||||
{
|
||||
Native.sd_image_t controlNetImage = new()
|
||||
Native.sd_image_t nativeControlNetImage = new()
|
||||
{
|
||||
width = (uint)parameter.ControlNet.Image.Width,
|
||||
height = (uint)parameter.ControlNet.Image.Height,
|
||||
channel = (uint)parameter.ControlNet.Image.ColorFormat.BytesPerPixel,
|
||||
width = (uint)controlNetImage.Width,
|
||||
height = (uint)controlNetImage.Height,
|
||||
channel = (uint)controlNetImage.ColorFormat.BytesPerPixel,
|
||||
data = Native.preprocess_canny(imagePtr,
|
||||
parameter.Width,
|
||||
parameter.Height,
|
||||
@ -246,6 +233,7 @@ public sealed unsafe class StableDiffusionModel : IDisposable
|
||||
parameter.NegativePrompt,
|
||||
parameter.ClipSkip,
|
||||
parameter.CfgScale,
|
||||
parameter.Guidance,
|
||||
parameter.Width,
|
||||
parameter.Height,
|
||||
parameter.SampleMethod,
|
||||
@ -253,17 +241,17 @@ public sealed unsafe class StableDiffusionModel : IDisposable
|
||||
parameter.Strength,
|
||||
parameter.Seed,
|
||||
1,
|
||||
&controlNetImage,
|
||||
&nativeControlNetImage,
|
||||
parameter.ControlNet.Strength,
|
||||
parameter.PhotoMaker.StyleRatio,
|
||||
parameter.PhotoMaker.NormalizeInput,
|
||||
parameter.PhotoMaker.InputIdImageDirectory);
|
||||
|
||||
Marshal.FreeHGlobal((nint)controlNetImage.data);
|
||||
Marshal.FreeHGlobal((nint)nativeControlNetImage.data);
|
||||
}
|
||||
else
|
||||
{
|
||||
Native.sd_image_t controlNetImage = new()
|
||||
Native.sd_image_t nativeControlNetImage = new()
|
||||
{
|
||||
width = (uint)parameter.ControlNet.Image.Width,
|
||||
height = (uint)parameter.ControlNet.Image.Height,
|
||||
@ -277,6 +265,7 @@ public sealed unsafe class StableDiffusionModel : IDisposable
|
||||
parameter.NegativePrompt,
|
||||
parameter.ClipSkip,
|
||||
parameter.CfgScale,
|
||||
parameter.Guidance,
|
||||
parameter.Width,
|
||||
parameter.Height,
|
||||
parameter.SampleMethod,
|
||||
@ -284,7 +273,7 @@ public sealed unsafe class StableDiffusionModel : IDisposable
|
||||
parameter.Strength,
|
||||
parameter.Seed,
|
||||
1,
|
||||
&controlNetImage,
|
||||
&nativeControlNetImage,
|
||||
parameter.ControlNet.Strength,
|
||||
parameter.PhotoMaker.StyleRatio,
|
||||
parameter.PhotoMaker.NormalizeInput,
|
||||
@ -300,6 +289,7 @@ public sealed unsafe class StableDiffusionModel : IDisposable
|
||||
parameter.NegativePrompt,
|
||||
parameter.ClipSkip,
|
||||
parameter.CfgScale,
|
||||
parameter.Guidance,
|
||||
parameter.Width,
|
||||
parameter.Height,
|
||||
parameter.SampleMethod,
|
||||
@ -317,74 +307,16 @@ public sealed unsafe class StableDiffusionModel : IDisposable
|
||||
return ImageHelper.ToImage(result);
|
||||
}
|
||||
|
||||
public IImage<ColorRGB> Upscale(IImage<ColorRGB> image, int upscaleFactor)
|
||||
{
|
||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||
ArgumentOutOfRangeException.ThrowIfLessThanOrEqual(upscaleFactor, 0, nameof(upscaleFactor));
|
||||
|
||||
if (_upscalerCtx == null) throw new NullReferenceException("The upscaler is not initialized.");
|
||||
|
||||
fixed (byte* imagePtr = image.ConvertTo<ColorRGB>().AsRefImage())
|
||||
{
|
||||
Native.sd_image_t result = Native.upscale(_upscalerCtx, image.ToSdImage(imagePtr), upscaleFactor);
|
||||
return ImageHelper.ToImage(&result);
|
||||
}
|
||||
}
|
||||
|
||||
private IImage<ColorRGB> Upscale(Native.sd_image_t image, int upscaleFactor)
|
||||
{
|
||||
Native.sd_image_t result = Native.upscale(_upscalerCtx, image, upscaleFactor);
|
||||
return ImageHelper.ToImage(&result);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_disposed) return;
|
||||
|
||||
Native.free_sd_ctx(_ctx);
|
||||
|
||||
if (_upscalerCtx != null)
|
||||
Native.free_upscaler_ctx(_upscalerCtx);
|
||||
if (_ctx != null)
|
||||
Native.free_sd_ctx(_ctx);
|
||||
|
||||
GC.SuppressFinalize(this);
|
||||
_disposed = true;
|
||||
}
|
||||
|
||||
public static void Convert(string modelPath, string vaePath, Quantization quantization, string outputPath)
|
||||
{
|
||||
ArgumentException.ThrowIfNullOrWhiteSpace(nameof(modelPath));
|
||||
ArgumentException.ThrowIfNullOrWhiteSpace(nameof(outputPath));
|
||||
ArgumentNullException.ThrowIfNull(vaePath);
|
||||
if (!Enum.IsDefined(quantization)) throw new ArgumentOutOfRangeException(nameof(quantization));
|
||||
|
||||
Native.convert(modelPath, vaePath, outputPath, quantization);
|
||||
}
|
||||
|
||||
public static string GetSystemInfo()
|
||||
{
|
||||
void* s = Native.sd_get_system_info();
|
||||
return Marshal.PtrToStringUTF8((nint)s) ?? "";
|
||||
}
|
||||
|
||||
public static int GetNumPhysicalCores() => Native.get_num_physical_cores();
|
||||
|
||||
private static void OnNativeLog(LogLevel level, string text, void* data)
|
||||
{
|
||||
try
|
||||
{
|
||||
Log?.Invoke(null, new StableDiffusionLogEventArgs(level, text));
|
||||
}
|
||||
catch { /**/ }
|
||||
}
|
||||
|
||||
private static void OnNativeProgress(int step, int steps, float time, void* data)
|
||||
{
|
||||
try
|
||||
{
|
||||
Progress?.Invoke(null, new StableDiffusionProgressEventArgs(step, steps, time));
|
||||
}
|
||||
catch { /**/ }
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
19
StableDiffusion.NET/Models/Parameter/ControlNetParameter.cs
Normal file
19
StableDiffusion.NET/Models/Parameter/ControlNetParameter.cs
Normal file
@ -0,0 +1,19 @@
|
||||
using HPPH;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace StableDiffusion.NET;
|
||||
|
||||
[PublicAPI]
|
||||
public sealed class ControlNetParameter
|
||||
{
|
||||
public bool IsEnabled => Image != null;
|
||||
|
||||
public IImage? Image { get; set; } = null;
|
||||
public float Strength { get; set; } = 0.9f;
|
||||
public bool CannyPreprocess { get; set; } = false;
|
||||
public float CannyHighThreshold { get; set; } = 0.08f;
|
||||
public float CannyLowThreshold { get; set; } = 0.08f;
|
||||
public float CannyWeak { get; set; } = 0.8f;
|
||||
public float CannyStrong { get; set; } = 1.0f;
|
||||
public bool CannyInverse { get; set; } = false;
|
||||
}
|
||||
@ -1,30 +1,35 @@
|
||||
using JetBrains.Annotations;
|
||||
namespace StableDiffusion.NET;
|
||||
|
||||
namespace StableDiffusion.NET;
|
||||
|
||||
[PublicAPI]
|
||||
public class ModelParameter
|
||||
public sealed class DiffusionModelParameter : IDiffusionModelParameter, IQuantizedModelParameter, IPhotomakerModelParameter
|
||||
{
|
||||
#region Properties & Fields
|
||||
public DiffusionModelType DiffusionModelType { get; set; } = DiffusionModelType.None;
|
||||
|
||||
public string VaePath { get; set; } = string.Empty;
|
||||
public string TaesdPath { get; set; } = string.Empty;
|
||||
|
||||
public string LoraModelDirectory { get; set; } = string.Empty;
|
||||
public string EmbeddingsDirectory { get; set; } = string.Empty;
|
||||
public string ControlNetPath { get; set; } = string.Empty;
|
||||
|
||||
public int ThreadCount { get; set; } = 1;
|
||||
|
||||
public int ThreadCount { get; set; } = 8;
|
||||
public bool VaeDecodeOnly { get; set; } = false;
|
||||
public bool VaeTiling { get; set; } = false;
|
||||
public string TaesdPath { get; set; } = string.Empty;
|
||||
public string LoraModelDir { get; set; } = string.Empty;
|
||||
public RngType RngType { get; set; } = RngType.Standard;
|
||||
public string VaePath { get; set; } = string.Empty;
|
||||
public string ControlNetPath { get; set; } = string.Empty;
|
||||
public string EmbeddingsDirectory { get; set; } = string.Empty;
|
||||
public string StackedIdEmbeddingsDirectory { get; set; } = string.Empty;
|
||||
public bool KeepControlNetOnCPU { get; set; } = false;
|
||||
public bool KeepClipOnCPU { get; set; } = false;
|
||||
public bool KeepVaeOnCPU { get; set; } = false;
|
||||
|
||||
//TODO DarthAffe 01.01.2024: K-Quants doesn't seem to work so far
|
||||
public Quantization Quantization { get; set; } = Quantization.F16;
|
||||
|
||||
public RngType RngType { get; set; } = RngType.Standard;
|
||||
public Schedule Schedule { get; set; } = Schedule.Default;
|
||||
|
||||
#endregion
|
||||
}
|
||||
public Quantization Quantization { get; set; } = Quantization.Unspecified;
|
||||
|
||||
// Stable Diffusion only
|
||||
public string ModelPath { get; set; } = string.Empty;
|
||||
public string StackedIdEmbeddingsDirectory { get; set; } = string.Empty;
|
||||
|
||||
// Flux only
|
||||
public string DiffusionModelPath { get; set; } = string.Empty;
|
||||
public string ClipLPath { get; set; } = string.Empty;
|
||||
public string T5xxlPath { get; set; } = string.Empty;
|
||||
}
|
||||
33
StableDiffusion.NET/Models/Parameter/DiffusionParameter.cs
Normal file
33
StableDiffusion.NET/Models/Parameter/DiffusionParameter.cs
Normal file
@ -0,0 +1,33 @@
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace StableDiffusion.NET;
|
||||
|
||||
[PublicAPI]
|
||||
public sealed class DiffusionParameter
|
||||
{
|
||||
#region Properties & Fields
|
||||
|
||||
public static DiffusionParameter SD1Default => new() { Width = 512, Height = 512, CfgScale = 7.5f, Guidance = 1f, SampleSteps = 25, SampleMethod = Sampler.Euler_A };
|
||||
public static DiffusionParameter SDXLDefault => new() { Width = 1024, Height = 1024, CfgScale = 7f, Guidance = 1f, SampleSteps = 30, SampleMethod = Sampler.Euler_A };
|
||||
public static DiffusionParameter FluxDefault => new() { Width = 1024, Height = 1024, CfgScale = 1, Guidance = 3.5f, SampleSteps = 20, SampleMethod = Sampler.Euler };
|
||||
|
||||
public string NegativePrompt { get; set; } = string.Empty;
|
||||
public int Width { get; set; } = 512;
|
||||
public int Height { get; set; } = 512;
|
||||
public Sampler SampleMethod { get; set; } = Sampler.Euler_A;
|
||||
public int SampleSteps { get; set; } = 25;
|
||||
public long Seed { get; set; } = -1;
|
||||
public float Strength { get; set; } = 0.7f;
|
||||
public int ClipSkip { get; set; } = -1;
|
||||
|
||||
public ControlNetParameter ControlNet { get; } = new();
|
||||
|
||||
// Stable Diffusion only
|
||||
public float CfgScale { get; set; } = 7.5f;
|
||||
public PhotoMakerParameter PhotoMaker { get; } = new();
|
||||
|
||||
// Flux only
|
||||
public float Guidance { get; set; } = 3.5f;
|
||||
|
||||
#endregion
|
||||
}
|
||||
@ -0,0 +1,114 @@
|
||||
using HPPH;
|
||||
|
||||
namespace StableDiffusion.NET;
|
||||
|
||||
public static class DiffusionParameterExtension
|
||||
{
|
||||
public static DiffusionParameter WithSize(this DiffusionParameter parameter, int? width = null, int? height = null)
|
||||
{
|
||||
if (width != null)
|
||||
parameter.Width = width.Value;
|
||||
|
||||
if (height != null)
|
||||
parameter.Height = height.Value;
|
||||
|
||||
return parameter;
|
||||
}
|
||||
|
||||
public static DiffusionParameter WithSampler(this DiffusionParameter parameter, Sampler sampler)
|
||||
{
|
||||
parameter.SampleMethod = sampler;
|
||||
|
||||
return parameter;
|
||||
}
|
||||
|
||||
public static DiffusionParameter WithSteps(this DiffusionParameter parameter, int steps)
|
||||
{
|
||||
parameter.SampleSteps = steps;
|
||||
|
||||
return parameter;
|
||||
}
|
||||
|
||||
public static DiffusionParameter WithSeed(this DiffusionParameter parameter, long seed)
|
||||
{
|
||||
parameter.Seed = seed;
|
||||
|
||||
return parameter;
|
||||
}
|
||||
|
||||
public static DiffusionParameter WithClipSkip(this DiffusionParameter parameter, int clipSkip)
|
||||
{
|
||||
parameter.ClipSkip = clipSkip;
|
||||
|
||||
return parameter;
|
||||
}
|
||||
|
||||
public static DiffusionParameter WithCfg(this DiffusionParameter parameter, float cfg)
|
||||
{
|
||||
parameter.CfgScale = cfg;
|
||||
|
||||
return parameter;
|
||||
}
|
||||
|
||||
public static DiffusionParameter WithGuidance(this DiffusionParameter parameter, float guidance)
|
||||
{
|
||||
parameter.Guidance = guidance;
|
||||
|
||||
return parameter;
|
||||
}
|
||||
|
||||
public static DiffusionParameter WithNegativePrompt(this DiffusionParameter parameter, string negativePrompt)
|
||||
{
|
||||
parameter.NegativePrompt = negativePrompt;
|
||||
|
||||
return parameter;
|
||||
}
|
||||
|
||||
public static DiffusionParameter WithControlNet(this DiffusionParameter parameter, IImage image, float? strength = null)
|
||||
{
|
||||
parameter.ControlNet.Image = image;
|
||||
|
||||
if (strength != null)
|
||||
parameter.ControlNet.Strength = strength.Value;
|
||||
|
||||
return parameter;
|
||||
}
|
||||
|
||||
public static DiffusionParameter WithCannyPreprocessing(this DiffusionParameter parameter,
|
||||
float? cannyHighThreshold = null, float? cannyLowThreshold = null,
|
||||
float? cannyWeak = null, float? cannyStrong = null,
|
||||
bool? cannyInverse = null)
|
||||
{
|
||||
parameter.ControlNet.CannyPreprocess = true;
|
||||
|
||||
if (cannyHighThreshold != null)
|
||||
parameter.ControlNet.CannyHighThreshold = cannyHighThreshold.Value;
|
||||
|
||||
if (cannyLowThreshold != null)
|
||||
parameter.ControlNet.CannyLowThreshold = cannyLowThreshold.Value;
|
||||
|
||||
if (cannyWeak != null)
|
||||
parameter.ControlNet.CannyWeak = cannyWeak.Value;
|
||||
|
||||
if (cannyStrong != null)
|
||||
parameter.ControlNet.CannyStrong = cannyStrong.Value;
|
||||
|
||||
if (cannyInverse != null)
|
||||
parameter.ControlNet.CannyInverse = cannyInverse.Value;
|
||||
|
||||
return parameter;
|
||||
}
|
||||
|
||||
public static DiffusionParameter WithPhotomaker(this DiffusionParameter parameter, string inputIdImageDirectory, float? styleRatio = null, bool? normalizeInput = null)
|
||||
{
|
||||
parameter.PhotoMaker.InputIdImageDirectory = inputIdImageDirectory;
|
||||
|
||||
if (styleRatio != null)
|
||||
parameter.PhotoMaker.StyleRatio = styleRatio.Value;
|
||||
|
||||
if (normalizeInput != null)
|
||||
parameter.PhotoMaker.NormalizeInput = normalizeInput.Value;
|
||||
|
||||
return parameter;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,22 @@
|
||||
namespace StableDiffusion.NET;
|
||||
|
||||
public interface IDiffusionModelParameter
|
||||
{
|
||||
DiffusionModelType DiffusionModelType { get; set; }
|
||||
|
||||
string VaePath { get; set; }
|
||||
string TaesdPath { get; set; }
|
||||
|
||||
string LoraModelDirectory { get; set; }
|
||||
string EmbeddingsDirectory { get; set; }
|
||||
string ControlNetPath { get; set; }
|
||||
|
||||
bool VaeDecodeOnly { get; set; }
|
||||
bool VaeTiling { get; set; }
|
||||
bool KeepControlNetOnCPU { get; set; }
|
||||
bool KeepClipOnCPU { get; set; }
|
||||
bool KeepVaeOnCPU { get; set; }
|
||||
|
||||
RngType RngType { get; set; }
|
||||
Schedule Schedule { get; set; }
|
||||
}
|
||||
@ -0,0 +1,6 @@
|
||||
namespace StableDiffusion.NET;
|
||||
|
||||
public interface IPhotomakerModelParameter
|
||||
{
|
||||
string StackedIdEmbeddingsDirectory { get; set; }
|
||||
}
|
||||
@ -0,0 +1,8 @@
|
||||
namespace StableDiffusion.NET;
|
||||
|
||||
public interface IQuantizedModelParameter
|
||||
{
|
||||
int ThreadCount { get; set; }
|
||||
|
||||
Quantization Quantization { get; set; }
|
||||
}
|
||||
11
StableDiffusion.NET/Models/Parameter/PhotoMakerParameter.cs
Normal file
11
StableDiffusion.NET/Models/Parameter/PhotoMakerParameter.cs
Normal file
@ -0,0 +1,11 @@
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace StableDiffusion.NET;
|
||||
|
||||
[PublicAPI]
|
||||
public sealed class PhotoMakerParameter
|
||||
{
|
||||
public string InputIdImageDirectory { get; set; } = string.Empty;
|
||||
public float StyleRatio { get; set; } = 20f;
|
||||
public bool NormalizeInput { get; set; } = false;
|
||||
}
|
||||
@ -0,0 +1,12 @@
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace StableDiffusion.NET;
|
||||
|
||||
[PublicAPI]
|
||||
public sealed class UpscaleModelParameter : IQuantizedModelParameter
|
||||
{
|
||||
public string ModelPath { get; set; } = string.Empty;
|
||||
public int ThreadCount { get; set; } = 1;
|
||||
|
||||
public Quantization Quantization { get; set; } = Quantization.F16;
|
||||
}
|
||||
83
StableDiffusion.NET/Models/UpscaleModel.cs
Normal file
83
StableDiffusion.NET/Models/UpscaleModel.cs
Normal file
@ -0,0 +1,83 @@
|
||||
using HPPH;
|
||||
using JetBrains.Annotations;
|
||||
using System;
|
||||
|
||||
namespace StableDiffusion.NET;
|
||||
|
||||
[PublicAPI]
|
||||
public sealed unsafe class UpscaleModel : IDisposable
|
||||
{
|
||||
#region Properties & Fields
|
||||
|
||||
private bool _disposed;
|
||||
|
||||
public UpscaleModelParameter ModelParameter { get; }
|
||||
|
||||
private Native.upscaler_ctx_t* _ctx;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public UpscaleModel(UpscaleModelParameter modelParameter)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(modelParameter, nameof(modelParameter));
|
||||
|
||||
modelParameter.Validate();
|
||||
|
||||
this.ModelParameter = modelParameter;
|
||||
|
||||
Initialize();
|
||||
}
|
||||
|
||||
~UpscaleModel() => Dispose();
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
private void Initialize()
|
||||
{
|
||||
_ctx = Native.new_upscaler_ctx(ModelParameter.ModelPath,
|
||||
ModelParameter.ThreadCount,
|
||||
ModelParameter.Quantization);
|
||||
|
||||
if (_ctx == null) throw new NullReferenceException("Failed to initialize upscale-model.");
|
||||
}
|
||||
|
||||
public IImage<ColorRGB> Upscale(IImage image, int upscaleFactor)
|
||||
{
|
||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||
ArgumentOutOfRangeException.ThrowIfLessThanOrEqual(upscaleFactor, 0, nameof(upscaleFactor));
|
||||
|
||||
if (_ctx == null) throw new NullReferenceException("The model is not initialized.");
|
||||
|
||||
if (image is not IImage<ColorRGB> sourceImage)
|
||||
sourceImage = image.ConvertTo<ColorRGB>();
|
||||
|
||||
fixed (byte* imagePtr = sourceImage.AsRefImage())
|
||||
{
|
||||
Native.sd_image_t result = Native.upscale(_ctx, sourceImage.ToSdImage(imagePtr), upscaleFactor);
|
||||
return ImageHelper.ToImage(&result);
|
||||
}
|
||||
}
|
||||
|
||||
private IImage<ColorRGB> Upscale(Native.sd_image_t image, int upscaleFactor)
|
||||
{
|
||||
Native.sd_image_t result = Native.upscale(_ctx, image, upscaleFactor);
|
||||
return ImageHelper.ToImage(&result);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_disposed) return;
|
||||
|
||||
if (_ctx != null)
|
||||
Native.free_upscaler_ctx(_ctx);
|
||||
|
||||
GC.SuppressFinalize(this);
|
||||
_disposed = true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@ -50,6 +50,9 @@ internal unsafe partial class Native
|
||||
|
||||
[LibraryImport(LIB_NAME, EntryPoint = "new_sd_ctx")]
|
||||
internal static partial sd_ctx_t* new_sd_ctx([MarshalAs(UnmanagedType.LPStr)] string model_path,
|
||||
[MarshalAs(UnmanagedType.LPStr)] string clip_l_path,
|
||||
[MarshalAs(UnmanagedType.LPStr)] string t5xxl_path,
|
||||
[MarshalAs(UnmanagedType.LPStr)] string diffusion_model_path,
|
||||
[MarshalAs(UnmanagedType.LPStr)] string vae_path,
|
||||
[MarshalAs(UnmanagedType.LPStr)] string taesd_path,
|
||||
[MarshalAs(UnmanagedType.LPStr)] string control_net_path_c_str,
|
||||
@ -76,6 +79,7 @@ internal unsafe partial class Native
|
||||
[MarshalAs(UnmanagedType.LPStr)] string negative_prompt,
|
||||
int clip_skip,
|
||||
float cfg_scale,
|
||||
float guidance,
|
||||
int width,
|
||||
int height,
|
||||
sample_method_t sample_method,
|
||||
@ -95,6 +99,7 @@ internal unsafe partial class Native
|
||||
[MarshalAs(UnmanagedType.LPStr)] string negative_prompt,
|
||||
int clip_skip,
|
||||
float cfg_scale,
|
||||
float guidance,
|
||||
int width,
|
||||
int height,
|
||||
sample_method_t sample_method,
|
||||
|
||||
@ -1,8 +1,16 @@
|
||||
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=attributes/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=backends/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=builder/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=enums/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=eventargs/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=extensions/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=helper/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=models/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=models_005Cbuilder/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=models_005Cbuilder_005Cextensions/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=models_005Cbuilder_005Cinterfaces/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=models_005Cparameter/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=models_005Cparameter_005Cextensions/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=models_005Cparameter_005Cinterfaces/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=native/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
|
||||
77
StableDiffusion.NET/StableDiffusionCpp.cs
Normal file
77
StableDiffusion.NET/StableDiffusionCpp.cs
Normal file
@ -0,0 +1,77 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace StableDiffusion.NET;
|
||||
|
||||
[PublicAPI]
|
||||
public static unsafe class StableDiffusionCpp
|
||||
{
|
||||
#region Properties & Fields
|
||||
|
||||
// ReSharper disable NotAccessedField.Local - They are important, the delegate can be collected if it's not stored!
|
||||
private static readonly Native.sd_log_cb_t LOG_CALLBACK;
|
||||
private static readonly Native.sd_progress_cb_t PROGRESS_CALLBACK;
|
||||
// ReSharper restore NotAccessedField.Local
|
||||
|
||||
#endregion
|
||||
|
||||
#region Events
|
||||
|
||||
public static event EventHandler<StableDiffusionLogEventArgs>? Log;
|
||||
public static event EventHandler<StableDiffusionProgressEventArgs>? Progress;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
static StableDiffusionCpp()
|
||||
{
|
||||
Native.sd_set_log_callback(LOG_CALLBACK = OnNativeLog, null);
|
||||
Native.sd_set_progress_callback(PROGRESS_CALLBACK = OnNativeProgress, null);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
public static bool LoadNativeLibrary(string libraryPath) => Native.LoadNativeLibrary(libraryPath);
|
||||
|
||||
public static void Convert(string modelPath, string vaePath, Quantization quantization, string outputPath)
|
||||
{
|
||||
ArgumentException.ThrowIfNullOrWhiteSpace(nameof(modelPath));
|
||||
ArgumentException.ThrowIfNullOrWhiteSpace(nameof(outputPath));
|
||||
ArgumentNullException.ThrowIfNull(vaePath);
|
||||
if (!Enum.IsDefined(quantization)) throw new ArgumentOutOfRangeException(nameof(quantization));
|
||||
|
||||
Native.convert(modelPath, vaePath, outputPath, quantization);
|
||||
}
|
||||
|
||||
public static string GetSystemInfo()
|
||||
{
|
||||
void* s = Native.sd_get_system_info();
|
||||
return Marshal.PtrToStringUTF8((nint)s) ?? "";
|
||||
}
|
||||
|
||||
public static int GetNumPhysicalCores() => Native.get_num_physical_cores();
|
||||
|
||||
private static void OnNativeLog(LogLevel level, string text, void* data)
|
||||
{
|
||||
try
|
||||
{
|
||||
Log?.Invoke(null, new StableDiffusionLogEventArgs(level, text));
|
||||
}
|
||||
catch { /**/ }
|
||||
}
|
||||
|
||||
private static void OnNativeProgress(int step, int steps, float time, void* data)
|
||||
{
|
||||
try
|
||||
{
|
||||
Progress?.Invoke(null, new StableDiffusionProgressEventArgs(step, steps, time));
|
||||
}
|
||||
catch { /**/ }
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@ -1,48 +0,0 @@
|
||||
using HPPH;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace StableDiffusion.NET;
|
||||
|
||||
[PublicAPI]
|
||||
public sealed class StableDiffusionParameter
|
||||
{
|
||||
#region Properties & Fields
|
||||
|
||||
public string NegativePrompt { get; set; } = string.Empty;
|
||||
public float CfgScale { get; set; } = 7.5f;
|
||||
public int Width { get; set; } = 512;
|
||||
public int Height { get; set; } = 512;
|
||||
public Sampler SampleMethod { get; set; } = Sampler.Euler_A;
|
||||
public int SampleSteps { get; set; } = 25;
|
||||
public long Seed { get; set; } = -1;
|
||||
public float Strength { get; set; } = 0.7f;
|
||||
public int ClipSkip { get; set; } = -1;
|
||||
|
||||
public StableDiffusionControlNetParameter ControlNet { get; } = new();
|
||||
public PhotoMakerParameter PhotoMaker { get; } = new();
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
[PublicAPI]
|
||||
public sealed class StableDiffusionControlNetParameter
|
||||
{
|
||||
public bool IsEnabled => Image != null;
|
||||
|
||||
public IImage<ColorRGB>? Image { get; set; } = null;
|
||||
public float Strength { get; set; } = 0.9f;
|
||||
public bool CannyPreprocess { get; set; } = false;
|
||||
public float CannyHighThreshold { get; set; } = 0.08f;
|
||||
public float CannyLowThreshold { get; set; } = 0.08f;
|
||||
public float CannyWeak { get; set; } = 0.8f;
|
||||
public float CannyStrong { get; set; } = 1.0f;
|
||||
public bool CannyInverse { get; set; } = false;
|
||||
}
|
||||
|
||||
[PublicAPI]
|
||||
public sealed class PhotoMakerParameter
|
||||
{
|
||||
public string InputIdImageDirectory { get; set; } = string.Empty;
|
||||
public float StyleRatio { get; set; } = 20f;
|
||||
public bool NormalizeInput { get; set; } = false;
|
||||
}
|
||||
@ -1,17 +0,0 @@
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace StableDiffusion.NET;
|
||||
|
||||
[PublicAPI]
|
||||
public class UpscalerModelParameter
|
||||
{
|
||||
#region Properties & Fields
|
||||
|
||||
public int ThreadCount { get; set; } = 8;
|
||||
public string ESRGANPath { get; set; } = string.Empty;
|
||||
|
||||
//TODO DarthAffe 01.01.2024: K-Quants doesn't seem to work so far
|
||||
public Quantization Quantization { get; set; } = Quantization.F16;
|
||||
|
||||
#endregion
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user