Skip to content

Commit 532c0a9

Browse files
authored
Merge pull request #3093 from bghira/agent/dataset-batch-resume-guard
Guard batch-size changes when resuming sampler state
2 parents 809a2c7 + 290b8ae commit 532c0a9

8 files changed

Lines changed: 109 additions & 8 deletions

File tree

documentation/OPTIONS.es.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1798,6 +1798,7 @@ Las opciones anteriores aplican en su mayor parte a `config.json`, pero algunas
17981798
- `TRAINING_NUM_PROCESSES` debe configurarse al número de GPUs del sistema. Para la mayoría de los casos de uso, esto es suficiente para habilitar entrenamiento DistributedDataParallel (DDP). Usa `num_processes` dentro de `config.json` si prefieres no usar `config.env`.
17991799
- `TRAINING_DYNAMO_BACKEND` por defecto es `no` pero puede configurarse a cualquier backend de torch.compile soportado (p. ej., `inductor`, `aot_eager`, `cudagraphs`) y combinarse con `--dynamo_mode`, `--dynamo_fullgraph` o `--dynamo_use_regional_compilation` para un ajuste más fino
18001800
- `SIMPLETUNER_LOG_LEVEL` por defecto es `INFO` pero puede configurarse a `DEBUG` para añadir más información para reportes de problemas en `debug.log`
1801+
- `SIMPLETUNER_ALLOW_MODIFYING_BSZ=1` omite la comprobación de discrepancia de batch_size del sampler al reanudar desde un checkpoint. Úsalo solo si has cambiado intencionalmente `train_batch_size` entre ejecuciones y aceptas el riesgo de estado inconsistente del sampler. Equivalente a `--i_know_what_i_am_doing`.
18011802
- `VENV_PATH` puede configurarse a la ubicación de tu entorno virtual de python si no está en la ubicación típica `.venv`
18021803
- `ACCELERATE_EXTRA_ARGS` puede dejarse sin configurar o contener argumentos extra como `--multi_gpu` o flags específicos de FSDP
18031804

@@ -2410,7 +2411,9 @@ options:
24102411
Source device used to generate validation seeds
24112412
--i_know_what_i_am_doing [I_KNOW_WHAT_I_AM_DOING]
24122413
Unlock experimental overrides and bypass built-in
2413-
safety limits.
2414+
safety limits. Also bypasses the sampler batch-size
2415+
mismatch check on resume (same effect as
2416+
SIMPLETUNER_ALLOW_MODIFYING_BSZ=1).
24142417
--flow_sigmoid_scale FLOW_SIGMOID_SCALE
24152418
Scale factor for sigmoid timestep sampling for flow-
24162419
matching models.

documentation/OPTIONS.hi.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1796,6 +1796,7 @@ Upstream option mapping (LayerSync → SimpleTuner):
17961796
- `TRAINING_NUM_PROCESSES` को सिस्टम में GPUs की संख्या पर सेट करें। अधिकांश उपयोग‑मामलों में इससे DistributedDataParallel (DDP) training सक्षम हो जाती है। यदि आप `config.env` उपयोग नहीं करना चाहते, तो `config.json` में `num_processes` उपयोग करें।
17971797
- `TRAINING_DYNAMO_BACKEND` डिफ़ॉल्ट रूप से `no` है, लेकिन इसे किसी भी समर्थित torch.compile backend (उदा. `inductor`, `aot_eager`, `cudagraphs`) पर सेट किया जा सकता है और `--dynamo_mode`, `--dynamo_fullgraph`, या `--dynamo_use_regional_compilation` के साथ finer tuning के लिए जोड़ा जा सकता है
17981798
- `SIMPLETUNER_LOG_LEVEL` डिफ़ॉल्ट रूप से `INFO` है, लेकिन issue reports के लिए `debug.log` में अधिक जानकारी जोड़ने हेतु इसे `DEBUG` पर सेट किया जा सकता है
1799+
- `SIMPLETUNER_ALLOW_MODIFYING_BSZ=1` checkpoint से resume करते समय sampler batch_size मेल न खाने की जांच को छोड़ देता है। इसे केवल तभी उपयोग करें जब आपने जानबूझकर `train_batch_size` बदला हो और असंगत sampler state के जोखिम को स्वीकार करते हों। `--i_know_what_i_am_doing` के समकक्ष है।
17991800
- `VENV_PATH` को आपके python virtual env की लोकेशन पर सेट किया जा सकता है यदि वह सामान्य `.venv` लोकेशन में नहीं है
18001801
- `ACCELERATE_EXTRA_ARGS` को unset छोड़ा जा सकता है, या इसमें `--multi_gpu` या FSDP‑specific flags जैसे अतिरिक्त arguments जोड़े जा सकते हैं
18011802

