오리지널 Inception 모듈은 GoogLeNet 용으로 설계되어 ImageNet 데이터 세트 (각 입력 이미지가 224 × 224 × 3 인 것으로 가정)에서 학습하고 최첨단 정확도를 얻을 수 있습니다. 그럼에도 더 적은 네트워크 매개 변수가 필요한 더 작은 데이터 세트 (더 작은 이미지 공간 차원 포함)의 경우 Inception 모듈을 단순화 할 수 있습니다. 아래 그림의 맨 위 행은 MiniGoogLeNet 구현에 사용 된 세 가지 모듈을 설명합니다.

Miniception 아키텍처는 convolution 모듈, Inception 모듈 및 다운 샘플 모듈을 포함한 빌딩 블록으로 구성됩니다. 이러한 모듈은 전체 아키텍처를 형성하기 위해 함께 결합됩니다.
• 왼쪽 : 컨볼루션, 배치 정규화 및 활성화를 수행하는 컨볼 루션 모듈입니다.
• 중간 : 1×1 필터 용과 3×3 필터 용으로 하나씩 두 세트의 컨볼 루션을 수행하는 미니 셉션 모듈이 결과를 연결합니다. (1) 입력 볼륨이 더 작아지고 (CIFAR-10 데이터 세트를 사용할 것이므로) (2) 네트워크의 매개 변수 수를 줄이기 위해 3×3 필터 전에 차원 축소가 수행되지 않습니다.
• 오른쪽 : 컨볼루션과 최대 풀링을 모두 적용하여 차원을 줄인 다음 필터 차원에서 연결하는 다운 샘플 모듈입니다.
그런 다음 이러한 빌딩 블록을 사용하여 맨 아래 줄에 MiniGoogLeNet 아키텍처를 구축합니다. 여기서는 CNN을 구현할 때 권장되는 것과 달리 작성자가 활성화 전에 배치 정규화를 배치했음을 알 수 있습니다 (아마도 Szegedy 등이 수행 한 작업이기 때문일 수 있음). 이 책에서는 결과를 복제하기 위해 활성화 전에 배치 정규화를 배치하여 원저자의 작업 구현을 고수했습니다. 자신의 실험에서는 이 순서를 바꾸는 것을 생각해 볼 수 있습니다. 다음 섹션에서는 MiniGoogLeNet 아키텍처를 구현하고이를 CIFAR-10 데이터 세트에 적용합니다. 여기에서 전체 Inception 모듈을 구현하고 cs231n Tiny ImageNet 과제를 해결할 준비가 될 것입니다.
먼저 nn의 conv 모듈 내에 minigooglenet.py라는 파일을 만듭니다. 여기에 MiniGoogLeNet 클래스 구현을 하겠습니다.

minigooglenet.py를 열고 다음 코드를 삽입하십시오.

2 ~ 13 행은 필수 Python 패키지를 가져옵니다. 한 레이어의 출력이 다음 레이어로 직접 공급되는 Sequential 클래스를 가져 오는 대신 Model 클래스 (11 행)를 사용해야합니다. Sequential이 아닌 Model을 사용하면 Inception 모듈 에서처럼 분할 및 분기가있는 네트워크 그래프를 만들 수 있습니다. 아직 보지 못한 또 다른 import는 12 행의 concatenate 함수입니다. 이름에서 알 수 있듯이이 함수는 입력 집합을 가져 와서 주어진 축을 따라 연결합니다. 이 경우에는 채널 차원이됩니다. 이전 그림에 설명 된대로 MiniGoogLeNet의 정확한 버전을 구현할 것이므로 conv_module부터 시작하겠습니다.
conv_module 함수는 컨볼 루션 적용, 배치 정규화, 마지막으로 활성화를 담당합니다. 메서드에 대한 매개 변수는 아래에 자세히 설명되어 있습니다.

• x : 함수에 대한 입력 계층.
• K : CONV 레이어가 학습 할 필터의 수
• kX 및 kY : 학습 할 각 K 필터의 크기
• stride : CONV 레이어의 스트라이드
• chanDim : “channels last”또는 “channels first” 순서에서 파생된 채널의 차원
• padding : CONV 레이어에 적용 할 패딩 유형
19 행에서 우리는 conv 층을 생성합니다. Conv2D에 대한 실제 매개 변수는 AlexNet 및 VGGNet과 같은 이전 아키텍처의 예제와 동일하지만 여기서 변경된 사항은 주어진 계층에 입력을 제공하는 방법입니다.
네트워크 아키텍처를 정의하기 위해 Sequential이 아닌 Model을 사용하고 있기 때문에 model.add를 호출 할 수 없습니다. 이것은 한 레이어의 출력이 순차적으로 다음 레이어로 이어진다는 것을 의미하기 때문입니다. 대신 함수 호출이 끝날 때 괄호 안에 입력 레이어를 제공합니다.이를 Functional API라고합니다. 모델의 각 레이어 인스턴스는 텐서에서 호출 할 수 있으며 텐서를 반환합니다. 따라서 객체가 인스턴스화되면 함수로 호출하여 주어진 레이어에 입력을 제공 할 수 있습니다. 이러한 방식으로 레이어를 구성하기위한 템플릿은 아래에서 볼 수 있습니다.
비 순차적 네트워크를 정의 할 때마다 사용하게 되므로 네트워크에 레이어를 추가하는이 새로운 스타일에 익숙해 지시길 바랍니다. Conv2D 계층의 출력은 20 행의 BatchNormalization 계층으로 전달됩니다. 그런 다음 BatchNormalization의 출력은 ReLU 활성화 (21 행)를 거칩니다. conv_module을 시각화하는 데 도움이되는 그림을 구성한다면 아래 그림과 같을 것입니다.

