본문으로 건너뛰기

© 2026 Molayo

Dev.to헤드라인2026. 05. 22. 20:30

HiDream Skeleton Mode: 프롬프트가 OpenPose 참조를 능가하다 — 8가지 패턴 벤치마크

요약

HiDream-O1-Image 모델의 스켈레톤 모드 성능을 8가지 패턴으로 벤치마킹한 결과, OpenPose 참조보다 프롬프트가 역동적인 포즈 생성에 더 효과적임을 발견했습니다. 또한 참조 개수에 따른 해상도 저하 문제와 shift 설정값에 따른 최적의 활용법을 분석했습니다.

핵심 포인트

  • 역동적인 포즈를 원할 경우 OpenPose 참조 대신 프롬프트를 사용해야 함
  • 참조 개수가 많아지면 해상도가 압축되어 디테일이 저하되므로 3~4개가 적당함
  • 용도에 따라 shift 값을 조절(Try-on: 1.0, Swap: 2.0-2.5, Scene: 3.0)해야 함
  • 스켈레톤 모드는 별도 경로 없이 multi-ref 파이프라인을 공유함

요약(TL;DR): HiDream-O1-Image (2026-05 출시, OpenWeight 8B, Artificial Analysis Text-to-Image Arena 8위 기록)를 8가지 스켈레톤 (try-on) 모드 패턴과 3가지 레이아웃 패턴에 대해 벤치마킹한 결과, 세 가지 직관에 반하는 발견이 있었습니다. OpenPose 참조(ref)를 통과시키는 것은 실제로 포즈를 해당 참조의 구도에 고정시켜 버립니다. 역동적인 포즈를 원할 때는 OpenPose 참조를 버리고 프롬프트를 통해 포즈를 지정하는 것이 더 효과적입니다. 6개의 참조(얼굴 + 배경 + 포즈 + 부위, 전체 세트)를 사용하면 각 참조가 768px로 압축되어 세부 디테일이 저하됩니다. 참조를 3~4개로 유지하면 1024px를 유지하여 더 나은 품질을 생성합니다. README에서 권장하는 shift=1.0 설정은 엄격하게 try-on 용도입니다. 포즈/의상 교체(swap)에는 shift=2.0-2.5를 사용하고, 완전한 장면 교체에는 shift=3.0을 사용하십시오. pipeline.py를 분석한 결과, 스켈레톤 모드를 위한 전용 코드 경로가 없음을 확인했습니다. /generate/skeleton과 /generate/ip는 내부적으로 정확히 동일한 multi-ref 파이프라인을 거치며, 참조가 얼굴인지, 배경인지, OpenPose인지, 또는 의상인지는 오직 프롬프트를 통해서만 전달됩니다. 이것이 모든 문제의 근본 원인입니다.

동기(Motivation): 로컬 GPU (RTX PRO 6000 Blackwell, 96 GB)에서 HiDream-O1-Image를 실행하고 자체 플랫폼에 통합하는 과정에서 한 가지 문제에 직면했습니다. 스켈레톤 (try-on) 모드가 프롬프트 지시를 따르지 않았습니다. "양손을 들고 점프하는 모습"이라고 작성해도 경직되고 똑바로 선 try-on 사진만 생성되었습니다. 가드레일(NSFW 필터, 안전 정책 등)을 의심하여 safety|nsfw|guard|filter|moderate|censor 키워드로 grep 검색을 수행했으나, HiDream의 코드베이스에는 해당 내용이 전혀 없었습니다 (유일한 검색 결과는 CSS의 backdrop-filter: blur 뿐이었습니다). MIT 라이선스를 가진 OpenWeight 모델답게 검열은 없었습니다. 그렇다면 실제로 무엇이 잘못된 것일까요? pipeline.py를 읽고 실제 하드웨어에서 8 + 3 패턴을 실행한 후 발견한 내용은 다음과 같습니다.

GPU 환경: NVIDIA RTX PRO 6000 Blackwell Max-Q (96 GB VRAM)
PyTorch: 2.12.0 + CUDA 13.0
flash-attn: 2.8.3 (sm_120-only build)
모델: HiDream-O1-Image Full (8B, bf16, ~16.4 GiB resident)
추론 서버: custom Python BaseHTTPRequestHandler (port 8895)
해상도: pipeline 내부 버킷이 2048×2048로 스냅(snap) 강제

