[태그:] 정수 양자화

  • 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편에서는 컴파일러 버전을 바꾸어 그래프 융합을 시도하고 속도·메모리 비용을 비교한다.