홈으로 돌아가기

Apple Silicon에서 FLUX.2-dev GGUF Q4_K_M: 29 GB VRAM

Apple M3 Pro에서 FLUX.2-dev GGUF Q4_K_M 모델의 메모리 소비 분석 결과 예상 19 GB 대신 피크 28.92 GB. 주요 비용 항목 — MPS-overhead 및 weight dequantization. incremental transfer와 empty_cache를 사용한 최적화 제안으로 피크 1.5 GB 감소.

FLUX.2-dev GGUF의 29 GB VRAM: M3 Pro에서의 내역 및 최적화
Advertisement 728x90

FLUX.2-dev GGUF Q4_K_M, 애플 실리콘에서 29GB VRAM 사용 이유 분석

양자화된 GGUF Q4_K_M 형식의 FLUX.2-dev 모델은 이론적으로 약 19GB의 메모리를 사용해야 하지만, M3 Pro 칩이 탑재된 애플 실리콘에서는 최대 28.92GB까지 증가합니다. 분석 결과, 추가적인 메모리 사용은 MPS 오버헤드, 가중치 재양자화, 그리고 통합 메모리 내 CPU와 GPU 간 데이터 전송에 기인합니다.

로딩 아키텍처와 순차적 오프로드

FLUX.2-dev는 전체 정밀도에서 45GB VRAM이 필요한 Mistral-Small-3.2-24B 텍스트 인코더를 사용합니다. 애플 실리콘 환경에서는 MLX를 통해 4비트 버전이 사용되며, 이는 16GB의 메모리를 소모합니다. 프로세스는 순차적 오프로드 패턴을 따릅니다:

  • MLX 인코더 로드 (~13GB)
  • CPU에서 프롬프트를 임베딩으로 변환
  • 인코더 오프로드 및 캐시 정리
  • 디스크에서 DiT 모델 (GGUF Q4_K_M) 로드 (~19GB)
  • CPU에서 VAE와 스케줄러 초기화
  • 전체 파이프라인을 MPS로 전달

이론적 피크는 개별 컴포넌트 크기의 최댓값이지만, 통합 메모리 동작 방식으로 인해 현실과 다릅니다.

Google AdInline article slot

테스트 환경

  • macOS: 26.3.1 (Tahoe)
  • 칩: Apple M3 Pro, 36GB 통합 메모리
  • Python: 3.14.3
  • PyTorch: 2.11.0
  • diffusers: 0.38.0.dev
  • mlx-lm: 0.31.1

프로파일링은 phys_footprint (Activity Monitor와 유사) 및 PyTorch의 MPS 메트릭을 사용했습니다. psutil.rss는 MPS 할당을 반영하지 않습니다.

상세 메모리 사용량 분석

단계별 측정값

| 단계 | phys_footprint | MPS 드라이버 | MPS 현재 사용량 |

|-------|----------------|------------|-------------|

Google AdInline article slot

| 기본 상태 | 0.27 GB | 0 | 0 |

| MLX 인코더 로드 | 13.22 GB | 0 | 0 |

| GGUF CPU 로드 | 19.23 GB | 0 | 0 |

Google AdInline article slot

| pipe.to(mps) | 23.79 GB | 20.06 GB | 18.75 GB |

| 중간 추론 시점 | 26.50 GB | 25.62 GB | 18.78 GB |

28.92GB의 피크는 pipe.to("mps") 과정에서 발생하며, 이는 CPU와 MPS 모두에서 데이터 복사본이 동시에 존재하기 때문입니다.

28GB 피크의 구성 요소

  • DiT Q4_K_M (uint8): 18.59 GB
  • VAE (bf16): 0.16 GB
  • MPS 풀 오버헤드: +1.31 GB
  • IOKit/Metal 그래프 캐시: ~3.73 GB (셰이더, 페이지 테이블, 리무보 버퍼)

GGUF 가중치는 MPS에서 uint8 그대로 유지되며, 포워드 패스 중 레이어 단위로 bf16으로 재양자화됩니다. 임시 bf16 텐서(최대 6.92GB)는 캐시에 누적됩니다.

피크 메모리 감소를 위한 최적화 전략

  • 단계별 MPS 전송: 매 30개 파라미터마다 gc.collect()를 호출하며 하나씩 파라미터를 이동합니다.
def _move_to_device_incremental(pipe, device):
    n = 0
    for attr in list(vars(pipe)):
        comp = getattr(pipe, attr, None)
        if not isinstance(comp, torch.nn.Module):
            continue
        for param in comp.parameters():
            param.data = param.data.to(device)
            n += 1
            if n % 30 == 0:
                gc.collect()
        for buf in comp.buffers():
            buf.data = buf.data.to(device)
        gc.collect()
    torch.mps.synchronize()
    torch.mps.empty_cache()
  • 단계 간 empty_cache() 활용: 추론 단계 중 콜백을 통해 torch.mps.empty_cache()를 사용하여 재양자화 캐시를 비웁니다.
  • 생성 후 캐시 플러시: 추론 후 gc.collect()를 실행한 다음 torch.mps.empty_cache()를 호출합니다.

최적화 효과 비교

| 지표 | 전 | 후 | 차이 |

|--------|--------|-------|-------|

| 피크 phys_footprint | 28.92 GB | 27.36 GB | -1.56 GB |

| 추론 후 안정 상태 | 26.25 GB | 21.76 GB | -4.49 GB |

| 생성 시간 (1단계) | 2:04 | 2:11 | +7초 |

피크 감소는 로딩 중 단계적 가비지 컬렉션 덕분이며, 안정 상태 개선은 캐시 플러시로 인한 것입니다. 최적화 불가능한 MPS/IOKit 오버헤드는 여전히 약 3.5GB 수준입니다.

핵심 요약:

  • 안정 상태 최소값: ~24GB, 추론 피크: ~27GB
  • 주요 비용: 18.59GB의 uint8 DiT 가중치 + 3.5GB MPS 오버헤드
  • bf16 재양자화로 인한 임시 버퍼 추가: 3–5GB
  • CPU→MPS 전송은 통합 메모리로 인해 피크를 두 배로 증가시킴
  • 최적화로 피크 -1.5GB, 안정 상태 -4.5GB 감소, 품질 손실 없음

FLUX.2-dev GGUF 모델의 실제 최소 요구 메모리는 M3 Pro 기준 24+ GB의 통합 메모리입니다. 더 작은 구성에서는 보다 강력한 양자화 또는 CPU 오프로드가 필요합니다.

— Editorial Team

Advertisement 728x90

다음 읽기