Convolutional Neural Network(CNN) 기초 개념
Oct 02, 2023
현재 듣고 있는 구글 부트캠프에서 준비했던 내용을 아주 늦게나마 블로그에 정리한다.
딥러닝으로는 항상 정형 데이터만을 다뤄봤지만 처음으로 CNN을 다뤄봤는데 엄청 흥미롭고 배울게 많은 영역인 것 같다 !!
내가 리뷰했던 논문은 알렉스넷이였는데 그것은 조만간 코드로 연습해보고 포스팅해야지
해당 영상이 CNN 과 관련된 부분을 시각적으로 가장 잘 나타내준 것 같아서 공유한다.
어쩌면 내 글보다 훨씬 유익할지도 .,.,
CNN의 시작이 된 Lenet , AlexNet 등을 다루기 전에 먼저 CNN과 관련된 기초 개념을 공부해봤다.
맨 처음 딥러닝에 대해서 공부할 때 해당 네트워크를 많이 보았고 나 또한 이런 것이 딥러닝이구나 .. 했지만
가끔씩 나오는 CNN 이니 RNN 이니 하는 네트워크들의 이름을 듣거나
이런 식의 이미지를 보면서 많이 겁먹었던 기억이 있다.
오늘은 이런 네트워크인 Convolutional Neural Network (이하 CNN) 의 기초 개념에 대해 공부해봤다.
- 등장배경 : Local receptive filed (국부수용체)
1958,1959년 대뇌 피질 시각 수용체를 연구하던 연구자들로 인해서 우리의 뇌는 어떠한 물체를 인식 할 때
뇌의 모든 뉴런이 모두 활성화 되는 것이 아니라 저차원의 패턴을 인식하는 일부 뉴런들만이 활성화 되며
저차원의 패턴을 인식한 뉴런들이 결합 되면서 더욱 고차원 적인 패턴을 인식해나가는 것을 발견하였다.
저차원의 패턴이란, 어떤 물체가 있다면 물체의 색상, 물체의 수평적인 선, 수직적인 선, 곡선, 질감 등
물체의 전부가 아닌 해당 패턴들만을 인식하는 뉴런이 존재하고, 해당 뉴런들이 결합되어 물체를 인식한다는 것이다
이러한 개념은 위에서 보여줬던 완전 연결망과는 다른 개념이면서도 이미지 인식과 관련된 CNN 에게 있어서는 매우 중요한 힌트가 되었다.
이런 Local receptive Filed는 이미지의 특성에서 또한 연관된다.
2. 이미지를 인식 할 때 CNN 을 사용해야 하는 이유
2.1 Local correlation
우리가 이미지를 Fully connected Layer만을 이용해서 학습하면 안되는 이유는 대표적으로 2가지 있는데
우선 이미지들은 지역적인 상관관계를 가진다는 것이다.
예를 들어 고양이 사진을 픽셀 픽셀로 나눴을 때는 눈 중앙 부분의 픽셀 근처에 있는 모든 픽셀들은 눈이거나, 눈 주변에 위치한 물체들일 것이다.
만약 이미지를 우리에게 익숙한 Fully connected layer 로 나타내려면 2D 이미지를 1D vector 형태로 변경시켜줘야 한다 (이를 flatten 시킨다고 한다)
이미지를 만약 1D vector 로 변경하게 된다면 이미지가 가지는 지역적인 정보를 담지 못한 채 무의미하게 정보들만이 담긴 벡터 형태로 학습하게 될 것이다.
예를 들어 눈동자와 관련된 픽셀이 예를들어 100번째 원소였다면, 눈 옆부분은 200번째 , 논 윗부분은 99번째 .. 등등
뭐 이런식으로라도 원소 번호만으로도 지역적 특성을 담을 수 있지 않을까 ? 하는 생각이 들기도 하였지만
2.2 Invarient feature
모든 물체들은 Invarient feature (불변하는 특성) 가 존재한다.
예를 들어 고양이가 가지는 Invarient feature를 생각해보자
우선 고양이는 눈이 두 개, 코가 하나, 귀가 두 개 존재한다. 그리고 귀는 머리의 윗 부분에 존재하고 눈과 눈 사이에 코가 있으며 코에는 수염이 달려있다.
온 세상 모든 고양이가 똑같이 멈춰있는 상태로 존재한다면 이미지를 1D vector 로 변환해서 보아도 상관 없겠지만
만약 위 이미지처럼 고양이 사진이 반대로 뒤집어져있거나, 고양이가 움직인다면 ?
1D vector 로 고양이의 눈 위치를 100번째 원소는 눈 중앙, 눈 옆부분은 200번째 , 논 윗부분은 99번째 .. 등등으로 인식했는데
다음 고양이의 눈 위치가 조금이라도 달라지게 된다면 똑같은 고양이라 할지라도 해당 위치에는 고양이의 눈이 존재하지 않으니 고양이가 아니라고 판단하게 될 것이다.
이런 Invarient feature 는 여러가지가 존재하는데
방금 위에서 말했던 것 처럼 위치와 관련된 것, 크기, 회전, 조명, 보는 위치 등이 존재한다.
노란색의 고양이가 있다면 해당 고양이를 위에서 보든, 아래에서 보든 혹은 다른 색의 고양이를 보거나 어두운 조명, 밝은 조명에서 보더라도
고양이는 고양이만의 특징이 존재하는데 1D vector 로 flatten 시켜 학습하게 된다면 Invarient feature 를 학습하기가 어렵다.
2.3 학습해야 하는 많은 파라미터 개수
또 이미지를 1D vector 로 변경시켜 Fully connected layer 로 학습시키려 한다면
매우 저화질의 사진인 100 x 100 x 3 의 고양이 이미지를 1D 로 flatten 시키기만 한다면 input layer 의 node 개수는 벌써 3만개이다.
그리고 그 다음 레이어의 노드들을 1000개만 쓴다고 하더라도 벌써 첫번째 레이어의 파라미터 개수만 하더라도 3천만개가 된다. (편향은 0이라고 가정하자)
또 레이어를 하나만 쓸건가 ? 레이어를 늘리면 늘릴 수록 파라미터 개수는 훠어어얼씬 많이 늘어나게 된다.
이러한 3가지 문제를 해결해주는 네트워크는 ~~
위에서 설명했던 Local receptive filed 개념과 유사한 CNN 이다
3. CNN 의 구조
3.1 Kernel (filter)
우선 CNN 은 이미지를 학습 할 때 파라미터가 담긴 matrix 를 이용해서 합성곱 (convolution) 을 이용해 특징을 추출한다.
나는 이것을 마치 이미지를 도장 찍어 가는 듯한 뉘앙스로 이해했다.
위 이미지를 보면 맨 밑 input 이미지가 있다면 2 x 2 size 의 커널을 이용해서 이미지의 가 부분을 도장을 쾅 찍고
출력값을 윗 부분에 위치 시킨다.
그리고 반복, 반복 , 반복 .. .
이 때 input 이미지에 kernel을 도장 찍듯이 꽝 찍을 때에는 kernel 과 도장 찍힘을 당하는 이미지의 픽셀값과의
원소곱의 합과 활성화 함수를 거친 후 feature map 을 생성한다.
3.2 feature map
그렇게 kernel 을 이용하여 도장찍은 결과값이 차곡 차곡 쌓이는 곳이 feature map 이다.
각 kernel 들은 이미지의 저차원의 일부 패턴만을 인식할 수 있다.
예를 들어 1번 kernel 은 이미지의 수평적인 선만을 인식하는 kernel 이라고 한다면 해당 kernel 을 통과한 feature map 은
input 이미지의 수평적인 특징들이 담겨 있을 것이다. 수직적인 것들 또한 그렇고
윗 부분은 16개의 feature map 에 대한 것들이다. 맨 밑부분인 3이라는 숫자를 인식 할 때 어떤 feature map 은 곡선적인 부분의 특성, 어떤 feature map 은 색상 등 다양한 저차원의 패턴들을 담고 있는 모습을 볼 수 있다.
이는 뇌 과학 분야에서 이야기하는 국부 수용체 처럼 특정 저차원 패턴을 인식하는 뉴런들이 존재하는 것과 유사한 아이디어다.
이 때 하나의 feature map 을 생성할 때는 동일한 kernel 을 이용해 feature map 을 생성해나가는데
이것은 이미지의 invarient feature 를 인식하는데 큰 도움을 준다.
예를 들어 만약 fully connected layer였다면 고양이의 귀와 관련된 정보를 100번째 원소, 201 번쨰 원소 .. 등에 대해서만 인식 했겠지만
고양이의 귀 특성을 찾아내는 kernel 이 존재한다면 해당 kernel 은 모든 input image 에 대해서 동일하게 귀에 대한 특성을 찾아내기 때문에
invarient feature 를 찾아내는데 Fully conneted layer 에 비해 효과적이다.
이미지는 흑백 이미지라면 1채널, 색상 이미지라면 3채널 (RGB) 로 이뤄져있는데
하나의 feature map 을 만들 때 kernel 은 그럼 몇개가 필요할까 ?
그것은 input 이미지의 채널 개수와 같은 kernel 이 필요하다 .
하나의 feature map 을 생성할 때는 RGB 채널에 개별적으로 kernel 들이 3개의 feature map 이 생성 된 후 해당 값들을 모두 합하여 하나의 feature map 으로 완성시킨다.
그렇다면 RGB 채널 개수와 같은 kernel 쌍들이 100개 존재한다면 feature map 들은 몇 개가 쌓일까 ?
100개의 feature map 이 생성된다.
이렇게 차곡 차곡 쌓인 feature map 이 다음 convolution layer 의 일부가 된다.
3.3 Stride
stride는 feature map 을 생성 할 때 kernel 을 input image 위에서 상하좌우로 몇 칸 씩 움직일 것이냐에 대한 이야기이다.
stide 를 적게 생성 할 수록 이미지의 더 많은 내용들을 convolution 해나가며 feature map 의 뉴런을 생성 할 수 있으니
(합성곱을 통해 계산된 하나의 스칼라 값을 feature map 의 뉴런이라고 한다) feature map 의 크기는 좀 더 커질 것이고
stride 를 크게 큼직 큼직하게 훑어 나가며 convolution 해나간다면 다음에 생성되는 feature map 들의 크기는 작아질 것이다.
3. Padding
feature map 을 생성 할 때 stride 를 아무리 작게 1로 설정해놔도 생성되는 feature map의 차원은 input 이미지에 비해서 작아지기도 한다.
위의 좌측의 경우엔 4행4열의 이미지에서 , 1열부터 3열까지 꽝 찍고, 2열부터 4열까지 꽝 찍고 나면 더 이상 오른쪽으로 가지 못하기 때문이다.
그렇게 되면 생성된 feature map 은 2 x 2 사이즈인데
만약 input iamge와 동일한 차원의 feature map 을 생성해내고 싶다면 Padding 이라는 기법을 이용하면 된다.
주로 이미지의 가측 부분에 0 으로 된 원소들을 통해 채워주는 것으로
생성된 feature map 이 input image 와 동일한 차원의 이미지가 되게 만들어 줄 수 있다.
4. Pooling
자~~~
그래서 어찌 저찌 feature map 을 생성해냈다고 해보자
이후 feature map 의 차원을 더 줄이고 싶다면 어떻게 할까 ?
feature map에서 가장 중요한 특징만 추출하고 싶다면 ? 혹은 주변 특징들을 평균내어 추출하고 싶다면 ?
그 때 사용하는 것이 pooling layer 로서 pooling filter (여태 kernel 이라고 썼지만 사실 filter 라는 말을 더 많이 쓰게 될 것 같다) 를 이용하여
생성된 feature map의 pooling filter의 차원안에 뉴런들 중 최대값만 뽑아내는 Max pooling을 쓰든 , 평균을 내든 Average pooling 을 쓰든 아니면 다른 pooling 방법등을 이용해서 feature map의 차원을 축소시켜주면 된다.
이 때 pooling layer 를 만드는 것 또한 feature map 을 생성해나갔던 것과 같은 방식으로 filter size 를 정하고 , stride 만큼 쾅쾅쾅 찍어내가면 된다.
이 때 pooling layer 의 파라미터는 Nontrainable parameter 로서 따로 학습을 시켜줄 필요가 없다.
5. Fully conneted layer
이렇게 convolution layer 와 pooling layer 를 쭉쭉쭉 진행해나간 이후에는 1D vector 형태로 변경 시킨 후 Fully conneted layer를 이용해 학습한 후 출력값을 내뱉는다.
맨 위에서 이미지를 1D vector 로 변경하면 Local correlation 이 무시되니 어쩌니 했지만
여러번의 합성곱을 거친 이후 만들어진 2D matrix들의 Local correlation 이 아예 없는 것은 아니지만
기존 이미지보다는 적을 뿐더러 오히려 정보들만이 담긴 2D matrix로서의 이미가 더 강하기 때문에 1D vector 로 변경한 후 Fully connected layer 로 학습해도 괜찮다.
model = models.Sequential([ layers.Conv2D(32, (3, 3), activation='relu', input_shape=(28, 28, 1)), layers.MaxPooling2D((2, 2)), layers.Conv2D(64, (3, 3), activation='relu'), layers.MaxPooling2D((2, 2)), layers.Conv2D(64, (3, 3), activation='relu'), layers.Flatten(), layers.Dense(64, activation='relu'), layers.Dense(10) ])
뭐 대충 텐서플로우로 CNN 을 이해하는 코드를 가져와본다면
정해줘야 할 파라미터는 kernel 의 사이즈와 채널 개수, 활성화 함수 등만을 이용해서 아키텍쳐를 생성 할 수 있다.
model.compile(optimizer='adam', loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True), metrics=['accuracy'])
이후에는 optimizer 는 뭐 쓸지, loss function , learning late , metrics 등을 이용해주면 ~~ 끝
Share article