Codex commited on
Commit
bcfd1a0
·
1 Parent(s): 9fe20c7

Run SoVITS CPU training in a single process

Browse files
Files changed (1) hide show
  1. app.py +98 -10
app.py CHANGED
@@ -68,7 +68,7 @@ MODEL_PATTERNS = [
68
  "*.safetensors",
69
  "*.model",
70
  ]
71
- UPSTREAM_PATCH_VERSION = "2026-05-25-worker0-v4"
72
 
73
  logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s")
74
  log = logging.getLogger(__name__)
@@ -269,16 +269,45 @@ def now_iso():
269
  return datetime.now().isoformat(timespec="seconds")
270
 
271
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
272
  def process_metrics(pid: int, previous=None):
273
- stat_path = Path(f"/proc/{pid}/stat")
274
- statm_path = Path(f"/proc/{pid}/statm")
275
- if not stat_path.exists() or not statm_path.exists():
 
 
 
 
 
 
 
 
 
 
 
276
  return {"alive": False, "cpu_percent": 0.0, "rss_mb": 0.0, "cpu_time_seconds": 0.0}
277
- stat_fields = stat_path.read_text(encoding="utf-8").split()
278
- cpu_ticks = int(stat_fields[13]) + int(stat_fields[14])
279
  clock_ticks = os.sysconf(os.sysconf_names["SC_CLK_TCK"])
280
  cpu_time_seconds = cpu_ticks / float(clock_ticks)
281
- rss_pages = int(statm_path.read_text(encoding="utf-8").split()[1])
282
  page_size = os.sysconf("SC_PAGE_SIZE")
283
  rss_mb = rss_pages * page_size / (1024 * 1024)
284
  cpu_percent = 0.0
@@ -291,9 +320,26 @@ def process_metrics(pid: int, previous=None):
291
  "cpu_percent": round(cpu_percent, 2),
292
  "rss_mb": round(rss_mb, 2),
293
  "cpu_time_seconds": round(cpu_time_seconds, 2),
 
294
  }
295
 
296
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
297
  def status_summary(status):
298
  if not status:
299
  return ""
@@ -303,6 +349,8 @@ def status_summary(status):
303
  ]
304
  if status.get("pid") is not None:
305
  parts.append(f"pid={status['pid']}")
 
 
306
  if status.get("cpu_percent") is not None:
307
  parts.append(f"cpu={status['cpu_percent']}%")
308
  if status.get("rss_mb") is not None:
@@ -996,6 +1044,46 @@ class Text2SemanticDataModule(LightningDataModule):
996
  s1_train.write_text(s1_train_content, encoding="utf-8")
997
  s2_train = GPT_SOVITS_DIR / "GPT_SoVITS" / "s2_train.py"
998
  s2_train_content = s2_train.read_text(encoding="utf-8")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
