0xFF

QCS6490 Linux Host에서 LLM 구동 실험 본문

LINUX

QCS6490 Linux Host에서 LLM 구동 실험

캡스락 2026. 2. 5. 22:35

Radxa Q6A의 SoC인 QCS6490에는 Hexagon DSP가 탑재되어 있다.

이름은 DSP지만, Dragonwing 같은 칩셋에 내장된 최신 헥사곤 아키텍처에는 하드웨어 차원의 벡터 및 텐서 연산 기능이 추가되어 NPU로도 기능한다고 한다.

그렇다면 로컬 LLM 구동도 가능할까 싶어 알아보니 가능하다고 한다!

간략히 알아본 바 퀄컴에서 제공하는 Qualcomm AI Engine Direct 라는 SDK(이하 QNN SDK)를 사용하여 타겟 보드에서 사용하고자 하는 onnx 포맷의 모델을 dlc 라는 확장자를 갖는 자체 포맷으로 변환 및 양자화(선택)하여 타겟 디바이스에 맞게 변환하고,

이를 QNN SDK에서 제공하는 런타임으로 타겟 디바이스의 NPU에서 구동한다는 흐름이다.
하지만 Qualcomm AI Hub를 이용하면 여러 메이저 AI 모델들(Yolo, Llama 등)에 대해서는 제공되는 툴을 이용하면 onnx 모델의 변환과 원하는 퀄컴 칩셋에 맞게 최적화까지 한 번에 가능하다고 하여 해당 방법으로 진행해 보기로 하였다.

QNN SDK 설치

우선 Ubuntu 22.04 환경을 준비해 놓고 시작하도록 한다.

QNN SDK에는 특정 버전의 파이썬에서 구동되는 유틸리티가 많이 포함되어 있으므로,

파이썬 특유의 의존성 지옥을 피하기 위해 본인이 리눅스를 메인 PC로 사용한다면 개인적으로 도커를 이용할 것을 권장하고 싶다.

wget <https://softwarecenter.qualcomm.com/api/download/software/sdks/Qualcomm_AI_Runtime_Community/All/2.42.0.251225/v2.42.0.251225.zip>
unzip v2.42.0.251225.zip

환경이 준비되었다면 QNN SDK를 다운로드 후 압축을 해제한다.

글이 작성되는 날짜(26. 01. 26.)를 기준으로 v2.42.0.251225가 최신 버전이다.

mv qairt /opt

다운로드한 QNN SDK를 /opt 디렉터리로 옮긴다.

source envsetup.sh

qairt/2.42.0.251225/bin 경로에 위치한 환경변수 설정 스크립트를 실행한다.

env | grep -A 99 QAIRT >> ~/.bashrc
source ~/.bashrc

스크립트에 의해 세팅된 환경변수들을 bashrc에 저장하여 세션이 시작될 때 자동으로 설정되도록 한다.

${QAIRT_SDK_ROOT}/bin/check-linux-dependency.sh


의존성 패키지들을 설치한다.

실행 도중 apt 레포지터리 추가 여부를 물어보면 엔터를 입력하여 넘어가면 된다.

${QAIRT_SDK_ROOT}/bin/envcheck -c


의존성 패키지 설치가 완료되었다면 이어서 위 명령어를 실행하여 툴체인의 정상 설치 여부를 확인한다.

[INFO] Found clang++ at /usr/bin/clang++” 가 출력되면 올바르게 설치된 것이다.

Python 3.10 설치

apt-get update && apt-get install python3.10 python3-distutils libpython3.10

QNN SDK가 의존하는 python 3.10 버전을 설치한다.

python3 --version


설치 완료 후 파이썬 버전이 3.10.x로 표시되어야 한다.

apt install python3.10-venv
python3 -m venv qcom_llm --without-pip
source qcom_llm/bin/activate
python3 -m ensurepip --upgrade

파이썬 3.10 venv를 설치하고 ‘qcom_llm’ 디렉터리에 venv 환경을 만든다.

당연하지만 디렉터리 이름 ‘qcom_llm’은 임의로 변경해도 된다.

python "${QAIRT_SDK_ROOT}/bin/check-python-dependency"

파이썬 의존 모듈을 설치한다.

pip install onnx==1.14.0

onnx 모듈을 설치한다.

타겟 보드에 SDK 설치

docker cp <컨테이너ID>:/opt/qairt/2.42.0.251225/bin/aarch64-oe-linux-gcc11.2/genie-t2e-run .
docker cp <컨테이너ID>:/opt/qairt/2.42.0.251225/bin/aarch64-oe-linux-gcc11.2/genie-t2t-run .
docker cp <컨테이너ID>:/opt/qairt/2.42.0.251225/bin/aarch64-oe-linux-gcc11.2/genie-app .
docker cp <컨테이너ID>:/opt/qairt/2.42.0.251225/lib/aarch64-oe-linux-gcc11.2/libGenie.so .
docker cp <컨테이너ID>:/opt/qairt/2.42.0.251225/lib/hexagon-v68 .

scp -r hexagon-v68 genie* libGenie.so ubuntu@<타겟 보드 IP>:~/

호스트 PC에서 위의 바이너리를 추출하여 타겟 보드로 전송한다.

도커를 사용하지 않았다면 그냥 해당 파일들만 골라서 scp로 전송하면 된다.

echo 'export QAIRT_HOME="/opt/qairt"' >> ~/.bashrc
source ~/.bashrc

타겟 보드에 QNN SDK 환경변수를 설정하고 적용한다.

mkdir -p ${QAIRT_HOME}/bin/aarch64-ubuntu-gcc9.4/
mkdir -p ${QAIRT_HOME}/lib/aarch64-ubuntu-gcc9.4/

