0으로 바꾸는 형식이다.저장하고 있고 (space)0을 곱하고 있기 때문이다.(time)Sparse Matrix Representation

전용 하드웨어 사용Pruning Ratio
파라미터의 몇 %를 제거할 것인지 비율
Local
레이어별로 동일하게 일정 비율을 제거
동일한 비율이라서 Uniform Shrink이라고도 함
더 좋은 방법은?
레이어별로 비율을 다르게 설정해보자
네트워크가 복잡하거나 / 층별 특성이 상이한 모델의 경우
각 레이어의 특성을 반영하여
각 레이어의 pruning 비율을 설정하는 중요도를 측정하는 개념의 방법. (Global pruning의 일종)
Sensitivity(민감도)를 측정
일반적으로는
가장 앞 부분 레이어가 민감
뒷 부분 레이어는 덜 민감
비유: 최종 판단을 내릴 때엔 그만큼의 연산량이 필요 없다.
한 레이어를 고르고
해당 레이어의 파라미터를 일정 비율만큼 prune 후 fine-tuning
이를 레이어별로 또는 비율별로 성능을 측정
성능 저하 허용 범휘 T(%)를 고정하고
그것을 기준으로 레이어별로 prune할 비율을 설정

출처: https://intellabs.github.io/distiller/pruning.html
레이어별로, 비율 별로 각각 측정해야하고
측정 한번에 pruning 전체 과정 1번 만큼의 iteration이 소요됨.
즉, 오래 걸리는 작업이기 때문에 주로 분석용으로 사용한다.
다만, 모델 구조가 같고 데이터만 다른 경우, 한번 계산해둔 비율은 재사용이 어느정도 가능하다.
어디서 가지치기를 해야할까요?
보통의 CNN모델은 CNN부분과 FC 부분으로 나눠진다,
대부분의 파라미터는 FC부분에 있음
그러나 연산 속도의 bottleneck은 CNN부분에 있음
따라서 공간과 시간의 효율을 모두 챙기려면 각각 pruning이 필요하다.

출처: https://www.researchgate.net/figure/Deep-features-from-the-convolutional-layer-and-FC-layer-of-CNN_fig1_350935646
CNN FIlters
레이어 별로 각각 여러 개의 filter가 있음
Filter Pruning
이 중 중요도가 작은 filter를 제거하는 것이 CNN의 pruning
한 레이어에 있는 실제 filter들의 모습을 보면
절반 정도는 sparse하거나 거의 0에 가까운 값들로 이루어진다.

출처: https://arxiv.org/pdf/1608.08710
Sparse 한 filter를 제거하는 것이 정말 좋은 기준이 되는가? => Sensitivity analysis 해봐라!

Sensitivity analysis에 따르면
요약
CNN 같은 경우의 가지치기 방법은
CNN 파트와 FC 파트 나눠서 진행하고
그 구조는 Structured Pruning이 맞고
레이어 별 filter 단위로 prune한다.그리고 prune할 대상을 정하는
Scoring의 경우 Filter의 sparsity를 중요도로 사용하고 Practical 하게는 L2-norm을 사용한다.
또한 레이어 별로 비율을 다르게 설정한다.
LLM 시대 직전에 있었던 다용도 언어 모델
BERT-base는 12개의 transformer layer로 이루어져 있음
어떻게 Pruning 할것인가?
Layers of BERT
언어모델도 보통은
그러나 레이어 별로 sparsity가 비일관적이다.
따라서 절대값 기준 pruning이 유효하다.First Layer
단어 모음인 vocabulary
- 벡터의 모음 = 행렬
- 실제로는 이 vocabulary가 첫번째 레이어를 담당하고
-정확히는, 이에 대응하는 embedding matrix- 특징: 짧은 단어일수록 벡터가 더 sparse 하다.
- Local Pruning을 하면, 짧은 단어 위주로 pruning을 하기 때문에 유효

BERT Pruning Summary
- Structure
- Unstructured Pruning
- Scoring
- 레이어별로 진행하는 Local Pruning
- 절댓밗을 기준으로 파라미터를 제거


class Model(nn.Module):
def __init__(self):
super(Model, self).__init__()
self.fc1 = nn.Linear(2, 10)
self.fc2 = nn.Linear(10, 2)
def forward(self, x):
x = self.fc1(x)
x = torch.relu(x)
x = self.fc2(x)
return x


기본 모델
# 모델 인스턴스 생성 및 학습
torch.manual_seed(42)
model = Model()
train(model, train_data, device)
# 성능 평가
test(model, test_data, device)
# Accuracy: 91%
# 전체 파라미터 수
total_params = sum(p.numel() for p in model.parameters())
# 0이 아닌 파라미터의 수
total_params_nz = sum((p != 0.0).sum() for p in model.parameters())
# 0이 아닌 파라미터의 비율
print(f"non-ziro portion: (100*total_params_nz / total_params: 6.02f)%")
torch 내장 라이브러리 사용
`import torch.nn.utils.prune as prune
랜덤하게 첫번째 레이어에서 50%를 제거 (prune.random_unstructured 함수)
layer = model.fc1
layer.weight
torch.manual_seed(42)
prune.random_unstructured(layer, name='weight', amount =0.5)
# 제거된 (0으로 바뀐) 파라미터 확인
layer.weight

# 0이 아닌 파라미터의 비율
total_params = sum(p.numel() for p in model.parameters())
total_params_nz = sum((p != 0.0).sum() for p in model.parameters())
print(f"non-zero portion: (100*total_params_nz / total_params: 5.02f)%")
- fc1: 2x10 + 10(weight & bias) = 30개
- fc2: 10x2 + 2(weight & bias) = 22개
- 총 30 + 22 = 52 개
- fc1.weight에서 10개 제거 -> 총 42개
- 42/52 = 80.77 %
그렇다면 랜덤하게 50%가 아니라, 파라미터 절대값이 작은 순으로 50%를 제거한다면?
- Magnitude Pruning
layer = model.fc1
prune.l1_unstructured(layer, name='weight', amount = 0.5)


layer=model.fc2
prune.l1_unstructured(layer, name='weight', amount = 0.5)

amount를 바꿔가며 변경할 수도 있다.
| Pruning 대상 | Pruning 방식 | Pruning 비율 | 학습 상태 | 성능 | 파라미터 압축률 |
|---|---|---|---|---|---|
| 기본 모델 | 학습 완료 | 91% | 100% | ||
| 레이어 1 | random | 50% | pruning 직후 | 72% | 80.77% |
| + fine-tuning 이후 | 90% | 80.77% | |||
| 레이어 1 | magnitude | 50% | pruning 직후 | 93% | 80.77% |
| + fine-tuning 이후 | 93% | 80.77% | |||
| 레이어 2 | magnitude | 50% | pruning 직후 | 82% | 80.77% |
| + fine-tuning 이후 | 92% | 80.77% | |||
| 레이어 1 | magnitude | 80% | pruning 직후 | 76% | 69.23% |
| + fine-tuning 이후 | 84% | 69.23% |