50단계 생성당 측정된 실제 시간 (Measured wall time):

모드시간반복 속도 (iter speed)
t2i (참조 없음)~33s1.52 it/s
edit (참조 1개)~76s1.01 it/s
skeleton (다중 참조)~84s1.34 it/s
ip (다중 참조)~76s1.81 it/s
layout (다중 참조 + bbox)~83s1.21 it/s

테스트 자산 (Test Assets)
HiDream 저장소의 assets/IP_skeleton/에는 전체 스켈레톤(skeleton) 세트가 포함되어 있습니다. 이들은 모든 테스트에서 있는 그대로 사용됩니다.

참조 (ref)콘텐츠의도된 역할
Person's face photo인물 얼굴 사진정체성 참조 (Identity reference)
Stick figure in OpenPose formatOpenPose 형식의 졸라맨포즈 지정 (Pose specification)
Background photo (interior)배경 사진 (실내)장면 참조 (Scene reference)
Clothing parts (sweater, boots)의류 부품 (스웨터, 부츠)의상 참조 (Outfit reference)

8-패턴 스켈레톤 벤치마크 (8-Pattern Skeleton Benchmark)
각 패턴은 /api/studio/skeleton을 호출합니다 (즉, skeleton-mode와 동일한 인자를 사용하는 generate_image()). shift와 guidance_scale을 제외한 모든 파라미터는 고정되었습니다 (50 steps, seed=42).

A — 베이스라인 (README 기본값, 6개 참조 모두 사용)
curl -X POST http://localhost:8895/generate/skeleton
-H 'Content-Type: application/json'
-d '{ "prompt": "Create a realistic try-on image of the person wearing the provided clothing.", "ref_image_paths": ["face","bg","openpose","part_1","part_2","part_3"], "shift": 1.0, "seed": 42 }'

결과: bg 참조의 벽과 선반이 정확하게 재현됩니다. 포즈 또한 openpose 참조의 직립 자세와 일치합니다. 착용(try-on) 결과물로서는 충실하지만, 움직임의 자유도는 전혀 없습니다.

B — 높은 shift (동일한 6개 참조, shift=2.5)
curl -X POST http://localhost:8895/generate/skeleton -d '{ "prompt": "Create a realistic try-on image of the person wearing the provided clothing.", "ref_image_paths": ["face","bg","openpose","part_1","part_2","part_3"], "shift": 2.5, "seed": 42 }'

결과: 선반이 약간 흐릿해지며, 캐릭터 디자인이 조금 변합니다. 배경은 여전히 bg 참조를 유지합니다.

shift 값만 높이는 것으로는 bg (배경) 참조의 영향력을 완전히 끊어낼 수 없습니다. C — guidance (가이드) 값도 함께 높이기 (shift=2.5, guidance=7.0)

curl -X POST http://localhost:8895/generate/skeleton -d '{ "prompt": "...", "ref_image_paths": [...6 refs...], "shift": 2.5, "guidance_scale": 7.0, "seed": 42 }'

결과: 목걸이가 이상하게 변형됩니다. guidance 값을 높이면 아티팩트 (artifacts)가 발생하기 시작합니다. Full 모델의 최적 지점 (sweet spot)은 5.0이며, 7.0은 너무 과합니다.

D — 3개의 참조로 축소 (얼굴 + openpose + 스웨터) + 구체적인 프롬프트 (prompt)

curl -X POST http://localhost:8895/generate/skeleton -d '{ "prompt": "A young Asian woman wearing a gray oversized sweater dress, standing in a relaxed pose, full body shot, soft natural lighting, white studio background.", "ref_image_paths": ["face","openpose","part_1"], "shift": 2.0, "seed": 42 }'

결과: 대폭 개선되었습니다. 배경은 깨끗한 화이트 스튜디오가 되고, 의상은 보존되며, 포즈는 자연스러워 보입니다. bg 참조를 제거한 것이 가장 큰 차이를 만들었습니다. 이것이 바로 올바른 try-on (가상 착용) 결과물이어야 하는 모습입니다.