MiniGoogLeNet 아키텍처의 conv_module. 이 모듈은 분기를 포함하지 않으며 간단한 CONV => BN => ACT입니다.
먼저 컨볼 루션이 적용된 다음 일괄 정규화가 적용된 다음 활성화됩니다. 이 모듈은 분기를 수행하지 않았습니다. 아래의 inception_module 정의로 변경 될 것입니다.

Mininception 모듈은 1×1 CONV와 3×3 CONV의 두 세트의 컨볼루션을 수행합니다. 이 두 컨볼루션은 병렬로 수행되고 결과 함수는 채널 차원에서 연결됩니다.
30 행과 31 행은 conv_module을 사용하여 numK1x1 필터 (1×1)를 학습합니다. 32 행과 33 행은 conv_module을 다시 적용하여 numK3x3 필터 (3 × 3)를 학습합니다. conv_module 함수를 사용하면 코드를 재사용 할 수 있고 CONV => BN => RELU 블록의 여러 블록을 삽입하여 MiniGoogLeNet 클래스를 부 풀릴 필요가 없습니다. 이 스택은 conv_module을 통해 간결하게 처리됩니다.
1×1 및 3×3 Conv2D 클래스에 대한 입력이 모두 레이어에 대한 입력 인 x 인 것을 확인하십시오. Sequential 클래스를 사용할 때 이러한 유형의 레이어 구조는 불가능했습니다. 그러나 Model 클래스를 사용하면 이제 여러 레이어가 동일한 입력을 받아들이도록 할 수 있습니다. conv_1x1과 conv_3x3이 모두 있으면 채널 차원에서 연결합니다.

(mini) -inception_module은 두 가지 분기로 구성됩니다. 첫 번째 분기는 1×1 필터를 학습하는 CONV 계층입니다. 두 번째 분기는 3×3 필터를 학습하는 또 다른 CONV 계층입니다. 그런 다음 필터 응답은 채널 차원을 따라 연결됩니다.
“Mini”-Inception 모듈을 시각화하려면 위 그림을 살펴보십시오. 1×1 및 3×3 CONV 레이어는 주어진 입력을 받아 각각의 컨볼루션을 적용합니다. 그런 다음 두 컨볼 루션의 출력이 연결됩니다 (33 행). padding = “same”으로 인해 두 컨볼루션의 출력 볼륨 크기가 동일하기 때문에 레이어 출력을 연결할 수 있습니다. 다음은 이름에서 알 수 있듯이 입력 볼륨의 공간 크기를 줄이는 역할을 하는 downsample_module입니다. @staticmethod def downsample_module(x, K, chanDim): # define the CONV module and POOL, then concatenate # across the channel dimensions conv_3x3 = MiniGoogLeNet.conv_module(x, K, 3, 3, (2, 2), chanDim, padding=”valid”) pool = MaxPooling2D((3, 3), strides=(2, 2))(x) x = concatenate([conv_3x3, pool], axis=chanDim) # return the block return x
이 메소드는 일괄 정규화 및 채널 연결을 위한 chanDim과 함께 컨벌루션 레이어가 학습 할 필터 수 K 인 입력 x를 전달해야합니다. downsample_module의 첫 번째 분기는 2×2의 스트라이드를 사용하여 K, 3×3 필터 세트를 학습하여 출력 볼륨 크기를 줄입니다 (라인 43 및 44). 우리는 볼륨 크기를 줄이기 위해 창 크기가 3×3이고 보폭이 2×2 인 라인 45 (두 번째 분기)에 최대 풀링을 적용합니다. conv_3x3 및 pool 출력은 연결되고 (46 행) 호출 함수로 반환됩니다.

