jhonier23 commited on
Commit
5038d62
·
1 Parent(s): 7bd78ac
Files changed (5) hide show
  1. .gitignore +55 -0
  2. README.md +94 -1
  3. app.py +140 -49
  4. requirements.txt +3 -6
  5. requirements_local.txt +13 -11
.gitignore ADDED
@@ -0,0 +1,55 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+ .pytest_cache/
6
+ .mypy_cache/
7
+ .ruff_cache/
8
+ .coverage
9
+ htmlcov/
10
+
11
+ # Virtual environments
12
+ .venv/
13
+ venv/
14
+ env/
15
+
16
+ # Local secrets and machine-specific configuration
17
+ .env
18
+ .env.*
19
+ !.env.example
20
+ *.local
21
+
22
+ # IDE and operating-system files
23
+ .idea/
24
+ .vscode/
25
+ .DS_Store
26
+ Thumbs.db
27
+
28
+ # Hugging Face, Gradio, and experiment caches
29
+ .cache/
30
+ huggingface/
31
+ gradio_cached_examples/
32
+ wandb/
33
+ runs/
34
+ logs/
35
+
36
+ # Helpers downloaded lazily by app.py
37
+ /train_dreambooth_lora_sdxl_advanced.py
38
+ /script.py
39
+
40
+ # Temporary dataset and SpaceRunner directories (UUID names)
41
+ /????????-????-????-????-????????????/
42
+
43
+ # Generated training artifacts
44
+ outputs/
45
+ output/
46
+ checkpoint-*/
47
+ *.safetensors
48
+ *.ckpt
49
+ *.pt
50
+ *.pth
51
+
52
+ # Build and packaging artifacts
53
+ build/
54
+ dist/
55
+ *.egg-info/
README.md CHANGED
@@ -14,7 +14,100 @@ hf_oauth_scopes:
14
  - read-repos
15
  - write-repos
16
  - manage-repos
 
 
17
  short_description: Train LoRAs with Ease
18
  ---
19
 
20
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
  - read-repos
15
  - write-repos
16
  - manage-repos
17
+ models:
18
+ - microsoft/Mage-VL
19
  short_description: Train LoRAs with Ease
20
  ---
21
 