E — 4개의 참조 + 번호가 매겨진 참조 프롬프트 (numbered-ref prompt)

curl -X POST http://localhost:8895/generate/skeleton -d '{ "prompt": "Full body try-on photograph. Subject: the woman from image 1. Pose: identical to the skeleton in image 2. Wearing: the gray oversized knit sweater dress shown in image 3, brown leather ankle boots shown in image 4. Studio lighting, plain background.", "ref_image_paths": ["face","openpose","part_1","part_2"], "shift": 2.0, "seed": 42 }'

결과: D와 대등한 품질이며, 부츠가 (다소 미묘하게) 반영되었습니다. 프롬프트에서 참조에 번호를 매기는 것이 도움이 되긴 하지만, 그 효과가 극적이지는 않습니다.

F — OpenPose를 제거하고 프롬프트로 포즈 지정
curl -X POST http://localhost:8895/generate/skeleton -d '{ "prompt": "Full body photograph of the woman wearing the gray sweater dress and brown ankle boots, dynamic dancing pose with both arms raised above her head, joyful expression, photo studio with white seamless background, professional lighting.", "ref_image_paths": ["face","part_1","part_2"], "shift": 2.5, "seed": 42 }'
결과 : 🏆 양팔을 머리 위로 올린 점프 동작, 완벽한 성공. 역동적인 움직임은 OpenPose 참조를 제거하고 포즈를 순수하게 프롬프트로 지정했을 때만 나타났습니다. 이는 OpenPose 참조가 프롬프트 기반의 포즈를 억제한다는 것을 확인시켜 줍니다.

G — 얼굴만 사용 + 자유 형식 프롬프트 (전체 의상 교체)
/generate/skeleton은 최소 2개의 참조(refs)를 요구하는 유효성 검사가 있으므로, /generate/ip를 사용합니다 :
curl -X POST http://localhost:8895/generate/ip -d '{ "prompt": "Elegant full-body portrait of the woman wearing a vibrant red sequined evening gown with a thigh-high slit, standing confidently with one hand on her hip, soft cinematic lighting, dark blurred background.", "ref_image_paths": ["face"], "shift": 3.0, "seed": 42 }'
결과 : 🏆 빨간색 이브닝 가운이 완벽하게 생성되었습니다. 얼굴의 정체성(Facial identity)은 유지되었으며, 그 외 모든 것은 자유롭습니다. 얼굴 전용 + shift=3.0은 최대 자유도(maximum-freedom) 패턴입니다.

H — E와 동일한 설정, seed=999 (변동성 확인)
curl -X POST http://localhost:8895/generate/skeleton -d '{ "prompt": "Full body try-on photograph. ...", "ref_image_paths": ["face","openpose","part_1","part_2"], "shift": 2.0, "seed": 999 }'
결과 : E와 미미한 차이만 있음; 부츠가 좀 더 명확하게 갈색으로 나옵니다. 시드(seed)를 변경하는 것은 세부 사항을 미세 조정(fine-tuning)하는 데 유용하므로, 실제 운영 환경에서는 3~5개의 시드를 실행하고 그중 최적의 결과(best-of-N)를 선택하는 것이 표준 관행입니다.

레이아웃 모드(Layout Mode) 요약 (3가지 추가 패턴)
layout_bboxes를 사용하면 상대 좌표 [x1, x2, y1, y2]를 사용하여 이미지 내에 여러 피사체가 나타날 위치를 지정할 수 있습니다. 실제 동작은 다음과 같습니다.

입력 참조(Input refs)는 두 사람(여성, 남성)의 얼굴 사진입니다:

L1 — 나란히 배치 (여성 왼쪽, 남성 오른쪽)
"layout_bboxes" : "[[0.0,0.5,0.1,0.95],[0.5,1.0,0.1,0.95]]"
결과: 좌우가 바뀌어 나타남 (남성 왼쪽, 여성 오른쪽). 참조 순서와 bbox(Bounding Box) 순서 사이의 일치성은 보장되지 않습니다.

