[diffusion] CI: change ground truth upload path and improve publish script (#24120)
This commit is contained in:
@@ -14,7 +14,12 @@ on:
|
|||||||
default: ''
|
default: ''
|
||||||
type: string
|
type: string
|
||||||
output_name:
|
output_name:
|
||||||
description: 'Custom output folder name (also used for artifact names and publish target dir). Leave empty to use defaults.'
|
description: 'Custom local output/artifact folder name. Leave empty to use defaults.'
|
||||||
|
required: false
|
||||||
|
default: ''
|
||||||
|
type: string
|
||||||
|
publish_target_dir:
|
||||||
|
description: 'Remote target directory in sglang-ci-data. Leave empty to use diffusion-ci/consistency_gt/sglang_generated.'
|
||||||
required: false
|
required: false
|
||||||
default: ''
|
default: ''
|
||||||
type: string
|
type: string
|
||||||
@@ -36,6 +41,7 @@ env:
|
|||||||
SGLANG_IS_IN_CI: true
|
SGLANG_IS_IN_CI: true
|
||||||
SGLANG_CUDA_COREDUMP: "1"
|
SGLANG_CUDA_COREDUMP: "1"
|
||||||
OUTPUT_NAME: ${{ inputs.output_name || 'diffusion-ci-outputs' }}
|
OUTPUT_NAME: ${{ inputs.output_name || 'diffusion-ci-outputs' }}
|
||||||
|
PUBLISH_TARGET_DIR: ${{ inputs.publish_target_dir || 'diffusion-ci/consistency_gt/sglang_generated' }}
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
compute-diffusion-partitions:
|
compute-diffusion-partitions:
|
||||||
@@ -136,7 +142,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
python scripts/ci/utils/diffusion/publish_diffusion_gt.py \
|
python scripts/ci/utils/diffusion/publish_diffusion_gt.py \
|
||||||
--source-dir python/${{ env.OUTPUT_NAME }} \
|
--source-dir python/${{ env.OUTPUT_NAME }} \
|
||||||
${{ inputs.output_name != '' && format('--target-dir diffusion-ci/{0}', inputs.output_name) || '' }}
|
--target-dir "${{ env.PUBLISH_TARGET_DIR }}"
|
||||||
|
|
||||||
multimodal-diffusion-gen-2gpu:
|
multimodal-diffusion-gen-2gpu:
|
||||||
needs: compute-diffusion-partitions
|
needs: compute-diffusion-partitions
|
||||||
@@ -202,7 +208,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
python scripts/ci/utils/diffusion/publish_diffusion_gt.py \
|
python scripts/ci/utils/diffusion/publish_diffusion_gt.py \
|
||||||
--source-dir python/${{ env.OUTPUT_NAME }} \
|
--source-dir python/${{ env.OUTPUT_NAME }} \
|
||||||
${{ inputs.output_name != '' && format('--target-dir diffusion-ci/{0}', inputs.output_name) || '' }}
|
--target-dir "${{ env.PUBLISH_TARGET_DIR }}"
|
||||||
|
|
||||||
multimodal-diffusion-gen-b200:
|
multimodal-diffusion-gen-b200:
|
||||||
needs: compute-diffusion-partitions
|
needs: compute-diffusion-partitions
|
||||||
@@ -268,4 +274,4 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
python scripts/ci/utils/diffusion/publish_diffusion_gt.py \
|
python scripts/ci/utils/diffusion/publish_diffusion_gt.py \
|
||||||
--source-dir python/${{ env.OUTPUT_NAME }} \
|
--source-dir python/${{ env.OUTPUT_NAME }} \
|
||||||
${{ inputs.output_name != '' && format('--target-dir diffusion-ci/{0}', inputs.output_name) || '' }}
|
--target-dir "${{ env.PUBLISH_TARGET_DIR }}"
|
||||||
|
|||||||
@@ -561,13 +561,13 @@ Consider updating perf_baselines.json with the snippets below:
|
|||||||
--- MISSING GROUND TRUTH DETECTED ---
|
--- MISSING GROUND TRUTH DETECTED ---
|
||||||
GT image(s) not found for '{case.id}'.
|
GT image(s) not found for '{case.id}'.
|
||||||
|
|
||||||
Add the expected file(s) to sglang-ci-data in diffusion-ci/consistency_gt/ with naming (n=num_gpus).
|
Add the expected file(s) to sglang-ci-data in diffusion-ci/consistency_gt/sglang_generated/ with naming (n=num_gpus).
|
||||||
Image: {case.id}_{{n}}gpu.<ext> (ext from output_format: png, jpg, webp)
|
Image: {case.id}_{{n}}gpu.<ext> (ext from output_format: png, jpg, webp)
|
||||||
Video: {case.id}_{{n}}gpu_frame_0.png, {case.id}_{{n}}gpu_frame_mid.png, {case.id}_{{n}}gpu_frame_last.png
|
Video: {case.id}_{{n}}gpu_frame_0.png, {case.id}_{{n}}gpu_frame_mid.png, {case.id}_{{n}}gpu_frame_last.png
|
||||||
|
|
||||||
For this case, expected file(s): {names}
|
For this case, expected file(s): {names}
|
||||||
|
|
||||||
Repository: https://github.com/sglang-bot/sglang-ci-data (path: diffusion-ci/consistency_gt/)
|
Repository: https://github.com/sglang-bot/sglang-ci-data (path: diffusion-ci/consistency_gt/sglang_generated/)
|
||||||
|
|
||||||
(Optional) Per-case override in consistency_threshold.json:
|
(Optional) Per-case override in consistency_threshold.json:
|
||||||
"cases": {{
|
"cases": {{
|
||||||
|
|||||||
@@ -33,11 +33,10 @@ logger = init_logger(__name__)
|
|||||||
|
|
||||||
SGL_TEST_FILES_OFFICIAL_CONSISTENCY_GT_BASE = "https://raw.githubusercontent.com/sglang-bot/sglang-ci-data/main/diffusion-ci/consistency_gt/official_generated"
|
SGL_TEST_FILES_OFFICIAL_CONSISTENCY_GT_BASE = "https://raw.githubusercontent.com/sglang-bot/sglang-ci-data/main/diffusion-ci/consistency_gt/official_generated"
|
||||||
SGL_TEST_FILES_SGLANG_CONSISTENCY_GT_BASE = "https://raw.githubusercontent.com/sglang-bot/sglang-ci-data/main/diffusion-ci/consistency_gt/sglang_generated"
|
SGL_TEST_FILES_SGLANG_CONSISTENCY_GT_BASE = "https://raw.githubusercontent.com/sglang-bot/sglang-ci-data/main/diffusion-ci/consistency_gt/sglang_generated"
|
||||||
SGL_TEST_FILES_CONSISTENCY_GT_BASE = "https://raw.githubusercontent.com/sglang-bot/sglang-ci-data/main/diffusion-ci/consistency_gt"
|
SGL_TEST_FILES_CONSISTENCY_GT_BASE = SGL_TEST_FILES_SGLANG_CONSISTENCY_GT_BASE
|
||||||
SGL_TEST_FILES_CONSISTENCY_GT_BASES = (
|
SGL_TEST_FILES_CONSISTENCY_GT_BASES = (
|
||||||
SGL_TEST_FILES_OFFICIAL_CONSISTENCY_GT_BASE,
|
SGL_TEST_FILES_OFFICIAL_CONSISTENCY_GT_BASE,
|
||||||
SGL_TEST_FILES_SGLANG_CONSISTENCY_GT_BASE,
|
SGL_TEST_FILES_SGLANG_CONSISTENCY_GT_BASE,
|
||||||
SGL_TEST_FILES_CONSISTENCY_GT_BASE,
|
|
||||||
)
|
)
|
||||||
CONSISTENCY_THRESHOLD_JSON_PATH = (
|
CONSISTENCY_THRESHOLD_JSON_PATH = (
|
||||||
Path(__file__).resolve().parent / "server" / "consistency_threshold.json"
|
Path(__file__).resolve().parent / "server" / "consistency_threshold.json"
|
||||||
|
|||||||
@@ -4,9 +4,12 @@ via the GitHub API (same pattern as publish_traces.py).
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
|
import hashlib
|
||||||
|
import json
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from urllib.error import HTTPError
|
||||||
|
|
||||||
# Reuse GitHub API helpers from publish_traces.
|
# Reuse GitHub API helpers from publish_traces.
|
||||||
# Support both direct script execution and package-style imports.
|
# Support both direct script execution and package-style imports.
|
||||||
@@ -19,6 +22,7 @@ if __package__:
|
|||||||
get_tree_sha,
|
get_tree_sha,
|
||||||
is_permission_error,
|
is_permission_error,
|
||||||
is_rate_limit_error,
|
is_rate_limit_error,
|
||||||
|
make_github_request,
|
||||||
update_branch_ref,
|
update_branch_ref,
|
||||||
verify_token_permissions,
|
verify_token_permissions,
|
||||||
)
|
)
|
||||||
@@ -32,6 +36,7 @@ else:
|
|||||||
get_tree_sha,
|
get_tree_sha,
|
||||||
is_permission_error,
|
is_permission_error,
|
||||||
is_rate_limit_error,
|
is_rate_limit_error,
|
||||||
|
make_github_request,
|
||||||
update_branch_ref,
|
update_branch_ref,
|
||||||
verify_token_permissions,
|
verify_token_permissions,
|
||||||
)
|
)
|
||||||
@@ -39,7 +44,7 @@ else:
|
|||||||
REPO_OWNER = "sglang-bot"
|
REPO_OWNER = "sglang-bot"
|
||||||
REPO_NAME = "sglang-ci-data"
|
REPO_NAME = "sglang-ci-data"
|
||||||
BRANCH = "main"
|
BRANCH = "main"
|
||||||
DEFAULT_TARGET_DIR = "diffusion-ci/consistency_gt"
|
DEFAULT_TARGET_DIR = "diffusion-ci/consistency_gt/sglang_generated"
|
||||||
|
|
||||||
IMAGE_EXTENSIONS = {".png", ".jpg", ".jpeg", ".webp"}
|
IMAGE_EXTENSIONS = {".png", ".jpg", ".jpeg", ".webp"}
|
||||||
|
|
||||||
@@ -61,6 +66,38 @@ def collect_images(source_dir, target_dir):
|
|||||||
return files
|
return files
|
||||||
|
|
||||||
|
|
||||||
|
def git_blob_sha(content):
|
||||||
|
header = f"blob {len(content)}\0".encode()
|
||||||
|
return hashlib.sha1(header + content).hexdigest()
|
||||||
|
|
||||||
|
|
||||||
|
def get_remote_blob_shas(repo_owner, repo_name, target_dir, token):
|
||||||
|
url = (
|
||||||
|
f"https://api.github.com/repos/{repo_owner}/{repo_name}/contents/"
|
||||||
|
f"{target_dir}?ref={BRANCH}"
|
||||||
|
)
|
||||||
|
try:
|
||||||
|
response = make_github_request(url, token)
|
||||||
|
except HTTPError as e:
|
||||||
|
if e.code == 404:
|
||||||
|
return {}
|
||||||
|
raise
|
||||||
|
entries = json.loads(response)
|
||||||
|
return {
|
||||||
|
item["path"]: item["sha"]
|
||||||
|
for item in entries
|
||||||
|
if item.get("type") == "file" and "sha" in item
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def filter_changed_files(files, remote_blob_shas):
|
||||||
|
return [
|
||||||
|
(path, content)
|
||||||
|
for path, content in files
|
||||||
|
if remote_blob_shas.get(path) != git_blob_sha(content)
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
def publish(source_dir, target_dir=None):
|
def publish(source_dir, target_dir=None):
|
||||||
target_dir = target_dir or DEFAULT_TARGET_DIR
|
target_dir = target_dir or DEFAULT_TARGET_DIR
|
||||||
token = os.getenv("GITHUB_TOKEN")
|
token = os.getenv("GITHUB_TOKEN")
|
||||||
@@ -86,9 +123,22 @@ def publish(source_dir, target_dir=None):
|
|||||||
print("Token permission verification failed.")
|
print("Token permission verification failed.")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
# Create blobs
|
# Commit with retry (handle concurrent pushes)
|
||||||
|
max_retries = 5
|
||||||
|
for attempt in range(max_retries):
|
||||||
try:
|
try:
|
||||||
tree_items = create_blobs(REPO_OWNER, REPO_NAME, files_to_upload, token)
|
branch_sha = get_branch_sha(REPO_OWNER, REPO_NAME, BRANCH, token)
|
||||||
|
tree_sha = get_tree_sha(REPO_OWNER, REPO_NAME, branch_sha, token)
|
||||||
|
remote_blob_shas = get_remote_blob_shas(
|
||||||
|
REPO_OWNER, REPO_NAME, target_dir, token
|
||||||
|
)
|
||||||
|
changed_files = filter_changed_files(files_to_upload, remote_blob_shas)
|
||||||
|
if not changed_files:
|
||||||
|
print("No image changes to publish.")
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
tree_items = create_blobs(REPO_OWNER, REPO_NAME, changed_files, token)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
if is_rate_limit_error(e):
|
if is_rate_limit_error(e):
|
||||||
print("Rate-limited during blob creation, skipping.")
|
print("Rate-limited during blob creation, skipping.")
|
||||||
@@ -101,22 +151,20 @@ def publish(source_dir, target_dir=None):
|
|||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
raise
|
raise
|
||||||
|
|
||||||
# Commit with retry (handle concurrent pushes)
|
|
||||||
max_retries = 5
|
|
||||||
for attempt in range(max_retries):
|
|
||||||
try:
|
|
||||||
branch_sha = get_branch_sha(REPO_OWNER, REPO_NAME, BRANCH, token)
|
|
||||||
tree_sha = get_tree_sha(REPO_OWNER, REPO_NAME, branch_sha, token)
|
|
||||||
new_tree_sha = create_tree(
|
new_tree_sha = create_tree(
|
||||||
REPO_OWNER, REPO_NAME, tree_sha, tree_items, token
|
REPO_OWNER, REPO_NAME, tree_sha, tree_items, token
|
||||||
)
|
)
|
||||||
commit_msg = f"diffusion-ci: update consistency_gt images ({len(files_to_upload)} files) [automated]"
|
if new_tree_sha == tree_sha:
|
||||||
|
print("No tree changes to publish.")
|
||||||
|
return
|
||||||
|
|
||||||
|
commit_msg = f"diffusion-ci: update images in {target_dir} ({len(changed_files)} files) [automated]"
|
||||||
commit_sha = create_commit(
|
commit_sha = create_commit(
|
||||||
REPO_OWNER, REPO_NAME, new_tree_sha, branch_sha, commit_msg, token
|
REPO_OWNER, REPO_NAME, new_tree_sha, branch_sha, commit_msg, token
|
||||||
)
|
)
|
||||||
update_branch_ref(REPO_OWNER, REPO_NAME, BRANCH, commit_sha, token)
|
update_branch_ref(REPO_OWNER, REPO_NAME, BRANCH, commit_sha, token)
|
||||||
print(
|
print(
|
||||||
f"Successfully pushed {len(files_to_upload)} images (commit {commit_sha[:10]})"
|
f"Successfully pushed {len(changed_files)} changed images (commit {commit_sha[:10]})"
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@@ -134,8 +182,6 @@ def publish(source_dir, target_dir=None):
|
|||||||
elif "Object does not exist" in e.error_body:
|
elif "Object does not exist" in e.error_body:
|
||||||
retryable = True
|
retryable = True
|
||||||
|
|
||||||
from urllib.error import HTTPError
|
|
||||||
|
|
||||||
if isinstance(e, HTTPError) and e.code in [422, 500, 502, 503, 504]:
|
if isinstance(e, HTTPError) and e.code in [422, 500, 502, 503, 504]:
|
||||||
retryable = True
|
retryable = True
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user