22
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
23
+
24
+ # LoRA Ease: SDXL training on Hugging Face
25
+
26
+ This fork trains LoRA adapters for `stabilityai/stable-diffusion-xl-base-1.0`.
27
+ The maintained Hugging Face Diffusers v0.39.0 advanced SDXL trainer is downloaded
28
+ from a pinned commit the first time training starts. Captions are generated by a
29
+ dedicated Mage-VL Space, while the face-prior dataset is loaded only when needed.
30
+
31
+ ## Deploy as a Hugging Face Space
32
+
33
+ Create or duplicate a Gradio Space and push these files to it. The UI itself can
34
+ remain on CPU Basic: when a user starts training, AutoTrain SpaceRunner creates a
35
+ temporary L40S training Space under that user's account and publishes the finished
36
+ LoRA to their model repository.
37
+
38
+ Captioning defaults to `lienthealien/mage-vl-demo`, which uses the Apache-2.0
39
+ `microsoft/Mage-VL` model. If that Space is private, add
40
+ `MAGE_VL_TOKEN` as a secret in this Space's settings. It only needs permission to
41
+ call the Mage-VL Space. `MAGE_VL_SPACE_ID` and `MAGE_VL_API_NAME` can be set as
42
+ Space variables if you use a different duplicate or endpoint. Uploaded images are
43
+ sent to that configured Space for captioning, so use a Space you trust.
44
+
45
+ The user must:
46
+
47
+ 1. Have a Hugging Face account with a payment method configured.
48
+ 2. Accept the SDXL base-model license on their Hugging Face account.
49
+ 3. Provide a Hugging Face **write** token when prompted. It is passed to the
50
+ temporary trainer and is not written into this repository.
51
+
52
+ Training currently targets the `l40sx1` hardware flavor (48 GB VRAM). The UI's
53
+ cost display is an estimate; Hugging Face billing and hardware pricing are the
54
+ source of truth.
55
+
56
+ ## Optional local development
57
+
58
+ Local mode remains useful for testing the UI or training on your own NVIDIA GPU.
59
+ Use Python 3.10 or 3.11, create a virtual environment, install a CUDA-enabled
60
+ PyTorch build appropriate for your driver, and then install the project:
61
+
62
+ ```powershell
63
+ py -3.11 -m venv .venv
64
+ .venv\Scripts\Activate.ps1
65
+ # Install CUDA PyTorch first: https://pytorch.org/get-started/locally/
66
+ pip install -r requirements_local.txt
67
+ python app.py
68
+ ```
69
+
70
+ SDXL training is memory-intensive. The UI defaults to batch size 1, gradient
71
+ accumulation 4, gradient checkpointing, latent caching, fp16, and 1024px. For local
72
+ out-of-memory errors, keep batch size 1 and try 768px; 1024px is preferred when the
73
+ GPU permits.
74
+
75
+ The base model is gated. Before the first run, accept its license on Hugging Face
76
+ and authenticate locally with `hf auth login`.
77
+
78
+ ## Training a Daggerfall-like face style
79
+
80
+ If the images show many different people sharing the same visual language, this is
81
+ a **style LoRA**, not a face/identity LoRA:
82
+
83
+ 1. Prepare roughly 20-60 varied, clean portraits. Remove menus, text, cursors,
84
+ duplicates, and unrelated UI. Do not mix modern fan art with original game art
85
+ unless you deliberately want both aesthetics.
86
+ 2. Crop loosely around each head and shoulders, keeping several face angles,
87
+ ancestries, genders, expressions, backgrounds, and lighting conditions. Do not
88
+ enlarge tiny source images with heavy smoothing; crisp nearest-neighbor or mild
89
+ restoration usually preserves the pixel-art language better.
90
+ 3. In the UI choose **style** and keep the concept sentence
91
+ `in the style of TOK`. `TOK` is the trainer's required token abstraction; do
92
+ not replace it with `daggerfall` or another common word.
93
+ 4. Caption what should remain controllable, for example:
94
+ `portrait of an elderly elf man, stern expression, dark background, in the style of TOK`.
95
+ Keep the trigger in every caption, but vary subject traits accurately.
96
+ 5. Start with rank 32 and 800-1500 steps. Save/test intermediate versions if you
97
+ raise the step count; overtraining shows up as every output copying the training
98
+ backgrounds, poses, or facial proportions.
99
+
100
+ After uploading the images, click **Caption all images with Mage-VL**. The portrait
101
+ instruction asks for controllable character traits while deliberately excluding
102
+ the shared art style; the concept sentence is appended automatically. Review the
103
+ generated text boxes and correct names, species, clothing, or expressions that the
104
+ captioner guessed incorrectly. **Export captions** downloads the reviewed entries
105
+ as ImageFolder-compatible `metadata.jsonl` for backup or offline editing.
106
+
107
+ Use **character** only if all images are the same fictional character. Use **face**
108
+ only for one consistent real or fictional identity; that preset enables prior
109
+ preservation and is not appropriate for learning a whole game's portrait style.
110
+
111
+ The output folder contains `pytorch_lora_weights.safetensors`, which can be loaded
112
+ as an SDXL LoRA by Diffusers, ComfyUI, or compatible Stable Diffusion frontends.
113
+ Only train and distribute assets you have the rights or permission to use.
app.py CHANGED
@@ -1,42 +1,79 @@
1
  import gradio as gr
2
- from PIL import Image
3
- import requests
4
  import subprocess
5
  import os
6
  is_spaces = True if os.environ.get('SPACE_ID') else False
7
- if(is_spaces):
8
- import spaces
9
- from transformers import Blip2Processor, Blip2ForConditionalGeneration
10
  from huggingface_hub import snapshot_download, HfApi
11
- import torch
12
  import uuid
13
  import shutil
14
  import json
15
  import random
 
16
  from slugify import slugify
17
  import argparse
18
  import importlib
19
  import sys
20
  from pathlib import Path
 
21
  import zipfile
 