L2 — 상/하 분할 (여성 상단, 남성 하단)
"layout_bboxes" : "[[0.2,0.8,0.0,0.5],[0.2,0.8,0.5,1.0]]"
결과: 여성이 배경에, 남성이 전경에 나타남 — 문자 그대로의 상/하 분할이 아닌, 깊이감이 레이어링된 구도로 나타납니다.

L3 — 크기 차이 (여성 크게, 남성 작게)
"layout_bboxes" : "[[0.1,0.65,0.1,0.95],[0.7,0.97,0.05,0.45]]"
결과: 두 피사체 모두 거의 동일한 크기로 나란히 렌더링됨. Bbox 크기는 상대적 스케일(scale)을 제어하지 못합니다.

→ 레이아웃 모드를 Photoshop 스타일의 정밀한 배치 도구가 아닌, 그룹 샷을 위한 느슨한 구도 힌트로 생각하십시오. 이는 여러 피사체를 단일 이미지에 맞추기 위한 대략적인 제안을 제공할 뿐이며, 좌표의 정확성을 기대해서는 안 됩니다.

이러한 현상이 발생하는 이유 — pipeline.py 분석
HiDream의 동작은 models/pipeline.py에 있는 generate_image() 함수에 의해 제어됩니다. 세 가지 구조적 사실이 모든 것을 설명합니다.

  1. 참조(ref)가 많아질수록 참조당 해상도가 낮아짐
    pipeline.py:198-202 :
    if K == 1 :
    max_size = max ( height , width ) # 2048
    elif K == 2 :
    max_size = max ( height , width ) * 48 // 64 # 1536
    elif K <= 4 :
    max_size = max ( height , width ) // 2 # 1024
    elif K <= 8 :
    max_size = max ( height , width ) * 24 // 64 # 768
    else :
    max_size = max ( height , width ) // 4 # 512

6개의 참조를 입력하면 각각 768px로 압축됩니다. 얇은 OpenPose 선, 미세한 의상 패턴, 얼굴 디테일이 모두 뭉개지게 됩니다. 참조를 3~4개로 유지하면 1024px를 보존하여 디테일을 유지할 수 있습니다.

  1. 스켈레톤 모드(Skeleton mode)를 위한 전용 코드 경로가 없음
    pipeline.py:178-275를 살펴보면, 스켈레톤 전용 분기(branch)가 존재하지 않습니다. /generate/skeleton과 /generate/ip는 모두 정확히 동일한 다중 참조(multi-ref) 경로를 거칩니다:
    content = [{ " type " : " image " } for _ in range ( K )]
    content .

append({ "type": "text", "text": caption}) messages = [{ "role": "user", "content": content }] 모델은 어떤 참조(ref)가 얼굴인지, 어떤 것이 OpenPose 스켈레톤(skeleton)인지, 그리고 어떤 것이 의상인지 나타내는 역할 힌트(role hints)를 전혀 받지 못합니다. 모든 참조는 "K개의 참조 이미지가 병렬로 제공됨"으로 취급됩니다. 만약 역할(roles)이 중요하게 작용하길 원한다면, 프롬프트 텍스트에서 이를 명시적으로 말해야 합니다. 이것이 바로 "프롬프트가 OpenPose 참조를 능가하는(prompt beats openpose ref)" 이유입니다. OpenPose 참조는 포즈 지정이라는 명시적인 신호 없이 "참조 이미지들 중의 어떤 라인 아트(line-art) 이미지"로 처리됩니다. 반면, 프롬프트에 포함된 "양팔을 들어 올린 역동적인 춤 동작(dynamic dancing pose with both arms raised)"은 어휘 수준(vocabulary level)에서 명시적인 동사와 명사로 파싱됩니다.

  1. shift 파라미터의 동작 방식
    shift는 스케줄러(scheduler)의 노이즈 스케줄 강도(noise schedule strength)를 제어합니다. 실제 적용 시:
    1.0 = 참조 구성에 대한 최대 충실도, 자유도 없음 → 시착(try-on) 전용
    2.0-2.5 = 실용적인 범위, 참조로부터의 이탈 허용
    3.0+ = 거의 자유 형식(freeform) 생성, 참조는 오직 정체성 앵커(identity anchors) 역할만 수행