@@ -2408,7 +2409,9 @@ options:
24082409
Source device used to generate validation seeds
24092410
--i_know_what_i_am_doing [I_KNOW_WHAT_I_AM_DOING]
24102411
Unlock experimental overrides and bypass built-in
2411-
safety limits.
2412+
safety limits. Also bypasses the sampler batch-size
2413+
mismatch check on resume (same effect as
2414+
SIMPLETUNER_ALLOW_MODIFYING_BSZ=1).
24122415
--flow_sigmoid_scale FLOW_SIGMOID_SCALE
24132416
Scale factor for sigmoid timestep sampling for flow-
24142417
matching models.

documentation/OPTIONS.ja.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1799,6 +1799,7 @@ LayerSync は同一 Transformer 内の「学生」レイヤーを、より強い
17991799
- `TRAINING_NUM_PROCESSES` はシステム内の GPU 数に設定します。ほとんどの用途で DistributedDataParallel(DDP)を有効化するには十分です。`config.env` を使いたくない場合は、`config.json``num_processes` を使用してください。
18001800
- `TRAINING_DYNAMO_BACKEND` は既定で `no` ですが、対応する torch.compile バックエンド(例: `inductor`, `aot_eager`, `cudagraphs`)に設定でき、`--dynamo_mode``--dynamo_fullgraph``--dynamo_use_regional_compilation` と組み合わせて微調整できます。
18011801
- `SIMPLETUNER_LOG_LEVEL` は既定で `INFO` ですが、`DEBUG` にすると `debug.log` に問題報告向けの詳細情報を追加できます。
1802+
- `SIMPLETUNER_ALLOW_MODIFYING_BSZ=1` を設定すると、チェックポイントから再開する際のサンプラー batch_size 不一致チェックをスキップします。意図的に `train_batch_size` を変更し、サンプラー状態の不整合リスクを許容する場合のみ使用してください。`--i_know_what_i_am_doing` と同等です。
18021803
- `VENV_PATH` は Python 仮想環境の場所を指定できます(標準の `.venv` 以外の場合)。
18031804
- `ACCELERATE_EXTRA_ARGS` は未設定でも構いませんが、`--multi_gpu` や FSDP 特有のフラグなど追加引数を含められます。
18041805

@@ -2410,7 +2411,9 @@ options:
24102411
Source device used to generate validation seeds
24112412
--i_know_what_i_am_doing [I_KNOW_WHAT_I_AM_DOING]
24122413
Unlock experimental overrides and bypass built-in
2413-
safety limits.
2414+
safety limits. Also bypasses the sampler batch-size
2415+
mismatch check on resume (same effect as
2416+
SIMPLETUNER_ALLOW_MODIFYING_BSZ=1).
24142417
--flow_sigmoid_scale FLOW_SIGMOID_SCALE
24152418
Scale factor for sigmoid timestep sampling for flow-
24162419
matching models.

documentation/OPTIONS.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1802,6 +1802,7 @@ The above options apply for the most part, to `config.json` - but some entries m
18021802
- `TRAINING_NUM_PROCESSES` should be set to the number of GPUs in the system. For most use-cases, this is enough to enable DistributedDataParallel (DDP) training. Use `num_processes` inside `config.json` if you prefer to not use `config.env`.
18031803
- `TRAINING_DYNAMO_BACKEND` defaults to `no` but can be set to any supported torch.compile backend (e.g. `inductor`, `aot_eager`, `cudagraphs`) and combined with `--dynamo_mode`, `--dynamo_fullgraph`, or `--dynamo_use_regional_compilation` for finer tuning
18041804
- `SIMPLETUNER_LOG_LEVEL` defaults to `INFO` but can be set to `DEBUG` to add more information for issue reports into `debug.log`
1805+
- `SIMPLETUNER_ALLOW_MODIFYING_BSZ=1` bypasses the sampler batch-size mismatch check when resuming from a checkpoint. Use this only if you intentionally changed `train_batch_size` between runs and accept the risk of inconsistent sampler state. Equivalent to passing `--i_know_what_i_am_doing`.
18051806
- `VENV_PATH` can be set to the location of your python virtual env, if it is not in the typical `.venv` location
18061807
- `ACCELERATE_EXTRA_ARGS` can be left unset, or, contain extra arguments to add like `--multi_gpu` or FSDP-specific flags
18071808

