일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
- 프로그래머스타겟넘버정답
- pytorch
- 프로그래머스게임맵최단거리
- 코딩테스트연습
- 프로그래머스bfs
- 최솟값 만들기
- deep learning
- Faster R-CNN
- One stage detector
- Two stage Detector
- 프로그래머스타겟넘버파이썬
- 코딩테스트네트워크
- 프로그래머스너비우선탐색
- Object Detection
- 커피후기
- Single Shot MultiBox Detector
- 프로그래머스타겟넘버
- ECCV
- ssd
- 다음큰숫자
- SSD 리뷰
- 프로그래머스
- 타겟넘버bfs
- 프로그래머스네트워크
- Code Study
- 프로그래머스파이썬
- Pytorch pruning
- 코딩테스트2단계
- Paper list
- Pruning Tutorial
- Today
- Total
soyeonland
Pruning Tutorial 본문
1. model 생성
import torch
from torch import nn
import torch.nn.utils.prune as prune
import torch.nn.functional as F
device = torch.device('cuda' if torch.cuda.is_available() else "cpu")
class LeNet(nn.Module):
def __init__(self):
super(LeNet, self).__init__()
self.conv1 = nn.Conv2d(1, 6, kernel_size=3)
self.conv2 = nn.Conv2d(6, 16, kernel_size=3)
self.fc1 = nn.Linear(16 * 5 *5, 120)
self.fc2 = nn.Linear(10, 84)
self.fc3 = nn.Linear(84,10)
def forward(self, x):
x = F.max_pool2d(F.relu(self.conv1(x)), (2,2))
x = F.max_pool2d(F.relu(self.conv2(x)), 2)
x = x.view(-1, int(x.nelement()/x.shape[0]))
x = F.relu(self.fc1(x))
x = F.relu(self.fc2(x))
x = self.fc3(x)
return x
2. weight 접근
conv1의 weight들 출력
model = LeNet().to(device = device)
module = model.conv1
print(list(module.named_parameters()))
print(list(module.named_buffers()))
=>
[('weight', Parameter containing:
tensor([[[[-0.2511, -0.2876, 0.2079],
[ 0.0291, -0.1426, 0.1376],
[-0.2901, -0.0334, 0.2352]]],
[[[-0.0660, -0.1610, 0.0728],
[ 0.0041, -0.3127, 0.1384],
[ 0.3017, 0.1271, 0.3223]]],
[[[ 0.2340, -0.1247, -0.3186],
[ 0.3174, -0.2277, -0.0598],
[ 0.1046, 0.1306, 0.1649]]],
[[[ 0.0397, 0.2533, 0.0615],
[ 0.0200, 0.1114, 0.0139],
[-0.0923, -0.1025, 0.2250]]],
[[[-0.3203, -0.1708, -0.0952],
[-0.0196, -0.3311, -0.1986],
[ 0.3165, -0.1322, 0.1062]]],
[[[-0.2047, -0.0777, -0.0955],
[-0.2469, -0.0815, -0.1437],
[ 0.1568, -0.1811, 0.2343]]]], device='cuda:0', requires_grad=True)), ('bias', Parameter containing:
tensor([-0.1787, -0.0440, 0.0534, -0.2793, 0.1707, -0.3073], device='cuda:0',
requires_grad=True))]
[]
list 없애보기
print(module.named_parameters())
=> list가 없으면 저장되 있는 위치가 불러와 진다.
<generator object Module.named_parameters at 0x7ff0fcdae780>
Weight만 꺼내보기
print(list(module.named_parameters())[0])
=> list에 'weight'와 'bias'가 tuple 형태로 저장되어 있다. 'weight'는 list index 0 에 해당
('weight', Parameter containing:
tensor([[[[-0.2511, -0.2876, 0.2079],
[ 0.0291, -0.1426, 0.1376],
[-0.2901, -0.0334, 0.2352]]],
[[[-0.0660, -0.1610, 0.0728],
[ 0.0041, -0.3127, 0.1384],
[ 0.3017, 0.1271, 0.3223]]],
[[[ 0.2340, -0.1247, -0.3186],
[ 0.3174, -0.2277, -0.0598],
[ 0.1046, 0.1306, 0.1649]]],
[[[ 0.0397, 0.2533, 0.0615],
[ 0.0200, 0.1114, 0.0139],
[-0.0923, -0.1025, 0.2250]]],
[[[-0.3203, -0.1708, -0.0952],
[-0.0196, -0.3311, -0.1986],
[ 0.3165, -0.1322, 0.1062]]],
[[[-0.2047, -0.0777, -0.0955],
[-0.2469, -0.0815, -0.1437],
[ 0.1568, -0.1811, 0.2343]]]], device='cuda:0', requires_grad=True))
type
print(type(list(module.named_parameters())[0]))
=> 튜플형태로 변수들이 저장되어 있다.
<class 'tuple'>
Weight 임의로 수정해보기
☞
print(list(module.named_parameters())[0][1])
=> weight에서 value 값만 불러오기 (참고: [0][0]은 'weight' 출력)
Parameter containing:
tensor([[[[-0.2511, -0.2876, 0.2079],
[ 0.0291, -0.1426, 0.1376],
[-0.2901, -0.0334, 0.2352]]],
[[[-0.0660, -0.1610, 0.0728],
[ 0.0041, -0.3127, 0.1384],
[ 0.3017, 0.1271, 0.3223]]],
[[[ 0.2340, -0.1247, -0.3186],
[ 0.3174, -0.2277, -0.0598],
[ 0.1046, 0.1306, 0.1649]]],
[[[ 0.0397, 0.2533, 0.0615],
[ 0.0200, 0.1114, 0.0139],
[-0.0923, -0.1025, 0.2250]]],
[[[-0.3203, -0.1708, -0.0952],
[-0.0196, -0.3311, -0.1986],
[ 0.3165, -0.1322, 0.1062]]],
[[[-0.2047, -0.0777, -0.0955],
[-0.2469, -0.0815, -0.1437],
[ 0.1568, -0.1811, 0.2343]]]], device='cuda:0', requires_grad=True)
☞
print(type(list(module.named_parameters())[0][1]))
=> Type: parameter
<class 'torch.nn.parameter.Parameter'>
☞
둘러보기
print((list(module.named_parameters())[0][1].shape))
=> Parameter의 shape (LeNet의 conv1 의 filter value라고 볼 수 있다. 3*3 filter가 6개)
torch.Size([6, 1, 3, 3])
☞
print((list(module.named_parameters())[0][1][0]))
=> weight의 첫 번째 channel 의 filter (module.parameters() 쓰면 더 쉽게 접근 가능)
tensor([[[-0.2511, -0.2876, 0.2079],
[ 0.0291, -0.1426, 0.1376],
[-0.2901, -0.0334, 0.2352]]], device='cuda:0',
grad_fn=<SelectBackward>)
☞
list(module.named_parameters())[0][1][0][0,1]=1
print((list(module.named_parameters())[0][1][0]))
=> Wegiht 수정하기
tensor([[[-0.2511, -0.2876, 0.2079],
[ 1.0000, 1.0000, 1.0000],
[-0.2901, -0.0334, 0.2352]]], device='cuda:0',
grad_fn=<SelectBackward>)
grad_fn이 True에서 Select BackWard로 수정되었음
☞
(힘들어서 함수랑 출력값을 동시에 작성)
print(list(module.named_parameters()))
[('weight', Parameter containing:
tensor([[[[-0.2511, -0.2876, 0.2079],
[ 1.0000, 1.0000, 1.0000],
[-0.2901, -0.0334, 0.2352]]],
[[[-0.0660, -0.1610, 0.0728],
[ 0.0041, -0.3127, 0.1384],
[ 0.3017, 0.1271, 0.3223]]],
[[[ 0.2340, -0.1247, -0.3186],
[ 0.3174, -0.2277, -0.0598],
[ 0.1046, 0.1306, 0.1649]]],
[[[ 0.0397, 0.2533, 0.0615],
[ 0.0200, 0.1114, 0.0139],
[-0.0923, -0.1025, 0.2250]]],
[[[-0.3203, -0.1708, -0.0952],
[-0.0196, -0.3311, -0.1986],
[ 0.3165, -0.1322, 0.1062]]],
[[[-0.2047, -0.0777, -0.0955],
[-0.2469, -0.0815, -0.1437],
[ 0.1568, -0.1811, 0.2343]]]], device='cuda:0',
grad_fn=<CopySlices>)), ('bias', Parameter containing:
tensor([-0.1787, -0.0440, 0.0534, -0.2793, 0.1707, -0.3073], device='cuda:0',
requires_grad=True))]
전체 결과, grad_fn이 CopySlices로 바꼈음
*grad_fn에 대해서 공부할 필요성이 있어보임.
3. prune 함수
☞
pruning이 되면
weight_orig에 원본 weigh들을 저장해둔다.
bias는 prune되지 않아서 변화가 없다.
amount = 0.3 만큼 weigh들을 없앤다.
prune.random_unstructured(module,name='weight', amount=0.3)
print(list(module.named_parameters()))
[('bias', Parameter containing:
tensor([-0.2179, 0.3039, 0.0210, 0.2159, -0.0538, 0.1727], device='cuda:0',
requires_grad=True)), ('weight_orig', Parameter containing:
tensor([[[[ 0.0553, -0.2966, 0.3259],
[-0.0673, -0.1419, 0.0502],
[-0.1520, 0.2030, 0.1565]]],
[[[ 0.2300, 0.1853, 0.1511],
[-0.2664, 0.0907, 0.0880],
[ 0.2731, 0.1323, -0.2508]]],
[[[ 0.0267, 0.2257, -0.1429],
[ 0.2152, -0.3155, -0.0194],
[-0.2857, -0.2567, 0.1992]]],
[[[-0.1144, 0.2800, -0.0774],
[-0.0859, -0.1653, -0.3080],
[ 0.0489, 0.1629, 0.2696]]],
[[[-0.0107, -0.2813, -0.0735],
[ 0.2105, 0.1150, 0.0696],
[-0.1975, -0.0789, -0.0035]]],
[[[ 0.1801, 0.2752, 0.1583],
[-0.1039, 0.2094, -0.2401],
[-0.0591, 0.0956, -0.1902]]]], device='cuda:0', requires_grad=True))]
☞
funtion: moudle.named_buffers()
pruning 이 일어나면 'weight_mask' 의 name으로 mask를 저장해둔다.
# 전체 파라미터 갯수: 9*6=54
#0 : 13
#0/parametrs : 13/54 = 0.24
print(list(module.named_buffers()))
[('weight_mask', tensor([[[[1., 1., 0.],
[1., 0., 1.],
[1., 1., 1.]]],
[[[0., 1., 1.],
[1., 0., 1.],
[1., 1., 1.]]],
[[[1., 0., 0.],
[1., 0., 1.],
[1., 0., 1.]]],
[[[1., 1., 1.],
[1., 0., 0.],
[1., 1., 1.]]],
[[[1., 1., 1.],
[0., 0., 1.],
[1., 0., 0.]]],
[[[1., 1., 1.],
[0., 1., 0.],
[1., 1., 1.]]]], device='cuda:0'))]
☞
forward가 변형없이 지나가기 위해서는 weight atrribute가 존재해야 한다.
torch.nn.utils.prune 이 mask과 original weight들을 합쳐서 pruned 된 weight 들을 생성한다.
그리고 weight 특성에 저장한다. 이때 주의할 점은 더이상 module 의 parameter가 아닌 단순 attribute이다.
:
print(module.weight)
tensor([[[[ 0.0553, -0.2966, 0.0000],
[-0.0673, -0.0000, 0.0502],
[-0.1520, 0.2030, 0.1565]]],
[[[ 0.0000, 0.1853, 0.1511],
[-0.2664, 0.0000, 0.0880],
[ 0.2731, 0.1323, -0.2508]]],
[[[ 0.0267, 0.0000, -0.0000],
[ 0.2152, -0.0000, -0.0194],
[-0.2857, -0.0000, 0.1992]]],
[[[-0.1144, 0.2800, -0.0774],
[-0.0859, -0.0000, -0.0000],
[ 0.0489, 0.1629, 0.2696]]],
[[[-0.0107, -0.2813, -0.0735],
[ 0.0000, 0.0000, 0.0696],
[-0.1975, -0.0000, -0.0000]]],
[[[ 0.1801, 0.2752, 0.1583],
[-0.0000, 0.2094, -0.0000],
[-0.0591, 0.0956, -0.1902]]]], device='cuda:0',
grad_fn=<MulBackward0>)
☞
마지막으로 pruning은 Pytorch의 forward_pre_hooks 라는 함수를 사용해서 pruning이 모든 forward pass에 적용된다.
구체적으로 module이 pruning이 되면, 우리는 pruning과 관련있는 parameter 각각에 대해서 forward_pre_hook 을 얻게된다.
이러한 상황안에서, 우리는 여태까지 weight라고 이름 붙여진 original parameter만 pruning을 해왔기 때문에 하나의 hook만 존재한다.
-특징: _forward_pre_hooks는 pruning 된 변수들을 orderdict로 가지고 있음
print(module._forward_pre_hooks)
OrderedDict([(0, <torch.nn.utils.prune.RandomUnstructured object at 0x7fae41905a90>)])
☞
for name, w in model.named_parameters():
print(name)
conv1.bias
conv1.weight_orig
conv2.weight
conv2.bias
fc1.weight
fc1.bias
fc2.weight
fc2.bias
fc3.weight
fc3.bias
<정리>
function
list(feature.named_parameters())
prune.random_unstructured(module, name="weight", amout=0.3)
[참조]https://pytorch.org/tutorials/intermediate/pruning_tutorial.html
'Study > Code Review' 카테고리의 다른 글
Github 모음(weight copy , pruning) (0) | 2020.08.16 |
---|---|
3D Convolution (0) | 2020.04.01 |
Learning both weights and connections for Efficient Neural Networks-(2) (0) | 2020.03.22 |
Learning both weights and connections for Efficient Neural Networks-(1) (0) | 2020.03.22 |
SSD - Pytorch (0) | 2020.02.28 |