MLP가 점 단위로 작동한다는 의미를 깊이 이해하기
많은 분들이 PointNet이나 PointMLP 구조를 볼 때 이런 의문을 가집니다.
💭 “MLP는 채널-wise로 차원을 바꾸는 건데,
어떻게 각 포인트에 독립적으로 적용된다고 말할 수 있죠?”
아주 좋은 질문이에요 👏
이건 3D 점군 네트워크를 이해할 때 꼭 짚고 넘어가야 할 포인트입니다.
| 관점 | 설명 | 예시 |
|---|---|---|
| Channel-wise MLP | 채널 간의 관계를 학습 (예: Vision Transformer의 FFN) | 입력: [B, N, C] → FC: [C → C'] |
| Point-wise MLP | 각 점(point)의 feature vector에 동일한 MLP를 독립적으로 적용 | 각 점의 C차원 벡터에 동일한 MLP 적용 |
즉,
이 두 개념은 충돌하는 게 아니라, 같은 연산을 보는 관점이 다를 뿐입니다.
PointMLP 논문에서의 MLP는 “point-wise MLP”입니다.
입력 텐서를 [B, N, C] (배치 × 포인트 수 × 채널 수)라고 할 때,
로 표현됩니다.
즉, 각 점 ( )에 대해 동일한 가중치의 MLP가 독립적으로 적용됩니다.
실제 구현은 아래와 같이 1×1 Convolution으로 표현됩니다 👇
# PyTorch 예시
h = nn.Conv1d(in_channels=C_in, out_channels=C_out, kernel_size=1)
이 연산은 수학적으로 “각 점마다 동일한 fully connected layer를 적용”하는 것과 같습니다.
즉, Conv1d(kernel_size=1)은 point-wise MLP의 구현 형태라고 보면 됩니다.
입력:
MLP(혹은 1×1 Conv)는 각 점에 대해 다음과 같이 작용합니다.
따라서 출력:
입력 점들의 순서를 바꿔도
각 점마다 독립적으로 동일한 연산이 수행되므로
결과는 Permutation Equivariant합니다.
이 부분이 많은 분들이 헷갈려하는 포인트입니다 👇
“MLP는 채널-wise로 차원을 조절하지 않나요?”
그 말은 정확합니다.
단, 다음처럼 두 가지 관점을 함께 이해해야 합니다.
C_in = 64 → C_out = 128)즉,
“MLP는 채널 방향으로 feature를 변환하지만,
모든 점에 대해 동일하게 작동하므로
‘point-wise MLP’로 표현할 수 있다.”
| 구분 | 설명 | 결과 |
|---|---|---|
| 연산 방향 | 각 점(feature vector)에 대해 채널 차원 변환 | Channel dimension 변화 |
| 적용 방식 | 모든 점에 동일한 가중치 공유 | Point-wise 적용 |
| 수식 표현 | (h_i = \text{MLP}(p_i)) | 정확한 표현 |
| 구현 | 1×1 Conv or Linear Layer | 효율적 구현 가능 |
🎯 비유하자면,
MLP는 “모든 점에게 같은 질문지를 주고,
각 점이 자기 좌표(feature)에 따라 답하는 시험”과 같습니다.
즉,
이렇게 하면
순서가 바뀌어도 (누가 먼저 답하든) 전체적인 의미는 변하지 않죠.
이게 바로 point-wise MLP의 핵심 직관입니다.
PyTorch에서 1×1 Conv를 사용하는 이유는 단순히 효율성 때문만이 아닙니다.
# PointMLP 블록 예시
self.mlp = nn.Sequential(
nn.Conv1d(64, 128, 1),
nn.BatchNorm1d(128),
nn.ReLU(),
nn.Conv1d(128, 256, 1)
)
이 구조는 사실상 각 점에 대해 다음과 같은 MLP를 독립적으로 수행하는 것과 동일합니다:
🔹 PointMLP의 MLP는 각 점(feature vector) 에 대해 채널 방향으로 작동하는 fully connected 연산이며,
🔹 이 연산은 모든 점에 동일한 가중치로 독립 적용되므로 point-wise MLP라 불립니다.
🔹 따라서 ( h_i = \text{MLP}(p_i) )라는 표현은 수학적·구현적으로 모두 타당합니다.