@@ -2413,7 +2414,9 @@ options:
24132414
Source device used to generate validation seeds
24142415
--i_know_what_i_am_doing [I_KNOW_WHAT_I_AM_DOING]
24152416
Unlock experimental overrides and bypass built-in
2416-
safety limits.
2417+
safety limits. Also bypasses the sampler batch-size
2418+
mismatch check on resume (same effect as
2419+
SIMPLETUNER_ALLOW_MODIFYING_BSZ=1).
24172420
--flow_sigmoid_scale FLOW_SIGMOID_SCALE
24182421
Scale factor for sigmoid timestep sampling for flow-
24192422
matching models.

documentation/OPTIONS.pt-BR.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1794,6 +1794,7 @@ As opcoes acima se aplicam em grande parte ao `config.json` — mas algumas entr
17941794
- `TRAINING_NUM_PROCESSES` deve ser definido para o numero de GPUs no sistema. Para a maioria dos casos, isso basta para habilitar treino DDP. Use `num_processes` no `config.json` se preferir nao usar `config.env`.
17951795
- `TRAINING_DYNAMO_BACKEND` padrao e `no`, mas pode ser definido para qualquer backend suportado do torch.compile (ex.: `inductor`, `aot_eager`, `cudagraphs`) e combinado com `--dynamo_mode`, `--dynamo_fullgraph` ou `--dynamo_use_regional_compilation` para ajuste fino.
17961796
- `SIMPLETUNER_LOG_LEVEL` padrao e `INFO`, mas pode ser definido para `DEBUG` para adicionar mais informacoes de issues no `debug.log`.
1797+
- `SIMPLETUNER_ALLOW_MODIFYING_BSZ=1` ignora a verificação de incompatibilidade de batch_size do sampler ao retomar de um checkpoint. Use apenas se intencionalmente alterou `train_batch_size` entre execuções e aceita o risco de estado inconsistente do sampler. Equivalente a `--i_know_what_i_am_doing`.
17971798
- `VENV_PATH` pode ser definido para o caminho do seu virtual env python, se nao estiver no local tipico `.venv`.
17981799
- `ACCELERATE_EXTRA_ARGS` pode ficar vazio ou conter argumentos extras como `--multi_gpu` ou flags especificas do FSDP.
17991800

@@ -2405,7 +2406,9 @@ options:
24052406
Source device used to generate validation seeds
24062407
--i_know_what_i_am_doing [I_KNOW_WHAT_I_AM_DOING]
24072408
Unlock experimental overrides and bypass built-in
2408-
safety limits.
2409+
safety limits. Also bypasses the sampler batch-size
2410+
mismatch check on resume (same effect as
2411+
SIMPLETUNER_ALLOW_MODIFYING_BSZ=1).
24092412
--flow_sigmoid_scale FLOW_SIGMOID_SCALE
24102413
Scale factor for sigmoid timestep sampling for flow-
24112414
matching models.

