Computer Vision/Deep learning

19. 풀링 층

jwjwvison 2021. 6. 12. 15:50

풀링 층의 목적은 계산량과 메모리 사용량, (과대적합의 위험을 줄이기 위한) 파라미터수를 줄이기 위해 입력 이미지의 부표본(즉, 축소본)을 만드는 것이다.

 합성곱 층에서와 마찬가지로 풀링 층의 각 뉴런은 이전 층의 작은 사각 영역의 수용장 안에 있는 뉴런의 출력과 연결되어 있다. 이전과 동일하게 크기, 스트라이드, 패딩 유형을 지정해야 한다. 하지만 풀링 뉴런은 가중치가 없다. 즉 최대나 평균 같은 합산 함수를 사용해 입력값을 더하는 것이 전부이다.

 다음 그림은 아주 널리 사용되는 풀링 층인 최대 풀링 층을 보여준다. 이 예에서는 2x2 풀링 커널(pooling kernel)과 스트라이드 2를 사용하며 패딩은 없다. 각 수용장에서 가장 큰 입력값이 다음 층으로 전달되고 다른 값은 버려진다.

 

 계산량, 메모리 사용량, 파라미터 수를 감소하는 것 외에도 그림 14-9 처럼 최대 풀링은 작은 변화에도 일정 수준의 불변성을 만들어준다.

 CNN에서 몇 개 층마다 최대 풀링은 회전과 확대, 축소에 대해 약간의 불변성을 제공한다. 이와 같은 불변성은 분류 작업처럼 예측이 이런 작은 부분에서 영향을 받지 않는 경우 유용할 수 있다.

 

 최대 풀링은 단점도 가지고 있다. 먼저 이 층은 매우 파괴적이다. 작은 2x2 커널과 스트라이드 2를 사용하더라도 출력은 양방향으로 절반이 줄어들어(그러므로 면적이 1/4로 줄어든다) 입력값의 75%를 잃게 된다.

 

 텐서플로에서 최대 풀링 층을 구현하는 것은 아주 쉽다. 다음 코드는 2x2 커널을 사용해 최대 풀링 층을 만든다. 스트라이드의 기본값은 커널 크기이므로 이 층은 스트라이드 2를 사용한다. 기본적으로 'valid' 패딩을 사용한다.

max_pool=keras.layers.MaxPool2D(pool_size=2)

 

 평균 풀링 층을 만들려면 MaxPool2D 대신 AvgPool2D를 사용한다. 일반적으로 최대 풀링 층이 더 성능이 좋다. 평균을 계산하면 최대값을 계산한는 것보다 정보 손실이 적다. 반면 최대 풀링은 의미 없는 것은 모두 제거하고 가장 큰 특징만 유지한다. 따라서 다음 층이 조금 더 명확한 신호로 작업할 수 있다. 또한 최대 풀링은 평균 풀링보다 강력한 이동 불변성을 제공하고 연산 비용이 조금 덜 든다.

 

 

 케라스는 깊이방향 풀링 층을 제공하지 않지만 텐서플로 저수준 딥러닝 API를 사용할 수 있다. tf.nn.max_pool() 함수를 사용하고 커널 크기와 스트라이드를 4개의 원소를 가진 튜플로 지정한다. 첫 번째 세 값은 1이어야 한다. 이는 배치, 높이, 너비 차원을 따라 커널 크기와 스트라이드가 1이란 뜻이다. 이는 배치, 높이, 너비 차원을 따라 커널 크기와 스트라이드가 1이란 뜻이다. 예를 들어 3과 같이 깊이 차원을 따라 원하는 커널 사이즈와 스트라이드를 마지막 값에 지정한다 (입력 깊이를 나누었을 때 떨어지는 값이어야 한다. 이전 층에서 20개의 특성 맵이 출력된다면 3의 배수가 아니므로 작동하지 않는다).

output=tf.nn.max_pool(images,
                      ksize=(1,1,1,3),
                      strides=(1,1,1,3),
                      padding='VALID')

 이를 케라스 모델의 층으로 사용하고 싶으면 Lambda 층으로 감싸면 된다.

depth_pool=keras.layers.Lambda(
    lambda X:tf.nn.max_pool(X,ksize=(1,1,1,3),strides=(1,1,1,3),
                            padding='valid')
)

 

 현대적인 신경망 구조에서 종종 보게될 마지막 풀링 층의 종류는 전역 평균 풀링 층(global average pooling layer)이다. 이 층의 작동 방식은 매우 다르다. 각 특성 맵의 평균을 계산하는 것이다. 각 샘플의 특성 맵마다 하나의 숫자를 출력한다는 의미이다. 물론 이는 매우 파괴적인 연산이지만(특성 맵에 있는 대부분의 정보를 잃는다) 출력층에는 유용할 수 있다. 이런 층을 만들려면 간단히 keras.layers.GlobalAvgPool2D 클래스를 사용한다.

global_avg_pool=keras.layers.GlobalAvgPool2D()