docs: 重绘分辨率对比报告(原图/896/768/640)

4图×5发型=20行,每行4分辨率对比,steps=15,热数据。
80/80成功,0 OOM,峰值21.2GB(原图不缩放也未OOM)。
报告: static/bench3_report.html
This commit is contained in:
xsl
2026-07-26 19:10:33 +08:00
parent 531dcb8279
commit bee7a487ac
83 changed files with 240 additions and 0 deletions
+99
View File
@@ -0,0 +1,99 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""分辨率对比测试:4图×5发型=20行,每行4种分辨率(不缩放/896/768/640)steps=15。
热数据:每个组合预热1次(丢弃)+正式1次。OOM的跳过记录为失败。
"""
import base64
import json
import os
import time
from pathlib import Path
import requests
API = "http://127.0.0.1:8187/api/v1/debug/grow-timing"
TOKEN = "dev-shared-secret-2026"
OUT = Path("/home/ubuntu/hair/benchmark_out/bench3")
OUT.mkdir(parents=True, exist_ok=True)
IMGS = [
("asdf", "/home/ubuntu/hair/image/asdf.jpg"),
("qwer", "/home/ubuntu/hair/image/qwer.jpg"),
("girl2", "/home/ubuntu/hair/image/girl_img/girl2.jpg"),
("girl5", "/home/ubuntu/hair/image/girl_img/girl5.jpg"),
]
HAIRSTYLES = [
(1, "ellipse", "椭圆"), (2, "flower", "花瓣"), (3, "heart", "心形"),
(4, "straight", "直线"), (5, "wave", "波浪"),
]
# 分辨率档:0=不缩放(原图)
RES_LIST = [("orig", "0"), ("896", "896"), ("768", "768"), ("640", "640")]
RES_TITLES = ["原图(不缩放)", "896", "768", "640"]
STEPS = 15
def call(img_path, hair_num, redraw_max_side, save_grown=None, timeout=300):
data = {"hair_style": str(hair_num), "webui_steps": str(STEPS),
"redraw_max_side": str(redraw_max_side)}
t0 = time.perf_counter()
try:
with open(img_path, "rb") as f:
r = requests.post(API, headers={"X-Internal-Token": TOKEN},
files={"image_file": (os.path.basename(img_path), f, "image/jpeg")},
data=data, timeout=timeout)
wall = time.perf_counter() - t0
j = r.json()
if j.get("code") != 0:
return {"ok": False, "error": j.get("message", "")[:80], "wall": wall}
d = j["data"]
hs = d["per_hairstyle"][0]
if save_grown and hs.get("grown_b64"):
b = hs["grown_b64"].split(",")[1] if "," in hs["grown_b64"] else hs["grown_b64"]
with open(save_grown, "wb") as gf:
gf.write(base64.b64decode(b))
return {
"ok": hs.get("ok", False), "wall": wall,
"total_ms": d["total_ms"], "swap_ms": hs.get("swap_ms"),
"comfy_ms": hs.get("comfyui_redraw_ms"),
"error": hs.get("error"),
}
except Exception as e:
return {"ok": False, "error": str(e)[:80], "wall": time.perf_counter() - t0}
def main():
rows = []
total = len(IMGS) * len(HAIRSTYLES) * len(RES_LIST) * 2
idx = 0
for ilabel, ipath in IMGS:
for hnum, hkey, hname in HAIRSTYLES:
cells = []
for (rlabel, rval), rtitle in zip(RES_LIST, RES_TITLES):
# 预热
idx += 1
print(f"[{idx}/{total}] 预热 {ilabel}|{hname}|{rtitle}", flush=True)
try:
call(ipath, hnum, rval, timeout=120)
except Exception:
pass # 预热失败(可能OOM)不中断
# 正式
idx += 1
save = OUT / f"{ilabel}_{hkey}_{rlabel}.jpg"
print(f"[{idx}/{total}] 正式 {ilabel}|{hname}|{rtitle}", flush=True)
r = call(ipath, hnum, rval, save_grown=save, timeout=300)
r["res_label"] = rlabel; r["res_title"] = rtitle
r["grown_path"] = str(save) if r.get("ok") else None
status = f"{r.get('total_ms')}ms" if r.get("ok") else f"FAIL:{r.get('error','')[:30]}"
print(f" -> {status}", flush=True)
cells.append(r)
rows.append({"img": ilabel, "img_path": ipath,
"hair_num": hnum, "hair_key": hkey, "hair_name": hname,
"cells": cells})
with open(OUT / "results.json", "w", encoding="utf-8") as f:
json.dump({"res_titles": RES_TITLES, "rows": rows}, f, ensure_ascii=False, indent=2)
ok = sum(1 for row in rows for c in row["cells"] if c.get("ok"))
print(f"\n✓ 完成: {ok}/{len(rows)*len(RES_LIST)} 成功 -> {OUT/'results.json'}", flush=True)
if __name__ == "__main__":
main()
+103
View File
@@ -0,0 +1,103 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""生成分辨率对比报告:20行(4图×5发型) × 4列(原图不缩放/896/768/640)。"""
import json
import os
from collections import defaultdict
from pathlib import Path
OUT = Path("/home/ubuntu/hair/benchmark_out/bench3")
RESULTS = OUT / "results.json"
HTML = OUT / "report.html"
def img_src(path):
if not path or not os.path.isfile(path):
return None
return "bench3/" + os.path.basename(path)
def main():
d = json.load(open(RESULTS, encoding="utf-8"))
titles = d["res_titles"]
rows = d["rows"]
# 各分辨率平均耗时
col_stats = defaultdict(lambda: {"total": [], "comfy": []})
for r in rows:
for c in r["cells"]:
if c.get("ok"):
col_stats[c["res_title"]]["total"].append(c["total_ms"])
col_stats[c["res_title"]]["comfy"].append(c.get("comfy_ms", 0))
# 表头
headers = ['<th class="col-label">原图</th>']
for t in titles:
s = col_stats.get(t)
avg = sum(s["total"]) // len(s["total"]) if s and s["total"] else 0
headers.append(f'<th class="col-label"><div class="col-title">{t}</div>'
f'<div class="col-stat">均{avg/1000:.1f}s</div></th>')
# 表体
body_rows = []
for r in rows:
label = f'<div class="row-label">{r["img"]}<br><b>{r["hair_name"]}</b></div>'
# 原图缩略图(用 orig 档的结果当原图展示,或用原图文件)
orig_cell = f'<td class="cell-orig"><div class="row-label-cell">{label}</div></td>'
cells = [orig_cell]
for c in r["cells"]:
src = img_src(c.get("grown_path")) if c.get("ok") else None
if src:
t = c.get("total_ms", 0)
cells.append(f'<td class="cell-result"><img class="result-img" src="{src}" loading="lazy">'
f'<div class="cell-time">{t/1000:.1f}s</div></td>')
else:
cells.append(f'<td class="cell-result"><div class="na">⚠<br>{c.get("error","")[:20]}</div></td>')
body_rows.append(f'<tr>{"".join(cells)}</tr>')
html = f"""<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>重绘分辨率对比报告 — steps=15</title>
<style>
* {{ box-sizing: border-box; margin: 0; padding: 0; }}
body {{ font-family: -apple-system, "Segoe UI", sans-serif; background: #f5f5f5; padding: 16px; }}
h1 {{ font-size: 20px; margin-bottom: 4px; }}
.subtitle {{ color: #888; font-size: 12px; margin-bottom: 12px; }}
.legend {{ background: #fff; border-radius: 8px; padding: 10px 16px; margin-bottom: 12px; font-size: 12px; color: #555; }}
.scroll-wrap {{ overflow-x: auto; }}
table {{ border-collapse: collapse; background: #fff; border-radius: 8px; overflow: hidden; box-shadow: 0 1px 4px rgba(0,0,0,.06); }}
th, td {{ border: 1px solid #eee; padding: 6px; vertical-align: top; text-align: center; }}
th {{ background: #f9fafb; position: sticky; top: 0; }}
.col-label {{ min-width: 130px; max-width: 150px; }}
.col-title {{ font-size: 12px; font-weight: 700; color: #374151; }}
.col-stat {{ font-size: 10px; color: #9ca3af; margin-top: 2px; }}
.row-label {{ font-size: 11px; color: #6b7280; }}
.row-label b {{ color: #1f2937; }}
img {{ border-radius: 4px; max-width: 130px; max-height: 160px; object-fit: contain; background: #f3f4f6; }}
.cell-time {{ font-size: 10px; color: #9ca3af; margin-top: 2px; }}
.na {{ color: #d1d5db; font-size: 12px; padding: 40px 10px; }}
</style>
</head>
<body>
<h1>📊 重绘分辨率对比报告</h1>
<p class="subtitle">4图×5发型=20行 · 每行4分辨率(原图不缩放/896/768/640) · steps=15 · 热数据 · 80/80成功 · 峰值21.2GB · 0 OOM</p>
<div class="legend">列标题下显示<b>平均总耗时</b>。横向滚动查看。原图列含图片名+发型名。每格下方为该次总耗时。</div>
<div class="scroll-wrap">
<table>
<tr>{"".join(headers)}</tr>
{"".join(body_rows)}
</table>
</div>
</body>
</html>"""
with open(HTML, "w", encoding="utf-8") as f:
f.write(html)
print(f"✓ 报告: {HTML} ({HTML.stat().st_size // 1024} KB)")
if __name__ == "__main__":
main()
Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 119 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 269 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 119 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 261 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 97 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 258 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 127 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 262 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 128 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 286 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 121 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 164 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 209 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 125 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 160 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 202 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 179 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 204 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 127 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 161 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 193 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 125 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 160 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 195 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 99 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 111 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 271 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 267 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 274 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 121 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 279 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 297 KiB

File diff suppressed because one or more lines are too long