---
title: "channel별 독립 계산이 큰 MAC array에 까다로운 이유"
author: "브레이브브라우저쓰자"
published_at: "2026-11-01T04:13:01.736Z"
updated_at: "2026-10-06T03:42:13.120Z"
tags: ["depthwise mapping"]
canonical_url: "https://ariser.io/@writer_a9817d5a8de0/channel%EB%B3%84-%EB%8F%85%EB%A6%BD-%EA%B3%84%EC%82%B0%EC%9D%B4-%ED%81%B0-mac-array%EC%97%90-%EA%B9%8C%EB%8B%A4%EB%A1%9C%EC%9A%B4-%EC%9D%B4%EC%9C%A0"
ai_assisted: true
---

# channel별 독립 계산이 큰 MAC array에 까다로운 이유

이 글은 AI가 활용됐습니다.

[원문](https://ariser.io/@writer_a9817d5a8de0/channel%EB%B3%84-%EB%8F%85%EB%A6%BD-%EA%B3%84%EC%82%B0%EC%9D%B4-%ED%81%B0-mac-array%EC%97%90-%EA%B9%8C%EB%8B%A4%EB%A1%9C%EC%9A%B4-%EC%9D%B4%EC%9C%A0)

depthwise convolution은 곱셈을 많이 줄이는 연산이다. 그런데 dense convolution에서 잘 작동하던 큰 MAC array에 넣으면 기대만큼 빨라지지 않을 수 있다. depthwise mapping의 어려움은 연산이 부족하다는 말보다, 서로 독립적인 channel의 작업을 기존의 공유 경로에 어떻게 넣을지에 있다. 연산량과 공급 가능한 병렬성을 함께 봐야 한다.

## channel마다 자기 입력과 filter를 쓴다

일반적인 dense convolution의 출력 channel 하나는 여러 input channel의 값을 filter와 곱해 더한다. 입력 하나가 여러 출력 channel의 계산에 사용될 수 있다. 반면 여기서 다루는 depth multiplier 1의 depthwise convolution은 input channel마다 filter 하나를 적용하고 같은 channel의 출력을 만든다. reduction은 kernel의 공간 방향에서 일어나며 서로 다른 channel끼리 더하지 않는다.

MobileNet의 원 논문은 이 filtering 단계와, 뒤에서 channel을 섞는 1×1 pointwise 단계를 구분한다. 두 단계를 합친 depthwise separable convolution의 MAC 수와 depthwise 부분만의 MAC 수는 다르다. 이번 질문은 앞의 독립적인 filtering을 array에 놓는 방법이다. [MobileNet 논문, 2–3쪽 3.1절](https://arxiv.org/pdf/1704.04861)

각 channel의 출력은 아래처럼 적을 수 있다. p는 출력 위치이며 r,s는 kernel 좌표다.

```text
Y[p,c] = Σ(r,s) X[window(p,r,s),c] × W[r,s,c]
```

filter가 3×3이면 출력 원소 하나의 reduction 길이는 9다. channel이 64개라도 한 출력에서 9×64개의 항을 합치지 않는다. 64개의 서로 다른 짧은 reduction이 있다는 쪽에 가깝다.

## 같은 연산을 큰 dense GEMM으로 나타내면 0이 늘어난다

가상 입력에 channel 네 개와 출력 위치 네 개가 있다고 하자. 각 위치에서 channel별 3×3 window를 펼치면, 한 위치의 입력 row는 4×9=36개다. 위치 네 개를 모은 P는 4×36이다.

weight 행렬 B를 36×4로 만들되, 출력 channel c의 column에는 같은 input channel c의 kernel 아홉 개만 놓고 나머지는 0으로 둔다. 그러면 P×B는 원하는 4×4 depthwise 출력을 만든다. 수학적으로 같은 filtering을 만든 표현이지만 dense GEMM은 4×36×4=576MAC 자리를 계산한다. 실제 필요한 비영 weight 항의 곱은 4×4×9=144개로 1/4이다.

한 PE가 출력 원소 하나를 담당하는 4×4 array를 생각하면, 36번의 공통 reduction 중 각 PE에 유효한 weight가 있는 경우는 아홉 번이다. 다른 channel의 구간에서는 곱의 weight가 0이다. 0을 gate해서 전력을 줄일 수 있어도, 별도 압축 실행 없이 36번의 공통 진행 시간을 자동으로 아홉 번으로 줄일 수는 없다.

이 25%는 정의한 dense lowering의 유효 곱 비율이다. 전체 실행 시간이나 실제 switching의 비율은 아니다. kernel 값 자체에 0이 있는 경우도 넣지 않았다. 또한 dense convolution과 depthwise convolution을 바꾸어 같은 모델의 정확도를 보장한다는 비교도 아니다.

## 네 channel을 병렬로 놓으려면 입력 경로도 나누어야 한다

출력 위치 네 개를 channel마다 맡겨 총 16개의 독립 dot product를 병렬로 진행하고 싶을 수 있다. 각 dot product가 매 cycle 자기 channel의 다음 kernel 항을 받으면, 이상적으로 아홉 번의 MAC으로 각 결과를 만들 수 있다. 그러나 이 설명에는 PE마다 필요한 입력을 공급할 수 있다는 조건이 숨어 있다.

기존 dense array에서 같은 row의 PE들은 하나의 A 값을 공유한다. depthwise의 서로 다른 channel을 옆 column에 놓으면 같은 시점에 필요한 X 값도 channel마다 달라진다. 하나의 공통 row 입력으로는 그 값들을 동시에 표현할 수 없다. channel별 partition과 독립 공급, 여러 bank의 port나 다른 dataflow가 필요한 이유다.

필요한 MAC이 독립적이라는 사실은 hardware의 모든 입력선도 독립적이라는 뜻이 아니다. 이미 만들어진 array에서 software의 좌표만 바꾸면 해결되는지, 새 routing이 필요한지 나누어 검토한다. 작은 channel 묶음으로 실행하는 방법도 가능하지만 묶음마다 생기는 시작·저장 비용을 더해야 한다.

## 재사용이 사라지는 방향과 남는 방향을 구분한다

depthwise에서는 한 input channel을 여러 output channel에 공유하는 dense 연산의 재사용이 줄어든다. 그렇다고 모든 재사용이 사라지는 것은 아니다. 같은 filter는 여러 출력 위치에 쓰이고, 이웃 window는 입력 영역이 겹칠 수 있다. channel 방향의 공유를 못 하는 것과 공간 방향의 재사용까지 못 하는 것은 다른 문제다.

Gemmini 원 논문도 MobileNet의 depthwise layer가 가진 낮은 데이터 재사용 때문에 해당 spatial accelerator에 효율적으로 매핑하기 어렵다고 설명한다. 그 평가는 논문의 특정 구성에 관한 것이며, 모든 depthwise 전용 구조가 비효율적이라는 결론은 아니다. [Gemmini 논문, 4쪽 IV.B절](https://arxiv.org/pdf/1911.09925)

좋은 depthwise mapping은 channel 수만 보고 PE 수를 채우지 않는다. 각 출력의 짧은 reduction, 입력의 channel별 독립성, filter와 window의 공간 재사용을 함께 배치한다. 이 관계를 실제 port와 buffer에 대응시키면, 곱셈을 줄인 모델이 기존 array에서는 왜 덜 활용되고 어떤 공급 경로에서 다시 병렬성을 얻는지 설명할 수 있다.

