neonforestmist commited on
Commit
59698fd
·
verified ·
1 Parent(s): a8c48b5

Add Modal training and inpainting model scaffold

Browse files
Files changed (1) hide show
  1. modal_inpaint.py +131 -0
modal_inpaint.py ADDED
@@ -0,0 +1,131 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """Run Clover Image Tiny inpainting training on Modal.
3
+
4
+ The default job writes its result to a persistent Modal Volume. This keeps
5
+ training independent from Hub credentials; the trained directory can be
6
+ downloaded and uploaded to the model repository after validation.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ import os
12
+ import subprocess
13
+ import sys
14
+ from pathlib import Path
15
+
16
+ import modal
17
+
18
+
19
+ APP_NAME = "clover-image-tiny-inpaint"
20
+ OUTPUT_VOLUME_NAME = "clover-image-tiny-inpaint-output"
21
+ OUTPUT_ROOT = Path("/outputs")
22
+
23
+ image = (
24
+ modal.Image.debian_slim(python_version="3.11")
25
+ .pip_install(
26
+ "accelerate==1.14.0",
27
+ "datasets==4.8.5",
28
+ "diffusers==0.39.0",
29
+ "ftfy==6.3.1",
30
+ "huggingface_hub==0.36.0",
31
+ "numpy==2.2.6",
32
+ "pillow==12.3.0",
33
+ "safetensors==0.8.0",
34
+ "torch==2.7.0",
35
+ "torchvision==0.22.0",
36
+ "transformers==4.57.6",
37
+ )
38
+ .add_local_dir("inpainting", remote_path="/root/inpainting")
39
+ )
40
+
41
+ output_volume = modal.Volume.from_name(OUTPUT_VOLUME_NAME, create_if_missing=True)
42
+ app = modal.App(
43
+ APP_NAME,
44
+ image=image,
45
+ volumes={str(OUTPUT_ROOT): output_volume},
46
+ )
47
+
48
+
49
+ @app.function(gpu="A10G", timeout=4 * 60 * 60)
50
+ def train(
51
+ *,
52
+ base_model: str = "neonforestmist/Clover-Image-Tiny",
53
+ base_revision: str = "63b0e9f6be9c00888ff464f342a9ef052bf76681",
54
+ dataset: str = "prithivMLmods/Caption3o-Opt",
55
+ dataset_revision: str = "17e893f785fcd3f5d6fc4a5d65a914b9f7b1ff5b",
56
+ dataset_split: str = "train",
57
+ image_column: str = "image",
58
+ caption_column: str = "caption",
59
+ max_train_steps: int = 4000,
60
+ output_name: str = "clover-image-tiny-inpaint",
61
+ max_train_samples: int | None = None,
62
+ learning_rate: float = 1e-5,
63
+ seed: int = 20260810,
64
+ ) -> str:
65
+ """Train once and return the Modal Volume path containing the pipeline."""
66
+
67
+ output_dir = OUTPUT_ROOT / output_name
68
+ if output_dir.exists():
69
+ raise RuntimeError(f"Output already exists; choose another --output-name: {output_dir}")
70
+
71
+ command = [
72
+ sys.executable,
73
+ "/root/inpainting/train.py",
74
+ "--pretrained_model_name_or_path",
75
+ base_model,
76
+ "--revision",
77
+ base_revision,
78
+ "--dataset_name",
79
+ dataset,
80
+ "--dataset_revision",
81
+ dataset_revision,
82
+ "--dataset_split",
83
+ dataset_split,
84
+ "--image_column",
85
+ image_column,
86
+ "--caption_column",
87
+ caption_column,
88
+ "--max_train_steps",
89
+ str(max_train_steps),
90
+ "--learning_rate",
91
+ str(learning_rate),
92
+ "--gradient_accumulation_steps",
93
+ "4",
94
+ "--gradient_checkpointing",
95
+ "--mixed_precision",
96
+ "fp16",
97
+ "--seed",
98
+ str(seed),
99
+ "--output_dir",
100
+ str(output_dir),
101
+ ]
102
+ if max_train_samples is not None:
103
+ command.extend(["--max_train_samples", str(max_train_samples)])
104
+
105
+ env = os.environ.copy()
106
+ env.setdefault("HF_HOME", "/root/.cache/huggingface")
107
+ subprocess.run(command, check=True, env=env)
108
+ output_volume.commit()
109
+ return str(output_dir)
110
+
111
+
112
+ @app.local_entrypoint()
113
+ def main(
114
+ smoke: bool = False,
115
+ steps: int = 4000,
116
+ output_name: str = "clover-image-tiny-inpaint",
117
+ ) -> None:
118
+ """Launch a bounded smoke job or the full A10G run."""
119
+
120
+ if smoke:
121
+ steps = min(steps, 2)
122
+ samples = 4
123
+ output_name = f"{output_name}-smoke"
124
+ else:
125
+ samples = None
126
+ result = train.remote(
127
+ max_train_steps=steps,
128
+ max_train_samples=samples,
129
+ output_name=output_name,
130
+ )
131
+ print(f"Training output is available in Modal Volume {OUTPUT_VOLUME_NAME}: {result}")