본문 바로가기
AI Project/Edge AI Agent - LLM(연구,분석,검증)

[분석/검증-1] BitNet.cpp 텐서 연산 붕괴(텐서 오류) 현상 분석 : Big.LITTLE 구조의 캐시 불일치

by 으노으뇨 2026. 4. 23.
728x90
반응형
SMALL

대상 기기: Samsung Galaxy A35 (Exynos 1380)

현상: BitNet.cpp 추론 시 논리적 문장이 아닌 무작위 토큰이 나열되는 '워드 샐러드(Word Salad)' 발생

https://uno-kim.tistory.com/454

 

#4. [Bitnet.cpp]모바일 환경에서 컨테이너띄우고 빌드

안녕하세요. 지난번 Edge Device 환경에서 Bitnet.cpp를 돌리고자 했지만 실패했었습니다.이번에 많은 프로젝트를 진행하면서 cpp 빌드도 많이 돌려봤는데요, 환경설정이 가장 어려웠습니다.그럴때마

uno-kim.tistory.com

갤럭시 A35(Exynos 1380) 환경에서 BitNet.cpp를 통해 1.58비트 양자화 모델을 구동했을 때,

모델이 "The capital of France is"라는 간단한 질문에도 Freedom reduce Dispatch linear...와 같은 무의미한 토큰을 뱉어내는 '워드 샐러드(Word Salad)' 현상이 관찰되었습니다.

이는 단순한 소프트웨어 버그가 아닌 연산 과정에서의 텐서 오염(Tensor Corruption)이 원인이라고 가정하였습니다.

가설 설정: 원인은 Big.LITTLE 구조의 캐시 불일치

원인은 Big.LITTLE 아키텍처의 캐시 불일치(Cache Coherency Failure)라고 추측됩니다.

  • 스레드 이주: 안드로이드 OS는 전력 효율을 위해 고성능 코어(Cortex-A78)에서 돌아가던 연산 스레드를 저전력 코어(Cortex-A55)로 강제 이주(Context Switching)시킵니다.
  • 동기화 실패: 이때 고성능 코어의 캐시에 머물던 최신 텐서 연산 값이 메인 메모리로 동기화되지 않은 상태에서, 저전력 코어가 과거의 유효하지 않은 데이터를 읽어 들이며 연산이 꼬이게 됩니다.

검증 방법: Taskset을 이용한 스레드 어피니티 제어 - 

먼저 termux의 Taskset 패키지를 이용해서 강제로 우분투에서의 동작을 1개의 연산 쓰레드만 사용하도록 설정해주고 진행해보곘습니다.

pkg install util-linux
# 현재 쉘(Termux)의 PID를 이용해 할당된 코어 확인
taskset -p $$
#또는 taskset -cp $$

지금 총 안드로이드 정책으로부터 8개 스레드중 3개만 적용된것을 알 수 있습니다.

왜 7이랴면...


숫자 7을 2진수로 바꾸면 111입니다.
이것을 코어 번호와 매칭하면 다음과 같습니다:
2번 코어: 사용 중 (1)
1번 코어: 사용 중 (1)
0번 코어: 사용 중 (1)
따라서 111 => 7
ㅋㅋ

PC에서 SSH로 폰의 PRoot Ubuntu에 접속한 상태에서 아래 명령어를 순차적으로 실행합니다.

우분투진행

#여기서 목록확인합니당
proot-distro list 
taskset -c 0 proot-distro login ubuntu

강제로 0번대 스레드만 적용한 Proot를 실행합니다. 이렇게 진행한다면 강제된 환경이 자손에게 종속되어서 

리눅스(및 안드로이드 커널)에서 CPU 친화도(CPU Affinity) 설정은 부모 프로세스에서 자식 프로세스로 상속됩니다.

확인해볼까요

동일하게 명령어를 쓰니 1개의 프로세서만 상속된게 확인됩니다.

# Conda 환경으로 진입 (프롬프트 앞에 (base)가 생깁니다)
source $HOME/miniforge3/bin/activate

# 만든 3.10 환경으로 접속! (프롬프트 앞에 (myenv310)이 생깁니다)
conda activate myenv310

#그리고 만든 워크스페이스 환경으로 진입합니다!
cd /root/workspace/BitNet
# PRoot Ubuntu 환경 내 실행
python run_inference.py -m models/BitNet-b1.58-2B-4T/ggml-model-i2_s.gguf -p "The capital of France is" -n 200 -temp 0.0 -t 1

여기중간에 n_threads =1 또는 밑에서 3번째줄 의 
system_info: n_threads = 1 (n_threads_batch = 1) / 8: 시스템 정보에서도 전체 8개 코어 중 1개의 스레드만 사용 중임을 보여줍니다.

그러나 또 터지고 마네요...


결록...

저는 이전에 코어와 코어 사이를 이동할 때 발생하는 캐시 불일치를 워드 샐러드의 유력한 원인으로 꼽았습니다.

ㅎㅏ지만 로그를 보면 

변인통제완료된 상태로, 스레드가 딱 1개 뿐이므로, 여러 쓰레드가 동시에 메모리를 건드려 데이터가 꼬이는 레이스컨디션이나 멀티 스레드 캐시 불일치는 발생할 수 없는 구조입니다.

그럼에도 워드 샐러드가 발생했는데요...

스레드를 1개만 써도 이전과 동일하게 외계어가 나온다면, 이건 코어간의 문제가 아니라 코어 하나 내부에서 일어나는 연산 자체의 문제라고 생각이 듭니다.


하드웨어 결함 유력하다는 가정으로

로그 하단에 찍힌 NEON = 1을 의심하며....

단일 스레드에서도 외계어가 나온다는 것은, 엑시노스의 NEON 연산기 자체가 BitNet의 1.58비트 특수 수학 연산을 처리하는 과정에서 숫자를 잘못 계산(오버플로우 혹은 소수점 강제 삭제)하고 있다는 결정적인 증거가 됩니다.

다음엔 NEON을 수정해서 혼을 내보겠습니다...

 

728x90
반응형
LIST

댓글