22
 
23
  MAX_IMAGES = 150
24
 
25
- training_script_url = "https://raw.githubusercontent.com/huggingface/diffusers/ba28006f8b2a0f7ec3b6784695790422b4f80a97/examples/advanced_diffusion_training/train_dreambooth_lora_sdxl_advanced.py"
26
- subprocess.run(['wget', '-N', training_script_url])
 
 
27
  orchestrator_script_url = "https://huggingface.co/datasets/multimodalart/lora-ease-helper/raw/main/script.py"
28
- subprocess.run(['wget', '-N', orchestrator_script_url])
29
 
30
- device = "cuda" if torch.cuda.is_available() else "cpu"
 
 
 
31
 
32
- FACES_DATASET_PATH = snapshot_download(repo_id="multimodalart/faces-prior-preservation", repo_type="dataset")
33
- #Delete .gitattributes to process things properly
34
- Path(FACES_DATASET_PATH, '.gitattributes').unlink(missing_ok=True)
35
 
36
- processor = Blip2Processor.from_pretrained("Salesforce/blip2-opt-2.7b")
37
- model = Blip2ForConditionalGeneration.from_pretrained(
38
- "Salesforce/blip2-opt-2.7b", device_map={"": 0}, torch_dtype=torch.float16
39
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
40
 
41
  training_option_settings = {
42
  "face": {
@@ -46,7 +83,7 @@ training_option_settings = {
46
  "class_prompt": "a photo of a person",
47
  "train_steps_multiplier": 75,
48
  "file_count": 150,
49
- "dataset_path": FACES_DATASET_PATH
50
  },
51
  "style": {
52
  "rank": 32,
@@ -156,7 +193,7 @@ def change_defaults(option, images):
156
 
157
  random_files = []
158
  if settings["with_prior_preservation"]:
159
- directory = settings["dataset_path"]
160
  file_count = settings["file_count"]
161
  files = [os.path.join(directory, file) for file in os.listdir(directory) if os.path.isfile(os.path.join(directory, file))]
162
  random_files = random.sample(files, min(len(files), file_count))
@@ -325,21 +362,26 @@ def start_training(
325
  spacerunner_args = ';'.join(commands)
326
  if not os.path.exists(spacerunner_folder):
327
  os.makedirs(spacerunner_folder)
328
- shutil.copy("train_dreambooth_lora_sdxl_advanced.py", f"{spacerunner_folder}/trainer.py")
 
 
329
  shutil.copy("script.py", f"{spacerunner_folder}/script.py")
330
  shutil.copytree(dataset_folder, f"{spacerunner_folder}/{dataset_folder}")
331
- requirements='''peft==0.7.1
332
- -huggingface_hub
333
  torch
334
- git+https://github.com/huggingface/diffusers@ba28006f8b2a0f7ec3b6784695790422b4f80a97
335
- transformers==4.36.2
336
- accelerate==0.25.0
337
- safetensors==0.4.1
338
  prodigyopt==1.0
339
- hf-transfer==0.1.4
340
- huggingface_hub==0.20.3
341
- git+https://github.com/huggingface/datasets.git@3f149204a2a5948287adcade5e90707aa5207a92
342
- numpy==1.26.4'''
 
 
 
343
  file_path = f'{spacerunner_folder}/requirements.txt'
344
  with open(file_path, 'w') as file:
345
  file.write(requirements)
@@ -495,6 +537,8 @@ def start_training_og(
495
  commands.append(f"--prodigy_beta3={prodigy_beta3}")
496
  if use_adam_weight_decay_text_encoder:
497
  commands.append(f"--adam_weight_decay_text_encoder={adam_weight_decay_text_encoder}")
 
 
498
  from train_dreambooth_lora_sdxl_advanced import main as train_main, parse_args as parse_train_args
499
  args = parse_train_args(commands)
500
 
@@ -503,27 +547,52 @@ def start_training_og(
503
  return f"Your model has finished training and has been saved to the `{slugged_lora_name}` folder"
504
 
505
  def run_captioning(*inputs):
506
- model.to("cuda")
507
  images = inputs[0]
508
- training_option = inputs[-1]
 
509
  final_captions = [""] * MAX_IMAGES
 
 
 
 
 
 
 
 
 
510
  for index, image in enumerate(images):
511
- original_caption = inputs[index + 1]
512
- pil_image = Image.open(image)
513
- blip_inputs = processor(images=pil_image, return_tensors="pt").to(device, torch.float16)
514
- generated_ids = model.generate(**blip_inputs)
515
- generated_text = processor.batch_decode(generated_ids, skip_special_tokens=True)[0].strip()
 
 
516
  if training_option == "style":
517
- final_caption = generated_text + " " + original_caption
518
  else:
519
- final_caption = original_caption + " " + generated_text
520
  final_captions[index] = final_caption
521
  yield final_captions
522
 
523
- if is_spaces:
524
- run_captioning = spaces.GPU()(run_captioning)
525
 
526
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
527
  def check_token(token):
528
  try:
529
  api = HfApi(token=token)
@@ -578,7 +647,9 @@ with gr.Blocks(css=css, theme=theme) as demo:
578
  with gr.Column(elem_classes=["main_logged"]) as main_ui:
579
  lora_name = gr.Textbox(label="The name of your LoRA", info="This has to be a unique name", placeholder="e.g.: Persian Miniature Painting style, Cat Toy")
580
  training_option = gr.Radio(
581
- label="What are you training?", choices=["object", "style", "character", "face", "custom"]
 
 
582
  )
583
  concept_sentence = gr.Textbox(
584
  label="Concept sentence",
@@ -604,7 +675,19 @@ with gr.Blocks(css=css, theme=theme) as demo:
604
  To improve the quality of your outputs, you can add a custom caption for each image, describing exactly what is taking place in each of them. Including TOK is mandatory. You can leave things as is if you don't want to include captioning.
605
  """
606
  )
607
- do_captioning = gr.Button("Add AI captions with BLIP-2")
 
 
 
 
 
 
 
 
 
 
 
 
608
  output_components = [captioning_area]
609
  caption_list = []
610
  for i in range(1, MAX_IMAGES + 1):
@@ -653,7 +736,7 @@ To improve the quality of your outputs, you can add a custom caption for each im
653
  mixed_precision = gr.Dropdown(
654
  label="Mixed Precision",
655
  choices=["no", "fp16", "bf16"],
656
- value="bf16",
657
  )
658
  learning_rate = gr.Number(
659
  label="UNet Learning rate",
@@ -753,12 +836,12 @@ To improve the quality of your outputs, you can add a custom caption for each im
753
  gradient_accumulation_steps = gr.Number(
754
  info="If you change this setting, the pricing calculation will be wrong",
755
  label="gradient_accumulation_steps",
756
- value=1
757
  )
758
  train_batch_size = gr.Number(
759
  info="If you change this setting, the pricing calculation will be wrong",
760
  label="Train batch size",
761
- value=2
762
  )
763
  num_train_epochs = gr.Number(
764
  info="If you change this setting, the pricing calculation will be wrong",
@@ -1070,9 +1153,17 @@ If you prefer command line, you can run our [training script]({training_script_u
1070
  )
1071
 
1072
  do_captioning.click(
1073
- fn=run_captioning, inputs=[images] + caption_list + [training_option], outputs=caption_list
 
 
 
 
 
 
 
 
1074
  )
1075
  #demo.load(fn=swap_opacity, outputs=[main_ui], queue=False, concurrency_limit=50)
1076
  if __name__ == "__main__":
1077
  demo.queue()
1078
- demo.launch(share=True)
 
1
  import gradio as gr
 
 
2
  import subprocess
3
  import os
4
  is_spaces = True if os.environ.get('SPACE_ID') else False
5
+ from gradio_client import Client, handle_file
 
 
6
  from huggingface_hub import snapshot_download, HfApi
 
7
  import uuid
8
  import shutil
9
  import json
10
  import random
11
+ import hashlib
12
  from slugify import slugify
13
  import argparse
14
  import importlib
15
  import sys
16
  from pathlib import Path
17
+ import tempfile
18
  import zipfile
19
+ from urllib.request import urlretrieve
20
 
21
  MAX_IMAGES = 150
22
 
23
+ DIFFUSERS_VERSION = "v0.39.0"
24
+ DIFFUSERS_COMMIT = "a3608b512ed7248499a44c61d954965ed9bdae4d"
25
+ TRAINING_SCRIPT = Path("train_dreambooth_lora_sdxl_advanced.py")
26
+ training_script_url = f"https://raw.githubusercontent.com/huggingface/diffusers/{DIFFUSERS_COMMIT}/examples/advanced_diffusion_training/{TRAINING_SCRIPT.name}"
27
  orchestrator_script_url = "https://huggingface.co/datasets/multimodalart/lora-ease-helper/raw/main/script.py"
 
28
 
29
+ MAGE_VL_SPACE_ID = os.environ.get("MAGE_VL_SPACE_ID", "lienthealien/mage-vl-demo")
30
+ MAGE_VL_API_NAME = os.environ.get("MAGE_VL_API_NAME", "/ask_image")
31
+ mage_vl_client = None
32
+ caption_cache = {}
33
 
 
 
 
34
 
35
+ def ensure_file(url, destination):
36
+ """Download a pinned helper only when it is actually needed."""
37
+ destination = Path(destination)
38
+ if not destination.exists():
39
+ print(f"Downloading {destination.name} from {url}")
40
+ urlretrieve(url, destination)
41
+ return destination
42
+
43
+
44
+ def get_face_prior_dataset():
45
+ dataset_path = snapshot_download(
46
+ repo_id="multimodalart/faces-prior-preservation", repo_type="dataset"
47
+ )
48
+ Path(dataset_path, ".gitattributes").unlink(missing_ok=True)
49
+ return dataset_path
50
+
51
+
52
+ def get_captioner():
53
+ """Connect to the dedicated Mage-VL Space without loading a VLM here."""
54
+ global mage_vl_client
55
+ if mage_vl_client is None:
56
+ token = os.environ.get("MAGE_VL_TOKEN") or os.environ.get("HF_TOKEN")
57
+ mage_vl_client = Client(MAGE_VL_SPACE_ID, hf_token=token, verbose=False)
58
+ return mage_vl_client
59
+
60
+
61
+ def caption_with_mage(client, image, instruction):
62
+ with open(image, "rb") as image_file:
63
+ cache_key = hashlib.sha256(image_file.read() + instruction.encode("utf-8")).hexdigest()
64
+ if cache_key in caption_cache:
65
+ return caption_cache[cache_key]
66
+
67
+ result = client.predict(
68
+ handle_file(image),
69
+ instruction,
70
+ 160,
71
+ api_name=MAGE_VL_API_NAME,
72
+ )
73
+ caption = result[0] if isinstance(result, (list, tuple)) else result
74
+ caption = str(caption).strip().rstrip(" .,")
75
+ caption_cache[cache_key] = caption
76
+ return caption
77
 
78
  training_option_settings = {
79
  "face": {
 
83
  "class_prompt": "a photo of a person",
84
  "train_steps_multiplier": 75,
85
  "file_count": 150,
86
+ "dataset_path": None
87
  },
88
  "style": {
89
  "rank": 32,
 
193
 
194
  random_files = []
195
  if settings["with_prior_preservation"]:
196
+ directory = settings["dataset_path"] or get_face_prior_dataset()
197
  file_count = settings["file_count"]
198
  files = [os.path.join(directory, file) for file in os.listdir(directory) if os.path.isfile(os.path.join(directory, file))]
199
  random_files = random.sample(files, min(len(files), file_count))
 
362
  spacerunner_args = ';'.join(commands)
363
  if not os.path.exists(spacerunner_folder):
364
  os.makedirs(spacerunner_folder)
365
+ ensure_file(training_script_url, TRAINING_SCRIPT)
366
+ ensure_file(orchestrator_script_url, "script.py")
367
+ shutil.copy(TRAINING_SCRIPT, f"{spacerunner_folder}/trainer.py")
368
  shutil.copy("script.py", f"{spacerunner_folder}/script.py")
369
  shutil.copytree(dataset_folder, f"{spacerunner_folder}/{dataset_folder}")
370
+ requirements='''diffusers==0.39.0
371
+ peft>=0.11.1
372
  torch
373
+ torchvision
374
+ transformers>=4.41.2
375
+ accelerate>=0.31.0
376
+ safetensors>=0.4.3
377
  prodigyopt==1.0
378
+ huggingface_hub>=0.34.0
379
+ hf-transfer>=0.1.4
380
+ datasets>=2.20.0
381
+ ftfy
382
+ tensorboard
383
+ Jinja2
384
+ sentencepiece'''
385
  file_path = f'{spacerunner_folder}/requirements.txt'
386
  with open(file_path, 'w') as file:
387
  file.write(requirements)
 
537
  commands.append(f"--prodigy_beta3={prodigy_beta3}")
538
  if use_adam_weight_decay_text_encoder:
539
  commands.append(f"--adam_weight_decay_text_encoder={adam_weight_decay_text_encoder}")
540
+ ensure_file(training_script_url, TRAINING_SCRIPT)
541
+ importlib.invalidate_caches()
542
  from train_dreambooth_lora_sdxl_advanced import main as train_main, parse_args as parse_train_args
543
  args = parse_train_args(commands)
544
 
 
547
  return f"Your model has finished training and has been saved to the `{slugged_lora_name}` folder"
548
 
549
  def run_captioning(*inputs):
 
550
  images = inputs[0]
551
+ training_option = inputs[-2]
552
+ caption_instruction = inputs[-1].strip()
553
  final_captions = [""] * MAX_IMAGES
554
+ try:
555
+ caption_client = get_captioner()
556
+ except Exception as exc:
557
+ raise gr.Error(
558
+ f"Could not connect to Mage-VL Space '{MAGE_VL_SPACE_ID}'. "
559
+ "If it is private, add MAGE_VL_TOKEN as a Hugging Face Space secret. "
560
+ f"Details: {exc}"
561
+ ) from exc
562
+
563
  for index, image in enumerate(images):
564
+ concept_caption = inputs[index + 1].strip()
565
+ try:
566
+ generated_text = caption_with_mage(caption_client, image, caption_instruction)
567
+ except Exception as exc:
568
+ raise gr.Error(
569
+ f"Mage-VL failed while captioning image {index + 1}: {exc}"
570
+ ) from exc
571
  if training_option == "style":
572
+ final_caption = f"{generated_text}, {concept_caption}"
573
  else:
574
+ final_caption = f"{concept_caption}, {generated_text}"
575
  final_captions[index] = final_caption
576
  yield final_captions
577
 
 
 
578
 
579
+ def export_captions(images, *captions):
580
+ if not images:
581
+ raise gr.Error("Upload images before exporting captions.")
582
+
583
+ with tempfile.NamedTemporaryFile(
584
+ mode="w", suffix=".jsonl", prefix="lora-captions-", encoding="utf-8", delete=False
585
+ ) as caption_file:
586
+ for image, caption in zip(images, captions):
587
+ caption_file.write(
588
+ json.dumps(
589
+ {"file_name": os.path.basename(image), "prompt": (caption or "").strip()},
590
+ ensure_ascii=False,
591
+ )
592
+ + "\n"
593
+ )
594
+ return caption_file.name
595
+
596
  def check_token(token):
597
  try:
598
  api = HfApi(token=token)
 
647
  with gr.Column(elem_classes=["main_logged"]) as main_ui:
648
  lora_name = gr.Textbox(label="The name of your LoRA", info="This has to be a unique name", placeholder="e.g.: Persian Miniature Painting style, Cat Toy")
649
  training_option = gr.Radio(
650
+ label="What are you training?",
651
+ info="For a shared game look across many different faces, choose style. Choose character only when every image depicts the same character.",
652
+ choices=["object", "style", "character", "face", "custom"],
653
  )
654
  concept_sentence = gr.Textbox(
655
  label="Concept sentence",
 
675
  To improve the quality of your outputs, you can add a custom caption for each image, describing exactly what is taking place in each of them. Including TOK is mandatory. You can leave things as is if you don't want to include captioning.
676
  """
677
  )
678
+ caption_instruction = gr.Textbox(
679
+ label="AI caption instruction",
680
+ value="Write one concise SDXL training caption for this portrait. Describe only visible, controllable content: character species or ancestry, approximate age, gender presentation, expression, hair, clothing, pose, lighting, and background. Do not identify the game, artist, rendering technique, image quality, or art style. Do not speculate about details that are not visible. Return only a natural comma-separated caption with no introduction.",
681
+ info="The LoRA concept sentence is added automatically to every generated caption.",
682
+ lines=3,
683
+ )
684
+ with gr.Row():
685
+ do_captioning = gr.Button("Caption all images with Mage-VL", variant="primary")
686
+ export_caption_button = gr.Button("Export captions")
687
+ exported_captions = gr.File(
688
+ label="Caption metadata (.jsonl)",
689
+ interactive=False,
690
+ )
691
  output_components = [captioning_area]
692
  caption_list = []
693
  for i in range(1, MAX_IMAGES + 1):
 
736
  mixed_precision = gr.Dropdown(
737
  label="Mixed Precision",
738
  choices=["no", "fp16", "bf16"],
739
+ value="fp16",
740
  )
741
  learning_rate = gr.Number(
742
  label="UNet Learning rate",
 
836
  gradient_accumulation_steps = gr.Number(
837
  info="If you change this setting, the pricing calculation will be wrong",
838
  label="gradient_accumulation_steps",
839
+ value=4
840
  )
841
  train_batch_size = gr.Number(
842
  info="If you change this setting, the pricing calculation will be wrong",
843
  label="Train batch size",
844
+ value=1
845
  )
846
  num_train_epochs = gr.Number(
847
  info="If you change this setting, the pricing calculation will be wrong",
 
1153
  )
1154
 
1155
  do_captioning.click(
1156
+ fn=run_captioning,
1157
+ inputs=[images] + caption_list + [training_option, caption_instruction],
1158
+ outputs=caption_list,
1159
+ )
1160
+ export_caption_button.click(
1161
+ fn=export_captions,
1162
+ inputs=[images] + caption_list,
1163
+ outputs=exported_captions,
1164
+ queue=False,
1165
  )
1166
  #demo.load(fn=swap_opacity, outputs=[main_ui], queue=False, concurrency_limit=50)
1167
  if __name__ == "__main__":
1168
  demo.queue()
1169
+ demo.launch(share=True)
requirements.txt CHANGED
@@ -1,9 +1,6 @@
1
  autotrain-advanced
2
  numpy==1.26.4
3
- transformers
4
- huggingface-hub
5
  python-slugify
6
- uuid
7
- torch
8
- torchvision
9
- spaces
 
1
  autotrain-advanced
2
  numpy==1.26.4
3
+ huggingface-hub==0.27.0
 
4
  python-slugify
5
+ gradio>=4.37,<6
6
+ gradio_client>=1.0
 
 
requirements_local.txt CHANGED
@@ -1,14 +1,16 @@
1
  torch
2
- python-slugify
3
- uuid
4
- torch
5
  torchvision
6
- peft==0.7.1
7
- huggingface-hub==0.23.4
8
- diffusers==0.29.2
9
- transformers==4.42.3
10
- accelerate==0.31.0
11
- safetensors==0.4.3
 
 
12
  prodigyopt==1.0
13
- hf-transfer==0.1.4
14
- datasets==2.20.0
 
 
 
 
1
  torch
 
 
 
2
  torchvision
3
+ python-slugify
4
+ gradio>=4.37,<6
5
+ diffusers==0.39.0
6
+ peft>=0.11.1
7
+ huggingface-hub>=0.34.0
8
+ transformers>=4.41.2
9
+ accelerate>=0.31.0
10
+ safetensors>=0.4.3
11
  prodigyopt==1.0
12
+ datasets>=2.20.0
13
+ ftfy
14
+ tensorboard
15
+ Jinja2
16
+ sentencepiece