ai-simple-engine-diffusion 0.0.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. ai_simple_engine_diffusion/__init__.py +4 -0
  2. ai_simple_engine_diffusion/consts.py +8 -0
  3. ai_simple_engine_diffusion/graph/__init__.py +0 -0
  4. ai_simple_engine_diffusion/graph/operation/__init__.py +0 -0
  5. ai_simple_engine_diffusion/graph/operation/decode_latents.py +46 -0
  6. ai_simple_engine_diffusion/graph/operation/diffusion_loop.py +57 -0
  7. ai_simple_engine_diffusion/graph/operation/encode_image.py +46 -0
  8. ai_simple_engine_diffusion/graph/operation/encode_prompt.py +46 -0
  9. ai_simple_engine_diffusion/graph/operation/generate_latents.py +74 -0
  10. ai_simple_engine_diffusion/graph/operation/predict_noise.py +53 -0
  11. ai_simple_engine_diffusion/graph/operation/sample_latents.py +53 -0
  12. ai_simple_engine_diffusion/model/__init__.py +0 -0
  13. ai_simple_engine_diffusion/model/executor/__init__.py +0 -0
  14. ai_simple_engine_diffusion/model/executor/abstract/__init__.py +0 -0
  15. ai_simple_engine_diffusion/model/executor/abstract/diffusion_model_executor_abstract.py +66 -0
  16. ai_simple_engine_diffusion/model/executor/diffusers_stable_diffusion_model_executor.py +43 -0
  17. ai_simple_engine_diffusion/model/executor/text_encoder_model_executor_abstract.py +27 -0
  18. ai_simple_engine_diffusion/model/executor/unet_model_executor_abstract.py +31 -0
  19. ai_simple_engine_diffusion/model/executor/vae_model_executor_abstract.py +39 -0
  20. ai_simple_engine_diffusion/model/info/__init__.py +4 -0
  21. ai_simple_engine_diffusion/model/info/diffusion_model_info.py +36 -0
  22. ai_simple_engine_diffusion/noise/__init__.py +0 -0
  23. ai_simple_engine_diffusion/noise/noise_generator_abstract.py +37 -0
  24. ai_simple_engine_diffusion/prompt_embeddings/__init__.py +0 -0
  25. ai_simple_engine_diffusion/prompt_embeddings/abstract.py +3 -0
  26. ai_simple_engine_diffusion/scheduler/__init__.py +0 -0
  27. ai_simple_engine_diffusion/scheduler/abstract.py +46 -0
  28. ai_simple_engine_diffusion/scheduler/spec/__init__.py +0 -0
  29. ai_simple_engine_diffusion/scheduler/spec/base.py +25 -0
  30. ai_simple_engine_diffusion/scheduler/utils.py +20 -0
  31. ai_simple_engine_diffusion/types/__init__.py +0 -0
  32. ai_simple_engine_diffusion/types/data_type.py +28 -0
  33. ai_simple_engine_diffusion/types/embeddings.py +21 -0
  34. ai_simple_engine_diffusion/types/latent_space.py +9 -0
  35. ai_simple_engine_diffusion/types/latents.py +21 -0
  36. ai_simple_engine_diffusion/types/noise_prediction.py +21 -0
  37. ai_simple_engine_diffusion-0.0.1.dist-info/METADATA +18 -0
  38. ai_simple_engine_diffusion-0.0.1.dist-info/RECORD +40 -0
  39. ai_simple_engine_diffusion-0.0.1.dist-info/WHEEL +4 -0
  40. ai_simple_engine_diffusion-0.0.1.dist-info/licenses/LICENSE +19 -0