documentation/OPTIONS.zh.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1801,6 +1801,7 @@ LayerSync 通过在同一 Transformer 内让“学生”层对齐更强的“教
18011801
- `TRAINING_NUM_PROCESSES` 应设置为系统中的 GPU 数量。多数场景下已足够启用 DistributedDataParallel(DDP)。如果不想使用 `config.env`,可在 `config.json` 中设置 `num_processes`
18021802
- `TRAINING_DYNAMO_BACKEND` 默认 `no`,但可设置为任意支持的 torch.compile 后端(例如 `inductor`, `aot_eager`, `cudagraphs`),并与 `--dynamo_mode``--dynamo_fullgraph``--dynamo_use_regional_compilation` 配合微调。
18031803
- `SIMPLETUNER_LOG_LEVEL` 默认 `INFO`,设置为 `DEBUG` 可在 `debug.log` 中记录更多问题报告信息。
1804+
- `SIMPLETUNER_ALLOW_MODIFYING_BSZ=1` 在从检查点恢复时跳过采样器 batch_size 不匹配检查。仅在您有意在不同训练轮次间更改 `train_batch_size` 并接受采样器状态不一致的风险时使用。等效于 `--i_know_what_i_am_doing`
18041805
- `VENV_PATH` 可设置为 Python 虚拟环境的位置(如果不在常见 `.venv` 目录)。
18051806
- `ACCELERATE_EXTRA_ARGS` 可留空,或包含额外参数,例如 `--multi_gpu` 或 FSDP 专用标志。
18061807

@@ -2411,7 +2412,9 @@ options:
24112412
Source device used to generate validation seeds
24122413
--i_know_what_i_am_doing [I_KNOW_WHAT_I_AM_DOING]
24132414
Unlock experimental overrides and bypass built-in
2414-
safety limits.
2415+
safety limits. Also bypasses the sampler batch-size
2416+
mismatch check on resume (same effect as
2417+
SIMPLETUNER_ALLOW_MODIFYING_BSZ=1).
24152418
--flow_sigmoid_scale FLOW_SIGMOID_SCALE
24162419
Scale factor for sigmoid timestep sampling for flow-
24172420
matching models.

simpletuner/helpers/multiaspect/sampler.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,24 @@ def load_states(self, state_path: str):
176176
except Exception as e:
177177
raise e
178178

179+
saved_batch_size = previous_state.get("batch_size")
180+
if "batch_size" in previous_state and saved_batch_size != self.batch_size:
181+
_allow = os.environ.get("SIMPLETUNER_ALLOW_MODIFYING_BSZ", "").lower() in (
182+
"1",
183+
"true",
184+
"yes",
185+
) or getattr(StateTracker.get_args(), "i_know_what_i_am_doing", False)
186+
if not _allow:
187+
raise ValueError(
188+
f"Dataset '{self.id}' checkpoint batch_size={saved_batch_size} does not match "
189+
f"current batch_size={self.batch_size}. Resume with the same per-dataset train_batch_size, "
190+
f"or set --i_know_what_i_am_doing / SIMPLETUNER_ALLOW_MODIFYING_BSZ=1 to bypass."
191+
)
192+
self.logger.warning(
193+
f"Dataset '{self.id}': resuming with batch_size={self.batch_size} but checkpoint recorded "
194+
f"batch_size={saved_batch_size}. Proceeding because override is set."
195+
)
196+
179197
# Checkpoints contain the rank-local schedule. Restore it before seen
180198
# state so legacy boolean flags can be expanded to all occurrences.
181199
saved_schedule = previous_state.get("aspect_ratio_bucket_indices")

tests/test_sampler.py

Lines changed: 67 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -270,10 +270,11 @@ def read_image(path):
270270
self.assertEqual(conditioning_sample.image_path(), "/conditioning/11.png")
271271
self.assertEqual(conditioning_sample.caption, "caption")
272272

