First model version
Browse files- args.json +58 -0
- feature_extractor/preprocessor_config.json +28 -0
- model_index.json +34 -0
- samples/0/0.png +0 -0
- samples/0/1.png +0 -0
- samples/0/2.png +0 -0
- samples/0/3.png +0 -0
- scheduler/scheduler_config.json +19 -0
- text_encoder/config.json +25 -0
- text_encoder/model.safetensors +3 -0
- tokenizer/merges.txt +0 -0
- tokenizer/special_tokens_map.json +24 -0
- tokenizer/tokenizer_config.json +33 -0
- tokenizer/vocab.json +0 -0
- train_inpainting_dreambooth.py +1032 -0
- unet/config.json +66 -0
- unet/diffusion_pytorch_model.safetensors +3 -0
- vae/config.json +32 -0
- vae/diffusion_pytorch_model.safetensors +3 -0
args.json
ADDED
@@ -0,0 +1,58 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"pretrained_model_name_or_path": "booth-ai/realisticVisionV20_v20_inpainting",
|
3 |
+
"pretrained_vae_name_or_path": "stabilityai/sd-vae-ft-mse",
|
4 |
+
"revision": "main",
|
5 |
+
"tokenizer_name": null,
|
6 |
+
"instance_data_dir": null,
|
7 |
+
"class_data_dir": null,
|
8 |
+
"instance_prompt": null,
|
9 |
+
"class_prompt": null,
|
10 |
+
"save_sample_negative_prompt": null,
|
11 |
+
"n_save_sample": 4,
|
12 |
+
"save_guidance_scale": 7.5,
|
13 |
+
"save_infer_steps": 50,
|
14 |
+
"pad_tokens": false,
|
15 |
+
"with_prior_preservation": false,
|
16 |
+
"prior_loss_weight": 1.0,
|
17 |
+
"num_class_images": 100,
|
18 |
+
"output_dir": "./models/outgrowths_7",
|
19 |
+
"seed": 3434554,
|
20 |
+
"resolution": 512,
|
21 |
+
"center_crop": false,
|
22 |
+
"train_text_encoder": false,
|
23 |
+
"train_batch_size": 4,
|
24 |
+
"sample_batch_size": 2,
|
25 |
+
"num_train_epochs": 176,
|
26 |
+
"max_train_steps": 10000,
|
27 |
+
"gradient_accumulation_steps": 1,
|
28 |
+
"gradient_checkpointing": false,
|
29 |
+
"learning_rate": 2e-06,
|
30 |
+
"scale_lr": false,
|
31 |
+
"lr_scheduler": "constant",
|
32 |
+
"lr_warmup_steps": 0,
|
33 |
+
"use_8bit_adam": false,
|
34 |
+
"adam_beta1": 0.9,
|
35 |
+
"adam_beta2": 0.999,
|
36 |
+
"adam_weight_decay": 0.01,
|
37 |
+
"adam_epsilon": 1e-08,
|
38 |
+
"max_grad_norm": 1.0,
|
39 |
+
"push_to_hub": false,
|
40 |
+
"hub_token": null,
|
41 |
+
"hub_model_id": null,
|
42 |
+
"logging_dir": "logs",
|
43 |
+
"log_interval": 10,
|
44 |
+
"save_interval": 500,
|
45 |
+
"save_min_steps": 500,
|
46 |
+
"mixed_precision": "no",
|
47 |
+
"not_cache_latents": true,
|
48 |
+
"hflip": true,
|
49 |
+
"local_rank": -1,
|
50 |
+
"concepts_list": [
|
51 |
+
{
|
52 |
+
"instance_prompt": "photo of zwx dog",
|
53 |
+
"class_prompt": "photo of a dog",
|
54 |
+
"instance_data_dir": "./512",
|
55 |
+
"class_data_dir": "../../../data/dog"
|
56 |
+
}
|
57 |
+
]
|
58 |
+
}
|
feature_extractor/preprocessor_config.json
ADDED
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"crop_size": {
|
3 |
+
"height": 224,
|
4 |
+
"width": 224
|
5 |
+
},
|
6 |
+
"do_center_crop": true,
|
7 |
+
"do_convert_rgb": true,
|
8 |
+
"do_normalize": true,
|
9 |
+
"do_rescale": true,
|
10 |
+
"do_resize": true,
|
11 |
+
"feature_extractor_type": "CLIPFeatureExtractor",
|
12 |
+
"image_mean": [
|
13 |
+
0.48145466,
|
14 |
+
0.4578275,
|
15 |
+
0.40821073
|
16 |
+
],
|
17 |
+
"image_processor_type": "CLIPFeatureExtractor",
|
18 |
+
"image_std": [
|
19 |
+
0.26862954,
|
20 |
+
0.26130258,
|
21 |
+
0.27577711
|
22 |
+
],
|
23 |
+
"resample": 3,
|
24 |
+
"rescale_factor": 0.00392156862745098,
|
25 |
+
"size": {
|
26 |
+
"shortest_edge": 224
|
27 |
+
}
|
28 |
+
}
|
model_index.json
ADDED
@@ -0,0 +1,34 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"_class_name": "StableDiffusionInpaintPipeline",
|
3 |
+
"_diffusers_version": "0.21.0.dev0",
|
4 |
+
"_name_or_path": "booth-ai/realisticVisionV20_v20_inpainting",
|
5 |
+
"feature_extractor": [
|
6 |
+
"transformers",
|
7 |
+
"CLIPFeatureExtractor"
|
8 |
+
],
|
9 |
+
"requires_safety_checker": true,
|
10 |
+
"safety_checker": [
|
11 |
+
null,
|
12 |
+
null
|
13 |
+
],
|
14 |
+
"scheduler": [
|
15 |
+
"diffusers",
|
16 |
+
"DDIMScheduler"
|
17 |
+
],
|
18 |
+
"text_encoder": [
|
19 |
+
"transformers",
|
20 |
+
"CLIPTextModel"
|
21 |
+
],
|
22 |
+
"tokenizer": [
|
23 |
+
"transformers",
|
24 |
+
"CLIPTokenizer"
|
25 |
+
],
|
26 |
+
"unet": [
|
27 |
+
"diffusers",
|
28 |
+
"UNet2DConditionModel"
|
29 |
+
],
|
30 |
+
"vae": [
|
31 |
+
"diffusers",
|
32 |
+
"AutoencoderKL"
|
33 |
+
]
|
34 |
+
}
|
samples/0/0.png
ADDED
samples/0/1.png
ADDED
samples/0/2.png
ADDED
samples/0/3.png
ADDED
scheduler/scheduler_config.json
ADDED
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"_class_name": "DDIMScheduler",
|
3 |
+
"_diffusers_version": "0.21.0.dev0",
|
4 |
+
"beta_end": 0.012,
|
5 |
+
"beta_schedule": "scaled_linear",
|
6 |
+
"beta_start": 0.00085,
|
7 |
+
"clip_sample": false,
|
8 |
+
"clip_sample_range": 1.0,
|
9 |
+
"dynamic_thresholding_ratio": 0.995,
|
10 |
+
"num_train_timesteps": 1000,
|
11 |
+
"prediction_type": "epsilon",
|
12 |
+
"rescale_betas_zero_snr": false,
|
13 |
+
"sample_max_value": 1.0,
|
14 |
+
"set_alpha_to_one": false,
|
15 |
+
"steps_offset": 1,
|
16 |
+
"thresholding": false,
|
17 |
+
"timestep_spacing": "leading",
|
18 |
+
"trained_betas": null
|
19 |
+
}
|
text_encoder/config.json
ADDED
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"_name_or_path": "booth-ai/realisticVisionV20_v20_inpainting",
|
3 |
+
"architectures": [
|
4 |
+
"CLIPTextModel"
|
5 |
+
],
|
6 |
+
"attention_dropout": 0.0,
|
7 |
+
"bos_token_id": 0,
|
8 |
+
"dropout": 0.0,
|
9 |
+
"eos_token_id": 2,
|
10 |
+
"hidden_act": "quick_gelu",
|
11 |
+
"hidden_size": 768,
|
12 |
+
"initializer_factor": 1.0,
|
13 |
+
"initializer_range": 0.02,
|
14 |
+
"intermediate_size": 3072,
|
15 |
+
"layer_norm_eps": 1e-05,
|
16 |
+
"max_position_embeddings": 77,
|
17 |
+
"model_type": "clip_text_model",
|
18 |
+
"num_attention_heads": 12,
|
19 |
+
"num_hidden_layers": 12,
|
20 |
+
"pad_token_id": 1,
|
21 |
+
"projection_dim": 768,
|
22 |
+
"torch_dtype": "float16",
|
23 |
+
"transformers_version": "4.32.1",
|
24 |
+
"vocab_size": 49408
|
25 |
+
}
|
text_encoder/model.safetensors
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:5f3183e9cd8a1c4cfd99fc68b0c6d1832d009ad672c3577ab0e81939ec1be15b
|
3 |
+
size 246144152
|
tokenizer/merges.txt
ADDED
The diff for this file is too large to render.
See raw diff
|
|
tokenizer/special_tokens_map.json
ADDED
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"bos_token": {
|
3 |
+
"content": "<|startoftext|>",
|
4 |
+
"lstrip": false,
|
5 |
+
"normalized": true,
|
6 |
+
"rstrip": false,
|
7 |
+
"single_word": false
|
8 |
+
},
|
9 |
+
"eos_token": {
|
10 |
+
"content": "<|endoftext|>",
|
11 |
+
"lstrip": false,
|
12 |
+
"normalized": true,
|
13 |
+
"rstrip": false,
|
14 |
+
"single_word": false
|
15 |
+
},
|
16 |
+
"pad_token": "<|endoftext|>",
|
17 |
+
"unk_token": {
|
18 |
+
"content": "<|endoftext|>",
|
19 |
+
"lstrip": false,
|
20 |
+
"normalized": true,
|
21 |
+
"rstrip": false,
|
22 |
+
"single_word": false
|
23 |
+
}
|
24 |
+
}
|
tokenizer/tokenizer_config.json
ADDED
@@ -0,0 +1,33 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"add_prefix_space": false,
|
3 |
+
"bos_token": {
|
4 |
+
"__type": "AddedToken",
|
5 |
+
"content": "<|startoftext|>",
|
6 |
+
"lstrip": false,
|
7 |
+
"normalized": true,
|
8 |
+
"rstrip": false,
|
9 |
+
"single_word": false
|
10 |
+
},
|
11 |
+
"clean_up_tokenization_spaces": true,
|
12 |
+
"do_lower_case": true,
|
13 |
+
"eos_token": {
|
14 |
+
"__type": "AddedToken",
|
15 |
+
"content": "<|endoftext|>",
|
16 |
+
"lstrip": false,
|
17 |
+
"normalized": true,
|
18 |
+
"rstrip": false,
|
19 |
+
"single_word": false
|
20 |
+
},
|
21 |
+
"errors": "replace",
|
22 |
+
"model_max_length": 77,
|
23 |
+
"pad_token": "<|endoftext|>",
|
24 |
+
"tokenizer_class": "CLIPTokenizer",
|
25 |
+
"unk_token": {
|
26 |
+
"__type": "AddedToken",
|
27 |
+
"content": "<|endoftext|>",
|
28 |
+
"lstrip": false,
|
29 |
+
"normalized": true,
|
30 |
+
"rstrip": false,
|
31 |
+
"single_word": false
|
32 |
+
}
|
33 |
+
}
|
tokenizer/vocab.json
ADDED
The diff for this file is too large to render.
See raw diff
|
|
train_inpainting_dreambooth.py
ADDED
@@ -0,0 +1,1032 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import argparse
|
2 |
+
import hashlib
|
3 |
+
import itertools
|
4 |
+
import json
|
5 |
+
import math
|
6 |
+
import os
|
7 |
+
import random
|
8 |
+
import shutil
|
9 |
+
from contextlib import nullcontext
|
10 |
+
from pathlib import Path
|
11 |
+
from typing import Optional
|
12 |
+
|
13 |
+
import torch
|
14 |
+
import torch.nn.functional as F
|
15 |
+
import torch.utils.checkpoint
|
16 |
+
from accelerate import Accelerator
|
17 |
+
from accelerate.logging import get_logger
|
18 |
+
from accelerate.utils import set_seed
|
19 |
+
from huggingface_hub import HfFolder, Repository, whoami
|
20 |
+
from PIL import Image, ImageOps
|
21 |
+
from torch.utils.data import Dataset
|
22 |
+
# from torchvision import transforms
|
23 |
+
# from torchvision.transforms import v2
|
24 |
+
from opencv_transforms import transforms
|
25 |
+
from tqdm.auto import tqdm
|
26 |
+
from transformers import CLIPTextModel, CLIPTokenizer
|
27 |
+
|
28 |
+
from diffusers import (AutoencoderKL, DDIMScheduler, DDPMScheduler,
|
29 |
+
StableDiffusionInpaintPipeline, UNet2DConditionModel)
|
30 |
+
from diffusers.optimization import get_scheduler
|
31 |
+
from diffusers.utils import is_wandb_available
|
32 |
+
|
33 |
+
if is_wandb_available():
|
34 |
+
import wandb
|
35 |
+
|
36 |
+
torch.backends.cudnn.benchmark = True
|
37 |
+
|
38 |
+
|
39 |
+
logger = get_logger(__name__)
|
40 |
+
|
41 |
+
|
42 |
+
def parse_args(input_args=None):
|
43 |
+
parser = argparse.ArgumentParser(description="Simple example of a training script.")
|
44 |
+
parser.add_argument(
|
45 |
+
"--pretrained_model_name_or_path",
|
46 |
+
type=str,
|
47 |
+
default=None,
|
48 |
+
required=True,
|
49 |
+
help="Path to pretrained model or model identifier from huggingface.co/models.",
|
50 |
+
)
|
51 |
+
parser.add_argument(
|
52 |
+
"--pretrained_vae_name_or_path",
|
53 |
+
type=str,
|
54 |
+
default=None,
|
55 |
+
help="Path to pretrained vae or vae identifier from huggingface.co/models.",
|
56 |
+
)
|
57 |
+
parser.add_argument(
|
58 |
+
"--revision",
|
59 |
+
type=str,
|
60 |
+
default="fp16",
|
61 |
+
required=False,
|
62 |
+
help="Revision of pretrained model identifier from huggingface.co/models.",
|
63 |
+
)
|
64 |
+
parser.add_argument(
|
65 |
+
"--tokenizer_name",
|
66 |
+
type=str,
|
67 |
+
default=None,
|
68 |
+
help="Pretrained tokenizer name or path if not the same as model_name",
|
69 |
+
)
|
70 |
+
parser.add_argument(
|
71 |
+
"--instance_data_dir",
|
72 |
+
type=str,
|
73 |
+
default=None,
|
74 |
+
help="A folder containing the training data of instance images.",
|
75 |
+
)
|
76 |
+
parser.add_argument(
|
77 |
+
"--class_data_dir",
|
78 |
+
type=str,
|
79 |
+
default=None,
|
80 |
+
help="A folder containing the training data of class images.",
|
81 |
+
)
|
82 |
+
parser.add_argument(
|
83 |
+
"--instance_prompt",
|
84 |
+
type=str,
|
85 |
+
default=None,
|
86 |
+
help="The prompt with identifier specifying the instance",
|
87 |
+
)
|
88 |
+
parser.add_argument(
|
89 |
+
"--class_prompt",
|
90 |
+
type=str,
|
91 |
+
default=None,
|
92 |
+
help="The prompt to specify images in the same class as provided instance images.",
|
93 |
+
)
|
94 |
+
# parser.add_argument(
|
95 |
+
# "--save_sample_prompt",
|
96 |
+
# type=str,
|
97 |
+
# default=None,
|
98 |
+
# help="The prompt used to generate sample outputs to save.",
|
99 |
+
# )
|
100 |
+
parser.add_argument(
|
101 |
+
"--save_sample_negative_prompt",
|
102 |
+
type=str,
|
103 |
+
default=None,
|
104 |
+
help="The negative prompt used to generate sample outputs to save.",
|
105 |
+
)
|
106 |
+
parser.add_argument(
|
107 |
+
"--n_save_sample",
|
108 |
+
type=int,
|
109 |
+
default=4,
|
110 |
+
help="The number of samples to save.",
|
111 |
+
)
|
112 |
+
parser.add_argument(
|
113 |
+
"--save_guidance_scale",
|
114 |
+
type=float,
|
115 |
+
default=7.5,
|
116 |
+
help="CFG for save sample.",
|
117 |
+
)
|
118 |
+
parser.add_argument(
|
119 |
+
"--save_infer_steps",
|
120 |
+
type=int,
|
121 |
+
default=50,
|
122 |
+
help="The number of inference steps for save sample.",
|
123 |
+
)
|
124 |
+
parser.add_argument(
|
125 |
+
"--pad_tokens",
|
126 |
+
default=False,
|
127 |
+
action="store_true",
|
128 |
+
help="Flag to pad tokens to length 77.",
|
129 |
+
)
|
130 |
+
parser.add_argument(
|
131 |
+
"--with_prior_preservation",
|
132 |
+
default=False,
|
133 |
+
action="store_true",
|
134 |
+
help="Flag to add prior preservation loss.",
|
135 |
+
)
|
136 |
+
parser.add_argument("--prior_loss_weight", type=float, default=1.0, help="The weight of prior preservation loss.")
|
137 |
+
parser.add_argument(
|
138 |
+
"--num_class_images",
|
139 |
+
type=int,
|
140 |
+
default=100,
|
141 |
+
help=(
|
142 |
+
"Minimal class images for prior preservation loss. If not have enough images, additional images will be"
|
143 |
+
" sampled with class_prompt."
|
144 |
+
),
|
145 |
+
)
|
146 |
+
parser.add_argument(
|
147 |
+
"--output_dir",
|
148 |
+
type=str,
|
149 |
+
default="text-inversion-model",
|
150 |
+
help="The output directory where the model predictions and checkpoints will be written.",
|
151 |
+
)
|
152 |
+
parser.add_argument("--seed", type=int, default=None, help="A seed for reproducible training.")
|
153 |
+
parser.add_argument(
|
154 |
+
"--resolution",
|
155 |
+
type=int,
|
156 |
+
default=512,
|
157 |
+
help=(
|
158 |
+
"The resolution for input images, all the images in the train/validation dataset will be resized to this"
|
159 |
+
" resolution"
|
160 |
+
),
|
161 |
+
)
|
162 |
+
parser.add_argument(
|
163 |
+
"--center_crop", action="store_true", help="Whether to center crop images before resizing to resolution"
|
164 |
+
)
|
165 |
+
parser.add_argument("--train_text_encoder", action="store_true", help="Whether to train the text encoder")
|
166 |
+
parser.add_argument(
|
167 |
+
"--train_batch_size", type=int, default=4, help="Batch size (per device) for the training dataloader."
|
168 |
+
)
|
169 |
+
parser.add_argument(
|
170 |
+
"--sample_batch_size", type=int, default=4, help="Batch size (per device) for sampling images."
|
171 |
+
)
|
172 |
+
parser.add_argument("--num_train_epochs", type=int, default=1)
|
173 |
+
parser.add_argument(
|
174 |
+
"--max_train_steps",
|
175 |
+
type=int,
|
176 |
+
default=None,
|
177 |
+
help="Total number of training steps to perform. If provided, overrides num_train_epochs.",
|
178 |
+
)
|
179 |
+
parser.add_argument(
|
180 |
+
"--gradient_accumulation_steps",
|
181 |
+
type=int,
|
182 |
+
default=1,
|
183 |
+
help="Number of updates steps to accumulate before performing a backward/update pass.",
|
184 |
+
)
|
185 |
+
parser.add_argument(
|
186 |
+
"--gradient_checkpointing",
|
187 |
+
action="store_true",
|
188 |
+
help="Whether or not to use gradient checkpointing to save memory at the expense of slower backward pass.",
|
189 |
+
)
|
190 |
+
parser.add_argument(
|
191 |
+
"--learning_rate",
|
192 |
+
type=float,
|
193 |
+
default=5e-6,
|
194 |
+
help="Initial learning rate (after the potential warmup period) to use.",
|
195 |
+
)
|
196 |
+
parser.add_argument(
|
197 |
+
"--scale_lr",
|
198 |
+
action="store_true",
|
199 |
+
default=False,
|
200 |
+
help="Scale the learning rate by the number of GPUs, gradient accumulation steps, and batch size.",
|
201 |
+
)
|
202 |
+
parser.add_argument(
|
203 |
+
"--lr_scheduler",
|
204 |
+
type=str,
|
205 |
+
default="constant",
|
206 |
+
help=(
|
207 |
+
'The scheduler type to use. Choose between ["linear", "cosine", "cosine_with_restarts", "polynomial",'
|
208 |
+
' "constant", "constant_with_warmup"]'
|
209 |
+
),
|
210 |
+
)
|
211 |
+
parser.add_argument(
|
212 |
+
"--lr_warmup_steps", type=int, default=500, help="Number of steps for the warmup in the lr scheduler."
|
213 |
+
)
|
214 |
+
parser.add_argument(
|
215 |
+
"--use_8bit_adam", action="store_true", help="Whether or not to use 8-bit Adam from bitsandbytes."
|
216 |
+
)
|
217 |
+
parser.add_argument("--adam_beta1", type=float, default=0.9, help="The beta1 parameter for the Adam optimizer.")
|
218 |
+
parser.add_argument("--adam_beta2", type=float, default=0.999, help="The beta2 parameter for the Adam optimizer.")
|
219 |
+
parser.add_argument("--adam_weight_decay", type=float, default=1e-2, help="Weight decay to use.")
|
220 |
+
parser.add_argument("--adam_epsilon", type=float, default=1e-08, help="Epsilon value for the Adam optimizer")
|
221 |
+
parser.add_argument("--max_grad_norm", default=1.0, type=float, help="Max gradient norm.")
|
222 |
+
parser.add_argument("--push_to_hub", action="store_true", help="Whether or not to push the model to the Hub.")
|
223 |
+
parser.add_argument("--hub_token", type=str, default=None, help="The token to use to push to the Model Hub.")
|
224 |
+
parser.add_argument(
|
225 |
+
"--hub_model_id",
|
226 |
+
type=str,
|
227 |
+
default=None,
|
228 |
+
help="The name of the repository to keep in sync with the local `output_dir`.",
|
229 |
+
)
|
230 |
+
parser.add_argument(
|
231 |
+
"--logging_dir",
|
232 |
+
type=str,
|
233 |
+
default="logs",
|
234 |
+
help=(
|
235 |
+
"[TensorBoard](https://www.tensorflow.org/tensorboard) log directory. Will default to"
|
236 |
+
" *output_dir/runs/**CURRENT_DATETIME_HOSTNAME***."
|
237 |
+
),
|
238 |
+
)
|
239 |
+
parser.add_argument("--log_interval", type=int, default=10, help="Log every N steps.")
|
240 |
+
parser.add_argument("--save_interval", type=int, default=10_000, help="Save weights every N steps.")
|
241 |
+
parser.add_argument("--save_min_steps", type=int, default=0, help="Start saving weights after N steps.")
|
242 |
+
parser.add_argument(
|
243 |
+
"--mixed_precision",
|
244 |
+
type=str,
|
245 |
+
default="no",
|
246 |
+
choices=["no", "fp16", "bf16"],
|
247 |
+
help=(
|
248 |
+
"Whether to use mixed precision. Choose"
|
249 |
+
"between fp16 and bf16 (bfloat16). Bf16 requires PyTorch >= 1.10."
|
250 |
+
"and an Nvidia Ampere GPU."
|
251 |
+
),
|
252 |
+
)
|
253 |
+
parser.add_argument("--not_cache_latents", action="store_true", help="Do not precompute and cache latents from VAE.")
|
254 |
+
parser.add_argument("--hflip", action="store_true", help="Apply horizontal flip data augmentation.")
|
255 |
+
parser.add_argument("--local_rank", type=int, default=-1, help="For distributed training: local_rank")
|
256 |
+
parser.add_argument(
|
257 |
+
"--concepts_list",
|
258 |
+
type=str,
|
259 |
+
default=None,
|
260 |
+
help="Path to json containing multiple concepts, will overwrite parameters like instance_prompt, class_prompt, etc.",
|
261 |
+
)
|
262 |
+
|
263 |
+
if input_args is not None:
|
264 |
+
args = parser.parse_args(input_args)
|
265 |
+
else:
|
266 |
+
args = parser.parse_args()
|
267 |
+
|
268 |
+
env_local_rank = int(os.environ.get("LOCAL_RANK", -1))
|
269 |
+
if env_local_rank != -1 and env_local_rank != args.local_rank:
|
270 |
+
args.local_rank = env_local_rank
|
271 |
+
|
272 |
+
return args
|
273 |
+
|
274 |
+
def get_cutout_holes(height, width, min_holes=8, max_holes=32, min_height=16, max_height=128, min_width=16, max_width=128):
|
275 |
+
holes = []
|
276 |
+
for _n in range(random.randint(min_holes, max_holes)):
|
277 |
+
hole_height = random.randint(min_height, max_height)
|
278 |
+
hole_width = random.randint(min_width, max_width)
|
279 |
+
y1 = random.randint(0, height - hole_height)
|
280 |
+
x1 = random.randint(0, width - hole_width)
|
281 |
+
y2 = y1 + hole_height
|
282 |
+
x2 = x1 + hole_width
|
283 |
+
holes.append((x1, y1, x2, y2))
|
284 |
+
return holes
|
285 |
+
|
286 |
+
import torchvision
|
287 |
+
|
288 |
+
def generate_random_mask(image):
|
289 |
+
# mask = torch.zeros_like(image[:1])
|
290 |
+
# print('foobar', mask.shape)
|
291 |
+
mask = image[-1].unsqueeze(0)
|
292 |
+
# torchvision.transforms.functional.to_pil_image(mask).save('foomask2.png')
|
293 |
+
|
294 |
+
# if random.uniform(0, 1) < 0.25:
|
295 |
+
# mask = torch.zeros_like(image[:1])
|
296 |
+
# mask.fill_(1.)
|
297 |
+
# print('foobar',image.shape)
|
298 |
+
# torchvision.transforms.functional.to_pil_image(image[:4]).save('fooimageinside2.png')
|
299 |
+
# print('foobar',image[:3].shape)
|
300 |
+
masked_image = image[:-1] * (mask < 0.5)
|
301 |
+
# torchvision.transforms.functional.to_pil_image(masked_image).save('foomaskedimage2.png')
|
302 |
+
return mask, masked_image
|
303 |
+
|
304 |
+
image_transforms = transforms.Compose(
|
305 |
+
[
|
306 |
+
torchvision.transforms.RandomHorizontalFlip(0.5 * True),
|
307 |
+
# transforms.Resize(size, interpolation=transforms.InterpolationMode.BILINEAR),
|
308 |
+
# transforms.CenterCrop(size) if center_crop else transforms.RandomCrop(size),
|
309 |
+
transforms.RandomResizedCrop(512, scale=(0.75,1.0)),
|
310 |
+
torchvision.transforms.ToTensor(),
|
311 |
+
torchvision.transforms.Normalize([0.5], [0.5]),
|
312 |
+
]
|
313 |
+
)
|
314 |
+
# instance_image = Image.open("/home/neil/Documents/diffusers/examples/dreambooth/512_/a corner sofa in midnight blue in a room with vibrant walls and eclectic artwork, creating a lively and energetic atmosphere. .png")
|
315 |
+
# alpha = instance_image.split()[-1]
|
316 |
+
# instance_image.putalpha(ImageOps.invert(alpha))
|
317 |
+
# instance_image.save('foofull.png')
|
318 |
+
# # rgb_instance_image = instance_image.convert('RGB')
|
319 |
+
# # rgb_instance_image.save('foofullrgb.png')
|
320 |
+
# example = {}
|
321 |
+
# example["instance_images"] = image_transforms(instance_image)
|
322 |
+
# torchvision.transforms.functional.to_pil_image(example["instance_images"]).save('fooimage.png')
|
323 |
+
# example["instance_masks"], example["instance_masked_images"] = generate_random_mask(example["instance_images"])
|
324 |
+
# example["instance_images"] = example["instance_images"][:3]
|
325 |
+
# torchvision.transforms.functional.to_pil_image(example["instance_images"]).save('fooimage1.png')
|
326 |
+
# breakpoint()
|
327 |
+
|
328 |
+
# example = {}
|
329 |
+
# instance_image = Image.open("/home/neil/Documents/diffusers/examples/dreambooth/512_/a corner sofa in midnight blue in a room with vibrant walls and eclectic artwork, creating a lively and energetic atmosphere. .png")
|
330 |
+
# instance_image.save('fooinstance2.png')
|
331 |
+
# alpha = instance_image.split()[-1]
|
332 |
+
# alpha.save('fooalpha2.png')
|
333 |
+
# instance_image.putalpha(ImageOps.invert(alpha))
|
334 |
+
# instance_image.convert("RGB").save('foofull2rgb.png')
|
335 |
+
# instance_image.save('foofull2.png')
|
336 |
+
|
337 |
+
# example["instance_images"] = image_transforms(instance_image)
|
338 |
+
# torchvision.transforms.functional.to_pil_image(example["instance_images"]).save('fooimage2.png')
|
339 |
+
# example["instance_masks"], example["instance_masked_images"] = generate_random_mask(example["instance_images"])
|
340 |
+
# torchvision.transforms.functional.to_pil_image(example["instance_masks"]).save('fooinstance_masks.png')
|
341 |
+
# torchvision.transforms.functional.to_pil_image(example["instance_masked_images"]).save('fooinstance_masked_images.png')
|
342 |
+
# example["instance_images"] = example["instance_images"][:3]
|
343 |
+
# final = torchvision.transforms.functional.to_pil_image(example["instance_images"])
|
344 |
+
# final.save('fooimage3.png')
|
345 |
+
# breakpoint()
|
346 |
+
|
347 |
+
class DreamBoothDataset(Dataset):
|
348 |
+
"""
|
349 |
+
A dataset to prepare the instance and class images with the prompts for fine-tuning the model.
|
350 |
+
It pre-processes the images and the tokenizes prompts.
|
351 |
+
"""
|
352 |
+
|
353 |
+
def __init__(
|
354 |
+
self,
|
355 |
+
concepts_list,
|
356 |
+
tokenizer,
|
357 |
+
with_prior_preservation=True,
|
358 |
+
size=512,
|
359 |
+
center_crop=False,
|
360 |
+
num_class_images=None,
|
361 |
+
pad_tokens=False,
|
362 |
+
hflip=False
|
363 |
+
):
|
364 |
+
self.size = size
|
365 |
+
self.center_crop = center_crop
|
366 |
+
self.tokenizer = tokenizer
|
367 |
+
self.with_prior_preservation = with_prior_preservation
|
368 |
+
self.pad_tokens = pad_tokens
|
369 |
+
|
370 |
+
self.instance_images_path = []
|
371 |
+
self.class_images_path = []
|
372 |
+
|
373 |
+
for concept in concepts_list:
|
374 |
+
inst_img_path = [(x, concept["instance_prompt"]) for x in Path(concept["instance_data_dir"]).iterdir() if x.is_file()]
|
375 |
+
self.instance_images_path.extend(inst_img_path)
|
376 |
+
|
377 |
+
if with_prior_preservation:
|
378 |
+
class_img_path = [(x, concept["class_prompt"]) for x in Path(concept["class_data_dir"]).iterdir() if x.is_file()]
|
379 |
+
self.class_images_path.extend(class_img_path[:num_class_images])
|
380 |
+
|
381 |
+
random.shuffle(self.instance_images_path)
|
382 |
+
self.num_instance_images = len(self.instance_images_path)
|
383 |
+
self.num_class_images = len(self.class_images_path)
|
384 |
+
self._length = max(self.num_class_images, self.num_instance_images)
|
385 |
+
|
386 |
+
self.image_transforms = transforms.Compose(
|
387 |
+
[
|
388 |
+
torchvision.transforms.RandomHorizontalFlip(0.5 * hflip),
|
389 |
+
transforms.RandomResizedCrop(size, scale=(0.75,1.0)),
|
390 |
+
torchvision.transforms.ToTensor(),
|
391 |
+
torchvision.transforms.Normalize([0.5], [0.5]),
|
392 |
+
]
|
393 |
+
)
|
394 |
+
|
395 |
+
def __len__(self):
|
396 |
+
return self._length
|
397 |
+
|
398 |
+
def __getitem__(self, index):
|
399 |
+
example = {}
|
400 |
+
instance_path, instance_prompt = self.instance_images_path[index % self.num_instance_images]
|
401 |
+
instance_image = Image.open(instance_path)
|
402 |
+
alpha = instance_image.split()[-1]
|
403 |
+
instance_image.putalpha(ImageOps.invert(alpha))
|
404 |
+
|
405 |
+
example["instance_images"] = self.image_transforms(instance_image)
|
406 |
+
example["instance_masks"], example["instance_masked_images"] = generate_random_mask(example["instance_images"])
|
407 |
+
# torchvision.transforms.functional.to_pil_image(example["instance_masks"][0]).save('foo_instance_masks.png')
|
408 |
+
# torchvision.transforms.functional.to_pil_image(example["instance_masked_images"][0]).save('foo_instance_masked_images.png')
|
409 |
+
example["instance_images"] = example["instance_images"][:3]
|
410 |
+
# torchvision.transforms.functional.to_pil_image(example["instance_images"]).save('foo_instance_image.png')
|
411 |
+
example["instance_prompt_ids"] = self.tokenizer(
|
412 |
+
# instance_prompt,
|
413 |
+
os.path.basename(instance_prompt),
|
414 |
+
padding="max_length" if self.pad_tokens else "do_not_pad",
|
415 |
+
truncation=True,
|
416 |
+
max_length=self.tokenizer.model_max_length,
|
417 |
+
).input_ids
|
418 |
+
if self.with_prior_preservation:
|
419 |
+
class_path, class_prompt = self.class_images_path[index % self.num_class_images]
|
420 |
+
class_image = Image.open(class_path)
|
421 |
+
alpha = instance_image.split()[-1]
|
422 |
+
instance_image.putalpha(ImageOps.invert(alpha))
|
423 |
+
example["instance_images"] = self.image_transforms(instance_image)
|
424 |
+
example["instance_masks"], example["instance_masked_images"] = generate_random_mask(example["instance_images"])
|
425 |
+
example["instance_images"] = self.image_transforms(instance_image.convert("RGB"))
|
426 |
+
example["class_prompt_ids"] = self.tokenizer(
|
427 |
+
class_prompt,
|
428 |
+
padding="max_length" if self.pad_tokens else "do_not_pad",
|
429 |
+
truncation=True,
|
430 |
+
max_length=self.tokenizer.model_max_length,
|
431 |
+
).input_ids
|
432 |
+
|
433 |
+
return example
|
434 |
+
|
435 |
+
|
436 |
+
class PromptDataset(Dataset):
|
437 |
+
"A simple dataset to prepare the prompts to generate class images on multiple GPUs."
|
438 |
+
|
439 |
+
def __init__(self, prompt, num_samples):
|
440 |
+
self.prompt = prompt
|
441 |
+
self.num_samples = num_samples
|
442 |
+
|
443 |
+
def __len__(self):
|
444 |
+
return self.num_samples
|
445 |
+
|
446 |
+
def __getitem__(self, index):
|
447 |
+
example = {}
|
448 |
+
example["prompt"] = self.prompt
|
449 |
+
example["index"] = index
|
450 |
+
return example
|
451 |
+
|
452 |
+
|
453 |
+
class LatentsDataset(Dataset):
|
454 |
+
def __init__(self, latents_cache, text_encoder_cache):
|
455 |
+
self.latents_cache = latents_cache
|
456 |
+
self.text_encoder_cache = text_encoder_cache
|
457 |
+
|
458 |
+
def __len__(self):
|
459 |
+
return len(self.latents_cache)
|
460 |
+
|
461 |
+
def __getitem__(self, index):
|
462 |
+
return self.latents_cache[index], self.text_encoder_cache[index]
|
463 |
+
|
464 |
+
|
465 |
+
class AverageMeter:
|
466 |
+
def __init__(self, name=None):
|
467 |
+
self.name = name
|
468 |
+
self.reset()
|
469 |
+
|
470 |
+
def reset(self):
|
471 |
+
self.sum = self.count = self.avg = 0
|
472 |
+
|
473 |
+
def update(self, val, n=1):
|
474 |
+
self.sum += val * n
|
475 |
+
self.count += n
|
476 |
+
self.avg = self.sum / self.count
|
477 |
+
|
478 |
+
|
479 |
+
def get_full_repo_name(model_id: str, organization: Optional[str] = None, token: Optional[str] = None):
|
480 |
+
if token is None:
|
481 |
+
token = HfFolder.get_token()
|
482 |
+
if organization is None:
|
483 |
+
username = whoami(token)["name"]
|
484 |
+
return f"{username}/{model_id}"
|
485 |
+
else:
|
486 |
+
return f"{organization}/{model_id}"
|
487 |
+
|
488 |
+
|
489 |
+
def main(args):
|
490 |
+
logging_dir = Path(args.output_dir, "0", args.logging_dir)
|
491 |
+
|
492 |
+
accelerator = Accelerator(
|
493 |
+
gradient_accumulation_steps=args.gradient_accumulation_steps,
|
494 |
+
mixed_precision=args.mixed_precision,
|
495 |
+
log_with="tensorboard",
|
496 |
+
project_dir=logging_dir,
|
497 |
+
)
|
498 |
+
|
499 |
+
# Currently, it's not possible to do gradient accumulation when training two models with accelerate.accumulate
|
500 |
+
# This will be enabled soon in accelerate. For now, we don't allow gradient accumulation when training two models.
|
501 |
+
# TODO (patil-suraj): Remove this check when gradient accumulation with two models is enabled in accelerate.
|
502 |
+
if args.train_text_encoder and args.gradient_accumulation_steps > 1 and accelerator.num_processes > 1:
|
503 |
+
raise ValueError(
|
504 |
+
"Gradient accumulation is not supported when training the text encoder in distributed training. "
|
505 |
+
"Please set gradient_accumulation_steps to 1. This feature will be supported in the future."
|
506 |
+
)
|
507 |
+
|
508 |
+
if args.seed is not None:
|
509 |
+
set_seed(args.seed)
|
510 |
+
|
511 |
+
if args.concepts_list is None:
|
512 |
+
args.concepts_list = [
|
513 |
+
{
|
514 |
+
"instance_prompt": args.instance_prompt,
|
515 |
+
"class_prompt": args.class_prompt,
|
516 |
+
"instance_data_dir": args.instance_data_dir,
|
517 |
+
"class_data_dir": args.class_data_dir
|
518 |
+
}
|
519 |
+
]
|
520 |
+
else:
|
521 |
+
with open(args.concepts_list, "r") as f:
|
522 |
+
args.concepts_list = json.load(f)
|
523 |
+
|
524 |
+
if args.with_prior_preservation:
|
525 |
+
pipeline = None
|
526 |
+
for concept in args.concepts_list:
|
527 |
+
class_images_dir = Path(concept["class_data_dir"])
|
528 |
+
class_images_dir.mkdir(parents=True, exist_ok=True)
|
529 |
+
cur_class_images = len(list(class_images_dir.iterdir()))
|
530 |
+
|
531 |
+
if cur_class_images < args.num_class_images:
|
532 |
+
torch_dtype = torch.float16 if accelerator.device.type == "cuda" else torch.float32
|
533 |
+
if pipeline is None:
|
534 |
+
pipeline = StableDiffusionInpaintPipeline.from_pretrained(
|
535 |
+
args.pretrained_model_name_or_path,
|
536 |
+
vae=AutoencoderKL.from_pretrained(
|
537 |
+
args.pretrained_vae_name_or_path or args.pretrained_model_name_or_path,
|
538 |
+
revision=None if args.pretrained_vae_name_or_path else args.revision,
|
539 |
+
torch_dtype=torch_dtype
|
540 |
+
),
|
541 |
+
torch_dtype=torch_dtype,
|
542 |
+
safety_checker=None,
|
543 |
+
revision=args.revision
|
544 |
+
)
|
545 |
+
pipeline.set_progress_bar_config(disable=True)
|
546 |
+
pipeline.to(accelerator.device)
|
547 |
+
|
548 |
+
num_new_images = args.num_class_images - cur_class_images
|
549 |
+
logger.info(f"Number of class images to sample: {num_new_images}.")
|
550 |
+
|
551 |
+
sample_dataset = PromptDataset(concept["class_prompt"], num_new_images)
|
552 |
+
sample_dataloader = torch.utils.data.DataLoader(sample_dataset, batch_size=args.sample_batch_size)
|
553 |
+
|
554 |
+
sample_dataloader = accelerator.prepare(sample_dataloader)
|
555 |
+
|
556 |
+
inp_img = Image.new("RGB", (512, 512), color=(0, 0, 0))
|
557 |
+
inp_mask = Image.new("L", (512, 512), color=255)
|
558 |
+
|
559 |
+
with torch.autocast("cuda"),torch.inference_mode():
|
560 |
+
for example in tqdm(
|
561 |
+
sample_dataloader, desc="Generating class images", disable=not accelerator.is_local_main_process
|
562 |
+
):
|
563 |
+
images = pipeline(
|
564 |
+
prompt=example["prompt"],
|
565 |
+
image=inp_img,
|
566 |
+
mask_image=inp_mask,
|
567 |
+
num_inference_steps=args.save_infer_steps
|
568 |
+
).images
|
569 |
+
|
570 |
+
for i, image in enumerate(images):
|
571 |
+
hash_image = hashlib.sha1(image.tobytes()).hexdigest()
|
572 |
+
image_filename = class_images_dir / f"{example['index'][i] + cur_class_images}-{hash_image}.jpg"
|
573 |
+
image.save(image_filename)
|
574 |
+
|
575 |
+
del pipeline
|
576 |
+
if torch.cuda.is_available():
|
577 |
+
torch.cuda.empty_cache()
|
578 |
+
|
579 |
+
# Load the tokenizer
|
580 |
+
if args.tokenizer_name:
|
581 |
+
tokenizer = CLIPTokenizer.from_pretrained(
|
582 |
+
args.tokenizer_name,
|
583 |
+
revision=args.revision,
|
584 |
+
)
|
585 |
+
elif args.pretrained_model_name_or_path:
|
586 |
+
tokenizer = CLIPTokenizer.from_pretrained(
|
587 |
+
args.pretrained_model_name_or_path,
|
588 |
+
subfolder="tokenizer",
|
589 |
+
revision=args.revision,
|
590 |
+
)
|
591 |
+
|
592 |
+
# Load models and create wrapper for stable diffusion
|
593 |
+
text_encoder = CLIPTextModel.from_pretrained(
|
594 |
+
args.pretrained_model_name_or_path,
|
595 |
+
subfolder="text_encoder",
|
596 |
+
revision=args.revision,
|
597 |
+
)
|
598 |
+
vae = AutoencoderKL.from_pretrained(
|
599 |
+
args.pretrained_model_name_or_path,
|
600 |
+
subfolder="vae",
|
601 |
+
revision=args.revision,
|
602 |
+
)
|
603 |
+
unet = UNet2DConditionModel.from_pretrained(
|
604 |
+
args.pretrained_model_name_or_path,
|
605 |
+
subfolder="unet",
|
606 |
+
revision=args.revision,
|
607 |
+
torch_dtype=torch.float32
|
608 |
+
)
|
609 |
+
|
610 |
+
vae.requires_grad_(False)
|
611 |
+
if not args.train_text_encoder:
|
612 |
+
text_encoder.requires_grad_(False)
|
613 |
+
|
614 |
+
if args.gradient_checkpointing:
|
615 |
+
unet.enable_gradient_checkpointing()
|
616 |
+
if args.train_text_encoder:
|
617 |
+
text_encoder.gradient_checkpointing_enable()
|
618 |
+
|
619 |
+
if args.scale_lr:
|
620 |
+
args.learning_rate = (
|
621 |
+
args.learning_rate * args.gradient_accumulation_steps * args.train_batch_size * accelerator.num_processes
|
622 |
+
)
|
623 |
+
|
624 |
+
# Use 8-bit Adam for lower memory usage or to fine-tune the model in 16GB GPUs
|
625 |
+
if args.use_8bit_adam:
|
626 |
+
try:
|
627 |
+
import bitsandbytes as bnb
|
628 |
+
except ImportError:
|
629 |
+
raise ImportError(
|
630 |
+
"To use 8-bit Adam, please install the bitsandbytes library: `pip install bitsandbytes`."
|
631 |
+
)
|
632 |
+
|
633 |
+
optimizer_class = bnb.optim.AdamW8bit
|
634 |
+
else:
|
635 |
+
optimizer_class = torch.optim.AdamW
|
636 |
+
|
637 |
+
params_to_optimize = (
|
638 |
+
itertools.chain(unet.parameters(), text_encoder.parameters()) if args.train_text_encoder else unet.parameters()
|
639 |
+
)
|
640 |
+
optimizer = optimizer_class(
|
641 |
+
params_to_optimize,
|
642 |
+
lr=args.learning_rate,
|
643 |
+
betas=(args.adam_beta1, args.adam_beta2),
|
644 |
+
weight_decay=args.adam_weight_decay,
|
645 |
+
eps=args.adam_epsilon,
|
646 |
+
)
|
647 |
+
|
648 |
+
noise_scheduler = DDPMScheduler.from_config(args.pretrained_model_name_or_path, subfolder="scheduler")
|
649 |
+
|
650 |
+
train_dataset = DreamBoothDataset(
|
651 |
+
concepts_list=args.concepts_list,
|
652 |
+
tokenizer=tokenizer,
|
653 |
+
with_prior_preservation=args.with_prior_preservation,
|
654 |
+
size=args.resolution,
|
655 |
+
center_crop=args.center_crop,
|
656 |
+
num_class_images=args.num_class_images,
|
657 |
+
pad_tokens=args.pad_tokens,
|
658 |
+
hflip=args.hflip
|
659 |
+
)
|
660 |
+
|
661 |
+
def collate_fn(examples):
|
662 |
+
input_ids = [example["instance_prompt_ids"] for example in examples]
|
663 |
+
pixel_values = [example["instance_images"] for example in examples]
|
664 |
+
mask_values = [example["instance_masks"] for example in examples]
|
665 |
+
masked_image_values = [example["instance_masked_images"] for example in examples]
|
666 |
+
|
667 |
+
# Concat class and instance examples for prior preservation.
|
668 |
+
# We do this to avoid doing two forward passes.
|
669 |
+
if args.with_prior_preservation:
|
670 |
+
input_ids += [example["class_prompt_ids"] for example in examples]
|
671 |
+
pixel_values += [example["class_images"] for example in examples]
|
672 |
+
mask_values += [example["class_masks"] for example in examples]
|
673 |
+
masked_image_values += [example["class_masked_images"] for example in examples]
|
674 |
+
|
675 |
+
pixel_values = torch.stack(pixel_values).to(memory_format=torch.contiguous_format).float()
|
676 |
+
mask_values = torch.stack(mask_values).to(memory_format=torch.contiguous_format).float()
|
677 |
+
masked_image_values = torch.stack(masked_image_values).to(memory_format=torch.contiguous_format).float()
|
678 |
+
|
679 |
+
input_ids = tokenizer.pad(
|
680 |
+
{"input_ids": input_ids},
|
681 |
+
padding=True,
|
682 |
+
return_tensors="pt",
|
683 |
+
).input_ids
|
684 |
+
|
685 |
+
batch = {
|
686 |
+
"input_ids": input_ids,
|
687 |
+
"pixel_values": pixel_values,
|
688 |
+
"mask_values": mask_values,
|
689 |
+
"masked_image_values": masked_image_values
|
690 |
+
}
|
691 |
+
return batch
|
692 |
+
|
693 |
+
train_dataloader = torch.utils.data.DataLoader(
|
694 |
+
train_dataset, batch_size=args.train_batch_size, shuffle=True, collate_fn=collate_fn, pin_memory=True, num_workers=8
|
695 |
+
)
|
696 |
+
|
697 |
+
weight_dtype = torch.float32
|
698 |
+
if args.mixed_precision == "fp16":
|
699 |
+
weight_dtype = torch.float16
|
700 |
+
elif args.mixed_precision == "bf16":
|
701 |
+
weight_dtype = torch.bfloat16
|
702 |
+
|
703 |
+
# Move text_encode and vae to gpu.
|
704 |
+
# For mixed precision training we cast the text_encoder and vae weights to half-precision
|
705 |
+
# as these models are only used for inference, keeping weights in full precision is not required.
|
706 |
+
vae.to(accelerator.device, dtype=weight_dtype)
|
707 |
+
if not args.train_text_encoder:
|
708 |
+
text_encoder.to(accelerator.device, dtype=weight_dtype)
|
709 |
+
|
710 |
+
if not args.not_cache_latents:
|
711 |
+
latents_cache = []
|
712 |
+
text_encoder_cache = []
|
713 |
+
for batch in tqdm(train_dataloader, desc="Caching latents"):
|
714 |
+
with torch.no_grad():
|
715 |
+
batch["pixel_values"] = batch["pixel_values"].to(accelerator.device, non_blocking=True, dtype=weight_dtype)
|
716 |
+
batch["input_ids"] = batch["input_ids"].to(accelerator.device, non_blocking=True)
|
717 |
+
latents_cache.append(vae.encode(batch["pixel_values"]).latent_dist)
|
718 |
+
if args.train_text_encoder:
|
719 |
+
text_encoder_cache.append(batch["input_ids"])
|
720 |
+
else:
|
721 |
+
text_encoder_cache.append(text_encoder(batch["input_ids"])[0])
|
722 |
+
train_dataset = LatentsDataset(latents_cache, text_encoder_cache)
|
723 |
+
train_dataloader = torch.utils.data.DataLoader(train_dataset, batch_size=1, collate_fn=lambda x: x, shuffle=True)
|
724 |
+
|
725 |
+
del vae
|
726 |
+
if not args.train_text_encoder:
|
727 |
+
del text_encoder
|
728 |
+
if torch.cuda.is_available():
|
729 |
+
torch.cuda.empty_cache()
|
730 |
+
|
731 |
+
# Scheduler and math around the number of training steps.
|
732 |
+
overrode_max_train_steps = False
|
733 |
+
num_update_steps_per_epoch = math.ceil(len(train_dataloader) / args.gradient_accumulation_steps)
|
734 |
+
if args.max_train_steps is None:
|
735 |
+
args.max_train_steps = args.num_train_epochs * num_update_steps_per_epoch
|
736 |
+
overrode_max_train_steps = True
|
737 |
+
|
738 |
+
lr_scheduler = get_scheduler(
|
739 |
+
args.lr_scheduler,
|
740 |
+
optimizer=optimizer,
|
741 |
+
num_warmup_steps=args.lr_warmup_steps * args.gradient_accumulation_steps,
|
742 |
+
num_training_steps=args.max_train_steps * args.gradient_accumulation_steps,
|
743 |
+
)
|
744 |
+
|
745 |
+
if args.train_text_encoder:
|
746 |
+
unet, text_encoder, optimizer, train_dataloader, lr_scheduler = accelerator.prepare(
|
747 |
+
unet, text_encoder, optimizer, train_dataloader, lr_scheduler
|
748 |
+
)
|
749 |
+
else:
|
750 |
+
unet, optimizer, train_dataloader, lr_scheduler = accelerator.prepare(
|
751 |
+
unet, optimizer, train_dataloader, lr_scheduler
|
752 |
+
)
|
753 |
+
|
754 |
+
# We need to recalculate our total training steps as the size of the training dataloader may have changed.
|
755 |
+
num_update_steps_per_epoch = math.ceil(len(train_dataloader) / args.gradient_accumulation_steps)
|
756 |
+
if overrode_max_train_steps:
|
757 |
+
args.max_train_steps = args.num_train_epochs * num_update_steps_per_epoch
|
758 |
+
# Afterwards we recalculate our number of training epochs
|
759 |
+
args.num_train_epochs = math.ceil(args.max_train_steps / num_update_steps_per_epoch)
|
760 |
+
|
761 |
+
# We need to initialize the trackers we use, and also store our configuration.
|
762 |
+
# The trackers initializes automatically on the main process.
|
763 |
+
if accelerator.is_main_process:
|
764 |
+
accelerator.init_trackers("dreambooth")
|
765 |
+
|
766 |
+
# Train!
|
767 |
+
total_batch_size = args.train_batch_size * accelerator.num_processes * args.gradient_accumulation_steps
|
768 |
+
|
769 |
+
logger.info("***** Running training *****")
|
770 |
+
logger.info(f" Num examples = {len(train_dataset)}")
|
771 |
+
logger.info(f" Num batches each epoch = {len(train_dataloader)}")
|
772 |
+
logger.info(f" Num Epochs = {args.num_train_epochs}")
|
773 |
+
logger.info(f" Instantaneous batch size per device = {args.train_batch_size}")
|
774 |
+
logger.info(f" Total train batch size (w. parallel, distributed & accumulation) = {total_batch_size}")
|
775 |
+
logger.info(f" Gradient Accumulation steps = {args.gradient_accumulation_steps}")
|
776 |
+
logger.info(f" Total optimization steps = {args.max_train_steps}")
|
777 |
+
|
778 |
+
def save_weights(step):
|
779 |
+
# Create the pipeline using using the trained modules and save it.
|
780 |
+
if accelerator.is_main_process:
|
781 |
+
if args.train_text_encoder:
|
782 |
+
text_enc_model = accelerator.unwrap_model(text_encoder, keep_fp32_wrapper=True)
|
783 |
+
else:
|
784 |
+
text_enc_model = CLIPTextModel.from_pretrained(args.pretrained_model_name_or_path, subfolder="text_encoder", revision=args.revision)
|
785 |
+
scheduler = DDIMScheduler(beta_start=0.00085, beta_end=0.012, beta_schedule="scaled_linear", clip_sample=False, set_alpha_to_one=False, steps_offset=1)
|
786 |
+
pipeline = StableDiffusionInpaintPipeline.from_pretrained(
|
787 |
+
args.pretrained_model_name_or_path,
|
788 |
+
unet=accelerator.unwrap_model(unet, keep_fp32_wrapper=True).to(torch.float16),
|
789 |
+
text_encoder=text_enc_model.to(torch.float16),
|
790 |
+
vae=AutoencoderKL.from_pretrained(
|
791 |
+
args.pretrained_vae_name_or_path or args.pretrained_model_name_or_path,
|
792 |
+
subfolder=None if args.pretrained_vae_name_or_path else "vae",
|
793 |
+
revision=None if args.pretrained_vae_name_or_path else args.revision,
|
794 |
+
# torch_dtype=torch.float16
|
795 |
+
).half(),
|
796 |
+
safety_checker=None,
|
797 |
+
scheduler=scheduler,
|
798 |
+
torch_dtype=torch.float16,
|
799 |
+
revision=args.revision,
|
800 |
+
)
|
801 |
+
save_dir = os.path.join(args.output_dir, f"{step}")
|
802 |
+
pipeline.save_pretrained(save_dir)
|
803 |
+
with open(os.path.join(save_dir, "args.json"), "w") as f:
|
804 |
+
json.dump(args.__dict__, f, indent=2)
|
805 |
+
|
806 |
+
shutil.copy("train_inpainting_dreambooth.py", save_dir)
|
807 |
+
|
808 |
+
pipeline = pipeline.to(accelerator.device)
|
809 |
+
pipeline.set_progress_bar_config(disable=True)
|
810 |
+
for idx, concept in enumerate(args.concepts_list):
|
811 |
+
g_cuda = torch.Generator(device=accelerator.device).manual_seed(args.seed)
|
812 |
+
sample_dir = os.path.join(save_dir, "samples", str(idx))
|
813 |
+
os.makedirs(sample_dir, exist_ok=True)
|
814 |
+
# inp_img = Image.new("RGB", (512, 512), color=(0, 0, 0))
|
815 |
+
inp_img = Image.open("/home/neil/Documents/diffusers/examples/dreambooth/512/a olive leather couch sofa Inside a Bedouin-inspired setting, soft sandy tones, hanging lanterns, and an endless view of sand dunes. .png")
|
816 |
+
inp_mask = ImageOps.invert(inp_img.split()[-1])
|
817 |
+
# inp_mask = Image.new("L", (512, 512), color=255)
|
818 |
+
with torch.inference_mode():
|
819 |
+
for i in tqdm(range(args.n_save_sample), desc="Generating samples"):
|
820 |
+
if i>1:
|
821 |
+
images = pipeline(
|
822 |
+
# prompt=concept["instance_prompt"],
|
823 |
+
prompt="a olive leather couch sofa in a sleek and sophisticated mid century home interior, emphasizing clean lines and subtle design details.",
|
824 |
+
image=inp_img.convert('RGB'),
|
825 |
+
mask_image=inp_mask,
|
826 |
+
negative_prompt=args.save_sample_negative_prompt,#"minimalist, sad, bad teeth, reflection, lens, lens flare, drawn, airbrush, blur, makeup, out of focus, hands, arms, veil, bad anatomy, mutation, deformed, cropped, signed, Mediocre, Screenshot, UI, watermark, cartoon",
|
827 |
+
guidance_scale=args.save_guidance_scale,
|
828 |
+
num_inference_steps=args.save_infer_steps,
|
829 |
+
generator=g_cuda
|
830 |
+
).images
|
831 |
+
else:
|
832 |
+
images = pipeline(
|
833 |
+
# prompt=concept["instance_prompt"],
|
834 |
+
prompt="a olive leather couch sofa Inside a Bedouin-inspired setting, soft sandy tones, hanging lanterns, and an endless view of sand dunes. ",
|
835 |
+
image=inp_img.convert('RGB'),
|
836 |
+
mask_image=inp_mask,
|
837 |
+
negative_prompt=args.save_sample_negative_prompt,
|
838 |
+
guidance_scale=args.save_guidance_scale,
|
839 |
+
num_inference_steps=args.save_infer_steps,
|
840 |
+
generator=g_cuda
|
841 |
+
).images
|
842 |
+
images[0].save(os.path.join(sample_dir, f"{i}.png"))
|
843 |
+
del pipeline
|
844 |
+
if torch.cuda.is_available():
|
845 |
+
torch.cuda.empty_cache()
|
846 |
+
print(f"[*] Weights saved at {save_dir}")
|
847 |
+
unet.to(torch.float32)
|
848 |
+
text_enc_model.to(torch.float32)
|
849 |
+
|
850 |
+
# Only show the progress bar once on each machine.
|
851 |
+
progress_bar = tqdm(range(args.max_train_steps), disable=not accelerator.is_local_main_process)
|
852 |
+
progress_bar.set_description("Steps")
|
853 |
+
global_step = 0
|
854 |
+
loss_avg = AverageMeter()
|
855 |
+
text_enc_context = nullcontext() if args.train_text_encoder else torch.no_grad()
|
856 |
+
for epoch in range(args.num_train_epochs):
|
857 |
+
unet.train()
|
858 |
+
if args.train_text_encoder:
|
859 |
+
text_encoder.train()
|
860 |
+
random.shuffle(train_dataset.class_images_path)
|
861 |
+
for step, batch in enumerate(train_dataloader):
|
862 |
+
with accelerator.accumulate(unet):
|
863 |
+
# Convert images to latent space
|
864 |
+
with torch.no_grad():
|
865 |
+
if not args.not_cache_latents:
|
866 |
+
latent_dist = batch[0][0]
|
867 |
+
else:
|
868 |
+
latent_dist = vae.encode(batch["pixel_values"].to(dtype=weight_dtype)).latent_dist
|
869 |
+
masked_latent_dist = vae.encode(batch["masked_image_values"].to(dtype=weight_dtype)).latent_dist
|
870 |
+
# torchvision.transforms.functional.to_pil_image(transforms.Normalize(mean=[-0.485/0.229, -0.456/0.224, -0.406/0.225],std=[1/0.229, 1/0.224, 1/0.255])(batch["pixel_values"][0])).save('batchim.png')
|
871 |
+
# breakpoint()
|
872 |
+
latents = latent_dist.sample() * 0.18215
|
873 |
+
masked_image_latents = masked_latent_dist.sample() * 0.18215
|
874 |
+
mask = F.interpolate(batch["mask_values"], scale_factor=1 / 8)
|
875 |
+
|
876 |
+
# Sample noise that we'll add to the latents
|
877 |
+
noise = torch.randn_like(latents)
|
878 |
+
bsz = latents.shape[0]
|
879 |
+
# Sample a random timestep for each image
|
880 |
+
timesteps = torch.randint(0, noise_scheduler.config.num_train_timesteps, (bsz,), device=latents.device)
|
881 |
+
timesteps = timesteps.long()
|
882 |
+
|
883 |
+
latents_copy = torch.clone(latents)
|
884 |
+
# Add noise to the latents according to the noise magnitude at each timestep
|
885 |
+
# (this is the forward diffusion process)
|
886 |
+
noisy_latents = noise_scheduler.add_noise(latents, noise, timesteps)
|
887 |
+
|
888 |
+
# Get the text embedding for conditioning
|
889 |
+
with text_enc_context:
|
890 |
+
if not args.not_cache_latents:
|
891 |
+
if args.train_text_encoder:
|
892 |
+
encoder_hidden_states = text_encoder(batch[0][1])[0]
|
893 |
+
else:
|
894 |
+
encoder_hidden_states = batch[0][1]
|
895 |
+
else:
|
896 |
+
encoder_hidden_states = text_encoder(batch["input_ids"])[0]
|
897 |
+
|
898 |
+
latent_model_input = torch.cat([noisy_latents, mask, masked_image_latents], dim=1)
|
899 |
+
# Predict the noise residual
|
900 |
+
noise_pred = unet(latent_model_input, timesteps, encoder_hidden_states).sample
|
901 |
+
|
902 |
+
def latents_to_pil(latents):
|
903 |
+
# bath of latents -> list of images
|
904 |
+
latents = (1 / 0.18215) * latents
|
905 |
+
with torch.no_grad():
|
906 |
+
image = vae.decode(latents).sample
|
907 |
+
image = (image / 2 + 0.5).clamp(0, 1)
|
908 |
+
image = image.detach().cpu().permute(0, 2, 3, 1).numpy()
|
909 |
+
images = (image * 255).round().astype("uint8")
|
910 |
+
pil_images = [Image.fromarray(image) for image in images]
|
911 |
+
return pil_images
|
912 |
+
|
913 |
+
def pil_to_latent(input_im):
|
914 |
+
# Single image -> single latent in a batch (so size 1, 4, 64, 64)
|
915 |
+
with torch.no_grad():
|
916 |
+
latent = vae.encode(tfms.ToTensor()(input_im).unsqueeze(0).to(torch_device)*2-1) # Note scaling
|
917 |
+
return 0.18215 * latent.latent_dist.sample()
|
918 |
+
|
919 |
+
if args.with_prior_preservation:
|
920 |
+
# Chunk the noise and noise_pred into two parts and compute the loss on each part separately.
|
921 |
+
noise_pred, noise_pred_prior = torch.chunk(noise_pred, 2, dim=0)
|
922 |
+
noise, noise_prior = torch.chunk(noise, 2, dim=0)
|
923 |
+
|
924 |
+
# Compute instance loss
|
925 |
+
loss = F.mse_loss(noise_pred.float(), noise.float(), reduction="none").mean([1, 2, 3]).mean()
|
926 |
+
|
927 |
+
# Compute prior loss
|
928 |
+
prior_loss = F.mse_loss(noise_pred_prior.float(), noise_prior.float(), reduction="mean")
|
929 |
+
|
930 |
+
# Add the prior loss to the instance loss.
|
931 |
+
loss = loss + args.prior_loss_weight * prior_loss
|
932 |
+
else:
|
933 |
+
loss = F.mse_loss(noise_pred.float(), noise.float(), reduction="mean")
|
934 |
+
|
935 |
+
# im_pred = torch.cat([noise_scheduler.step(noise_pred[:1], timesteps[0], noisy_latents[:1]).prev_sample,
|
936 |
+
# noise_scheduler.step(noise_pred[1:2], timesteps[1], noisy_latents[1:2]).prev_sample,
|
937 |
+
# noise_scheduler.step(noise_pred[2:3], timesteps[2], noisy_latents[2:3]).prev_sample,
|
938 |
+
# noise_scheduler.step(noise_pred[3:4], timesteps[3], noisy_latents[3:4]).prev_sample])
|
939 |
+
|
940 |
+
# im_real = torch.cat([noise_scheduler.step(noise[:1], timesteps[0], noisy_latents[:1]).prev_sample,
|
941 |
+
# noise_scheduler.step(noise[1:2], timesteps[1], noisy_latents[1:2]).prev_sample,
|
942 |
+
# noise_scheduler.step(noise[2:3], timesteps[2], noisy_latents[2:3]).prev_sample,
|
943 |
+
# noise_scheduler.step(noise[3:4], timesteps[3], noisy_latents[3:4]).prev_sample])
|
944 |
+
|
945 |
+
# import numpy as np
|
946 |
+
# import cv2
|
947 |
+
|
948 |
+
# # def tensor_to_canny(tensor):
|
949 |
+
# # canny_image = np.asarray(tensor.to('cpu'))
|
950 |
+
# # canny_image = cv2.Canny(np.uint8(canny_image), 100, 200)
|
951 |
+
# # # return Image.fromarray(canny_image)
|
952 |
+
# # return canny_image
|
953 |
+
# # canny = batch["mask_values"][0][0]
|
954 |
+
# # canny = tensor_to_canny(canny)
|
955 |
+
# # Image.fromarray(canny).save('pcanny.png')
|
956 |
+
# # canny = cv2.dilate(canny, np.ones((5,5),np.uint8), iterations=5)
|
957 |
+
# # Image.fromarray(canny).save('pdilatecanny.png')
|
958 |
+
# # breakpoint()
|
959 |
+
# def get_band(tensor):
|
960 |
+
# canny_image = np.uint8(np.asarray(tensor.to('cpu')))
|
961 |
+
# dilated = cv2.dilate(canny_image, np.ones((5,5),np.uint8), iterations=10)
|
962 |
+
# # return torchvision.transforms.ToTensor()(dilated) * (tensor < 0.5)
|
963 |
+
# return dilated, canny_image
|
964 |
+
# dilated, canny_image = get_band(batch["mask_values"][0][0])
|
965 |
+
# # Image.fromarray(dilated).save('pdilated.png')
|
966 |
+
# # Image.fromarray(canny_image).save('pcanny.png')
|
967 |
+
# # Image.fromarray(dilated-canny_image).save('pxor.png')
|
968 |
+
# band = dilated-canny_image
|
969 |
+
# band = torch.from_numpy(band*0.3 + 1)
|
970 |
+
# breakpoint()
|
971 |
+
# im_pred = im_pred*band
|
972 |
+
# im_real = im_real*band
|
973 |
+
# breakpoint()
|
974 |
+
# loss = F.mse_loss(im_real.float(), im_pred.float(), reduction="mean")
|
975 |
+
|
976 |
+
# # latents_to_pil(latents_copy[:1])[0].save('ppp1.png')
|
977 |
+
# # noise_scheduler.step(noise_pred, timesteps, latents, return_dict=False)[0]
|
978 |
+
# # loss = F.mse_loss(vae.decode(noise_pred.float()).sample, vae.decode(noise.float()).sample, reduction="mean")
|
979 |
+
|
980 |
+
# def generate_random_mask(image):
|
981 |
+
# # mask = torch.zeros_like(image[:1])
|
982 |
+
# # print('foobar', mask.shape)
|
983 |
+
# mask = image[-1].unsqueeze(0)
|
984 |
+
# # torchvision.transforms.functional.to_pil_image(mask).save('foomask2.png')
|
985 |
+
|
986 |
+
# # if random.uniform(0, 1) < 0.25:
|
987 |
+
# # mask = torch.zeros_like(image[:1])
|
988 |
+
# # mask.fill_(1.)
|
989 |
+
# # print('foobar',image.shape)
|
990 |
+
# # torchvision.transforms.functional.to_pil_image(image[:4]).save('fooimageinside2.png')
|
991 |
+
# # print('foobar',image[:3].shape)
|
992 |
+
# masked_image = image[:-1] * (mask < 0.5)
|
993 |
+
# # torchvision.transforms.functional.to_pil_image(masked_image).save('foomaskedimage2.png')
|
994 |
+
# return mask, masked_image
|
995 |
+
|
996 |
+
accelerator.backward(loss)
|
997 |
+
# if accelerator.sync_gradients:
|
998 |
+
# params_to_clip = (
|
999 |
+
# itertools.chain(unet.parameters(), text_encoder.parameters())
|
1000 |
+
# if args.train_text_encoder
|
1001 |
+
# else unet.parameters()
|
1002 |
+
# )
|
1003 |
+
# accelerator.clip_grad_norm_(params_to_clip, args.max_grad_norm)
|
1004 |
+
optimizer.step()
|
1005 |
+
lr_scheduler.step()
|
1006 |
+
optimizer.zero_grad(set_to_none=True)
|
1007 |
+
loss_avg.update(loss.detach_(), bsz)
|
1008 |
+
|
1009 |
+
if not global_step % args.log_interval:
|
1010 |
+
logs = {"loss": loss_avg.avg.item(), "lr": lr_scheduler.get_last_lr()[0]}
|
1011 |
+
progress_bar.set_postfix(**logs)
|
1012 |
+
accelerator.log(logs, step=global_step)
|
1013 |
+
|
1014 |
+
if global_step > 0 and not global_step % args.save_interval and global_step >= args.save_min_steps:
|
1015 |
+
save_weights(global_step)
|
1016 |
+
|
1017 |
+
progress_bar.update(1)
|
1018 |
+
global_step += 1
|
1019 |
+
|
1020 |
+
if global_step >= args.max_train_steps:
|
1021 |
+
break
|
1022 |
+
|
1023 |
+
accelerator.wait_for_everyone()
|
1024 |
+
|
1025 |
+
save_weights(global_step)
|
1026 |
+
|
1027 |
+
accelerator.end_training()
|
1028 |
+
|
1029 |
+
|
1030 |
+
if __name__ == "__main__":
|
1031 |
+
args = parse_args()
|
1032 |
+
main(args)
|
unet/config.json
ADDED
@@ -0,0 +1,66 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"_class_name": "UNet2DConditionModel",
|
3 |
+
"_diffusers_version": "0.21.0.dev0",
|
4 |
+
"_name_or_path": "booth-ai/realisticVisionV20_v20_inpainting",
|
5 |
+
"act_fn": "silu",
|
6 |
+
"addition_embed_type": null,
|
7 |
+
"addition_embed_type_num_heads": 64,
|
8 |
+
"addition_time_embed_dim": null,
|
9 |
+
"attention_head_dim": 8,
|
10 |
+
"attention_type": "default",
|
11 |
+
"block_out_channels": [
|
12 |
+
320,
|
13 |
+
640,
|
14 |
+
1280,
|
15 |
+
1280
|
16 |
+
],
|
17 |
+
"center_input_sample": false,
|
18 |
+
"class_embed_type": null,
|
19 |
+
"class_embeddings_concat": false,
|
20 |
+
"conv_in_kernel": 3,
|
21 |
+
"conv_out_kernel": 3,
|
22 |
+
"cross_attention_dim": 768,
|
23 |
+
"cross_attention_norm": null,
|
24 |
+
"down_block_types": [
|
25 |
+
"CrossAttnDownBlock2D",
|
26 |
+
"CrossAttnDownBlock2D",
|
27 |
+
"CrossAttnDownBlock2D",
|
28 |
+
"DownBlock2D"
|
29 |
+
],
|
30 |
+
"downsample_padding": 1,
|
31 |
+
"dual_cross_attention": false,
|
32 |
+
"encoder_hid_dim": null,
|
33 |
+
"encoder_hid_dim_type": null,
|
34 |
+
"flip_sin_to_cos": true,
|
35 |
+
"freq_shift": 0,
|
36 |
+
"in_channels": 9,
|
37 |
+
"layers_per_block": 2,
|
38 |
+
"mid_block_only_cross_attention": null,
|
39 |
+
"mid_block_scale_factor": 1,
|
40 |
+
"mid_block_type": "UNetMidBlock2DCrossAttn",
|
41 |
+
"norm_eps": 1e-05,
|
42 |
+
"norm_num_groups": 32,
|
43 |
+
"num_attention_heads": null,
|
44 |
+
"num_class_embeds": null,
|
45 |
+
"only_cross_attention": false,
|
46 |
+
"out_channels": 4,
|
47 |
+
"projection_class_embeddings_input_dim": null,
|
48 |
+
"resnet_out_scale_factor": 1.0,
|
49 |
+
"resnet_skip_time_act": false,
|
50 |
+
"resnet_time_scale_shift": "default",
|
51 |
+
"sample_size": 64,
|
52 |
+
"time_cond_proj_dim": null,
|
53 |
+
"time_embedding_act_fn": null,
|
54 |
+
"time_embedding_dim": null,
|
55 |
+
"time_embedding_type": "positional",
|
56 |
+
"timestep_post_act": null,
|
57 |
+
"transformer_layers_per_block": 1,
|
58 |
+
"up_block_types": [
|
59 |
+
"UpBlock2D",
|
60 |
+
"CrossAttnUpBlock2D",
|
61 |
+
"CrossAttnUpBlock2D",
|
62 |
+
"CrossAttnUpBlock2D"
|
63 |
+
],
|
64 |
+
"upcast_attention": false,
|
65 |
+
"use_linear_projection": false
|
66 |
+
}
|
unet/diffusion_pytorch_model.safetensors
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:057028cbeb1ca5aacd36fc81ed7f2c5ae063330d4bfd37c1a42b63cc77d0e50d
|
3 |
+
size 1719154104
|
vae/config.json
ADDED
@@ -0,0 +1,32 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"_class_name": "AutoencoderKL",
|
3 |
+
"_diffusers_version": "0.21.0.dev0",
|
4 |
+
"_name_or_path": "stabilityai/sd-vae-ft-mse",
|
5 |
+
"act_fn": "silu",
|
6 |
+
"block_out_channels": [
|
7 |
+
128,
|
8 |
+
256,
|
9 |
+
512,
|
10 |
+
512
|
11 |
+
],
|
12 |
+
"down_block_types": [
|
13 |
+
"DownEncoderBlock2D",
|
14 |
+
"DownEncoderBlock2D",
|
15 |
+
"DownEncoderBlock2D",
|
16 |
+
"DownEncoderBlock2D"
|
17 |
+
],
|
18 |
+
"force_upcast": true,
|
19 |
+
"in_channels": 3,
|
20 |
+
"latent_channels": 4,
|
21 |
+
"layers_per_block": 2,
|
22 |
+
"norm_num_groups": 32,
|
23 |
+
"out_channels": 3,
|
24 |
+
"sample_size": 256,
|
25 |
+
"scaling_factor": 0.18215,
|
26 |
+
"up_block_types": [
|
27 |
+
"UpDecoderBlock2D",
|
28 |
+
"UpDecoderBlock2D",
|
29 |
+
"UpDecoderBlock2D",
|
30 |
+
"UpDecoderBlock2D"
|
31 |
+
]
|
32 |
+
}
|
vae/diffusion_pytorch_model.safetensors
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:3e4c08995484ee61270175e9e7a072b66a6e4eeb5f0c266667fe1f45b90daf9a
|
3 |
+
size 167335342
|