3편에서 AWS 환경 세팅을 마쳤다.
이제 Qwen-Image-Edit-2511 모델을 실제로 올려보자.
생각보다 순탄하지 않았다.
작업 폴더를 만들고 모델을 내려받는다.
모델 크기가 약 40GB라 시간이 좀 걸린다.
mkdir -p ~/qwen-project
cd ~/qwen-project
from huggingface_hub import snapshot_download
snapshot_download(
repo_id="Qwen/Qwen-Image-Edit-2511",
local_dir="./model",
local_dir_use_symlinks=False,
resume_download=True
)
resume_download=True 덕분에 중간에 끊겨도 이어받을 수 있다 !
모델을 GPU에 전부 올리는 방식으로 시작했다.
pipeline = QwenImageEditPlusPipeline.from_pretrained(
"Qwen/Qwen-Image-Edit-2511",
torch_dtype=torch.float16,
device_map="cuda",
low_cpu_mem_usage=True
)
바로 에러가 떴다.
torch.OutOfMemoryError: CUDA out of memory.
Tried to allocate 72.00 MiB.
GPU 0 has a total capacity of 21.99 GiB of which 69.38 MiB is free.
Of the allocated memory 21.48 GiB is allocated by PyTorch
VRAM 상태를 보면 이렇다.
Total VRAM : 21.99 GiB
사용 중 : 21.91 GiB (99.6%)
├─ PyTorch : 21.48 GiB
└─ 기타 : 0.43 GiB
남은 공간 : 0.069 GiB (69MB)
72MB가 필요한데 69MB밖에 없었다.
모델이 VRAM을 꽉 채워버린 것이다.
GPU 메모리가 부족하면 자동으로 CPU로 offload하는 방식으로 바꿨다.
pipeline = QwenImageEditPlusPipeline.from_pretrained(
"Qwen/Qwen-Image-Edit-2511",
torch_dtype=torch.float16,
device_map="balanced",
low_cpu_mem_usage=True
)
실행은 됐다.
근데 문제가 생겼다.
40%|████████| 12/30 [4:09:33<6:09:14, 1230.82s/it]
30 스텝 중 12번째(40%)에 4시간 9분이 걸렸다.
스텝당 약 20분, 총 예상 시간이 10시간이 넘었다.
GPU와 CPU를 계속 왔다갔다하면서 속도가 처참하게 느려진 것이다.
결국 KeyboardInterrupt 로 중단했다.
VRAM 사용량을 줄이려면 데이터 타입을 낮추면 된다.
# 기존
torch_dtype=torch.float16
# 변경 시도
torch_dtype=torch.float8
바로 막혔다.
PyTorch에는 torch.float8 이 없다 !
AttributeError: module 'torch' has no attribute 'float8'
float16보다 더 낮은 타입을 쓰려면 다른 방법이 필요했다.
원래 쓰던 서버는 VRAM 8GB였다.
모델 자체가 너무 커서 8GB로는 아예 올라가지도 않았다.
서버를 교체했지만 모델 전체를 다 올릴 수 있는 사양으로 바꾼 건 아니었다.
그래서 두 가지를 함께 적용했다.
sequential CPU offload — 레이어 단위로 필요할 때만 GPU에 올리고 나머지는 CPU에 둔다.
model 방식보다 느리지만 메모리를 훨씬 적게 쓴다.
pipeline.enable_sequential_cpu_offload()
bfloat16으로 타입 변경 — float16 대비 수치 안정성이 높고 메모리 사용량은 동일하다.
torch_dtype=torch.bfloat16
이 두 가지 조합으로 정상적으로 동작했다 !
서버를 바꾼 뒤 정상적으로 동작했다.
GPU 상태도 안정적이었다.

GPU 사용률 : 89%
온도 : 73°C
전력 : 58W / 72W
메모리 사용 : 890 MiB / 23034 MiB (약 3.9%)
여유 메모리 : 약 21.6 GB
원본 사진에 다양한 각도와 스타일 변환을 적용해봤다.
원본 강아지 사진

right side view high-angle shot close-up

back side view high-angle shot close-up

left side view high-angle shot close-up


지브리 스타일 변환에 사용한 프롬프트다.
Transform the actual photo provided into an anime-style landscape scene.
Keep the core composition and elements from the original photo,
but render everything in vibrant anime aesthetics with exaggerated colors,
dynamic lighting, soft gradients, and cel-shaded outlines typical of
Studio Ghibli-inspired landscapes.


LoRA까지 붙이고 외부에서 접근할 수 있는 Gradio 서버를 구축했다.

단일 편집과 배치 편집(다중 각도 한 번에 생성) 두 가지 탭으로 구성했다.
import gradio as gr
import torch
from PIL import Image
from diffusers import QwenImageEditPlusPipeline
import gc
import os
os.environ['PYTORCH_CUDA_ALLOC_CONF'] = 'expandable_segments:True'
pipeline = QwenImageEditPlusPipeline.from_pretrained(
"./model",
torch_dtype=torch.bfloat16
)
pipeline.enable_sequential_cpu_offload()
pipeline.load_lora_weights(
"fal/Qwen-Image-Edit-2511-Multiple-Angles-LoRA",
adapter_name="multi_angle"
)
pipeline.set_adapters(["multi_angle"], adapter_weights=[0.9])
서버는 0.0.0.0:7860 으로 띄운다.
demo.launch(
server_name="0.0.0.0",
server_port=7860,
share=False,
debug=True
)

일반적인 Diffusion 모델과 파라미터가 다르다.
공식 문서 기준으로 아래 값을 써야 제대로 동작한다.
output = pipeline(
image=[img], # 리스트로 전달
prompt=prompt,
negative_prompt=" ", # 빈 문자열이 아닌 공백 하나
true_cfg_scale=4.0, # Qwen 필수 파라미터
guidance_scale=1.0, # Qwen 기본값
num_inference_steps=20,
)
negative_prompt=" " 에서 "" 이 아니라 " " (공백 하나)를 써야 한다.
처음엔 이걸 몰라서 한참 헤맸다 !
T4에서 삽질하면서 배운 최적화 포인트 4가지다.
| 항목 | 변경 전 | 변경 후 | 효과 |
|---|---|---|---|
| CPU Offload | model | sequential | 메모리 절약 |
| 환경 변수 | 없음 | expandable_segments | 단편화 방지 |
| 이미지 크기 | 원본 그대로 | 512px | 메모리 1/4 감소 |
| Steps | 40 | 20 | 속도 2배 향상 |
1024x1024 → 512x512로 줄이는 것만으로 메모리 사용량이 1/4로 줄어든다 !
처음엔 단순히 모델을 올리는 거라 쉽게 생각했는데, VRAM 용량과 속도 사이에서 꽤 고생했다.
이번에 배운 건 하나다.
VRAM이 모델 크기를 전부 수용할 수 있으면 제일 좋다.
하지만 그렇지 않더라도 방법이 있다.
서버 사양이 부족하다고 바로 포기할 필요가 없다는 걸 직접 경험했다.
물론 속도 트레이드오프는 있다. 하지만 테스트 목적이라면 충분히 쓸 만하다 !