273-
def test_load_states_restores_schedule_before_normalizing_legacy_seen_flags(self):
273+
def test_load_states_with_matching_batch_size_restores_schedule_before_normalizing_legacy_seen_flags(self):
274274
self.sampler.state_manager.load_state.return_value = {
275275
"aspect_ratio_bucket_indices": {"1.0": ["same.jpg", "same.jpg", "other.jpg"]},
276276
"buckets": ["1.0"],
277+
"batch_size": self.batch_size,
277278
"current_bucket": 0,
278279
"exhausted_buckets": ["old"],
279280
"seen_images": {"same.jpg": True, "other.jpg": False, "legacy.jpg": True},
@@ -296,7 +297,71 @@ def test_load_states_restores_schedule_before_normalizing_legacy_seen_flags(self
296297
self.assertEqual(self.metadata_backend.seen_images["other.jpg"], 0)
297298
self.assertTrue(self.metadata_backend.seen_images["legacy.jpg"])
298299

299-
def test_load_states_keeps_the_fresh_split_when_the_checkpoint_records_no_layout(self):
300+
def test_load_states_rejects_batch_size_mismatch_before_mutation(self):
301+
self.sampler.state_manager.load_state.return_value = {
302+
"aspect_ratio_bucket_indices": {"saved": ["saved.jpg"]},
303+
"buckets": ["saved"],
304+
"batch_size": 3,
305+
"current_bucket": "saved",
306+
"exhausted_buckets": ["saved-exhausted"],
307+
"seen_images": {"saved.jpg": 1},
308+
"current_epoch": 9,
309+
"dp_size": 1,
310+
"dp_rank": 0,
311+
}
312+
313+
self.metadata_backend.aspect_ratio_bucket_indices = {"fresh": ["fresh.jpg"]}
314+
self.metadata_backend.seen_images = {"fresh.jpg": 1}
315+
self.sampler._val_master_list = ["fresh.jpg"]
316+
self.sampler.buckets = ["fresh"]
317+
self.sampler.current_bucket = "fresh"
318+
self.sampler.exhausted_buckets = ["fresh-exhausted"]
319+
self.sampler.current_epoch = 7
320+
321+
with (
322+
patch.dict(os.environ, {"SIMPLETUNER_ALLOW_MODIFYING_BSZ": ""}),
323+
patch.object(StateTracker, "get_args", return_value=SimpleNamespace(i_know_what_i_am_doing=False)),
324+
self.assertRaises(ValueError) as error,
325+
):
326+
self.sampler.load_states(self.state_path)
327+
328+
self.assertEqual(
329+
str(error.exception),
330+
"Dataset 'foo' checkpoint batch_size=3 does not match current batch_size=2. "
331+
"Resume with the same per-dataset train_batch_size, "
332+
"or set --i_know_what_i_am_doing / SIMPLETUNER_ALLOW_MODIFYING_BSZ=1 to bypass.",
333+
)
334+
self.assertEqual(self.metadata_backend.aspect_ratio_bucket_indices, {"fresh": ["fresh.jpg"]})
335+
self.assertEqual(self.metadata_backend.seen_images, {"fresh.jpg": 1})
336+
self.assertEqual(self.sampler._val_master_list, ["fresh.jpg"])
337+
self.assertEqual(self.sampler.buckets, ["fresh"])
338+
self.assertEqual(self.sampler.current_bucket, "fresh")
339+
self.assertEqual(self.sampler.exhausted_buckets, ["fresh-exhausted"])
340+
self.assertEqual(self.sampler.current_epoch, 7)
341+
342+
def test_load_states_batch_size_mismatch_allowed_via_env_var(self):
343+
self.sampler.state_manager.load_state.return_value = {
344+
"aspect_ratio_bucket_indices": {"saved": ["saved.jpg"]},
345+
"buckets": ["saved"],
346+
"batch_size": 3,
347+
}
348+
self.metadata_backend.aspect_ratio_bucket_indices = {"fresh": ["fresh.jpg"]}
349+
350+
with patch.dict(os.environ, {"SIMPLETUNER_ALLOW_MODIFYING_BSZ": "1"}):
351+
with patch.object(StateTracker, "get_args", return_value=SimpleNamespace(i_know_what_i_am_doing=False)):
352+
self.sampler.load_states(self.state_path)
353+
354+
def test_load_states_batch_size_mismatch_allowed_via_i_know_flag(self):
355+
self.sampler.state_manager.load_state.return_value = {
356+
"aspect_ratio_bucket_indices": {"saved": ["saved.jpg"]},
357+
"buckets": ["saved"],
358+
"batch_size": 3,
359+
}
360+
self.metadata_backend.aspect_ratio_bucket_indices = {"fresh": ["fresh.jpg"]}
361+
with patch.object(StateTracker, "get_args", return_value=SimpleNamespace(i_know_what_i_am_doing=True)):
362+
self.sampler.load_states(self.state_path)
363+
364+
def test_load_states_legacy_state_without_batch_size_keeps_fresh_split_when_no_layout(self):
300365
# Checkpoints written before the layout was recorded cannot be attributed to a rank, so
301366
# the schedule is left alone. Seen state still loads.
302367
self.sampler.state_manager.load_state.return_value = {

0 commit comments

Comments
 (0)