페이지

2022년 7월 30일 토요일

5.1 합성곱 신경망 소개

 컨브넷 정의와 컨브넷이 컴퓨터 비전 관련 작업에 잘 맞는 이유에 대해 이론적 배경을 알아봅시다. 하지만 먼저 간단한 컨브넷 예제를 둘러보죠. 2장에서 환전 연결 네트워크(densely connected network)로 풀었던(이 방식의 테스트 정확도는 97.8%였습니다) MNIST숫자 이미지 분류에 컨브넷을 사용해 보겠습니다. 기본적이 컨브넷이라도 2장에서 다룬 완전 연결된 모델의 성능을 훨씬 앞지를 것입니다.

다음 코드는 기본거인 커브넷의 모습입니다. Conv2D와 MaxPooling2D층을 쌓아 올렸습니다. 잠시 후에 이들이 무성인지 배웁니다.


    from keras import layers

    from keras import models

    

    model = moldes.Sequential()

    model.add(layers.Conv2D(32, (3, 3), activation='relu', input_shape=(28, 28, 1)))

    model.add(layers.MaxPooling2D((2, 2)))

    model.add(layers.Conv2D(643, (3, 3), activation='relu'))

    model.add(layers.MaxPooling2D((2, 2)))

    model.add(layers.Conv2D(64, (3, 3), activation='relue'))


컨브넷이 (image_height, image_width, image_channels) 크기의 입력 텐설르 사용한다는 점이 중요합니다(배치 차원은 포함하지 않습니다). 이 예제에서는 MNIST 이미지 포맷인 (28, 28, 1) 크기의 입력을 처리하도록 컨브넷을 설정해야 합니다. 이 때문에 첫 번째 층의 매개 변수로 input_shape=(28, 28, 1)을 전달했습니다.

지금까지의 컨브넷 구조를 출력해 보죠

>>> model.summary()

--------------------------------------------------------------------------------------------

Layer(type)                    Ouput Shape                Params #

========================================================

conv2d_1(Conv2D)        (None, 26, 26, 32)            320

---------------------------------------------------------------------------------------------

maxpooling2D_1(MaxPooling2D)        (None, 13, 13, 32)        0

----------------------------------------------------------------------------------------------

conv2d_2(Conv2D)        (None, 11, 11, 64)            18496

-----------------------------------------------------------------------------------------------

maxpooling2d_2 (MaxPooling2D)        (None, 5, 5, 64)        0

------------------------------------------------------------------------------------------------

conv2d_3 (Conv2D)        (None, 3, 3, 64)                36928

==========================================================

Total params: 55,744

Trainable params: 55,744

Non-trainable params: 0

Conv2D와 MaxPooling2D 층의 출력은 (height, width, channels) 크기의 3D텐서입니다. 높이와 너비 차원은 네트워크가 깊어질수록 작아지는 경향이 있습니다. 채널의 수는 Conv2D층에 전달된 첫 번째 매개변수에 의해 조절됩니다(32개 또는 64개).

다음 단계에서 마지막 층의 ((3, 3, 64) 크기인) 출력 텐서를 완전 연결 네트워크에 주입합니다. 이 네트워크는 이미 익숙하게 보았던 Dense 층을 쌓은 분류기입니다. 이 분류기는 1D벡터를 처리하는데, 이전 층의 출력이 3D 텐서입니다. 그래서 먼저 3D출력을 1D텐서로 펼쳐야 합니다. 그다음 몇 개의 Dense층을 추가합니다.

    

    model.add(layersd.Flatten())

    model.add(layers.Dense(64, activation='relu'))

    model.add(layers.Dense(10, activation='softmax'))

10개의 클래스를 분류하기 위해 마지막 층의 출력 크기를 10으로 하고 소프트맥스 활성화함수를 사용합니다. 이제 전체 네트워크는 다음과 같습니다.

>>> model.summary()

Layer(type)                               Output Shape                Param #

==========================================================

conv2d_1 (Conv2D)                (None, 26, 26, 32)                320

maxpooling2d_1 (MaxPooling2D)        (None, 13, 13, 32)            0

conv2d_2 (Conv2D)                (None, 11, 11, 64)                18496

maxpooling2d_2 (MaxPooling2D)        (None, 5, 5, 64)                0

conv2d_3 (Conv2D)                (None, 3, 3, 64)                    36928

flatten_1 (Flatten)                    (None, 576)                            0

dense_1 (Dense)                    (None, 64)                            36928

dense_2 (Dense)                    (None, 10)                            650

===========================================================

Total params:93,322

Trainable params: 93,322

Non-trainable params: 0

여기에서 볼 수 있듯이 (3, 3, 64) 출력이 (576,)크기의 벡터로 펼쳐진 후 Dense 층으로 주입되었습니다.

이제 MNIST숫자 이미지에 이 컨브넷을 훈련합니다. 2장의 MNIST예제 코드를 많이 재상요하겠습니다.


        from keras.datasets import mnist

        from keras.utils import to_categorical

    

        (train_iamges, train_labels), (test_images, test_labels) = mnist.load_data()

        train_images = train_images.reshape((60000, 28, 28, 1))

        train_images = train_images.astype('float32') / 255


        test_images = test_images.reshape((10000, 28, 28, 1))

        test_images = test_images.astype('float32') / 255


        train_labels = to_catetorical(train_labels)

        test_labels = to_catetorical(test_labels)


        model.compile(optimizer='resprop', 

                        loss='categorical_crossentropy',

                        metrics=['accuracy'])

        model.fit(train_images, train_labels, epochs=5, batch_size=64)


테스트 데이터에서 모델을 평가해 보죠.

>>> test_loss, test_acc = model.evaluate(test_images, test_labels)

>>> test_acc

0.9921

2장의 완전 연결 네트워크는 97.8%의 테스트 정확도를 얻은 반면에 기본적인 컨브넷은 99.2%의 테스트 정확도를 얻었습니다. 에러율이 (상태적으로) 64%나 줄었습니다. 나쁘지 않군요!

완전 연결된 모델보다 왜 간단한 컨브넷이 더 잘 작동할까요? 이에 대해 알아보기 위해 Conv2D 와 MaxPooling2D 층의 어떤 일을 하는지 살펴보겠 습니다.





댓글 없음: