[CNN] Dogs vs Cats

2021. 5. 13. 12:54Artificial_Intelligence/Computer Vision

캐글(Kaggle)에서 데이터셋을 전부 다운받고, small폴더를 만들어서 train data, validation data, test data를 강아지와 고양이 각각 1000, 500, 500장을 분리해 총 4천장에 사진 데이터를 가지고 실습을 하였다.

그리고 가져온 사진 데이터들을 네트워크에 넣기 위해 부동 소수 타입의 텐서로 전처리 한다.

케라스에서 제공되는 ImageDataGenerator은 이미지 파일을 전처리된 배치 텐서로 바꾸어주는 제너레이터를 만드는 클래스이다. , 사진 파일을 읽고, 타입을 RGB 픽셀 값으로 디코딩하고, 부동 소수타입의 텐서로 변환하여 픽셀값의 스케일을 0~255에서 0~1로 조정하는 과정을 쉽게 만들어주는 명령어이다.

모든이미지를 float형으로 255로 나누어 스케일을 0~1로 조정한 값이 datagen 변수이다.

Train_dir을 타깃 디렉토리로 설정하고, 모든 이미지를 150 * 150 크기로 변경하고, batch_size20으로, lossbinary_crossentropy를 사용하기에 이진레이블이 필요해서 binary로 설정했다.

 

배치 데이터의 크기는 4차원 텐서값이고, 배치 레이블 크기는 1차원 텐서값이다. 제너레이터는 문한 루프이기에 break을 설정하여 종료시켜주어야 한다.

입력 데이터를 전처리 하였으니 먼저, 교재에서 나온 모델과 동일한 모델을 제작하였다.

 

Conv2DMaxPooling2D층을 번갈아가면서 레이어를 구성하여 Convnet을 제작한다.

이전까지 모델에서는 3차원 텐서 데이터를 입력에 넣기위해서는 1차원 데이터로 바꾸어 넣어주었는데, 이렇게하면 데이터의 형상이 무시된다. , 가까운 픽셀의 값은 비슷하거나, RGB 각 채널의 밀접한 관련성 등 이미지는 3차원 공간에서 여러 정보들이 내포되어있는데 이러한 공간적 구조가 무너지게 되는 것이다. 따라서 3차원 이미지를 그대로 입력층에 받으며 출력도 3차원 데이터 그대로 출력하게 만드는 것이 합성곱층이다.

합성곱층의 뉴런은 입력이미지의 모든 픽셀에 연결되지 않고, 필터안에 있는 픽셀에만 연결이 되어 저수준 특성에서 고수준 특성으로 조합하며 나가게 된다. 이 필터는 합성곱층의 가중치가 되어 특성맵을 출력하면서 다음 레이어로 전달된다.

합성곱층을 거치면 풀링층으로 가게 되는데, 모델의 전체 매개변수의 수를 줄이기 위해 데이터의 크기를 줄이는 레이어이다. 여기서는 해당영역에서 최대값을 찾는 MaxPooling을 사용하였다. 풀링은 계산된 특징이 이미지 내의 위치에 대한 변화에 대해 영향을 덜 받는다. , 풀링을 사용하여 불변성을 찾아내고 이미지의 공간적 구조를 지키는 것이다.

input_shape(150, 150, 3)으로 설정하였다. 이는 현재 입력받는 이미지의 길이와 높이가 각 150이며, RGB이기에 3채널을 가지기에 그렇다. 이러한 입력데이터를 받으면 합성곱층으로 간다. 합성곱층에서 filter3*3, stride1로 설정하여 돌리면 입력받은 데이터의 크기는 148*148로 줄어들고 층은 32개로 깊어진다. 이 데이터를 MaxPooling을 사용하는 풀링층으로 전달하여 2*2 크기의 윈도우로 설정하여 데이터의 크기를 절반으로 줄인다. 풀링 윈도우 크기만 정의했기에 strides는 디폴트 값인 풀링 윈도우 사이즈만큼 이동하여 반으로 줄어드는 것이다. 이런식으로 총 4번의 Convnet을 구성하여 데이터의 크기는 7*7, 깊이()128로 증가하였다.

이렇게 만들어진 입력 데이터는 Flatten() 명령어를 사용하여 입력 데이터의 개수를 자동 계산시킨다. 현재 입력 데이터는 7*7 사이즈를 가지고 128의 깊이를 가졌으니 입력 데이터 개수는 6272이 된다. 이를 이진 분류를 하기 위해 Relu함수를 사용하는 하나의 레이어를 구성하고 데이터를 512개로 줄인다. 그리고 강아지 or 고양이 이기에 마지막 출력 아웃풋은 1로 설정하고 sigmoid함수를 사용한다. 그림에서 보이다 싶이 Flatten층 이후 Fully Connected layer로 구성된다.  

이제 모델을 제작하였으니 모델을 학습시켜본다.

 

제너레이터를 사용하기 위해 fit 메서드와 동일한 fit_generator을 사용하여 모델을 훈련시켰다.

Step_per_epoch만큼 경사 하강법을 실행하고 다음 에포크로 넘어간다. 20개의 샘플을 하나의 배치 사이즈로 설정하였으니 2000개의 훈련용 데이터 샘플을 처리하기 위해 steps_per_epoch100으로, 100개의 배치로 설정한다.

Validation_data 또한 제너레이터로 전달했기에 검증 데이터의 배치가 무한번 반환된다. 따라서 validation_steps를 지정하여 50번만 반환되게 설정한다.

 

Epochs5 이후로 overfitting이 되었고, 검증 정확도는 약 71%가 나왔다. loss또한 epoch가 돌수록 점점 크게 증가되었다. 정확한 측정을 해보기위해 결과창을 확인해보았다.

그 후, 정확도를 올리기위해 모델을 수정해보았다. 전결합층의 레이어를 하나 더 추가하였고, 각 합성곱레이어에 깊이를 32, 32, 64, 256으로 바꾸었다.

이렇게 모델을 만들고, 학습을 위해 compile 방식에서 옵티마이저를 RMSprop에서 Adam으로  설정하여 학습을 진행하였다.

정확도 같은 경우에는 꾸준히 70% ~ 75%사이로 맞았지만, 검증 손실값이 큰 것으로 보아, 전체 데이터에 대해 예측은 이전보다 조금이나마 상승했지만, 오차의 범위가 급격하게 증가하여 손실이 크다는 것을 알 수 있었다.

이전 모델과 비교해서 레이어의 수를 증가시키고, 레이어안의 매개변수들를 조정하고, 옵티마이저를 다른 것으로 바꾸어도 정확도가 72% 되는 것으로 보아, 큰 차이가 없는 것을 알았다. 따라서 과대적합을 감소시키고 정확도를 향상시키기 위해서는 데이터 증식을 사용하거나 드롭아웃 등을 써서 모델을 만들고 학습해야 정확도가 더욱 향상될 것이라 판단을 하였고, 더 확실하고 쉽게 정확도를 올리기 위해서는 사전 훈련된 네트워크를 튜닝하여 사용하는 것이 맞는 것이라고 생각하였다.

 

다음 게시글은 데이터 증식과 VGG16을 사용한 미세조정, 학습동결에 대해 적어볼려한다.

728x90