[태그:] Diffusion Transformer

  • Anima RKNN 추론 최적화: Spectrum으로 생성 시간 41% 단축

    Anima RKNN 추론 최적화: Spectrum으로 생성 시간 41% 단축

    제휴 링크 안내: 이 글에는 알리익스프레스 제휴 링크가 포함되어 있으며, 링크를 통해 구매하면 작성자가 수수료를 받습니다.

    1. 이미지 생성 시간을 줄이려면

    단일 보드 컴퓨터(Single Board Computer, SBC) 환경에서 대규모 확산 변환기(Diffusion Transformer, DiT)를 온디바이스로 구동할 때는 메모리 제약과 연산 시간이 주요 병목이다. Radxa 알리익스프레스 공식 스토어에서 직접 구매한 Radxa ROCK 5C 8GB 보드를 사용해 2026년 8월 환경 기준으로 Anima DiT 추론 최적화 실험을 진행했다.

    512×512 이미지의 20스텝 디노이징에는 2,408.54초가 걸렸다. VAE로 이미지를 복원하는 시간까지 합하면 한 장을 만드는 데 30분을 넘겼다. 계산량을 줄이면서 결과의 화질을 유지할 방법이 필요했다.

    1편에서 실행한 FP16 RKNN 구성에 Spectrum을 적용했다. Euler 스케줄러는 유지하면서 일부 스텝의 모델 계산을 이전 결과에 기반한 예측으로 대체하고, 속도와 화질을 비교했다.

    2. 비교에 사용한 하드웨어와 모델 구성

    실험 하드웨어는 Rockchip RK3588S2 SoC와 8GB 시스템 메모리를 탑재한 Radxa ROCK 5C 단일 보드 컴퓨터다.

    RKNN 런타임 타깃은 rk3588이다. 실험 장비는 ROCK 5C 8GB이며, 같은 상품 페이지의 ROCK 5C Lite와 구분해야 한다.

    Anima의 28개 DiT 블록을 self-attention·cross-attention·FFN으로 나눈 84개 FP16 RKNN 모델을 사용했다. 기본 변환 구조는 1편에서 다룬 구성과 같다.

    NPU는 주요 행렬·어텐션 연산을 처리한다. CPU는 AdaLN과 FP32 잔차 누적, Euler 스케줄러, 텍스트 인코딩과 VAE 디코딩을 담당한다. Spectrum을 추가한 뒤에도 이 역할 분담은 유지했다.

    3. Spectrum은 어떤 계산을 생략하는가

    Spectrum은 Euler를 대체하는 샘플러가 아니다. 이전 계산 결과로 현재 스텝의 denoised 상태를 예측해 모델 재계산을 줄이는 캐싱 기법이다. stable-diffusion.cpp의 Spectrum 구현을 NumPy로 옮겨 Euler 루프에 적용했다.

    Spectrum의 핵심 원리는 확산 과정에서 스텝 간 잠재 변수의 궤적이 급격하게 변화하지 않는 특성을 활용하여, 이전 히스토리 버퍼로부터 denoised 상태인 \(x_0\) 추정치를 예측(forecasting)하는 방식이다.

    각 스텝에서 직접 계산과 예측 중 하나를 선택한다. 두 경로 모두 같은 Euler 스케줄러에 결과를 전달한다.

    • 직접 계산하는 스텝에서는 조건부·무조건부 출력을 CFG로 합성하고, x₀ = xₜ − σ × prediction으로 denoised 상태를 구해 이력에 저장한다.
    • 예측 스텝에서는 이전 이력으로 현재의 x₀를 추정해 NPU 모델 계산을 생략한다.
    • 추정한 x₀는 prediction = (xₜ − x₀) / σ로 흐름 예측값에 되돌린다. 두 경로 모두 같은 Euler 적분기로 다음 상태를 갱신한다.

    이 구조 덕분에 스케줄러 자체는 FlowMatch Euler 방식을 유지하면서도 NPU에 가해지는 텐서 연산 횟수를 줄일 수 있다.

    4. 20스텝 중 11회 계산, 9회 예측

    20스텝 실행에서 직접 계산한 스텝과 예측으로 대체한 스텝은 다음과 같다.

    • 실제 모델 계산 스텝 (11회): Step 1, 2, 3, 4, 6, 8, 11, 14, 18, 19, 20
    • 상태 예측 건너뛰기 스텝 (9회): Step 5, 7, 9, 10, 12, 13, 15, 16, 17

    처음 4개 스텝은 모두 계산해 예측에 필요한 이력을 쌓았다. 중간 구간에서는 9개 스텝을 예측으로 대체했고, 마지막 18~20스텝은 다시 직접 계산했다.

    20-Step Sampling Policy: Baseline vs Spectrum Forecasting
    20-Step Sampling Policy: Baseline vs Spectrum Forecasting

    여기서 계산 스텝 11회는 NPU 실행 11회를 뜻하지 않는다. CFG 한 번에는 조건부·무조건부 입력에 대한 DiT 평가가 각각 필요하다.

    각 transformer 평가는 28개 블록에 배치된 84개의 RKNN 서브그래프를 순회하므로, 1회의 CFG 평가는 168회(84 × 2)의 서브그래프 NPU 실행으로 구성된다. 따라서 Spectrum 파이프라인의 11회 모델 계산은 다음과 같은 실제 하드웨어 순회량을 가진다.

    • 전체 모델 순회(Transformer Pass): 11회 × 2 = 22회
    • 서브그래프 NPU 실행 횟수: 11회 × 2 × 84개 = 1,848회

    반면 기준선 파이프라인은 20스텝 동안 40회의 transformer pass와 3,360회의 서브그래프 NPU 실행을 거친다. 즉, Spectrum은 정확히 18회의 모델 순회와 1,512회의 서브그래프 실행을 건너뜀으로써 하드웨어 부하를 절감했다.

    5. 실측 결과: 전체 생성 시간 41.02% 단축

    기준선과 Spectrum은 같은 ROCK 5C 8GB에서 비교했다. 해상도 512×512, 20스텝, CFG 4.0, 시드 20260812를 동일하게 고정했다.

    평가 항목 기존 비캐시 FP16 RKNN + sd-cpp VAE Spectrum 가속 시험 파이프라인 변화폭 및 배율
    20-step Denoise 시간 2,408.54초 1,356.58초 1,051.96초 단축 (43.68% 감소, 1.775배 가속)
    sd-cpp tiled CPU VAE 디코딩 155.04초 155.46초 +0.42초 (동일 범주의 실행 변동)
    합계 소요 시간 (프롬프트 인코딩 제외) 2,563.58초 1,512.04초 1,051.54초 단축 (41.02% 감소, 1.695배 가속)

    실측 수치가 보여주는 병목과 최적화의 특성은 다음과 같다.

    1. Denoise 연산 가속의 집중: 순수 20스텝 denoise 소요 시간은 기준선 2,408.54초에서 Spectrum 시험 시 1,356.58초로 1,051.96초 감소했다. 이는 43.68%의 시간 단축이자 1.775배의 속도 향상이다. 20스텝 중 9스텝의 연산(45%)을 건너뛴 비율과 거의 일치하는 선형적 가속 효율을 달성했다.
    2. VAE 디코딩의 독립성: ggml 백엔드 기반 ARM NEON/OpenMP로 구동되는 sd-cpp 경량 타일드 CPU VAE 디코더는 기준선 155.04초, Spectrum 파이프라인 155.46초로 0.42초의 차이를 보였다. 이번 비교에서 VAE 시간은 거의 같았으며, 시간 절감은 주로 denoise 구간에서 나타났다.
    3. 전체 파이프라인 가속: 프롬프트 인코딩을 제외한 전체 파이프라인 합계 소요 시간은 기준선 2,563.58초(약 42분 43초)에서 1,512.04초(약 25분 12초)로 1,051.54초 단축되었다. 전체 생성 파이프라인은 41.02% 단축되어 1.695배의 가속을 달성하였으며, 30분 이내 생성을 달성하겠다는 프로젝트 목표를 충족했다.

    6. 빨라진 결과의 화질은 어떤가

    스텝 예측을 수행하는 캐시 알고리즘은 누적 오차로 인해 잠재 공간이 발산하거나 비정상적인 수치(NaN, Inf)를 생성할 위험이 있다. 따라서 파이프라인 완료 직후 생성된 텐서에 대한 수치 검증과 이미지 레벨의 품질 검증을 단계별로 수행했다.

    20스텝을 완료한 최종 잠재 변수에서 NaN과 Inf는 발생하지 않았다. 수치가 발산하지 않는지는 최종 이미지의 화질과 별도로 확인했다.

    512×512 생성 이미지는 이 실험의 육안 화질 기준을 충족했다. 따라서 이번 조건에서는 생성 시간을 줄이면서 허용 가능한 결과를 얻었다.

    본 사용자 육안 판정 결과는 특정 조건(512×512 해상도, 20 스텝, Guidance Scale 4.0, Seed 20260812)의 단일 실험 1건에 한정된 검증이다. Spectrum의 \(x_0\) 예측은 수학적으로 완전한 무손실(lossless) 계산이 아니며, 근사 예측에 따른 미세한 잠재공간 오차가 존재한다. 따라서 이 결과가 기준선과의 완벽한 수치적 일치를 의미하거나, 임의의 다른 프롬프트와 시드에서도 품질 저하가 전혀 발생하지 않는다는 무손실 품질을 보증하는 것은 아니다.

    7. 같은 가중치로 기준선과 비교하기

    Spectrum은 어느 스텝을 직접 계산할지 바꾸며, 모델 가중치를 다시 양자화하거나 변환하는 방식이 아니다.

    같은 84개 FP16 RKNN 모델을 사용하므로, 예측 캐싱을 끄면 모든 스텝을 계산하는 기준선으로 돌아갈 수 있다.

    • 같은 프롬프트·시드·스텝 수로 캐싱을 켠 결과와 끈 결과를 비교한다.
    • 수치 안정성뿐 아니라 최종 생성 이미지의 화질도 함께 확인한다.
    • 새 조건에서 품질이 기준에 못 미치면 예측을 끄고 전체 스텝을 계산한다.

    이번 조건에서는 총 생성 시간이 41.02% 줄었다. 다른 프롬프트와 시드에 적용할 때도 기준선과 화질을 비교한 뒤 사용할 필요가 있다. 3편에서는 연산 속도를 줄여도 화질이나 메모리 때문에 채택하지 못한 다른 최적화를 살펴본다.

  • Anima RKNN 최적화의 한계: W8A8 화질 실패와 8GB 모델 상주 실험

    Anima RKNN 최적화의 한계: W8A8 화질 실패와 8GB 모델 상주 실험

    제휴 링크 안내: 이 글에는 알리익스프레스 제휴 링크가 포함되어 있으며, 링크를 통해 구매하면 작성자가 수수료를 받습니다.


    1. 더 빠른 추론을 위한 두 가지 시도

    ROCK 5C 8GB에서 Anima 추론을 실행한 뒤, FFN 양자화와 모델 상주라는 두 가지 최적화를 비교했다. 보드는 RK3588S2를 탑재했으며, 실험은 2026년 8월 RKNN-Toolkit2 2.3.2 환경에서 진행했다.

    1편과 같은 84개 FP16 RKNN 분할 구성을 기준으로 삼았다. NPU가 attention과 FFN을 처리하고 CPU가 AdaLN과 FP32 잔차 누적을 담당한다. 이번 질문은 계산을 더 빠르게 하거나, 반복되는 모델 준비 시간을 줄일 수 있는가다.

    512×512 고정 해상도에서 84개 서브그래프를 순차 실행하는 구조는 매 스텝마다 모델을 로드, 초기화, 해제하는 고유한 오버헤드를 발생시킨다. 이에 따라 시스템 최적화를 위한 두 가지 핵심 가설을 설정했다. 1. 연산 가속 가설: 연산 부하가 큰 FFN 레이어에 W8A8 정수 양자화를 적용해 NPU 실행 시간을 단축한다. 2. 라이프사이클 단축 가설: 84개 RKNN 모델의 런타임 컨텍스트를 메모리에 상주(Resident Context)시켜 매 스텝 반복되는 로드 및 초기화 시간을 제거한다.

    이 두 가지 접근법을 ROCK 5C 8GB 환경에서 실측 검증한 결과, 화질 저하와 물리 메모리 한계라는 구체적인 병목에 직면했다.


    2. FFN 양자화로 디노이징 시간 18.48% 단축

    DiT의 전체 84개 RKNN 서브그래프 중 연산량이 집중된 28개 블록의 FFN(Feed-Forward Network) 영역에 정수 양자화를 적용했다. FFN 내부의 Linear(2048→8192) 및 Linear(8192→2048) 레이어의 weight와 activation을 INT8로 양자화(W8A8)하고, 비선형 활성화 함수인 GELU와 분기 출력부는 FP16으로 유지하는 하이브리드 빌드 방식을 채택했다. self-attention 및 cross-attention 코어는 기존 FP16 구성을 유지했으며, 호스트 측의 residual stream 역시 FP32 정밀도를 보존했다.

    양자화 보정에는 기존 FP16 디노이징 과정에서 수집한 활성화 텐서를 사용했다. 높은 시그마·낮은 시그마와 조건부·무조건부 CFG 분기를 조합해 블록당 4개, 총 112개를 수집했다. 28개 FFN 블록이 모두 변환되었다.

    동일한 초기 잠재 변수(seed: 20260812), 프롬프트 컨텍스트, CFG 4.0 스케일, 20스텝 조건에서 성능을 비교 측정한 결과는 다음과 같다.

    항목 기존 FP16 FFN Linear W8A8 변화량
    20스텝 디노이즈 시간 2,408.54초 1,963.45초 445.09초 단축 (18.48% 개선)
    스텝당 평균 소요 시간 120.40초 98.15초 22.25초 단축
    스텝당 평균 FFN 코어 실행 44.76초 23.57초 1.90배 가속
    스텝당 평균 Self 코어 실행 24.00초 25.74초 실행 편차 수준
    스텝당 평균 Cross 코어 실행 7.45초 7.69초 실행 편차 수준

    전체 디노이징은 1.227배, 양자화를 적용한 FFN 구간은 1.90배 빨라졌다. 실행 중 NaN과 Inf는 발생하지 않았다.


    3. 실행은 빨라졌지만 화질은 기준 미달

    디노이징 시간은 18.48% 줄었지만, VAE 디코딩을 거친 512×512 이미지는 육안 화질 기준을 충족하지 못했다.

    수치가 발산하지 않는 것과 이미지의 품질이 충분한 것은 별개였다. 이번 W8A8 구성은 수치 안정성은 유지했지만 화질 기준을 통과하지 못했다.

    따라서 FFN 양자화는 채택하지 않고 FP16 구성으로 돌아갔다. 생성 모델의 최적화는 실행 시간뿐 아니라 최종 이미지 품질을 함께 비교해야 한다.


    4. 모델을 메모리에 두면 줄일 수 있는 시간

    화질 저하 없이 추론 시간을 단축하기 위해 다음으로 검토한 가설은 84개 서브그래프의 로드 및 초기화 오버헤드를 제거하는 런타임 모델 상주(Resident Context) 방식이다.

    분할 구성은 각 모델을 로드하고 런타임을 초기화한 뒤 추론을 수행하고 해제한다. 84개 모델을 한 번 순회하는 이 준비·정리 비용을 3회 측정한 평균은 다음과 같다.

    라이프사이클 단계 84개 모델 1회 순회 소요 시간 (평균) 비고
    load_rknn 13.96초 호스트 메모리로 모델 가중치 로드
    init_runtime 12.90초 NPU 드라이버 컨텍스트 생성 및 DMA 매핑
    release 4.84초 NPU 런타임 및 디바이스 매핑 해제
    순수 단계 합계 31.71초 루프 오버헤드 포함 wall time: 33.84초

    분기별 모델당 평균 라이프사이클 시간은 self-attention 0.423초, cross-attention 0.200초, FFN 0.510초로 나타났다.

    28스텝 Spectrum 샘플러 운용 조건에서는 전체 28스텝 중 15스텝이 예측 연산으로 대체되고 실제 NPU 연산은 13회의 compute 스텝에 걸쳐 발생한다. 따라서 이미지 1장을 생성할 때 수행되는 총 라이프사이클 횟수는 84 models × 13 steps = 1,092회이며, 순수 라이프사이클 누적 시간은 약 412.2초에 달한다.

    만약 84개 컨텍스트를 메모리에 상시 상주시키는 것이 가능하다면, 최초 1회의 준비(load/init) 및 최종 1회의 해제(release)에 소요되는 31.71초를 제외한 나머지 12회분의 라이프사이클 시간을 이론적으로 제거할 수 있다.

    \[\Delta T_{\text{theoretical}} = 31.708\,\text{s} \times (13 – 1) = 380.50\,\text{s} \approx 6.34\,\text{분}\]

    이 계산에 따르면 평균 28.56분(1,713.78초)이 소요되던 전체 생성 시간을 22.22분(1,333.28초)까지 단축할 수 있다는 계산이 성립한다. 그러나 이 수치는 84개 컨텍스트 상주가 물리적으로 가능하다는 전제하에 도출된 이론적 상한일 뿐이며, 실제 상주 디노이즈 파이프라인에서 측정되거나 달성된 성능이 아니다.


    5. 18개 컨텍스트에서 드러난 메모리 한계

    모델을 하나씩 메모리에 올리면서 실제 메모리 점유와 스왑 증가량을 측정했다. 전체 상주를 실행하기 전에 8GB 환경에서 감당할 수 있는지 확인하기 위한 실험이다.

    벤치마크의 안전 중단 조건은 여유 메모리(MemAvailable) 1.5 GiB 미만 또는 시스템 스왑 16 MiB 초과로 설정했다. 1개부터 순차적으로 컨텍스트를 로드한 결과는 다음과 같다.

    상주 컨텍스트 수 프로세스 절대 PSS 기준선 대비 추가 PSS MemAvailable 변화 시스템 스왑 증가량
    1개 365.4 MiB 154.9 MiB -151.8 MiB 0 MiB
    4개 765.6 MiB 555.1 MiB -558.5 MiB 0 MiB
    8개 1,262.6 MiB 1,052.1 MiB -1,000.3 MiB 1.3 MiB
    12개 1,823.3 MiB 1,612.8 MiB -1,567.6 MiB 5.0 MiB
    16개 2,354.9 MiB 2,144.4 MiB -2,104.2 MiB 9.0 MiB
    18개 2,631.4 MiB 2,420.9 MiB -2,372.5 MiB 21.4 MiB (중단)

    18번째 컨텍스트를 로드하는 시점에서 프로세스의 절대 PSS는 약 2.57 GiB(2,631.4 MiB)에 도달했으며, 기준선 대비 추가 PSS는 약 2.36 GiB(2,420.9 MiB)를 기록했다. 시스템 스왑이 기준선 대비 21.4 MiB 증가하여 안전 기준(16 MiB 초과)에 의해 실험이 조기 중단되었다. 로드된 18개 컨텍스트는 즉각 안전하게 해제(release wall time: 1.05초)되었으며 디바이스 매핑이 회수되었다.

    메모리 증가는 호스트 텐서뿐 아니라 NPU 드라이버의 디바이스 매핑에서도 나타났다. 16개 컨텍스트를 유지했을 때 디바이스 매핑이 약 1.357 GiB였고, 30초 유지 중 시스템 스왑은 19.5 MiB 증가했다.

    16~18개 컨텍스트의 실측 메모리 증가율을 바탕으로 84개 전체 모델 상주 시의 소요량을 선형 외삽하면 다음과 같은 계산이 나온다. – 예상 디바이스 매핑 메모리: 약 7.1 GiB – 예상 프로세스 총 추가 PSS: 약 11.3 GiB

    ROCK 5C 보드의 전체 물리 RAM은 7.75 GiB다. OS 기본 점유 메모리, CPU 호스트 측 가중치 및 연산 버퍼(약 0.8~1.0 GiB), 프롬프트 인코더와 VAE 디코더의 상주 공간을 감안하기 이전에도 추가 PSS 11.3 GiB의 메모리 요구량은 하드웨어 한계를 초과한다. 따라서 84개 서브그래프의 동시 상주는 메모리 게이트를 통과할 수 없다.


    6. 작은 LRU 캐시로 해결할 수 있을까

    전체 84개 상주가 불가능하다면, 4~16개 정도의 제한된 컨텍스트 풀을 LRU(Least Recently Used) 방식으로 운용하거나 일부 모델만 고정 상주시키는 대안을 검토할 수 있다.

    새로운 독립 프로세스에서 4, 8, 12, 16개 컨텍스트 풀을 할당하여 실측한 추가 PSS 메모리는 각각 554.8 MiB(약 0.54 GiB), 1,046.1 MiB(약 1.02 GiB), 1,621.5 MiB(약 1.58 GiB), 2,185.4 MiB(약 2.13 GiB)였다.

    Radxa ROCK 5C 8GB 환경에서 독립 프로세스 실행 시 RKNN 상주 컨텍스트 수(4, 8, 12, 16개)에 따른 추가 PSS(MiB) 실측 증가 추이.
    Radxa ROCK 5C 8GB 환경에서 독립 프로세스 실행 시 RKNN 상주 컨텍스트 수(4, 8, 12, 16개)에 따른 추가 PSS(MiB) 실측 증가 추이.

    컨텍스트 증가에 따라 추가 PSS는 대체로 증가하는 경향을 나타내지만 엄밀한 완전 선형 관계는 아니다. 또한 이러한 제한 캐시 전략은 DiT의 순방향 연산 구조로 인해 실효성을 상실한다.

    스텝 n의 순차 호출열 (총 84개 모델)
    [Model 00 (self) → Model 01 (cross) → Model 02 (FFN) → ... → Model 83 (FFN)]
      ↓ 잔차 연결 누적 및 스케줄러 잠재 변수 갱신
    스텝 n+1의 순차 호출열 (총 84개 모델 동일 순회)
    [Model 00 (self) → Model 01 (cross) → Model 02 (FFN) → ... → Model 83 (FFN)]
    

    DiT 블록의 각 분기 출력은 즉시 호스트의 FP32 residual stream에 합산되어 다음 분기 및 블록의 입력으로 주입된다. 또한 84개 분기 연산이 모두 완료된 후에야 샘플러가 디노이즈 잠재 변수를 갱신하고 다음 디퓨전 스텝으로 진행할 수 있다. 즉, 모델 간의 순차적 의존성 때문에 호출 루프의 순서를 바꾸는 루프 인터체인지(Loop Interchange)가 불가능하다.

    구조상 84개 모델은 고정된 순서로 1스텝당 1회씩 순환 참조된다. 같은 모델이 다시 호출되기 전에는 다른 83개 모델을 거친다. 따라서 캐시 용량이 84 미만인 일반 LRU 캐시(예: capacity 4, 8, 16, 28, 56 등)를 적용할 경우, 캐시에 적재된 모델은 재사용되기 직전에 반드시 캐시 밖으로 축출된다. – LRU 시뮬레이션 결과: 총 1,092회 호출 중 0 hit / 1,092 miss (캐시 적중률 0%)

    일부 모델(예: 0~15번 모델)을 축출 없이 메모리에 고정 적재하는 방식(Static Pinning)을 적용하더라도, 16개 모델 기준 절감 가능한 시간은 compute 스텝당 16개분의 라이프사이클에 불과하여 이미지 1장당 이론상 최대 약 72.4초 절감에 그치며 이는 실제 달성된 측정값이 아니다. 반면 이를 위해 지불해야 하는 비용은 2.13 GiB(2,185.4 MiB)의 추가 PSS 점유와 장기 유지 시 발생하는 스왑이다. 72.4초의 제한된 이론적 절감을 위해 시스템 안정성을 희생하고 스왑 지터를 유발하는 것은 엔지니어링 관점에서 불합리한 선택이다.


    7. 8GB에서 유지한 구성

    W8A8 FFN 정수 양자화와 모델 상주 컨텍스트 캐시 실험을 통해 도출된 핵심 병목과 검증 결과는 다음과 같다.

    • FFN W8A8 양자화: 계산은 빨라졌지만 육안 화질 기준에 못 미쳤다.
    • 전체 모델 상주: 18개 컨텍스트에서 스왑이 늘었고, 84개 상주의 추가 PSS는 약 11.3 GiB로 외삽됐다.
    • 제한 캐시: 순환 호출에서는 재사용 전에 축출되어 LRU 적중을 얻지 못했다.

    ROCK 5C 8GB에서는 FP16 모델을 유지하고, 필요한 모델만 준비해 실행한 뒤 해제하는 방식을 선택했다. 이번 비교에서는 상주 시간을 늘리는 이득보다 메모리 부담이 컸다.

    이 판단은 이번 8GB 보드와 분할 구성에 대한 결과다. 메모리 용량이나 모델 분할 방식이 달라지면 상주의 손익도 다시 비교해야 한다.

    모델을 메모리에 쌓아두는 대신, 84개로 나뉜 그래프를 더 적은 수로 합칠 수는 없을까? 4편에서는 컴파일러 버전을 바꾸어 그래프 융합을 시도하고 속도·메모리 비용을 비교한다.

  • RKNN Toolkit 2.3.2와 2.3.0 비교: AdaLN 컴파일 충돌과 fusion 실험

    RKNN Toolkit 2.3.2와 2.3.0 비교: AdaLN 컴파일 충돌과 fusion 실험

    제휴 링크 안내: 이 글에는 알리익스프레스 제휴 링크가 포함되어 있으며, 링크를 통해 구매하면 작성자가 수수료를 받습니다.


    1. 분할한 DiT 블록을 다시 합칠 수 있을까

    임베디드 NPU 환경에서 생성형 확산 모델(Diffusion Transformer)을 구동할 때, 런타임 메모리 제한과 연산자 지원 여부는 아키텍처 설계를 직접 결정짓는 핵심 요인이다. 이번 심화 실험은 2026년 8월 20일 Radxa ROCK 5C 8GB 단일 보드 컴퓨터 환경에서 진행되었다.

    실험에는 직접 구매한 ROCK 5C 8GB 보드를 사용했다.

    실험 보드는 RK3588S2 기반 ROCK 5C이며, RKNN 타깃은 rk3588이다. 같은 판매 페이지의 ROCK 5C Lite와 구분해야 한다.

    1편의 Anima 구성은 28개 DiT 블록을 각각 attention·cross-attention·FFN으로 나눈 84개 FP16 RKNN 모델이다. AdaLN과 잔차 연결은 CPU에서 처리한다. 여기서는 블록당 3개 모델을 하나로 합칠 수 있는지 살펴봤다.

    기존 파이프라인에서는 AdaLN(Adaptive LayerNorm) 연산과 잔차 연결(Residual Addition)을 호스트 CPU 파이썬 런타임에서 처리해 왔다. 그러나 단일 DiT 블록 내에서 3개의 서브그래프를 매 스텝마다 각각 로드·실행·해제하고 중간 결과를 CPU 호스트로 왕복시키는 구조는 상당한 드라이버 오버헤드를 발생시킨다. 만약 블록 내의 Self-Attention, Cross-Attention, FFN 및 AdaLN을 단일 RKNN 그래프로 융합(fused 1-model)할 수 있다면, 블록당 라이프사이클 호출 횟수를 3회에서 1회로 줄이고 호스트 텐서 전송 비용을 절감할 수 있을 것으로 기대되었다.

    그러나 당시 기본 컴파일러로 사용하던 RKNN Toolkit 2.3.2 환경에서 AdaLN 연산자가 포함된 그래프를 컴파일할 때 치명적인 컴파일러 세그멘테이션 폴트(SIGSEGV, exit code 139)가 발생했다. 이 크래시가 Anima DiT 구조 자체의 근본적인 하드웨어 비지원인지, 컴파일러 버그인지 검증하는 작업이 선행되어야 했다.


    2. 같은 AdaLN 그래프를 다른 툴킷으로 빌드하기

    컴파일러 충돌 문제를 분석하기 위해, 거대한 전체 DiT 블록 대신 충돌을 유발하는 AdaLN 연산자만 격리한 최소 재현용 ONNX 모델(Minimal AdaLN reproducer)을 추출하여 컴파일 실험을 수행했다.

    같은 AdaLN 재현 그래프를 RKNN Toolkit 2.3.2와 2.3.0으로 각각 빌드했다. 다른 조건은 유지하고 컴파일러 버전에 따른 결과를 비교했다.

    동일한 reproducer ONNX 모델, 동일한 타깃(rk3588), 동일한 단일 코어 최적화 옵션에서 측정된 빌드 결과는 다음과 같다.

    툴킷 버전AdaLN 그래프 빌드종료 코드
    2.3.2실패: SIGSEGV139
    2.3.0성공0

    2.3.2에서는 LayerNorm 관련 그래프 최적화 뒤 SIGSEGV로 빌드가 중단됐다. 2.3.0에서는 같은 그래프가 정상적으로 빌드됐다.

    동일한 입력 그래프와 타깃에서 버전에 따라 결과가 달라져, 이번 실패는 컴파일러 회귀 문제로 판단했다. 이전 버전인 2.3.0이 이번 그래프의 회피 경로가 되었으며, 새 버전으로 올려 해결한 사례는 아니다.


    3. 64px·512px 융합 모델 실행 확인

    Toolkit 2.3.0으로 첫 번째 DiT 블록의 융합 모델을 빌드했다. 64px 테스트 구성과 512px 실제 추론 구성을 나누어 확인했다.

    융합 블록 해상도RKNN 변환보드에서 실행
    64px성공초기화·추론 확인
    512px성공초기화·추론·해제 확인

    512px 모델 빌드는 스왑 없이 완료됐다. 일부 Transpose와 Erf 연산은 CPU로 배치되었으므로, 단일 RKNN 파일로 합쳤다고 해서 모든 연산이 NPU에서 실행되는 것은 아니다.

    더 중요한 검증 포인트는 타깃 보드 로컬 런타임과의 바이너리 호환성이었다. 컴파일러를 2.3.0으로 빌드했더라도 보드 OS의 RKNPU 커널 드라이버나 런타임 라이브러리를 강제로 교체해야 한다면 배포 복잡도가 급격히 상승한다.

    빌드한 모델은 런타임 API 2.3.0·드라이버 0.9.8 환경에서 실행했다. 커널이나 드라이버를 교체하지 않고 로드·초기화·추론·해제를 확인했으며, 조건부·무조건부 추론을 3라운드 반복했다.

    이번 단일 블록 검증에서는 컴파일러 환경만 바꾸어도 기존 보드 런타임에서 실행할 수 있었다.


    4. 단일 블록 출력의 수치 차이

    융합 모델의 하드웨어 실행이 확인된 후, NPU 융합 연산 결과가 원본 부동소수점 기준 텐서와 수치적으로 일치하는지 단일 블록 수치 검증(Correctness Gate)을 수행했다. 기준 참조 텐서는 PyTorch FP16 원본 블록 연산 결과와 ONNX Runtime(ORT) 결과다.

    대상 아키텍처 기준 참조 텐서 (Reference) 코사인 유사도 (Cosine) 최대 절대 오차 (Max Abs) 평균 절대 오차 (Mean Abs) 평균 제곱 오차 (MSE) NaN/Inf 검출
    64px Fused PyTorch 0.99998315 0.28125 0.0018879 4.2748e-05 0 / 0
    64px Fused ONNX Runtime 0.99998608 0.28125 0.0018948 3.5387e-05 0 / 0
    512px Split (기존) PyTorch 0.99999881 0.14937 0.0002283 1.0841e-06 0 / 0
    512px Fused (후보) PyTorch 0.99997673 0.25000 0.0011279 2.1100e-05 0 / 0
    512px Fused (후보) ONNX Runtime 0.99997590 0.28906 0.0011662 2.1854e-05 0 / 0

    512px 융합 모델은 PyTorch 기준 출력과의 코사인 유사도 0.99997673, 최대 절대 오차 0.25000을 기록했고 NaN과 Inf는 발생하지 않았다.

    다만 융합 모델의 MSE는 2.1100e-05로, 기존 분할 방식의 1.0841e-06보다 약 19.5배 컸다. 단일 블록의 높은 코사인 유사도만으로는 전체 28개 블록과 여러 스텝을 거친 최종 이미지의 화질까지 확인할 수 없다.


    5. 호출은 줄었지만 속도 이득은 0.47%

    서브그래프 융합을 추진했던 가장 핵심적인 목적은 지연 시간 단축이었다. 호스트 파이썬에서 실행되던 AdaLN 및 잔차 연산을 컴파일된 그래프 내부로 옮기고 드라이버 컨텍스트 호출 횟수를 줄임으로써 속도 향상을 기대했다.

    ROCK 5C 보드에서 512px 단일 블록에 대해 CFG(Classifier-Free Guidance) 2회 연산 스트림을 3라운드 실행하고, 각 단계별 소요 시간의 평균치를 정밀 계측했다.

    512px DiT 단일 블록의 구성요소별 실측 시간. 1=load, 2=init, 3=inference×2, 4=release, 5=host AdaLN/residual. 구성요소 합계는 Split 4.3856초, Fused 4.3650초다.
    Comparison of component latency breakdown between Split 3-Model baseline and Fused 1-Model candidate for 512px single block on Radxa ROCK 5C.

    아래 표는 기존 3-model 분할 방식과 Fused 1-model 방식의 단계별 실측 수치 비교다.

    실행 단계 및 구성요소 기존 3-Model Split Fused 1-Model 후보 Fused 변동량 변동 원인 및 분석
    Model Load 0.4863초 0.4814초 -0.0049초 가중치 파일 로딩 시간 (단일 블록 기준 미미한 단축)
    Runtime Init 0.4464초 0.4240초 -0.0224초 NPU 런타임 컨텍스트 초기화 시간 소폭 단축
    NPU Inference (×2) 3.1177초 3.2972초 +0.1795초 (+5.76%) 연산자 융합에 따른 NPU 실행 지연 발생
    Context Release 0.1694초 0.1623초 -0.0071초 컨텍스트 메모리 해제 시간
    Host AdaLN & Residual 0.1658초 0.0000초 -0.1658초 (-100%) 별도 Python 호스트 AdaLN 경로 제거
    순수 구성요소 합계 4.3856초 4.3650초 -0.0206초 (-0.47%) 실제 획득된 순수 단축 시간은 0.0206초에 불과
    계측 Wall Time 4.7379초 4.4981초 -0.2398초 (-5.06%) 분할 모드의 다중 메모리 스냅샷 계측 왜곡치 포함

    실측 데이터는 직관적인 예상과 상반된 병목 현상을 보여주었다. 첫째, 호스트 연산 시간인 0.1658초는 Fused 모델에서 완전히 0초로 제거되었다. 그러나 NPU의 순수 순방향 추론 시간(Inference ×2)이 기존 3.1177초에서 3.2972초로 +0.1795초(+5.76%) 증가했다. 융합 구성에서 추론 시간이 늘어나면서, 호스트 연산 제거로 얻은 이득(0.1658초)을 완전히 상쇄했다.

    둘째, 컨텍스트 호출 횟수는 3회에서 1회로 66.7% 줄어들었으나, 수명주기(Load, Init, Release) 오버헤드는 기대만큼 줄어들지 않았다. 단일 블록의 수명주기 총 시간은 기존 1.1021초에서 1.0678초로 3.1% 단축되는 데 그쳤다. RKNPU 드라이버의 실제 초기화 및 로드 오버헤드는 단순한 C API 호출 횟수보다 모델 파일의 전체 가중치 용량(약 140~155 MB)과 그래프 복잡도에 지배된다는 사실이 드러났다.

    셋째, 계측된 Wall Time상으로는 0.2398초(5.06%)가 줄어든 것처럼 관측되지만, 이는 분할 모드에서 3개의 서브 컨텍스트마다 디버깅용 메모리 스냅샷을 6회 반복 수집한 계측 오버헤드가 포함된 수치다. 스냅샷 계측 왜곡을 배제한 순수 구성요소 합계 기준 실제 단축 효과는 블록당 0.0206초(-0.47%)에 불과했다.


    6. NPU 디바이스 매핑은 94.30 MiB 증가

    지연 시간 단축 효과가 미미한 반면, 런타임 메모리 측면에서는 심각한 손실이 발생했다. 보드 레벨에서 계측된 메모리 지표는 다음과 같다.

    메모리 측정 지표 기존 3-Model Split Fused 1-Model 후보 차이 및 증감률
    NPU 디바이스 매핑 디바이스 PSS 127,144 KiB 223,704 KiB +96,560 KiB (+94.30 MiB, +75.9%)
    실행 시 피크 프로세스 PSS 648,282 KiB 694,882 KiB +46,600 KiB (+45.51 MiB, +7.2%)
    신규 시스템 스왑(Swap) 발생량 0 0 0 (단일 블록 기준 안전)

    분할 방식은 각 브랜치를 순서대로 실행한 뒤 해제한다. 한 번에 유지하는 NPU 디바이스 매핑의 피크는 127,144 KiB, 약 124.16 MiB였다.

    융합 방식은 블록 전체를 하나의 런타임 컨텍스트로 유지한다. 디바이스 매핑은 223,704 KiB, 약 218.46 MiB로 늘어 추가로 94.30 MiB를 차지했다.

    총 8GB의 LPDDR4X 메모리를 공유하는 ROCK 5C 환경에서, 백그라운드 OS와 텍스트 인코더, VAE가 공존해야 하는 상황에 디바이스 매핑 메모리가 75.9%나 급증하는 것은 심각한 시스템 압박 요인이다.


    7. 융합을 채택하지 않은 이유

    단일 블록의 차이를 전체 구성에 외삽한 예상 절감량은 약 7.51초였다. 이는 전체 이미지 생성을 실행해 측정한 결과가 아니다.

    • 속도: 호스트 연산을 줄인 이득이 NPU 추론 지연 증가로 대부분 상쇄됐다.
    • 메모리: 같은 블록을 실행하는 데 필요한 디바이스 매핑이 늘었다.
    • 정밀도: 단일 블록의 코사인 유사도는 높았지만 MSE는 기존 분할 방식보다 커졌다.

    속도 이득은 0.47%에 그쳤고 메모리 사용량은 늘었으므로, 이번 보드에서는 기존 분할 방식을 유지했다.

    검증 범위는 단일 블록에 한정된다. 전체 28개 블록을 융합해 이미지를 생성하는 실험이나 장시간 운용 검증까지 진행한 결과는 아니다.

    3편의 상주 실험과 이번 융합 실험 모두, 호출 횟수를 줄이는 것만으로는 전체 성능을 설명할 수 없었다. NPU 연산 시간과 메모리 비용까지 함께 비교해야 8GB 보드에서 실제로 쓸 수 있는 최적화를 고를 수 있다.

  • RK3588에서 Anima 이미지 생성하기: ROCK 5C 8GB의 RKNN 변환과 실행 결과

    RK3588에서 Anima 이미지 생성하기: ROCK 5C 8GB의 RKNN 변환과 실행 결과

    제휴 링크 안내: 이 글에는 알리익스프레스 제휴 링크가 포함되어 있으며, 링크를 통해 구매하면 작성자가 수수료를 받습니다.

    1. ROCK 5C 8GB에서 Anima 실행하기

    8GB 메모리를 탑재한 단일 보드 컴퓨터(Single Board Computer, SBC)인 Radxa ROCK 5C 8GB 환경에서 수십억 파라미터 규모의 Diffusion Transformer(DiT) 모델 온디바이스 구동을 검증했다.

    보드 메인 프로세서는 Rockchip RK3588S2 SoC이며, Rockchip 전용 NPU 런타임 타깃은 rk3588이다. 동일 제조사의 Radxa ROCK 5C 상품군 중 Lite 모델인 RK3582 옵션은 NPU 유닛 및 CPU 코어 구성이 축소된 별개 칩셋이다. 따라서 8GB DiT 연산 파이프라인 재현을 위해서는 반드시 RK3588S2 기반의 ROCK 5C 8GB 모델을 확인해야 한다.

    Anima의 이미지 생성을 담당하는 DiT는 28개 블록으로 구성된다. 이번 실험에서는 이를 ROCK 5C의 NPU에서 실행할 수 있는 형태로 나누어 변환했다.

    온디바이스 변환의 고정 입출력 사양은 다음과 같다: – 배치 크기: 1 – 생성 해상도: 512×512 픽셀 – 입력 토큰 규격: 이미지 토큰 1024개, 텍스트 컨디셔닝 토큰 512개 – ONNX 타깃 버전: Opset 19

    텍스트 인코딩에는 Qwen3, 이미지 복원에는 Qwen-Image VAE를 사용했다. DiT의 주요 연산은 NPU가 처리하고, 텍스트 인코딩과 VAE 디코딩은 CPU가 담당하는 구성이다.


    2. DiT를 84개 RKNN 모델로 나눈 이유

    DiT 아키텍처의 28개 블록 전체를 단일 거대 RKNN 모델로 패키징하는 방식은 RKNN 컴파일러의 구조적 한계에 부딪혔다. 2026년 8월 실험 당시 사용된 RKNN-Toolkit2 2.3.2 환경에서 DiT 블록 전체를 컴파일하거나 AdaLN(Adaptive Layer Normalization) 연산이 결합된 브랜치를 빌드할 때 네이티브 세그폴트(native segfault, exit 139)가 발생했다.

    디버깅을 위해 그래프를 최소 단위로 분해한 결과, 대용량 Linear 레이어나 표준 GELU FFN 그래프는 NPU 타깃으로 정상 빌드되었으나, AdaLN LayerNorm + broadcast shift/scale/gate 패턴이 포함된 서브그래프는 가중치 크기와 무관하게 동일한 세그폴트를 일으켰다. 메모리 부족 문제가 아니라 컴파일러의 특정 그래프 연산자 패턴 해석 오류임이 확인되었다.

    각 DiT 블록에서 NPU로 실행할 수 있는 3개 연산 분기를 분리하고, 정규화·게이트·잔차 합산은 CPU에서 처리했다.

    28개 DiT 블록을 각각 self-attention, cross-attention, FFN의 3개 서브그래프로 나누었다. self-attention은 이미지 토큰 사이의 관계를, cross-attention은 텍스트 조건과 이미지 토큰의 관계를 계산한다. FFN은 각 토큰의 특징을 변환한다.

    파란 CPU 단계와 주황 NPU 단계를 번갈아 실행하는 DiT 블록 구조. CPU는 각 분기의 AdaLN과 게이트 곱셈·FP32 잔차 누적을, NPU는 FP16 self-attention·cross-attention·FFN을 처리한다.
    DiT 블록 하나의 CPU·NPU 실행 순서. NPU는 FP16 attention·FFN을, CPU는 각 분기 앞의 AdaLN과 분기 뒤의 게이트 곱셈·FP32 잔차 누적을 처리한다. 이 구조가 28개 블록에서 반복된다.

    총 84개(28 × 3)의 FP16 RKNN 모델이 만들어졌으며, 크기 합계는 약 3.99GB다. AdaLN, 게이트 곱셈, RoPE, 입력·타임스텝 임베딩과 최종 프로젝션은 CPU에서 처리했다. 잔차 누적은 FP32로 유지했다.

    • 원본 모델에서 CPU가 처리할 연산과 NPU가 처리할 연산을 분리한다.
    • NPU용 연산을 고정 입출력 형상의 ONNX 그래프로 만든 뒤 RKNN으로 변환한다.
    • 단일 블록과 전체 블록의 출력을 원본과 비교한 다음 이미지 생성을 실행한다.

    3. 변환 전후 출력은 얼마나 비슷한가

    하이브리드 분할 변환에서 가장 중요한 단계는 프레임워크 간 수치 오차의 누적 방지다. 단일 블록 검증과 28개 전체 블록의 순차 누적 검증을 나누어 수행했다.

    단일 블록 비교

    원본 PyTorch 블록의 FP16 분기 연산과 FP32 잔차 누적을 기준으로 ONNX 및 RKNN 출력을 비교했다. 변환한 연산이 원래 모델과 같은 방향의 출력을 내는지 확인하는 과정이다.

    비교 대상 코사인 유사도 (Cosine) 평균 절대 오차 (MAE) 최대 절대 오차 (Max AE) NaN / Inf 발생
    PyTorch → ONNX 0.9999994183 0.00012350 0.09396 0 / 0
    PyTorch → RKNN 0.9999990896 0.00019535 0.11446 0 / 0
    ONNX → RKNN 0.9999995474 0.00014175 0.06969 0 / 0

    PyTorch 기준 출력과 RKNN 출력의 코사인 유사도는 0.9999990896이었다. 단일 블록에서는 변환 전후 출력이 매우 비슷한 방향을 유지했다.

    28개 블록을 통과한 출력 비교

    Block 0부터 Block 27까지 28개 블록 전체를 통과하는 동안 수치 오차가 증폭되지 않는지 확인하기 위해 순수 ONNX 누적 텐서와 RKNN 84코어 누적 텐서를 비교했다.

    • 개별 블록 최저 코사인 유사도: 0.999993668 (전체 28개 블록 중 최저치)
    • 최종 히든 레이어 유사도 (Hidden Cosine): 0.9999989412
    • 최종 16채널 예측 텐서 유사도 (Final Prediction Cosine): 0.9999989072
    • 최종 예측 텐서 MAE: 0.00129712
    • 최종 예측 텐서 Max AE: 0.00830078
    • 경계 구간 NaN / Inf 발생 건수: 0건

    28개 블록을 통과한 뒤에도 NaN이나 Inf는 발생하지 않았고, 기준 출력과 높은 유사도를 유지했다. 다만 이 수치 비교와 최종 생성 이미지의 화질 평가는 구분해야 한다.


    4. 디노이징에는 얼마나 걸렸나

    28블록 전체 forward의 분기별 순수 NPU 시간

    RK3588 NPU에서 28개 DiT 블록 전체를 통과하는 forward 한 번의 순수 추론 시간 합계는 약 38.90초다. 아래 분기별 값은 각각 28개 블록의 실행 시간을 합산한 값이다.

    각 코어별 세부 소요 시간은 다음과 같다: – Self-Attention Core: 12.99초 – Cross-Attention Core: 3.92초 – FFN Core: 21.99초

    ROCK 5C의 28블록 전체 DiT forward 한 번에서 분기별 NPU 추론 시간 합계. 1: self-attention, 2: cross-attention, 3: FFN. 단일 블록 시간이 아니다.
    ROCK 5C의 28블록 전체 DiT forward 한 번에서 분기별 NPU 추론 시간 합계. 1: self-attention, 2: cross-attention, 3: FFN. 단일 블록 시간이 아니다.

    파라미터 비중이 큰 FFN 코어가 전체 순수 NPU 추론 시간의 약 56.5%를 차지한다. 참고로 ONNX 수치 검증 로직이 동반된 28블록 전체 테스트의 전체 실행 시간(Wall Time)은 162.8초였으며, 이는 순수 NPU 연산 시간(38.90초)과 구분된다.

    20스텝 순차 CFG 디노이징 결과

    실제 이미지 생성 과정인 20스텝 순차 분류기 없는 가이던스(Sequential Classifier-Free Guidance, CFG, guidance scale 4.0) 디노이징을 보드에서 직접 수행했다. 조건부(Positive) 및 무조건부(Negative) 예측을 단일 배치로 묶지 않고 메모리 한계를 감안하여 순차 호출 방식으로 처리했다.

    • 20스텝 디노이징: 2,408.54초
    • 스텝당 평균: 120.40초
    • 스텝당 순수 NPU 연산: 76.21초
    • 스텝당 모델 준비·호스트 처리 등: 약 44.19초
    • 20스텝 전체 구간 NaN/Inf: 0건

    스텝당 약 44.19초의 비-NPU 시간에는 84개 RKNN 모델의 로드·초기화·해제(load/init/release)뿐 아니라 호스트 연산과 경계 처리 비용도 포함된다. 후속 최적화에서는 이 비용을 나누어 계측해야 한다.


    5. VAE를 바꿔 이미지 복원 시간 줄이기

    디노이징이 완료된 잠재 변수(Latent)를 512×512 픽셀 RGB 이미지로 복원하는 VAE 디코딩 과정은 CPU 연산 부담이 큰 단계다. 공식 Diffusers의 Qwen-Image VAE FP32 CPU 구현을 그대로 사용했을 때의 디코딩 시간은 2,154.51초(약 35분 54초)에 달해, 20스텝 DiT 디노이징 전체 시간과 맞먹는 심각한 병목을 유발했다.

    VAE 디코딩에는 stable-diffusion.cpp의 ARM NEON·OpenMP 최적화 CPU 구현을 적용했다. 텍스트 인코더와 트랜스포머를 다시 초기화하지 않고, 디노이징이 끝난 잠재 텐서만 받아 이미지로 복원하도록 연결했다.

    CPU 4스레드, 타일 크기 32×32, 오버랩 0.5 설정으로 측정한 VAE 백엔드 비교 결과는 다음과 같다:

    평가 지표 공식 Diffusers FP32 VAE sd-cpp 타일형 CPU VAE 개선폭
    디코딩 소요 시간 2,154.51초 155.04초 13.90배 단축 (1,999.47초 절감)
    PSNR (Diffusers 출력 대비) 기준 출력 31.444 dB 참조 출력과 비교
    11×11 Gaussian SSIM 1.00000 0.96109 참조 출력과 비교
    출력 해상도 및 규격 512×512 RGB 512×512 RGB NaN / Inf 0건

    육안 검토에서는 구성·색·세부 표현이 유지된 것으로 평가했다. PSNR과 SSIM은 두 출력이 완전히 동일하다는 뜻은 아니다. 디코딩 시간은 2분 35초 수준으로 단축했다.

    디노이징과 이미지 복원 시간 합계

    VAE 가속을 통합한 전체 이미지 생성 시간은 다음과 같다: – DiT 20스텝 순차 CFG 디노이징: 2,408.54초 – sd-cpp 타일형 VAE 디코딩: 155.04초 – 총 생성 시간 (프롬프트 1회 인코딩 제외): 2,563.58초 (약 42분 44초)


    6. 다음 병목은 디노이징

    VAE 디코딩 시간을 2,154.51초에서 155.04초로 단축함에 따라, 전체 파이프라인에서 VAE가 차지하는 비중은 기존 47.2%에서 6.0%로 대폭 축소되었다. 이에 따라 전체 시스템의 지배적 병목은 DiT 20스텝 디노이징(2,408.54초, 전체의 94.0%)으로 전환되었다.

    DiT 디노이징 내부를 분해하면, 순수 NPU 연산에 소요되는 시간은 스텝당 76.21초(20스텝 합계 1,524.20초)이며, 나머지 약 884.34초는 모델 수명주기와 호스트 처리 등을 포함한 비-NPU 시간이다. 컨텍스트 상주는 반복 초기화 비용을 줄이기 위한 후보였지만, 8GB 환경에서는 메모리 여유와 실제 절감량을 별도로 검증해야 했다. 그 실험 결과는 3편에서 다룬다.

    이후 최적화에서는 연산 횟수와 메모리 사용량을 함께 살펴봤다. 2편은 Spectrum으로 계산 스텝을 줄인 결과, 3편은 양자화와 모델 상주가 화질·메모리 제한에 부딪힌 결과를 다룬다. 4편에서는 컴파일러 버전 비교와 그래프 융합의 손익을 살펴본다.