Implementing Pruning Convolutional Neural Networks for Resource Efficient Inference in Mxnet

6073 단어 심도 있는 학습
1. 코드 분석:
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라는 것이다

좋은 웹페이지 즐겨찾기