@@ -0,0 +1,4 @@
1
+ """
2
+ The plugin to add classes and utilities related
3
+ to Diffusion.
4
+ """
@@ -0,0 +1,8 @@
1
+ from ai_simple_engine_common.consts.model_spec.families import TEXT_ENCODER_MODEL_FAMILY, VAE_MODEL_FAMILY, UNET_MODEL_FAMILY
2
+
3
+
4
+ __all__ = [
5
+ 'TEXT_ENCODER_MODEL_FAMILY',
6
+ 'VAE_MODEL_FAMILY',
7
+ 'UNET_MODEL_FAMILY'
8
+ ]
File without changes
File without changes
@@ -0,0 +1,46 @@
1
+ from ai_simple_engine_diffusion.types.data_type import LATENTS
2
+ from ai_simple_engine.models.executor.registry.family_model_executor_registry import FamilyModelExecutorRegistry
3
+ from ai_simple_engine.graph.operation.abstract.atomic_operation import AtomicOperation
4
+ from ai_simple_engine.graph.input import Input
5
+ from ai_simple_engine.graph.output import Output
6
+ from ai_simple_engine.types.data_type.base import IMAGE, LOADED_MODEL
7
+
8
+
9
+ class DecodeLatents(
10
+ AtomicOperation
11
+ ):
12
+ """
13
+ *Atomic Operation*
14
+
15
+ Decode the `latents` provided with the `model`
16
+ given, obtaining an `image`.
17
+
18
+ Inputs:
19
+ - `model` (`LOADED_MODEL`)
20
+ - `latents` (`LATENTS`)
21
+
22
+ Outputs:
23
+ - `image` (`IMAGE`)
24
+ """
25
+
26
+ model = Input(LOADED_MODEL)
27
+ latents = Input(LATENTS)
28
+
29
+ image = Output(IMAGE)
30
+
31
+ async def execute(
32
+ self,
33
+ context
34
+ ):
35
+ registry = context.services.get(FamilyModelExecutorRegistry)
36
+
37
+ executor = registry.resolve(self.model)
38
+
39
+ image = await executor.decode(
40
+ model = self.model,
41
+ latents = self.latents
42
+ )
43
+
44
+ return {
45
+ 'image': image
46
+ }
@@ -0,0 +1,57 @@
1
+ from ai_simple_engine_diffusion.types.data_type import EMBEDDINGS, LATENTS
2
+ from ai_simple_engine.graph.operation.abstract.atomic_operation import AtomicOperation
3
+ from ai_simple_engine.types.data_type.base import INT, FLOAT, LOADED_MODEL
4
+ from ai_simple_engine.graph.input import Input
5
+ from ai_simple_engine.graph.output import Output
6
+
7
+
8
+ class DiffusionLoop(
9
+ AtomicOperation
10
+ ):
11
+ """
12
+ *Atomic Operation*
13
+
14
+ Performs the complete denoising process,
15
+ iteratively updating the latent tensor.
16
+
17
+ This operation encapsulates the whole diffusion
18
+ loop. Internally it repeatedly asks the model
19
+ to predict the noise and delegates the latent
20
+ update to the scheduler.
21
+
22
+ Inputs:
23
+ - `model` (`LOADED_MODEL`)
24
+ - `latents` (`LATENTS`)
25
+ - `embeddings` (`EMBEDDINGS`)
26
+ - `steps` (`INT)
27
+ - `guidance_scale` (`FLOAT`)
28
+
29
+ Outputs:
30
+ - `latents_output` (`LATENTS`)
31
+ """
32
+
33
+ model = Input(LOADED_MODEL)
34
+ latents = Input(LATENTS)
35
+ embeddings = Input(EMBEDDINGS)
36
+ steps = Input(INT)
37
+ guidance_scale = Input(FLOAT)
38
+
39
+ latents_output = Output(LATENTS)
40
+
41
+ async def execute(
42
+ self,
43
+ context
44
+ ):
45
+ executor = context.model_executors.resolve(self.model)
46
+
47
+ latents = await executor.diffuse(
48
+ model = self.model,
49
+ latents = self.latents,
50
+ embeddings = self.embeddings,
51
+ steps = self.steps,
52
+ guidance_scale = self.guidance_scale
53
+ )
54
+
55
+ return {
56
+ 'latents': latents
57
+ }
@@ -0,0 +1,46 @@
1
+ from ai_simple_engine_diffusion.types.data_type import LATENTS
2
+ from ai_simple_engine.models.executor.registry.family_model_executor_registry import FamilyModelExecutorRegistry
3
+ from ai_simple_engine.graph.operation.abstract.atomic_operation import AtomicOperation
4
+ from ai_simple_engine.graph.input import Input
5
+ from ai_simple_engine.graph.output import Output
6
+ from ai_simple_engine.types.data_type.base import IMAGE, LOADED_MODEL
7
+
8
+
9
+ class EncodeImage(
10
+ AtomicOperation
11
+ ):
12
+ """
13
+ *Atomic Operation*
14
+
15
+ Encode the `image` provided with the `model`
16
+ given, obtaining the corresponding `latents`.
17
+
18
+ Inputs:
19
+ - `model` (`LOADED_MODEL`)
20
+ - `image` (`IMAGE`)
21
+
22
+ Outputs:
23
+ - `latents` (`LATENTS`)
24
+ """
25
+
26
+ model = Input(LOADED_MODEL)
27
+ image = Input(IMAGE)
28
+
29
+ latents = Output(LATENTS)
30
+
31
+ async def execute(
32
+ self,
33
+ context
34
+ ):
35
+ registry = context.services.get(FamilyModelExecutorRegistry)
36
+
37
+ executor = registry.resolve(self.model)
38
+
39
+ latents = await executor.encode(
40
+ model = self.model,
41
+ image = self.image
42
+ )
43
+
44
+ return {
45
+ 'latents': latents
46
+ }
@@ -0,0 +1,46 @@
1
+ from ai_simple_engine_diffusion.types.data_type import EMBEDDINGS
2
+ from ai_simple_engine.types.data_type.base import LOADED_MODEL, STRING
3
+ from ai_simple_engine.models.executor.registry.family_model_executor_registry import FamilyModelExecutorRegistry
4
+ from ai_simple_engine.graph.operation.abstract.atomic_operation import AtomicOperation
5
+ from ai_simple_engine.graph.input import Input
6
+ from ai_simple_engine.graph.output import Output
7
+
8
+
9
+ class EncodePrompt(
10
+ AtomicOperation
11
+ ):
12
+ """
13
+ *Atomic Operation*
14
+
15
+ Encode the `prompt` given with the `text_encoder`
16
+ also provided.
17
+
18
+ Inputs:
19
+ - `text_encoder` (`LOADED_MODEL`)
20
+ - `prompt` (`STRING`)
21
+
22
+ Outputs:
23
+ - `embeddings` (`EMBEDDINGS`)
24
+ """
25
+
26
+ text_encoder = Input(LOADED_MODEL)
27
+ prompt = Input(STRING)
28
+
29
+ embeddings = Output(EMBEDDINGS)
30
+
31
+ async def execute(
32
+ self,
33
+ context
34
+ ):
35
+ registry = context.services.get(FamilyModelExecutorRegistry)
36
+
37
+ runner = registry.resolve(self.text_encoder)
38
+
39
+ embeddings = await runner.encode(
40
+ model = self.text_encoder,
41
+ prompt = self.prompt
42
+ )
43
+
44
+ return {
45
+ 'embeddings': embeddings
46
+ }
@@ -0,0 +1,74 @@
1
+ from ai_simple_engine_diffusion.types.data_type import LATENTS
2
+ from ai_simple_engine_diffusion.graph.operation.encode_prompt import EncodePrompt
3
+ from ai_simple_engine_diffusion.graph.operation.sample_latents import SampleLatents
4
+ from ai_simple_engine_diffusion.graph.operation.diffusion_loop import DiffusionLoop
5
+ from ai_simple_engine.graph.operation.abstract.composite_operation import CompositeOperation
6
+ from ai_simple_engine.graph.input import Input
7
+ from ai_simple_engine.graph.output import Output
8
+ from ai_simple_engine.types.data_type.base import INTEGER, LOADED_MODEL, STRING, FLOAT
9
+
10
+
11
+ class GenerateLatents(
12
+ CompositeOperation
13
+ ):
14
+ """
15
+ *Composite Operation*
16
+
17
+ Generate `latents` for the given `prompt`
18
+ and instructions.
19
+
20
+ Inputs:
21
+ - `model` (`LOADED_MODEL`)
22
+ - `prompt` (`STRING`)
23
+ - `negative_prompt` (`STRING`)
24
+ - `width` (`INTEGER`)
25
+ - `height` (`INTEGER`)
26
+ - `steps` (`INTEGER`)
27
+ - `guidance_scale` (`FLOAT`)
28
+ - `seed` (`INTEGER`)
29
+
30
+ Outputs:
31
+ - `latents` (`LATENTS`)
32
+ """
33
+
34
+ model = Input(LOADED_MODEL)
35
+ prompt = Input(STRING)
36
+ negative_prompt = Input(
37
+ STRING,
38
+ default = ''
39
+ )
40
+ width = Input(INTEGER)
41
+ height = Input(INTEGER)
42
+ steps = Input(INTEGER)
43
+ guidance_scale = Input(FLOAT)
44
+ seed = Input(INTEGER)
45
+
46
+ latents = Output(LATENTS)
47
+
48
+ def expand(
49
+ self
50
+ ):
51
+ embeddings = EncodePrompt(
52
+ model = self.model,
53
+ prompt = self.prompt,
54
+ negative_prompt = self.negative_prompt
55
+ )
56
+
57
+ sampled_latents = SampleLatents(
58
+ model = self.model,
59
+ width = self.width,
60
+ height = self.height,
61
+ seed = self.seed
62
+ )
63
+
64
+ latents = DiffusionLoop(
65
+ model = self.model,
66
+ latents = sampled_latents.latents,
67
+ embeddings = embeddings.embeddings,
68
+ steps = self.steps,
69
+ guidance_scale = self.guidance_scale
70
+ )
71
+
72
+ return {
73
+ 'latents': latents.latents
74
+ }
@@ -0,0 +1,53 @@
1
+ from ai_simple_engine_diffusion.types.data_type import EMBEDDINGS, LATENTS, NOISE_PREDICTION
2
+ from ai_simple_engine.models.executor.registry.family_model_executor_registry import FamilyModelExecutorRegistry
3
+ from ai_simple_engine.types.data_type.base import LOADED_MODEL, INT
4
+ from ai_simple_engine.graph.operation.abstract.atomic_operation import AtomicOperation
5
+ from ai_simple_engine.graph.input import Input
6
+ from ai_simple_engine.graph.output import Output
7
+
8
+
9
+ class PredictNoise(
10
+ AtomicOperation
11
+ ):
12
+ """
13
+ *Atomic Operation*
14
+
15
+ Predict the `noise` from the given
16
+ `latents` and `embeddings`, using the
17
+ `model` provided.
18
+
19
+ Inputs:
20
+ - `model` (`LOADED_MODEL`)
21
+ - `latents` (`LATENTS`)
22
+ - `embeddings` (`EMBEDDINGS`)
23
+ - `timestep` (`INT`)
24
+
25
+ Outputs:
26
+ - `noise` (`NOISE_PREDICTION`)
27
+ """
28
+
29
+ model = Input(LOADED_MODEL)
30
+ latents = Input(LATENTS)
31
+ embeddings = Input(EMBEDDINGS)
32
+ timestep = Input(INT)
33
+
34
+ noise = Output(NOISE_PREDICTION)
35
+
36
+ async def execute(
37
+ self,
38
+ context
39
+ ):
40
+ registry = context.services.get(FamilyModelExecutorRegistry)
41
+
42
+ executor = registry.resolve(self.model)
43
+
44
+ noise = await executor.predict_noise(
45
+ model = self.model,
46
+ latents = self.latents,
47
+ embeddings = self.embeddings,
48
+ timestep = self.timestep
49
+ )
50
+
51
+ return {
52
+ 'noise': noise
53
+ }
@@ -0,0 +1,53 @@
1
+ from ai_simple_engine_diffusion.types.data_type import LATENTS
2
+ from ai_simple_engine_diffusion.noise.noise_generator_abstract import NoiseGenerator
3
+ from ai_simple_engine.graph.operation.abstract.atomic_operation import AtomicOperation
4
+ from ai_simple_engine.graph.input import Input
5
+ from ai_simple_engine.graph.output import Output
6
+ from ai_simple_engine.types.data_type.base import INTEGER, LOADED_MODEL
7
+
8
+
9
+ class SampleLatents(
10
+ AtomicOperation
11
+ ):
12
+ """
13
+ *Atomic Operation*
14
+
15
+ Get `latents` sampled using the given
16
+ `model` and the instructions provided.
17
+
18
+ Inputs:
19
+ - `model` (`LOADED_MODEL`)
20
+ - `width` (`INTEGER`)
21
+ - `height` (`INTEGER`)
22
+ - `seed` (`INTEGER`)
23
+
24
+ Outputs:
25
+ - `latents` (`LATENTS`)
26
+ """
27
+
28
+ model = Input(LOADED_MODEL)
29
+ width = Input(INTEGER)
30
+ height = Input(INTEGER)
31
+ seed = Input(INTEGER)
32
+
33
+ latents = Output(LATENTS)
34
+
35
+ async def execute(
36
+ self,
37
+ context
38
+ ):
39
+ generator = context.services.get(NoiseGenerator)
40
+
41
+ space = self.model.info.latent_space(
42
+ width = self.width,
43
+ height = self.height
44
+ )
45
+
46
+ latents = await generator.generate(
47
+ space = space,
48
+ seed = self.seed
49
+ )
50
+
51
+ return {
52
+ 'latents': latents
53
+ }
File without changes
File without changes
@@ -0,0 +1,66 @@
1
+ from ai_simple_engine_diffusion.model.info.diffusion_model_info import DiffusionModelInfo
2
+ from ai_simple_engine.models.executor.abstract import ModelExecutor
3
+ from ai_simple_engine.models.loaded_model import LoadedModel
4
+ from abc import ABC, abstractmethod
5
+
6
+
7
+ class DiffusionModelExecutorAbstract(
8
+ ModelExecutor,
9
+ ABC
10
+ ):
11
+
12
+ @abstractmethod
13
+ def info(
14
+ self,
15
+ model: LoadedModel
16
+ ) -> DiffusionModelInfo:
17
+ ...
18
+
19
+ @abstractmethod
20
+ def create_scheduler(
21
+ self,
22
+ model: LoadedModel
23
+ ):
24
+ ...
25
+
26
+ @abstractmethod
27
+ async def predict_noise(
28
+ self,
29
+ *,
30
+ model: LoadedModel,
31
+ latents,
32
+ embeddings,
33
+ timestep,
34
+ guidance_scale
35
+ ):
36
+ ...
37
+
38
+ async def diffuse(
39
+ self,
40
+ *,
41
+ model: LoadedModel,
42
+ latents,
43
+ embeddings,
44
+ steps: int,
45
+ guidance_scale: float
46
+ ):
47
+ scheduler = self.create_scheduler(model)
48
+
49
+ scheduler.set_timesteps(steps)
50
+
51
+ for timestep in scheduler.timesteps:
52
+ noise = await self.predict_noise(
53
+ model = model,
54
+ latents = latents,
55
+ embeddings = embeddings,
56
+ timestep = timestep,
57
+ guidance_scale = guidance_scale
58
+ )
59
+
60
+ latents = scheduler.step(
61
+ noise_prediction = noise,
62
+ latents = latents,
63
+ timestep = timestep
64
+ )
65
+
66
+ return latents
@@ -0,0 +1,43 @@
1
+ from ai_simple_engine_diffusion.model.executor.abstract.diffusion_model_executor_abstract import DiffusionModelExecutorAbstract
2
+ from ai_simple_engine.models.loaded_model import LoadedModel
3
+
4
+
5
+ class DiffusersStableDiffusionModelExecutor(
6
+ DiffusionModelExecutorAbstract
7
+ ):
8
+
9
+ def create_scheduler(
10
+ self,
11
+ model: LoadedModel
12
+ ):
13
+ # TODO: Move this
14
+ from ai_simple_engine_diffusion.scheduler.utils import SCHEDULERS
15
+
16
+ scheduler_cls = SCHEDULERS[model.info.scheduler]
17
+
18
+ return scheduler_cls.from_config(
19
+ model.model.scheduler.config
20
+ )
21
+
22
+ async def predict_noise(
23
+ self,
24
+ *,
25
+ model: LoadedModel,
26
+ latents,
27
+ embeddings,
28
+ timestep,
29
+ guidance_scale
30
+ ):
31
+ pipeline = model.model
32
+
33
+ noise_prediction = pipeline.unet(
34
+ latents,
35
+ timestep,
36
+ encoder_hidden_states = embeddings
37
+ ).sample
38
+
39
+ if guidance_scale > 1:
40
+ # TODO: Apply CFG (?)
41
+ pass
42
+
43
+ return noise_prediction
@@ -0,0 +1,27 @@
1
+ from ai_simple_engine.models.executor.abstract import ModelExecutor
2
+ from ai_simple_engine.models.loaded_model import LoadedModel
3
+ from ai_simple_engine_diffusion.types.data_type import Embeddings
4
+ from abc import ABC, abstractmethod
5
+
6
+
7
+ # This will be to perform 'EncodePrompt()'
8
+ class TextEncoderModelExecutorAbstract(
9
+ ModelExecutor,
10
+ ABC
11
+ ):
12
+ """
13
+ *Abstract class*
14
+
15
+ To convert text into embeddings
16
+ """
17
+
18
+ @abstractmethod
19
+ async def encode(
20
+ self,
21
+ model: LoadedModel,
22
+ prompt: str
23
+ ) -> Embeddings:
24
+ """
25
+ Encode the given prompt into embeddings.
26
+ """
27
+ ...
@@ -0,0 +1,31 @@
1
+ from ai_simple_engine_diffusion.types.latents import Latents
2
+ from ai_simple_engine_diffusion.types.noise_prediction import NoisePrediction
3
+ from ai_simple_engine_diffusion.types.embeddings import Embeddings
4
+ from ai_simple_engine.models.executor.abstract import ModelExecutor
5
+ from ai_simple_engine.models.loaded_model import LoadedModel
6
+ from abc import ABC, abstractmethod
7
+
8
+
9
+ class UNetModelExecutorAbstract(
10
+ ModelExecutor,
11
+ ABC
12
+ ):
13
+ """
14
+ *Abstract class*
15
+
16
+ To predict the noise.
17
+ """
18
+
19
+ @abstractmethod
20
+ async def predict_noise(
21
+ self,
22
+ model: LoadedModel,
23
+ latents: Latents,
24
+ embeddings: Embeddings,
25
+ timestep: int
26
+ ) -> NoisePrediction:
27
+ """
28
+ Predict the noise residual for the given
29
+ latents at the specified timestep.
30
+ """
31
+ ...
@@ -0,0 +1,39 @@
1
+ from ai_simple_engine_diffusion.types.latents import Latents
2
+ from ai_simple_engine.models.executor.abstract import ModelExecutor
3
+ from ai_simple_engine.models.loaded_model import LoadedModel
4
+ from ai_simple_engine.types.image import Image
5
+ from abc import ABC, abstractmethod
6
+
7
+
8
+ class VAEModelExecutorAbstract(
9
+ ModelExecutor,
10
+ ABC
11
+ ):
12
+ """
13
+ *Abstract class*
14
+
15
+ To transform images into latents and
16
+ latents into images.
17
+ """
18
+
19
+ @abstractmethod
20
+ async def encode(
21
+ self,
22
+ model: LoadedModel,
23
+ image: Image
24
+ ) -> Latents:
25
+ """
26
+ Encode an image into latent space.
27
+ """
28
+ ...
29
+
30
+ @abstractmethod
31
+ async def decode(
32
+ self,
33
+ model: LoadedModel,
34
+ latents: Latents
35
+ ) -> Image:
36
+ """
37
+ Decode latent representations into an image.
38
+ """
39
+ ...
@@ -0,0 +1,4 @@
1
+
2
+
3
+ # TODO: Create a 'ModelInfo' abstract class to
4
+ # inherit for this (?)
@@ -0,0 +1,36 @@
1
+ from ai_simple_engine_diffusion.scheduler.spec.base import SchedulerSpec
2
+ from ai_simple_engine_diffusion.types.latent_space import LatentSpace
3
+ from ai_simple_engine.models.info.abstract import ModelInfo
4
+ from dataclasses import dataclass
5
+ # from typing import Union
6
+
7
+
8
+ @dataclass(frozen = True)
9
+ class DiffusionModelInfo(
10
+ ModelInfo
11
+ ):
12
+
13
+ latent_channels: int
14
+ vae_scale_factor: int
15
+ # latent_shape: tuple[int, ...] instead (?)
16
+ scheduler: SchedulerSpec
17
+ """
18
+ The scheduler that must be used for this
19
+ specific model: 'euler', 'flow_match', etc.
20
+ """
21
+
22
+ def latent_space(
23
+ self,
24
+ width: int,
25
+ height: int
26
+ ) -> LatentSpace:
27
+ return LatentSpace(
28
+ width = width // self.vae_scale_factor,
29
+ height = height // self.vae_scale_factor,
30
+ channels = self.latent_channels
31
+ )
32
+
33
+ # TODO: Near in the future
34
+ # supports_negative_prompt: bool
35
+ # max_resolution: Union[tuple[int, int], None]
36
+ # scheduler_defaults: ...
File without changes
@@ -0,0 +1,37 @@
1
+ from ai_simple_engine_diffusion.types.latents import Latents
2
+ from ai_simple_engine_diffusion.types.latent_space import LatentSpace
3
+ from abc import ABC, abstractmethod
4
+
5
+
6
+ class NoiseGenerator(
7
+ ABC
8
+ ):
9
+
10
+ @abstractmethod
11
+ async def generate(
12
+ self,
13
+ *,
14
+ space: LatentSpace,
15
+ seed: int
16
+ ) -> Latents:
17
+ """
18
+ Generate the initial latent noise.
19
+ """
20
+ ...
21
+
22
+
23
+ """
24
+ This will be implemented as:
25
+ class TorchNoiseGenerator(
26
+ NoiseGenerator
27
+ ):
28
+ ...
29
+
30
+ in 'ai_simple_engine_runtime_diffusers'
31
+
32
+ and will be registered like this:
33
+ builder.add_service(
34
+ NoiseGenerator,
35
+ TorchNoiseGenerator()
36
+ )
37
+ """
@@ -0,0 +1,3 @@
1
+ class PromptEmbeddings:
2
+
3
+ pass
File without changes
@@ -0,0 +1,46 @@
1
+ """
2
+ TODO: Remove this class, it is no longer used.
3
+ """
4
+ from ai_simple_engine_diffusion.types.latents import Latents
5
+ from ai_simple_engine_diffusion.types.noise_prediction import NoisePrediction
6
+ from abc import ABC, abstractmethod
7
+
8
+
9
+ class Scheduler(
10
+ ABC
11
+ ):
12
+
13
+ @abstractmethod
14
+ def set_timesteps(
15
+ self,
16
+ *,
17
+ steps: int
18
+ ) -> None:
19
+ """
20
+ Prepare the scheduler for a diffusion run.
21
+ """
22
+ ...
23
+
24
+ @abstractmethod
25
+ def timesteps(
26
+ self
27
+ ) -> list[int]:
28
+ """
29
+ Return the timesteps used during inference.
30
+ """
31
+ ...
32
+
33
+ @abstractmethod
34
+ def step(
35
+ self,
36
+ *,
37
+ latents: Latents,
38
+ noise_prediction: NoisePrediction,
39
+ timestep: int
40
+ ) -> Latents:
41
+ """
42
+ Update the latent tensor using the predicted
43
+ noise for the current timestep, which means
44
+ computing the next latent sample.
45
+ """
46
+ ...
File without changes
@@ -0,0 +1,25 @@
1
+ from dataclasses import dataclass, field
2
+
3
+
4
+ @dataclass(frozen = True)
5
+ class SchedulerSpec:
6
+ """
7
+ The specifications of the scheduler that must
8
+ be used, which means the arguments that must
9
+ be provided to the scheduler when creating it.
10
+ """
11
+
12
+ name: str
13
+ kwargs: dict[str, object] = field(default_factory = dict)
14
+
15
+
16
+ """
17
+ Example:
18
+
19
+ SchedulerSpec(
20
+ name="euler",
21
+ kwargs={
22
+ "use_karras_sigmas": True
23
+ }
24
+ )
25
+ """
@@ -0,0 +1,20 @@
1
+ """
2
+ TODO: Maybe rename and move this module.
3
+ """
4
+ SCHEDULERS = {
5
+ 'ddim': DDIMScheduler,
6
+ 'euler': EulerDiscreteScheduler,
7
+ 'euler_a': EulerAncestralDiscreteScheduler,
8
+ 'dpmpp_2m': DPMSolverMultistepScheduler,
9
+ }
10
+
11
+
12
+ def get_scheduler_class(
13
+ scheduler: str,
14
+ model: LoadedModel
15
+ ) -> object:
16
+ scheduler_cls = SCHEDULERS[model.info.scheduler]
17
+
18
+ return scheduler_cls.from_config(
19
+ model.model.scheduler.config
20
+ )
File without changes
@@ -0,0 +1,28 @@
1
+ from ai_simple_engine_diffusion.types.latents import Latents
2
+ from ai_simple_engine_diffusion.types.embeddings import Embeddings
3
+ from ai_simple_engine_diffusion.types.noise_prediction import NoisePrediction
4
+ from ai_simple_engine.types.data_type.base import DataType
5
+
6
+
7
+ LATENTS = DataType(
8
+ name = 'Latents',
9
+ runtime_type = Latents,
10
+ parent = None
11
+ )
12
+ EMBEDDINGS = DataType(
13
+ name = 'Embeddings',
14
+ runtime_type = Embeddings,
15
+ parent = None
16
+ )
17
+ NOISE_PREDICTION = DataType(
18
+ name = 'NoisePrediction',
19
+ runtime_type = NoisePrediction,
20
+ parent = None
21
+ )
22
+
23
+
24
+ __all__ = [
25
+ 'LATENTS',
26
+ 'EMBEDDINGS',
27
+ 'NOISE_PREDICTION'
28
+ ]
@@ -0,0 +1,21 @@
1
+ from dataclasses import dataclass
2
+
3
+
4
+ @dataclass(frozen = True)
5
+ class Embeddings:
6
+
7
+ instance: object
8
+
9
+
10
+ """
11
+ I don't use 'torch.Tensor' here because this
12
+ one is general and the implementation could
13
+ be 'torch.Tensor' or could be not.
14
+
15
+ Having a specific 'Latents' class allows us
16
+ to avoid receiving 'Embeddings' in a method
17
+ that is not expected, even if the 'Latents'
18
+ and the 'Embeddings' have a 'torch' value
19
+ inside. They are distinct concepts. same with
20
+ 'NoisePrediction'.
21
+ """
@@ -0,0 +1,9 @@
1
+ from dataclasses import dataclass
2
+
3
+
4
+ @dataclass(frozen = True)
5
+ class LatentSpace:
6
+
7
+ width: int
8
+ height: int
9
+ channels: int
@@ -0,0 +1,21 @@
1
+ from dataclasses import dataclass
2
+
3
+
4
+ @dataclass(frozen = True)
5
+ class Latents:
6
+
7
+ instance: object
8
+
9
+
10
+ """
11
+ I don't use 'torch.Tensor' here because this
12
+ one is general and the implementation could
13
+ be 'torch.Tensor' or could be not.
14
+
15
+ Having a specific 'Latents' class allows us
16
+ to avoid receiving 'Embeddings' in a method
17
+ that is not expected, even if the 'Latents'
18
+ and the 'Embeddings' have a 'torch' value
19
+ inside. They are distinct concepts. same with
20
+ 'NoisePrediction'.
21
+ """
@@ -0,0 +1,21 @@
1
+ from dataclasses import dataclass
2
+
3
+
4
+ @dataclass(frozen = True)
5
+ class NoisePrediction:
6
+
7
+ instance: object
8
+
9
+
10
+ """
11
+ I don't use 'torch.Tensor' here because this
12
+ one is general and the implementation could
13
+ be 'torch.Tensor' or could be not.
14
+
15
+ Having a specific 'Latents' class allows us
16
+ to avoid receiving 'Embeddings' in a method
17
+ that is not expected, even if the 'Latents'
18
+ and the 'Embeddings' have a 'torch' value
19
+ inside. They are distinct concepts. same with
20
+ 'NoisePrediction'.
21
+ """
@@ -0,0 +1,18 @@
1
+ Metadata-Version: 2.4
2
+ Name: ai-simple-engine-diffusion
3
+ Version: 0.0.1
4
+ Summary: AI Simple Engine Diffusion Module
5
+ License-File: LICENSE
6
+ Author: danialcala94
7
+ Author-email: danielalcalavalera@gmail.com
8
+ Requires-Python: >=3.10,<3.12
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: Programming Language :: Python :: 3.10
11
+ Classifier: Programming Language :: Python :: 3.11
12
+ Requires-Dist: ai-simple-engine (>=0.2.0,<1.0.0)
13
+ Requires-Dist: ai-simple-engine-common (>=0.0.3,<1.0.0)
14
+ Description-Content-Type: text/markdown
15
+
16
+ # AI Simple Engine Diffusion Module
17
+
18
+ The module that implements the abstract classes and utilities to be able to do Diffusion (image creation), for the AI Simple Engine `ai-simple-engine`.
@@ -0,0 +1,40 @@
1
+ ai_simple_engine_diffusion/__init__.py,sha256=Ornd59rNW32VowUSiT_7QnuryUp9NMREBiw34ms7qUU,72
2
+ ai_simple_engine_diffusion/consts.py,sha256=nxSeOtv3Y_ezmMoPAdjCjzZg533iqaJVu8jTerU2QRE,229
3
+ ai_simple_engine_diffusion/graph/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
+ ai_simple_engine_diffusion/graph/operation/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
+ ai_simple_engine_diffusion/graph/operation/decode_latents.py,sha256=y69ivvQnqy8VigNyYJYZyJpwyN7vq0KgjAqkpAP7BZ8,1197
6
+ ai_simple_engine_diffusion/graph/operation/diffusion_loop.py,sha256=81FxdgzROaN7_i9T6N08IgVlhC1ayypVifB1PxW0CLc,1573
7
+ ai_simple_engine_diffusion/graph/operation/encode_image.py,sha256=0C46darLjm3erFgR3HNPsXeoPH3xKMxJbYEtwJmCc7E,1212
8
+ ai_simple_engine_diffusion/graph/operation/encode_prompt.py,sha256=d5QctkPhIkbzmlzHLFbHIKPwAgwWvrTPH1vQ58_HKLc,1242
9
+ ai_simple_engine_diffusion/graph/operation/generate_latents.py,sha256=dl-3MeDHct6QrXQL91xg67-RElnMoayBCTLrnYoLQa4,2113
10
+ ai_simple_engine_diffusion/graph/operation/predict_noise.py,sha256=cfykfp9GFHFSpkY-bIl7BGD5tDN7z-rsVNvJdQ7SdKA,1483
11
+ ai_simple_engine_diffusion/graph/operation/sample_latents.py,sha256=pmeWCz7Jn7T8w77uChXUoDcOV4VQpXHSjo1eXd0st7I,1348
12
+ ai_simple_engine_diffusion/model/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
13
+ ai_simple_engine_diffusion/model/executor/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
14
+ ai_simple_engine_diffusion/model/executor/abstract/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
15
+ ai_simple_engine_diffusion/model/executor/abstract/diffusion_model_executor_abstract.py,sha256=lb50F6hyKXLMpIlWoQBNUX-LwMCSPyRhsQQy4QIAKrY,1561
16
+ ai_simple_engine_diffusion/model/executor/diffusers_stable_diffusion_model_executor.py,sha256=zqoOlVapev-hvVo_zuHwHp9G3zB6G1MoQK2uMAqKDuw,1107
17
+ ai_simple_engine_diffusion/model/executor/text_encoder_model_executor_abstract.py,sha256=78SLwFMIQvnYhSpe9bNS5eVMaNGYHVimCiphaNSoPYU,656
18
+ ai_simple_engine_diffusion/model/executor/unet_model_executor_abstract.py,sha256=7pIgudVQHpsKUSWRmlcDtAbYM_zpSeIA2rw4Q4Niz5E,855
19
+ ai_simple_engine_diffusion/model/executor/vae_model_executor_abstract.py,sha256=VmAmEiSfH1Mk9vwp2ZcQtWYA3-NQRshRtnNRCCGHEr8,896
20
+ ai_simple_engine_diffusion/model/info/__init__.py,sha256=OwlQ20tWdB11fWKzDnPlSXr1Es2LJ-JQ_VdBq10xCrA,74
21
+ ai_simple_engine_diffusion/model/info/diffusion_model_info.py,sha256=ITx8dbRCWqTDARKBKldCO9XwwwR0eJKaU5suidALTsc,1044
22
+ ai_simple_engine_diffusion/noise/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
23
+ ai_simple_engine_diffusion/noise/noise_generator_abstract.py,sha256=WlSvbjgNUUtueYUjQ9pAQ4bP2VrUS5ZAmAF7U4VxRE0,691
24
+ ai_simple_engine_diffusion/prompt_embeddings/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
25
+ ai_simple_engine_diffusion/prompt_embeddings/abstract.py,sha256=BqhDxBpioPa2ZwIdCapmgqQeOozk-1Msf5sOlp90MP8,39
26
+ ai_simple_engine_diffusion/scheduler/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
27
+ ai_simple_engine_diffusion/scheduler/abstract.py,sha256=BkE46-rRKVa3bpEhSpV3hwiA_0m4pp5Aw5JUPeiMV-M,1007
28
+ ai_simple_engine_diffusion/scheduler/spec/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
29
+ ai_simple_engine_diffusion/scheduler/spec/base.py,sha256=8IswyXklrmmUrjfGkQKTtz4HFQ27NMoA9mnZrp3hZNs,464
30
+ ai_simple_engine_diffusion/scheduler/utils.py,sha256=d0ToobCjOxjfP8V555WRW8ctQz8N7M3naXTl4fNhcfU,459
31
+ ai_simple_engine_diffusion/types/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
32
+ ai_simple_engine_diffusion/types/data_type.py,sha256=_30TMYvyOXlzFAzV4RyGKKTv10_pg8LmBxMoiRzCgGg,669
33
+ ai_simple_engine_diffusion/types/embeddings.py,sha256=dSr_o3h_owAAkjao8fHujQg4rF5_3W_BUCB_TB5R0lY,495
34
+ ai_simple_engine_diffusion/types/latent_space.py,sha256=tRtT1afGxc0H8_J_irW8NLcvBYjgQT12JPV-hKfKwiI,138
35
+ ai_simple_engine_diffusion/types/latents.py,sha256=KobTwk-LlJ1ftFuiuy1T-LgwWMGSY5hqU0vhHQ5uzt8,496
36
+ ai_simple_engine_diffusion/types/noise_prediction.py,sha256=10FxCykTxPbzV5CcJj9LvaIEBiyLFCH2tR3nRP0xP60,500
37
+ ai_simple_engine_diffusion-0.0.1.dist-info/licenses/LICENSE,sha256=6kbiFSfobTZ7beWiKnHpN902HgBx-Jzgcme0SvKqhKY,1091
38
+ ai_simple_engine_diffusion-0.0.1.dist-info/METADATA,sha256=3xjsj58ohnrVjYmzI_M2gKIhqw_hngX-xtR8EAWfcnc,714
39
+ ai_simple_engine_diffusion-0.0.1.dist-info/WHEEL,sha256=M5asmiAlL6HEcOq52Yi5mmk9KmTVjY2RDPtO4p9DMrc,88
40
+ ai_simple_engine_diffusion-0.0.1.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: poetry-core 2.2.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2018 The Python Packaging Authority
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in all
11
+ copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19
+ SOFTWARE.