README에서는 IP/Skeleton/Layout의 경우 1.0을 권장하는데, 이는 일반적인 시착(try-on) 또는 캐릭터 일관성(character-consistency) 사용 사례를 가정하기 때문입니다. 만약 포즈를 바꾸거나, 의상을 교체하거나, 참조와 다른 새로운 장면을 구축하고 싶다면 2.0 이상의 값이 필요합니다.

사용 사례별 베스트 프랙티스 (검증 완료)

목표엔드포인트(Endpoint)참조(Refs)Shift비고
충실한 시착(Faithful try-on)matching original scene /skeleton6 (face+bg+pose+3parts)1.0README 기본값. 모든 참조에 매우 충실함
의상 유지 + 자연스러운 서 있는 포즈/skeleton3-4 (face + clothing, no bg/pose)2.0배경(bg) 참조를 제거하면 흰색 스튜디오가 됨; 참조 수가 적을수록 각 이미지는 768→1024px 유지
극적인 포즈 변화/skeleton3 (no openpose)2.5프롬프트가 OpenPose 참조보다 동작을 더 잘 제어함
완전한 의상 교체/ip1 (face only)3.0최대 자유도; 오직 얼굴만 보존됨

스켈레톤 모드(Skeleton mode)는 < 2개의 참조(refs)를 거부함 | 그룹 샷 / 레이아웃(layout) | 다중 얼굴 참조 + 거친 바운딩 박스(bboxes) | 1.0 | 바운딩 박스(Bboxes)는 느슨한 구도 힌트일 뿐이며, 크기 계층 구조가 작동하지 않고 참조(ref)와 바운딩 박스(bbox) 간의 순서가 보장되지 않음 | 미세 디테일 최적화 | 동일한 설정 | 동일함 | 동일함 | 3~5개의 시드(seeds)를 실행하고 최적의 N개(best-of-N)를 선택함 |

요약: HiDream-O1-Image의 스켈레톤 모드(skeleton mode)를 "착용 시뮬레이터(try-on simulator)"로 취급하면, 잘못된 가드레일(guardrails)을 탓할 수밖에 없는 "말을 듣지 않는다"는 좌절감을 느끼게 됩니다. 진짜 원인은 파이프라인(pipeline) 구조에 있습니다. 참조(refs)의 수가 증가함에 따라 해상도가 손실되고, 스켈레톤 전용 프로세싱(skeleton-specific processing)이 없으며, 시프트(shift) 값이 참조(refs)가 얼마나 강하게 끌어당기는지를 제어합니다.

실질적인 권장 사항:
착용(Try-on): 6개의 참조(refs) 전체 + 시프트(shift) 1.0 (README 기본값)
포즈 변경: OpenPose 참조(ref) 제거 + 프롬프트(prompt)에 포즈를 동사로 묘사 + 시프트(shift) 2.5
완전 자유로운 장면 생성: 얼굴만(face only) + 시프트(shift) 3.0 + /ip 엔드포인트(endpoint)

레이아웃 모드(Layout mode) 또한 이를 "정밀한 바운딩 박스(bbox) 배치"가 아닌 "그룹 사진 힌트(group photo hint)"로 이해하면 타당해집니다. 이 벤치마크(benchmark)에 사용된 모든 에셋(assets)과 명령(commands)은 HiDream-O1-Image 리포지토리(repository)의 assets/IP_skeleton/assets/IP_layout/ 디렉토리에서 가져왔으므로, 결과는 완전히 재현 가능합니다. 시프트(shift)와 참조(ref) 수만 변경해도 극적으로 다른 동작을 생성하므로, 직관을 빠르게 기르기에 좋은 샌드박스(sandbox)입니다.

부록: OpenPose 참조(ref)를 변경할 때 발생하는 일 — "프롬프트가 항상 승리한다"에는 조건이 있다
게시 후, 다른 형태의 OpenPose 참조(ref)를 사용할 때 어떤 일이 발생하는지에 대해 추가 테스트를 수행했으며, 원래의 결론을 수정할 필요가 있었습니다.

수정된 OpenPose 참조(4가지 패턴): 원래의 OpenPose 이미지(0.openpose.jpg, 서 있는 포즈)를 가져와 뒤집기(flip)

AI 자동 생성 콘텐츠

본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.

원문 바로가기
0

댓글

0