애플 뉴럴엔진 역공학이 3년 만에 재개돼 M1 ANE 내부 구조를 드러낸다.

Hacker News28일 전조회 2

애플 뉴럴엔진(ANE)을 리눅스에서 구동하려던 역공학 프로젝트가 3년 만에 재개됐다. 개발자 Eileen Yoon은 이번에 드라이버 완성보다 M1 ANE의 내부 아키텍처 전모를 밝히는 쪽에 무게를 뒀다. 컴퓨트 코어와 데이터패스, 스케줄러, 메모리, 실행 모델까지 훑어 애플이 2017년 A11 Bionic에서 실리콘에 먼저 굳힌 ML 워크로드 가정이 무엇이었는지 확인하는 것이 목표다. 코드는 GitHub의 ane 저장소에서 볼 수 있다.

ANE의 컴퓨트 코어는 16개다. 코어마다 FP16 기준 128개, INT8 기준 256개의 MAC 레인이 병렬로 들어가므로 전체 병렬 MAC 레인 수는 2048개(128×16)가 된다. 각 레인은 곱셈기, 덧셈기, 32비트 누산기로 구성되며 매 사이클 곱셈 결과를 직전 누적값에 더한다. 즉 하나의 MAC 레인은 시간축을 따라 스칼라 리덕션을 수행하고, 16개 코어는 공간적으로 2048개의 리덕션을 동시에 처리한다. 행렬곱인지 컨볼루션인지는 하드웨어가 정하는 게 아니라 오퍼랜드를 어떻게 매핑하고 스케줄하느냐가 정한다.

정밀도 처리 방식도 드러났다. 곱셈은 16비트로 하고 결과는 Q16.16 고정소수점으로 32비트 레지스터에 누적한 뒤 FP16으로 읽어낸다. CoreML로 all-ones 벡터 내적을 돌려 누산기 범위를 찔러본 결과, 127.9375는 32752로, -128은 -32768로 나왔지만 -128.125는 0xfc00, 즉 -∞로 포화됐다. 32768 자체가 유효한 FP16 워드라는 점에서 이 클램프는 출력단이 아니라 누산기 내부, 2^15 지점에서 일어난다.

활성화 함수는 룩업 테이블로 구현된다. tanh 모델을 컴파일해 하드웨어 레지스터 파일을 열어보면 0x4288부터 33개의 연속된 FP16 워드가 나오는데, 이는 tanh(i/8)을 16비트로 반올림한 값들과 일치한다. ReLU 계열은 모드 2가 33엔트리 커스텀 LUT를 선택하며, R=3일 때 매듭점은 i/8 (i=0…32)로 [0,4] 구간을 1/8 간격으로 덮는다. 입력은 u = 2^R|x|로 테이블 좌표에 매핑되고, 인접 엔트리 사이는 선형 보간된다. 한 칸만 1인 임펄스 LUT를 넣고 입력을 쓸어보면 출력이 |x|=7/8에서 0, |x|=1에서 1, |x|=9/8에서 다시 0으로 가는 삼각형을 그려 보간 동작이 확인된다. 저자는 이 비선형 보간 하드웨어를 추가 커널 패스 계산이나 int8→int4 가중치 양자화에 악용하는 아이디어도 덧붙였다.

컴파일 단계에서 상수 스케일과 바이어스가 컨볼루션에 접히는 것도 확인됐다. y = ReLU(z/2 + 1) 모델에서 원본 컨볼루션이 W=4, b=-2였다면 컴파일 후에는 W'=2, b'=0이 된다. 바이어스와 활성화가 같은 post-MAC 경로에 컴파일 타임에 융합된다는 뜻이다.

드라이버 쪽은 의외로 단순하다. ANE 드라이버는 CONV, MATMUL, RELU 같은 opcode를 하드웨어에 전달하지 않는다. 모든 신경망 연산은 이미 태스크 디스크립터(TD) 명령 스트림으로 컴파일돼 있고, 드라이버는 그 blob을 메모리에 올린 뒤 TM_ADDR/TM_INFO에 포인터와 크기를 스테이징하고 TM_PUSH를 써서 제출한다. 이는 NVIDIA pushbuffer/PBDMA 같은 GPU 명령 제출 방식과 닮았다. TM_INFO는 상위 16비트에 descriptor_dwords-1, 하위 16비트에 디스크립터 개수를 담는데, 길이에서 1을 빼는 건 제로 기반 카운터를 임계 경로 밖에서 종료시키는 RTL 친화적 인코딩이다. GPU가 가변 길이 링버퍼를 파싱하는 것과 달리 ANE는 총 개수만 받으므로 디스크립터 크기가 고정이라는 점도 읽힌다. 태스크 큐는 8개(qid 0~7)이고, 각 큐는 상태·우선순위·여유 공간 같은 스케줄링 정보와 두 세트의 명령 스트림 디스크립터(ADDR1/ADDR2, SIZE1/SIZE2, NID1/NID2, BAR 32개)를 가진다. 두 슬롯은 한쪽이 실행되는 동안 다른 쪽을 소프트웨어가 고치는 핑퐁 스테이징이다.

배경에는 ANE의 위상 변화가 있다. 애플은 원래 조밀한 이미지 처리 CNN, 즉 재사용 패턴이 예측 가능한 텐서 리덕션을 겨냥해 ANE를 설계했다. MAC 자체는 컨볼루션이든 어텐션이든 같은 내적이지만, ANE를 2017년 CNN 모델에 특화시킨 것은 MAC 주변의 데이터플로우, 즉 입력과 출력이 언제 어디로 들어오고 머무르고 움직이는가였다. 트랜스포머, 특히 자기회귀 디코딩이 깨뜨린 것이 바로 이 예측 가능한 재사용 패턴이다. 2025년 M5는 "LLM 성능"을 전면에 내세우면서 ANE 코어를 GPU 코어 안으로 접어 넣었는데, 이는 ANE의 컴퓨트 코어 자체는 트랜스포머에도 여전히 쓸모 있지만 더 이상 독립 NPU로 남지는 않는다는 신호로 읽힌다.

개발자 입장에서 이 분석은 두 가지를 시사한다. 첫째, NPU 성능을 좌우하는 것은 MAC 개수가 아니라 데이터플로우와 스케줄링이라는 점이다. 같은 내적 하드웨어도 오퍼랜드 매핑에 따라 컨볼루션이 되고 어텐션이 된다. 둘째, ANE 드라이버처럼 opcode 없이 태스크 디스크립터만 제출하는 구조는 가속기 소프트웨어 스택을 설계할 때 참고할 만한 패턴이다. 컴파일러가 모든 융합과 스케일 접기를 끝내고 런타임은 포인터와 카운트만 넘긴다는 발상은 오늘날 NPU·GPU 런타임에서도 반복적으로 나타난다.

다만 이 작업은 저자 스스로 "더 쓸모없는 일"이라고 부른 회고적 분석이며, 대상은 M1 세대 ANE다. ANE가 범용 가속기로 부적합하다는 판단과 macOS에서의 제한적 활용도 저자 개인의 관찰이다. 후속 세대에서 내부 구조가 그대로 유지된다는 보장도 없다.