datasety 0.1.0__py3-none-any.whl → 0.2.0__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.
- datasety/__init__.py +1 -1
- datasety/cli.py +178 -1
- {datasety-0.1.0.dist-info → datasety-0.2.0.dist-info}/METADATA +75 -8
- datasety-0.2.0.dist-info/RECORD +8 -0
- datasety/py.typed +0 -0
- datasety-0.1.0.dist-info/RECORD +0 -9
- {datasety-0.1.0.dist-info → datasety-0.2.0.dist-info}/WHEEL +0 -0
- {datasety-0.1.0.dist-info → datasety-0.2.0.dist-info}/entry_points.txt +0 -0
- {datasety-0.1.0.dist-info → datasety-0.2.0.dist-info}/licenses/LICENSE +0 -0
datasety/__init__.py
CHANGED
datasety/cli.py
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
2
|
"""
|
|
3
|
-
datasety - CLI tool for dataset preparation:
|
|
3
|
+
datasety - CLI tool for dataset preparation: resize, caption, and synthetic generation.
|
|
4
4
|
|
|
5
5
|
Usage:
|
|
6
6
|
datasety resize --input ./in --output ./out --resolution 768x1024 --crop-position top
|
|
7
7
|
datasety caption --input ./in --output ./out --trigger-word "[trigger]" --florence-2-large
|
|
8
|
+
datasety synthetic --input ./in --output ./out --prompt "add a winter hat"
|
|
8
9
|
"""
|
|
9
10
|
|
|
10
11
|
import argparse
|
|
@@ -283,6 +284,114 @@ def cmd_caption(args):
|
|
|
283
284
|
print(f"Done! Processed: {processed} images")
|
|
284
285
|
|
|
285
286
|
|
|
287
|
+
def cmd_synthetic(args):
|
|
288
|
+
"""Execute the synthetic image generation command."""
|
|
289
|
+
# Lazy import for faster CLI startup
|
|
290
|
+
try:
|
|
291
|
+
import torch
|
|
292
|
+
except ImportError:
|
|
293
|
+
print("Error: PyTorch not installed.")
|
|
294
|
+
print("Run: pip install 'datasety[synthetic]'")
|
|
295
|
+
sys.exit(1)
|
|
296
|
+
|
|
297
|
+
input_dir = Path(args.input)
|
|
298
|
+
output_dir = Path(args.output)
|
|
299
|
+
|
|
300
|
+
if not input_dir.exists():
|
|
301
|
+
print(f"Error: Input directory '{input_dir}' does not exist.")
|
|
302
|
+
sys.exit(1)
|
|
303
|
+
|
|
304
|
+
output_dir.mkdir(parents=True, exist_ok=True)
|
|
305
|
+
|
|
306
|
+
# Determine device
|
|
307
|
+
if args.device == "cuda" and not torch.cuda.is_available():
|
|
308
|
+
print("Warning: CUDA not available, falling back to CPU")
|
|
309
|
+
device = "cpu"
|
|
310
|
+
else:
|
|
311
|
+
device = args.device
|
|
312
|
+
|
|
313
|
+
# Import the correct pipeline based on model
|
|
314
|
+
try:
|
|
315
|
+
from diffusers import QwenImageEditPlusPipeline
|
|
316
|
+
pipeline_class = QwenImageEditPlusPipeline
|
|
317
|
+
except ImportError:
|
|
318
|
+
print("Error: QwenImageEditPlusPipeline not found.")
|
|
319
|
+
print("Make sure you have the latest diffusers: pip install -U diffusers")
|
|
320
|
+
sys.exit(1)
|
|
321
|
+
|
|
322
|
+
print(f"Loading model: {args.model}")
|
|
323
|
+
print(f"Device: {device}")
|
|
324
|
+
|
|
325
|
+
torch_dtype = torch.bfloat16 if device == "cuda" else torch.float32
|
|
326
|
+
|
|
327
|
+
try:
|
|
328
|
+
pipeline = pipeline_class.from_pretrained(
|
|
329
|
+
args.model,
|
|
330
|
+
torch_dtype=torch_dtype
|
|
331
|
+
)
|
|
332
|
+
pipeline.to(device)
|
|
333
|
+
pipeline.set_progress_bar_config(disable=False)
|
|
334
|
+
except Exception as e:
|
|
335
|
+
print(f"Error loading model: {e}")
|
|
336
|
+
sys.exit(1)
|
|
337
|
+
|
|
338
|
+
# Find images
|
|
339
|
+
formats = ["jpg", "jpeg", "png", "webp", "bmp", "tiff"]
|
|
340
|
+
image_files = get_image_files(input_dir, formats)
|
|
341
|
+
|
|
342
|
+
if not image_files:
|
|
343
|
+
print(f"No images found in '{input_dir}'")
|
|
344
|
+
sys.exit(0)
|
|
345
|
+
|
|
346
|
+
print(f"Found {len(image_files)} images")
|
|
347
|
+
print(f"Prompt: {args.prompt}")
|
|
348
|
+
print(f"Steps: {args.steps}, CFG: {args.cfg_scale}, True CFG: {args.true_cfg_scale}")
|
|
349
|
+
print("-" * 50)
|
|
350
|
+
|
|
351
|
+
processed = 0
|
|
352
|
+
|
|
353
|
+
for img_path in image_files:
|
|
354
|
+
try:
|
|
355
|
+
image = Image.open(img_path).convert("RGB")
|
|
356
|
+
|
|
357
|
+
# Set up generation parameters
|
|
358
|
+
gen_kwargs = {
|
|
359
|
+
"image": [image],
|
|
360
|
+
"prompt": args.prompt,
|
|
361
|
+
"negative_prompt": args.negative_prompt,
|
|
362
|
+
"num_inference_steps": args.steps,
|
|
363
|
+
"guidance_scale": args.cfg_scale,
|
|
364
|
+
"true_cfg_scale": args.true_cfg_scale,
|
|
365
|
+
"num_images_per_prompt": args.num_images,
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
# Add seed if specified
|
|
369
|
+
if args.seed is not None:
|
|
370
|
+
gen_kwargs["generator"] = torch.manual_seed(args.seed)
|
|
371
|
+
|
|
372
|
+
with torch.inference_mode():
|
|
373
|
+
output = pipeline(**gen_kwargs)
|
|
374
|
+
|
|
375
|
+
# Save output image(s)
|
|
376
|
+
for idx, out_img in enumerate(output.images):
|
|
377
|
+
if args.num_images > 1:
|
|
378
|
+
out_name = f"{img_path.stem}_{idx + 1}.png"
|
|
379
|
+
else:
|
|
380
|
+
out_name = f"{img_path.stem}.png"
|
|
381
|
+
|
|
382
|
+
out_path = output_dir / out_name
|
|
383
|
+
out_img.save(out_path)
|
|
384
|
+
|
|
385
|
+
print(f"[OK] {img_path.name} -> {len(output.images)} image(s)")
|
|
386
|
+
processed += 1
|
|
387
|
+
|
|
388
|
+
except Exception as e:
|
|
389
|
+
print(f"[ERROR] {img_path.name}: {e}")
|
|
390
|
+
|
|
391
|
+
print("-" * 50)
|
|
392
|
+
print(f"Done! Processed: {processed} images")
|
|
393
|
+
|
|
394
|
+
|
|
286
395
|
def main():
|
|
287
396
|
parser = argparse.ArgumentParser(
|
|
288
397
|
prog="datasety",
|
|
@@ -379,6 +488,74 @@ def main():
|
|
|
379
488
|
)
|
|
380
489
|
caption_parser.set_defaults(func=cmd_caption)
|
|
381
490
|
|
|
491
|
+
# === SYNTHETIC command ===
|
|
492
|
+
synthetic_parser = subparsers.add_parser(
|
|
493
|
+
"synthetic",
|
|
494
|
+
help="Generate synthetic images using image editing models"
|
|
495
|
+
)
|
|
496
|
+
synthetic_parser.add_argument(
|
|
497
|
+
"--input", "-i",
|
|
498
|
+
required=True,
|
|
499
|
+
help="Input directory containing images"
|
|
500
|
+
)
|
|
501
|
+
synthetic_parser.add_argument(
|
|
502
|
+
"--output", "-o",
|
|
503
|
+
required=True,
|
|
504
|
+
help="Output directory for generated images"
|
|
505
|
+
)
|
|
506
|
+
synthetic_parser.add_argument(
|
|
507
|
+
"--prompt", "-p",
|
|
508
|
+
required=True,
|
|
509
|
+
help="Edit prompt (e.g., 'add a winter hat to the person')"
|
|
510
|
+
)
|
|
511
|
+
synthetic_parser.add_argument(
|
|
512
|
+
"--model",
|
|
513
|
+
default="Qwen/Qwen-Image-Edit-2511",
|
|
514
|
+
help="Model to use (default: Qwen/Qwen-Image-Edit-2511)"
|
|
515
|
+
)
|
|
516
|
+
synthetic_parser.add_argument(
|
|
517
|
+
"--device",
|
|
518
|
+
choices=["cpu", "cuda"],
|
|
519
|
+
default="cuda",
|
|
520
|
+
help="Device to run model on (default: cuda)"
|
|
521
|
+
)
|
|
522
|
+
synthetic_parser.add_argument(
|
|
523
|
+
"--steps",
|
|
524
|
+
type=int,
|
|
525
|
+
default=40,
|
|
526
|
+
help="Number of inference steps (default: 40)"
|
|
527
|
+
)
|
|
528
|
+
synthetic_parser.add_argument(
|
|
529
|
+
"--cfg-scale",
|
|
530
|
+
type=float,
|
|
531
|
+
default=1.0,
|
|
532
|
+
help="Guidance scale (default: 1.0)"
|
|
533
|
+
)
|
|
534
|
+
synthetic_parser.add_argument(
|
|
535
|
+
"--true-cfg-scale",
|
|
536
|
+
type=float,
|
|
537
|
+
default=4.0,
|
|
538
|
+
help="True CFG scale (default: 4.0)"
|
|
539
|
+
)
|
|
540
|
+
synthetic_parser.add_argument(
|
|
541
|
+
"--negative-prompt",
|
|
542
|
+
default=" ",
|
|
543
|
+
help="Negative prompt (default: ' ')"
|
|
544
|
+
)
|
|
545
|
+
synthetic_parser.add_argument(
|
|
546
|
+
"--num-images",
|
|
547
|
+
type=int,
|
|
548
|
+
default=1,
|
|
549
|
+
help="Number of images to generate per input (default: 1)"
|
|
550
|
+
)
|
|
551
|
+
synthetic_parser.add_argument(
|
|
552
|
+
"--seed",
|
|
553
|
+
type=int,
|
|
554
|
+
default=None,
|
|
555
|
+
help="Random seed for reproducibility"
|
|
556
|
+
)
|
|
557
|
+
synthetic_parser.set_defaults(func=cmd_synthetic)
|
|
558
|
+
|
|
382
559
|
# Parse and execute
|
|
383
560
|
args = parser.parse_args()
|
|
384
561
|
args.func(args)
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: datasety
|
|
3
|
-
Version: 0.
|
|
4
|
-
Summary: CLI tool for dataset preparation:
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: CLI tool for dataset preparation: resize, caption, and synthetic image generation
|
|
5
5
|
Project-URL: Homepage, https://github.com/kontextox/datasety
|
|
6
6
|
Project-URL: Repository, https://github.com/kontextox/datasety
|
|
7
7
|
Project-URL: Issues, https://github.com/kontextox/datasety/issues
|
|
8
8
|
Author: kontextox
|
|
9
9
|
License-Expression: MIT
|
|
10
10
|
License-File: LICENSE
|
|
11
|
-
Keywords: captioning,cli,dataset,florence-2,image-processing,machine-learning
|
|
11
|
+
Keywords: captioning,cli,dataset,diffusers,florence-2,image-editing,image-processing,machine-learning,synthetic
|
|
12
12
|
Classifier: Development Status :: 4 - Beta
|
|
13
13
|
Classifier: Environment :: Console
|
|
14
14
|
Classifier: Intended Audience :: Developers
|
|
@@ -23,6 +23,15 @@ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
|
23
23
|
Classifier: Topic :: Scientific/Engineering :: Image Processing
|
|
24
24
|
Requires-Python: >=3.10
|
|
25
25
|
Requires-Dist: pillow>=9.0.0
|
|
26
|
+
Provides-Extra: all
|
|
27
|
+
Requires-Dist: accelerate; extra == 'all'
|
|
28
|
+
Requires-Dist: diffusers>=0.32.0; extra == 'all'
|
|
29
|
+
Requires-Dist: einops; extra == 'all'
|
|
30
|
+
Requires-Dist: sentencepiece; extra == 'all'
|
|
31
|
+
Requires-Dist: timm; extra == 'all'
|
|
32
|
+
Requires-Dist: torch>=2.0.0; extra == 'all'
|
|
33
|
+
Requires-Dist: transformers<4.46.0,>=4.38.0; extra == 'all'
|
|
34
|
+
Requires-Dist: transformers>=4.38.0; extra == 'all'
|
|
26
35
|
Provides-Extra: caption
|
|
27
36
|
Requires-Dist: einops; extra == 'caption'
|
|
28
37
|
Requires-Dist: timm; extra == 'caption'
|
|
@@ -31,11 +40,17 @@ Requires-Dist: transformers<4.46.0,>=4.38.0; extra == 'caption'
|
|
|
31
40
|
Provides-Extra: dev
|
|
32
41
|
Requires-Dist: pytest>=7.0.0; extra == 'dev'
|
|
33
42
|
Requires-Dist: ruff>=0.1.0; extra == 'dev'
|
|
43
|
+
Provides-Extra: synthetic
|
|
44
|
+
Requires-Dist: accelerate; extra == 'synthetic'
|
|
45
|
+
Requires-Dist: diffusers>=0.32.0; extra == 'synthetic'
|
|
46
|
+
Requires-Dist: sentencepiece; extra == 'synthetic'
|
|
47
|
+
Requires-Dist: torch>=2.0.0; extra == 'synthetic'
|
|
48
|
+
Requires-Dist: transformers>=4.38.0; extra == 'synthetic'
|
|
34
49
|
Description-Content-Type: text/markdown
|
|
35
50
|
|
|
36
51
|
# datasety
|
|
37
52
|
|
|
38
|
-
CLI tool for dataset preparation:
|
|
53
|
+
CLI tool for dataset preparation: resize, caption, and synthetic image generation.
|
|
39
54
|
|
|
40
55
|
## Installation
|
|
41
56
|
|
|
@@ -43,10 +58,12 @@ CLI tool for dataset preparation: image resizing and captioning with Florence-2.
|
|
|
43
58
|
pip install datasety
|
|
44
59
|
```
|
|
45
60
|
|
|
46
|
-
|
|
61
|
+
Install with specific features:
|
|
47
62
|
|
|
48
63
|
```bash
|
|
49
|
-
pip install datasety[caption]
|
|
64
|
+
pip install datasety[caption] # Florence-2 captioning
|
|
65
|
+
pip install datasety[synthetic] # Qwen image editing
|
|
66
|
+
pip install datasety[all] # All features
|
|
50
67
|
```
|
|
51
68
|
|
|
52
69
|
## Usage
|
|
@@ -88,7 +105,7 @@ datasety resize \
|
|
|
88
105
|
1. Finds all images matching input formats
|
|
89
106
|
2. Skips images where either dimension is smaller than target
|
|
90
107
|
3. Resizes proportionally so the smaller side matches target
|
|
91
|
-
4. Crops from the specified
|
|
108
|
+
4. Crops from the specified position to exact dimensions
|
|
92
109
|
5. Saves with high quality (95% for jpg/webp)
|
|
93
110
|
|
|
94
111
|
### Generate Captions
|
|
@@ -130,6 +147,43 @@ datasety caption \
|
|
|
130
147
|
|
|
131
148
|
This creates a `.txt` file for each image with the generated caption.
|
|
132
149
|
|
|
150
|
+
### Generate Synthetic Images
|
|
151
|
+
|
|
152
|
+
Generate synthetic variations of images using Qwen-Image-Edit:
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
datasety synthetic --input ./images --output ./synthetic --prompt "add a winter hat"
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
**Options:**
|
|
159
|
+
|
|
160
|
+
| Option | Description | Default |
|
|
161
|
+
| ------------------- | --------------------------------- | -------------------------- |
|
|
162
|
+
| `--input`, `-i` | Input directory | (required) |
|
|
163
|
+
| `--output`, `-o` | Output directory | (required) |
|
|
164
|
+
| `--prompt`, `-p` | Edit prompt | (required) |
|
|
165
|
+
| `--model` | Model to use | `Qwen/Qwen-Image-Edit-2511`|
|
|
166
|
+
| `--device` | `cpu` or `cuda` | `cuda` |
|
|
167
|
+
| `--steps` | Number of inference steps | `40` |
|
|
168
|
+
| `--cfg-scale` | Guidance scale | `1.0` |
|
|
169
|
+
| `--true-cfg-scale` | True CFG scale | `4.0` |
|
|
170
|
+
| `--negative-prompt` | Negative prompt | `" "` |
|
|
171
|
+
| `--num-images` | Images to generate per input | `1` |
|
|
172
|
+
| `--seed` | Random seed for reproducibility | (random) |
|
|
173
|
+
|
|
174
|
+
**Example:**
|
|
175
|
+
|
|
176
|
+
```bash
|
|
177
|
+
datasety synthetic \
|
|
178
|
+
--input ./dataset \
|
|
179
|
+
--output ./synthetic \
|
|
180
|
+
--prompt "add sunglasses to the person, keep everything else the same" \
|
|
181
|
+
--device cuda \
|
|
182
|
+
--steps 40 \
|
|
183
|
+
--true-cfg-scale 4.0 \
|
|
184
|
+
--seed 42
|
|
185
|
+
```
|
|
186
|
+
|
|
133
187
|
## Common Workflows
|
|
134
188
|
|
|
135
189
|
### Prepare a LoRA Training Dataset
|
|
@@ -142,6 +196,18 @@ datasety resize -i ./raw -o ./dataset -r 1024x1024 --crop-position center
|
|
|
142
196
|
datasety caption -i ./dataset -o ./dataset --trigger-word "[trigger]" --device cuda
|
|
143
197
|
```
|
|
144
198
|
|
|
199
|
+
### Augment Dataset with Synthetic Variations
|
|
200
|
+
|
|
201
|
+
```bash
|
|
202
|
+
# Generate variations with different accessories
|
|
203
|
+
datasety synthetic \
|
|
204
|
+
-i ./dataset \
|
|
205
|
+
-o ./synthetic \
|
|
206
|
+
--prompt "add a red scarf" \
|
|
207
|
+
--num-images 2 \
|
|
208
|
+
--device cuda
|
|
209
|
+
```
|
|
210
|
+
|
|
145
211
|
### Batch Process with Numbered Files
|
|
146
212
|
|
|
147
213
|
```bash
|
|
@@ -157,7 +223,8 @@ datasety resize \
|
|
|
157
223
|
|
|
158
224
|
- Python 3.10+
|
|
159
225
|
- Pillow (for resize)
|
|
160
|
-
- PyTorch + Transformers (for caption
|
|
226
|
+
- PyTorch + Transformers (for caption: `pip install datasety[caption]`)
|
|
227
|
+
- PyTorch + Diffusers (for synthetic: `pip install datasety[synthetic]`)
|
|
161
228
|
|
|
162
229
|
## License
|
|
163
230
|
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
datasety/__init__.py,sha256=rApR3JxIHU0q1LJ8_k_oM-5alQO0mW-4Ac9-GH5HmhA,105
|
|
2
|
+
datasety/__main__.py,sha256=rhdW0XGNAX-GC5IqU62ulCVccf3kgelddrGghYMZzn4,115
|
|
3
|
+
datasety/cli.py,sha256=lI18ORKHQdiZdIJ5icr3lo4YS8divLp8tz8yrrhtkF4,17807
|
|
4
|
+
datasety-0.2.0.dist-info/METADATA,sha256=xmi3GjI3mNVgu-tvls6HUA8yM8Wrsul6IcuZjK0xqGo,8170
|
|
5
|
+
datasety-0.2.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
6
|
+
datasety-0.2.0.dist-info/entry_points.txt,sha256=oWbVHN1_qyuWezjxuhsAGAqqwmivRUtG2jCYKm8bVnE,47
|
|
7
|
+
datasety-0.2.0.dist-info/licenses/LICENSE,sha256=dUhuoK-TCRQMpuLEAdfme-qPSJI0TlcH9jlNxeg9_EQ,1056
|
|
8
|
+
datasety-0.2.0.dist-info/RECORD,,
|
datasety/py.typed
DELETED
|
File without changes
|
datasety-0.1.0.dist-info/RECORD
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
datasety/__init__.py,sha256=LeNjBou33I9yomQhLmpfZWXEJeW2Io9ZvHnZmYXltQ4,105
|
|
2
|
-
datasety/__main__.py,sha256=rhdW0XGNAX-GC5IqU62ulCVccf3kgelddrGghYMZzn4,115
|
|
3
|
-
datasety/cli.py,sha256=K5doc2QZBLKDS3MjVkTsGe4giz31eo6xMCx8G4wdBEM,12399
|
|
4
|
-
datasety/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
5
|
-
datasety-0.1.0.dist-info/METADATA,sha256=u-9NanmOw3QZ3pWI1VNmrUG8CBAjFwyCnVVY_I6TpSE,5429
|
|
6
|
-
datasety-0.1.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
7
|
-
datasety-0.1.0.dist-info/entry_points.txt,sha256=oWbVHN1_qyuWezjxuhsAGAqqwmivRUtG2jCYKm8bVnE,47
|
|
8
|
-
datasety-0.1.0.dist-info/licenses/LICENSE,sha256=dUhuoK-TCRQMpuLEAdfme-qPSJI0TlcH9jlNxeg9_EQ,1056
|
|
9
|
-
datasety-0.1.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|