Implementing Pruning Convolutional Neural Networks for Resource Efficient Inference in Mxnet
6073 단어 심도 있는 학습
pytorch 코드를 참고하여 논문'Pruning Convolutional Neural Networks for Resource Efficient Inference'를 mxnet 프레임워크로 재현했다. 코드는 하나의 GitHub 프로젝트에서 나온 것이다. 본고는 주로 그 코드를 바탕으로 mxnet의 프레임워크에 이식한 것이다. 이식하는 과정에서 많은 문제점을 발견했다. mxnet을 잘 배운 셈이다.
우선 가지치기 과정은 주로PrunningFineTuner를 통해CNN 클래스의 prune() 함수는 다음과 같은 기본 절차로 완료됩니다.
① 가지치기 교체 횟수를 계산한다->②rank값을 계산한다(논문에서 테일러 전개식의 값, 이 단계에서는 귀일화 등 조작도 관련된다)->③ 가지치기된 층과 권적핵 index(실제로 두 번째 단계는 이 함수에서)->④가지치기->⑤fine-tuning
-> 반복 ②-> ⑥ 반복 횟수를 아는 프로세스
1、가지치기layer and filter index 함수 get 획득prunning_Plan()은 PrunningFineTuner 에 포함됩니다.CNN 중
def get_prunning_plan(self, num_filters_to_prune):
filters_to_prune = self.lowest_ranking_filters(num_filters_to_prune)
filters_to_prune_per_layer = {}
for (l, f, _) in filters_to_prune:
# l:layer index
# f:filter index
if l not in filters_to_prune_per_layer:
filters_to_prune_per_layer[l] = []
filters_to_prune_per_layer[l].append(f)
for l in filters_to_prune_per_layer:
#
filters_to_prune_per_layer[l] = sorted(filters_to_prune_per_layer[l])
for i in range(len(filters_to_prune_per_layer[l])):
filters_to_prune_per_layer[l][i] = filters_to_prune_per_layer[l][i] - i
filters_to_prune = []
for l in filters_to_prune_per_layer:
for i in filters_to_prune_per_layer[l]:
filters_to_prune.append((l, i))
return filters_to_prune
함수 lowestranking_filters(num filters to prune)의 역할은 계산을 통한rank가 가장 작은numfilters_to_prune 볼륨 핵의 index입니다. 되돌아오는 값은list 내부 매개 변수 형식입니다. (layerindex,filterindex,rank value), 즉return [(layerindex,filterindex,rank value)]
항상 맞아요.
filters_to_prune_per_layer[l][i] = filters_to_prune_per_layer[l][i] - i
의문이 있습니다. 왜 i를 빼야 하는지 모르겠습니다. 그 목적은 가지치기 후의 가지치기를 기다리는 Filter index를 업데이트하기 위해서입니다. 저희lowestranking_filters 함수에서 반환되는 데이터는 다음과 같습니다.
[(1,1,1),(1,3,1),(2,1,4),(2,2,6),(2,10,6),(3,2,6),(4,3,10)]
(2,1,4) 세 번째 권적층을 나타내는 두 번째 필터의rank값은 4로 get 을 거친다prunning_plan 함수에서 처리된 데이터는 다음과 같습니다.
[(1, 1), (1, 2), (2, 1), (2, 1), (2, 8), (3, 2), (4, 3)]
우리는 여기에 중복된 (2,1)이 있는 것을 보았다. 그리고 원래(2,10,6)도 (2,8)로 바뀌었다. 이것은 프로그램에서 하나하나가 감가했기 때문이다. 매번 하나의 권적핵만 줄일 수 있기 때문이다. 우리가 3층 두 번째 권적핵을 빼면 이 층의 권적핵은 하나가 줄어들고 원래 세 번째는 현재의 두 번째가 되고 열 번째는 앞의 두 개를 자른 후에 아홉 번째(계수는 0부터)가 된다.
2. mxnet 재현 과정
1. ARgparse 모듈의 사용
로드 모듈 import argparse
def get_args():
parser = argparse.ArgumentParser()
parser.add_argument("--train", dest="train", action="store_true")
parser.add_argument("--prune", dest="prune", action="store_true")
parser.add_argument("--train_path", type = str, default = "train")
parser.add_argument("--test_path", type = str, default = "test")
parser.set_defaults(train=False)
parser.set_defaults(prune=False)
args = parser.parse_args()
return args
add_gument () 첫 번째 파라미터는 명령행 파라미터 이름이고 dest는 저장된 이름이며 기본적으로 첫 번째 파라미터 뒤에 있는 문자열입니다. 위 코드와 같이 우리는args,train을 사용하여train이 저장한 파라미터에 접근할 수 있습니다. action 파라미터는 기본적으로'store'기본 저장소이고'store'를 사용하면true'는 부울 값으로 저장됩니다. 명령줄에 -train이 나타나면args입니다.train==True,default는 기본값입니다. 위에서 보듯이 앞의 두 파라미터도default=False의 방법으로 기본값을 설정할 수 있습니다.
2、권적핵 획득 개수
먼저 설명해야 할 것은 이 권적핵은 3차원 권적핵이다. 예를 들어 하나의 권적 조작 입력 출력 권적핵은 각각 in 이다.channels와 outchannels, 그럼 이번 조작에outchannels개 권적핵, 각 권적핵은 inchannels 차원의.
코드는 다음과 같습니다.
def total_num_filters(self):
filter = 0
for name, block in model.feature._children.items():
if isinstance(block, nn.Conv2D):
filter += block._channels
return filter
class block._children은 사전 형식으로 add () 함수를 통해 추가된 모든 Block을 저장합니다.registerchild() 함수 등록children 중입니다.
add는 각각
def add(self, *blocks):
"""Adds block on top of the stack."""
for block in blocks:
self.register_child(block)
def register_child(self, block, name=None):
"""Registers block as a child of self. :py:class:`Block` s assigned to self as
attributes will be registered automatically."""
if name is None:
name = str(len(self._children))
self._children[name] = block
2. 볼륨 층수:
nn.Conv2D(in_channels=3, channels=64, kernel_size=3, strides=1, padding=1),
nn.BatchNorm(),
nn.Activation('relu'),
nn.Conv2D(in_channels=64, channels=64, kernel_size=3, strides=1, padding=1),
nn.BatchNorm(),
nn.Activation('relu'),
nn.MaxPool2D(pool_size=2, strides=2),
nn.Conv2D(in_channels=64, channels=128, kernel_size=3, strides=1, padding=1),
nn.BatchNorm(),
nn.Activation('relu'),
nn.Conv2D(in_channels=128, channels=128, kernel_size=3, strides=1, padding=1),
nn.BatchNorm(),
nn.Activation('relu'),
nn.AvgPool2D(pool_size=2,strides=2),
nn.Conv2D(in_channels=128, channels=256, kernel_size=3, strides=1, padding=1),
nn.BatchNorm(),
nn.Activation('relu'),
nn.Conv2D(in_channels=256, channels=256, kernel_size=3, strides=1, padding=1),
nn.BatchNorm(),
nn.Activation('relu'),
nn.AvgPool2D(pool_size=8,strides=8)
프로그램 통계를 낼 때 모든 Block은 바로batchnorm,conv2d,activation이layer라는 것이다
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
[Caffe] mnist 인식 프로세스cd $CAFFE_ROOT 트레이닝 데이터 다운로드 ./data/mnist/get_mnist.sh 데이터 세트 만들기: ./examples/mnist/create_mnist.sh 트레이닝 모델: ./examples/...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.