999
  old_loader = """ train_loader = DataLoader(
1000
  train_dataset,
1001
  num_workers=5,
@@ -1505,9 +1593,9 @@ def agent_status(version=DEFAULT_VERSION):
1505
  "gpt": [file_record(path) for path in gpt_files[:10]],
1506
  },
1507
  "tasks": {
1508
- "prepare": read_status_file(ctx.prep_status_path),
1509
- "sovits": read_status_file(ctx.sovits_status_path),
1510
- "gpt": read_status_file(ctx.gpt_status_path),
1511
  },
1512
  }
1513
 
 
68
  "*.safetensors",
69
  "*.model",
70
  ]
71
+ UPSTREAM_PATCH_VERSION = "2026-05-26-s2-cpu-singleproc-v5"
72
 
73
  logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s")
74
  log = logging.getLogger(__name__)
 
269
  return datetime.now().isoformat(timespec="seconds")
270
 
271
 
272
+ def child_pids(pid: int):
273
+ children_path = Path(f"/proc/{pid}/task/{pid}/children")
274
+ if not children_path.exists():
275
+ return []
276
+ try:
277
+ direct_children = [int(item) for item in children_path.read_text(encoding="utf-8").split() if item.strip()]
278
+ except Exception:
279
+ return []
280
+ descendants = []
281
+ seen = set()
282
+ queue = list(direct_children)
283
+ while queue:
284
+ current = queue.pop(0)
285
+ if current in seen:
286
+ continue
287
+ seen.add(current)
288
+ descendants.append(current)
289
+ queue.extend(child_pids(current))
290
+ return descendants
291
+
292
+
293
  def process_metrics(pid: int, previous=None):
294
+ pids = [pid, *child_pids(pid)]
295
+ live_pids = []
296
+ cpu_ticks = 0
297
+ rss_pages = 0
298
+ for current_pid in pids:
299
+ stat_path = Path(f"/proc/{current_pid}/stat")
300
+ statm_path = Path(f"/proc/{current_pid}/statm")
301
+ if not stat_path.exists() or not statm_path.exists():
302
+ continue
303
+ stat_fields = stat_path.read_text(encoding="utf-8").split()
304
+ cpu_ticks += int(stat_fields[13]) + int(stat_fields[14])
305
+ rss_pages += int(statm_path.read_text(encoding="utf-8").split()[1])
306
+ live_pids.append(current_pid)
307
+ if not live_pids:
308
  return {"alive": False, "cpu_percent": 0.0, "rss_mb": 0.0, "cpu_time_seconds": 0.0}
 
 
309
  clock_ticks = os.sysconf(os.sysconf_names["SC_CLK_TCK"])
310
  cpu_time_seconds = cpu_ticks / float(clock_ticks)
 
311
  page_size = os.sysconf("SC_PAGE_SIZE")
312
  rss_mb = rss_pages * page_size / (1024 * 1024)
313
  cpu_percent = 0.0
 
320
  "cpu_percent": round(cpu_percent, 2),
321
  "rss_mb": round(rss_mb, 2),
322
  "cpu_time_seconds": round(cpu_time_seconds, 2),
323
+ "process_count": len(live_pids),
324
  }
325
 
326
 
327
+ def refresh_task_status(task):
328
+ if not task:
329
+ return None
330
+ pid = task.get("pid")
331
+ if pid is None:
332
+ return task
333
+ metrics = process_metrics(int(pid))
334
+ refreshed = dict(task)
335
+ refreshed.update(metrics)
336
+ refreshed["refreshed_at"] = now_iso()
337
+ if not metrics.get("alive"):
338
+ if refreshed.get("state") in {"starting", "running"} and refreshed.get("exit_code") is None:
339
+ refreshed["state"] = "stale"
340
+ return refreshed
341
+
342
+
343
  def status_summary(status):
344
  if not status:
345
  return ""
 
349
  ]
350
  if status.get("pid") is not None:
351
  parts.append(f"pid={status['pid']}")
352
+ if status.get("process_count") is not None:
353
+ parts.append(f"proc={status['process_count']}")
354
  if status.get("cpu_percent") is not None:
355
  parts.append(f"cpu={status['cpu_percent']}%")
356
  if status.get("rss_mb") is not None:
 
1044
  s1_train.write_text(s1_train_content, encoding="utf-8")
1045
  s2_train = GPT_SOVITS_DIR / "GPT_SoVITS" / "s2_train.py"
1046
  s2_train_content = s2_train.read_text(encoding="utf-8")
1047
+ old_main = """def main():
1048
+ if torch.cuda.is_available():
1049
+ n_gpus = torch.cuda.device_count()
1050
+ else:
1051
+ n_gpus = 1
1052
+ os.environ["MASTER_ADDR"] = "localhost"
1053
+ os.environ["MASTER_PORT"] = str(randint(20000, 55555))
1054
+
1055
+ mp.spawn(
1056
+ run,
1057
+ nprocs=n_gpus,
1058
+ args=(
1059
+ n_gpus,
1060
+ hps,
1061
+ ),
1062
+ )
1063
+ """
1064
+ new_main = """def main():
1065
+ if torch.cuda.is_available():
1066
+ n_gpus = torch.cuda.device_count()
1067
+ else:
1068
+ n_gpus = 1
1069
+ os.environ["MASTER_ADDR"] = "localhost"
1070
+ os.environ["MASTER_PORT"] = str(randint(20000, 55555))
1071
+
1072
+ if not torch.cuda.is_available() and n_gpus == 1:
1073
+ run(0, n_gpus, hps)
1074
+ return
1075
+
1076
+ mp.spawn(
1077
+ run,
1078
+ nprocs=n_gpus,
1079
+ args=(
1080
+ n_gpus,
1081
+ hps,
1082
+ ),
1083
+ )
1084
+ """
1085
+ if old_main in s2_train_content:
1086
+ s2_train_content = s2_train_content.replace(old_main, new_main, 1)
1087
  old_loader = """ train_loader = DataLoader(
1088
  train_dataset,
1089
  num_workers=5,
 
1593
  "gpt": [file_record(path) for path in gpt_files[:10]],
1594
  },
1595
  "tasks": {
1596
+ "prepare": refresh_task_status(read_status_file(ctx.prep_status_path)),
1597
+ "sovits": refresh_task_status(read_status_file(ctx.sovits_status_path)),
1598
+ "gpt": refresh_task_status(read_status_file(ctx.gpt_status_path)),
1599
  },
1600
  }
1601