cp -r libGenie.so ${QAIRT_HOME}/lib/aarch64-ubuntu-gcc9.4/
cp -r genie-* ${QAIRT_HOME}/bin/aarch64-ubuntu-gcc9.4/

디렉터리를 만들고 파일들을 복사한다.

export PATH=${QAIRT_HOME}/bin/aarch64-ubuntu-gcc9.4/:${PATH}
export LD_LIBRARY_PATH=${QAIRT_HOME}/lib/aarch64-ubuntu-gcc9.4:${LD_LIBRARY_PATH}
export ADSP_LIBRARY_PATH=${QAIRT_HOME}/lib/hexagon-v68/unsigned

위 환경 변수를 .bashrc에 추가한 뒤 source ~/.bashrc로 적용한다.

 

스왑 할당하기

모델을 export하는 과정에서 약 80GB의 대용량 메모리 공간이 필요하다고 한다.

아래는 80GB의 스왑공간을 할당하는 방법이다.

sudo swapon -s
sudo swapoff /swapfile # 기존 스왑 해제(존재하는 경우)
sudo dd if=/dev/zero of=/swapfile bs=1M count=81960
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile

위와 같이 진행하고 나면 free -h를 실행하였을 때 스왑 영역으로 80GB가 할당된 것을 확인할 수 있을 것이다.

 

Llama v3.2 3B 모델 다운로드 및 변환

만약 이 과정에서 “You must have access to it and be authenticated to access it. Please log in.” 라고 출력되며 진행이 되지 않는다면

https://huggingface.co/meta-llama/Llama-3.2-3B-Instruct 에 접속하여 로그인하고 “LLAMA 3.2 COMMUNITY LICENSE AGREEMENT” 를 펼친 후,

간단한 개인정보를 입력한 뒤 허가를 요청하면 된다.

그런 다음 토큰을 발급받는다. 토큰은 레포지터리에 대한 읽기 권한만 있어도 된다.

발급된 토큰은 hf auth login 명령을 실행한 뒤 나타나는 로그인 화면에서 붙여넣고 로그인하면 된다.

python3.10 -m qai_hub_models.models.llama_v3_2_3b_instruct.export --chipset qcs6490 --skip-profiling --output-dir genie_bundle

사용신청이 승인되면 허깅페이스 로그인 이메일로 알림이 오는데,

이때부터 위 명령을 통해 모델 다운로드가 가능해진다.

허가는 접수 후 10분 정도면 떨어지는 것 같다.

모델 변환이 완료되면 genie 런타임에서 구동될 수 있는 모델 가중치와 함께 토크나이저 및 genie 런타임용 설정 파일(genie_config.json) 등이 포함된 zip 압축 파일이 생성된다.

해당 zip 파일을 타겟 보드로 전송한 다음 압축을 풀고 타겟 보드에 설치한 SDK에 포함된 런타임을 사용하여 LLM을 NPU에서 구동할 수 있다.

런타임은 (SDK 경로)/bin/bin/aarch64-ubuntu-gcc9.4/genie-t2t-run 이다.

genie-t2t-run -c genie_config.json -p -p "<|begin_of_text|><|start_header_id|>user<|end_header_id|>\n\nWhat is France's capital?<|eot_id|><|start_header_id|>assistant<|end_header_id|>"

기본적인 llama의 구동 명령어는 위와 같다.

[ERROR] "Failed to create device: 14001"

[ERROR] "Device Creation failure"

하지만 어째서인지 위와 같은 이유로 구동이 되지 않는다.

확인해 본 바 아래의 커널 메시지가 문제 발생과 관련이 있는 것 같다.

[    4.250065] qcom,fastrpc a300000.remoteproc:glink-edge.fastrpcglink-apps-dsp.-1.-1: no reserved DMA memory for FASTRPC
[    4.862697] qcom,fastrpc 3700000.remoteproc:glink-edge.fastrpcglink-apps-dsp.-1.-1: no reserved DMA memory for FASTRPC

https://github.com/qualcomm/fastrpc?tab=readme-ov-file

검색해 본 바 퀄컴 SoC 내에서 메인 CPU와 헥사곤 NPU는 퀄컴에서 제공되는 fastrpc 라는 유저스페이스 라이브러리를 통해 서로 통신이 이뤄진다고 한다.

이 fastrpc 레이어는 미리 할당된 공유 메모리 영역을 이용해 DMA 방식으로 칩 패키지 내의 다른 프로세서와 고속으로 통신하는데,

아무래도 armbian 빌드시에 사용된 디바이스 트리 명세에서 fastrpc를 위한 메모리 영역이 지정되어 있지 않아 NPU와 통신을 하지 못한 것으로 보인다.

여기까지 내장 NPU를 활성화해보고 싶다는 일념 하나로 꾸역꾸역 시도해보고 있었지만

꼴랑 12 TOPS짜리 NPU로 LLM을 돌리면 차라리 안돌리느니만 못하겠다는 생각이 갑자기 들어 NPU LLM 구동의 꿈은 잠시 접어두기로 했다.

대신 현재 프로젝트에서는 동일한 SBC 보드를 하나 더 구매하여 CPU만을 사용한 LLM 및 RAG 처리 전용 노드로 사용하기로 했다.

* 본 글은 퀄컴 공식 매뉴얼(https://docs.qualcomm.com/doc/80-63442-10/topic/linux_setup.html)을 일부 참고하여 작성하였음을 알려드립니다.
* https://github.com/quic/ai-hub-apps/tree/main/tutorials/llm_on_genie

'LINUX' 카테고리의 다른 글

Dragon Q6A Armbian에서 spidev 활성화  (0) 2026.02.08
터미널 폰트 추천 - Neo둥근모  (0) 2020.01.05