downsample_module은 입력 볼륨의 공간 차원을 줄이는 역할을합니다. 첫 번째 분기는 출력 볼륨을 줄이기 위해 스트라이드가 2×2 인 필터 세트를 학습합니다. 두 번째 분기도 이번에는 최대 풀링을 적용하여 공간 차원을 줄입니다. downsample_module의 출력은 채널 차원을 따라 연결됩니다.
위 그림에서 downsample_module을 시각화 할 수 있습니다. 그림에서 알 수 있듯이 컨볼루션 및 최대 풀링 작업이 동일한 입력에 적용된 다음 연결됩니다.
이제 모든 조각을 모을 준비가되었습니다. @staticmethod def build(width, height, depth, classes): # initialize the input shape to be “channels last” and the # channels dimension itself inputShape = (height, width, depth) chanDim = -1 # if we are using “channels first”, update the input shape # and channels dimension if K.image_data_format() == “channels_first”: inputShape = (depth, height, width) chanDim = 1
52 행은 네트워크에 대한 빌드 방법을 정의합니다. 우리의 빌드 방법은 입력 너비, 높이, 깊이 및 학습 할 총 클래스 수를 허용합니다. 55 행과 56 행은 우리가 “channels last”순서를 사용한다고 가정하고 inputShape와 chanDim을 초기화합니다. 대신 “channels first”순서를 사용하는 경우 60-62 행은 이러한 변수를 각각 업데이트합니다. 첫 번째 conv_module과 함께 모델 입력을 정의 해 보겠습니다. # define the model input and first CONV module inputs = Input(shape=inputShape) x = MiniGoogLeNet.conv_module(inputs, 96, 3, 3, (1, 1), chanDim)
65 행의 입력에 대한 호출은 아키텍처를 초기화합니다. 네트워크에 대한 모든 입력은 단순히 입력 데이터를 “holds”하는 이 계층에서 시작됩니다 (모든 네트워크에 입력이 있어야 함). 첫 번째 CONV => BN => RELU는 66 번과 67 번 줄에 적용되어 96, 3×3 필터를 학습합니다. 여기에서 두 개의 Inception 모듈과 다운 샘플 모듈을 쌓습니다. # two Inception modules followed by a downsample module x = MiniGoogLeNet.inception_module(x, 32, 32, chanDim) x = MiniGoogLeNet.inception_module(x, 32, 48, chanDim) x = MiniGoogLeNet.downsample_module(x, 80, chanDim)
첫 번째 Inception 모듈 (70 행)은 1×1 및 3×3 CONV 레이어 모두에 대해 32 개의 필터를 학습합니다. 연결되면이 모듈은 K = 32 + 32 = 64 필터로 볼륨을 출력합니다. 두 번째 Inception 모듈 (71 행)은 32, 1 × 1 필터와 48, 3 × 3 필터를 학습합니다. 다시 연결하면 출력 볼륨 크기가 K = 32 + 48 = 80임을 알 수 있습니다. 다운 샘플 모듈은 입력 볼륨 크기를 줄이지 만 80에서 학습 한 필터 수는 동일하게 유지합니다. 다음으로 4 개의 Inception 모듈을 위에 쌓아 보겠습니다. 다운 샘플을 적용하기 전에 GoogLeNet이 더 깊고 풍부한 기능을 학습 할 수 있도록 합니다. # four Inception modules followed by a downsample module x = MiniGoogLeNet.inception_module(x, 112, 48, chanDim) x = MiniGoogLeNet.inception_module(x, 96, 64, chanDim) x = MiniGoogLeNet.inception_module(x, 80, 80, chanDim) x = MiniGoogLeNet.inception_module(x, 48, 96, chanDim) x = MiniGoogLeNet.downsample_module(x, 96, chanDim)
일부 레이어에서는 3×3 필터보다 1×1 필터를 더 많이 학습하는 반면 다른 Inception 모듈은 1×1보다 3×3 필터를 더 많이 학습합니다. 이러한 유형의 변형 패턴은 Szegedy et al. 이 많은 실험을 결과로 의도적으로 수행된 것입니다.. 이 장 뒷 부분에서 GoogLeNet의 더 깊은 변형을 구현할 때 이 패턴을 볼 수 있습니다. 구현을 계속하면서 이제 두 개의 시작 모듈을 더 적용한 다음 글로벌 풀 및 드롭 아웃을 적용 할 것입니다. # two Inception modules followed by global POOL and dropout x = MiniGoogLeNet.inception_module(x, 176, 160, chanDim) x = MiniGoogLeNet.inception_module(x, 176, 160, chanDim) x = AveragePooling2D((7, 7))(x) x = Dropout(0.5)(x)
83 행 이후의 출력 볼륨 크기는 7×7×336 입니다. 7×7의 평균 풀링을 적용하면 볼륨 크기가 1×1×336으로 줄어들 기 때문에 많은 완전 연결 레이어를 적용 할 필요성이 줄어 듭니다. 대신 간단히 컨볼루션의 공간 출력을 평균해 버립니다. 드롭 아웃은 과적 합을 줄이기 위해 85행에서 50 % 확률로 적용됩니다. 마지막으로 배우고 자하는 클래스 수에 따라 소프트맥스 분류기를 추가합니다. # softmax classifier x = Flatten()(x) x = Dense(classes)(x) x = Activation(“softmax”)(x) # create the model model = Model(inputs, x, name=”googlenet”) # return the constructed network architecture return model
그런 다음 실제 모델은 inputs, layer (내부 분기를 포함하는 x) 및 선택적으로 네트워크의 이름을 전달하는 93 행에서 인스턴스화됩니다. 구성된 아키텍처는 96 행의 호출 함수로 반환됩니다.