제가 CNN을 공부하면서 정리한 용어들입니다.


epochs : 반복 횟수


batch size : 몇 개 단위로 epochs 수행할 건지. 1이라면 1개 넣고 결과보고 값 수정-> 1 epochs 지나감


convolution : 인접한 픽셀에 convolution 필터를 곱해서 얻어지는 출력값. 인접한 픽셀값의 영향력 값. 특징 추출을 위해 사용


padding : input 이미지와 convolution 필터가 곱해질 때 이미지가 작아지는데 출력되는 값을 input 이미지와 같도록 유지해주는 것. 해주지 않으면 몇 차례만 지나도 이미지가 너무 작아져버림. 사방으로 확장되기 때문에 (1,1) 해주면 (10,10)->(12,12) 됨


activation : convolution으로 특징 추출되었다면 활성화 함수를 적용해 값 활성화 시킴. 이 특징을 가지고 있다/없다로 구분해줌. 대표적으로 sigmoid, relu가 있으나 sigmoid는 계층 깊어지면 그라디언트 소실 발생. 주로 relu 사용


pool_size : 영역을 정해서 그 안에서 값을 찾는 것(ex (2,2)). max-pooling, average-pooling이 있는데 이미지에서는 주로 max(최대값 채택) 사용. 특징의 위치 변화에 대한 영향을 덜 받기위해 사용


dense(fully connected, fc) : 활성화 함수와 이전 계층이 완전히 연결된 계층. CNN에서는 convolution layer, pooling layer를 활성화 함수 앞뒤에 배치하나 출력에 가까운 층은 fc layer를 사용할 수 있음


softmax :  fc layer에서 이미지가 어떤 레이블을 가질 가능성이 높은지 나타냄


loss : 손실 함수. 학습 시 손실을 최소로 만들어주는 가중치를 찾음. 종류가 다양하므로 적합한 것 선택하면 됨


optimizer : 학습 속도를 빠르고 안정적이게 하는 것. 종류 다양해 맞는 거 쓰면 됨. adam


metrics : 평가 함수. 평가 시 어떤 지표로 평가할 것인지 설정.


dropout : 과적합 방지

 

'CNN' 카테고리의 다른 글

ResNet 라이브러리 사용해보기  (0) 2020.10.03
CNN  (0) 2020.09.29

 

ResNet이 무엇인지에 대한 내용은 다른 분들 블로그에 많으니 자세한 설명은 하지 않겠습니다.

 

어쨌든 CNN보다 성능이 좋다는 것이 정설처럼 되어 있는 구조입니다.

 

앞선 CNN에서는 95% 정도가 나왔었는데, 같은 데이터로 ResNet을 사용했을 때는 어떻게 되는 지 실행해봤습니다.

 

ResNet은 직접 구현할 수도 있지만 라이브러리에도 존재합니다. 층의 개수에 따라 ResNet50, 101, 152 ... 등이 있습니다. 저 또한 직접 구현하지 않고 라이브러리를 사용했습니다.

 

ResNet50

from keras.applications import ResNet50, ResNet101, ResNet152

이렇게 상단에 import를 시켜주고

resnet50 = ResNet50(weights=None, include_top=False, input_shape=(64, 64, 3))

이렇게 작성해주시면 됩니다. 위의 코드에 보면 weights와 include_top이 있는데 사용한 것과 안한 것의 차이가 있으니 자신에게 맞게 사용해주시면 됩니다.

with K.tf_ops.device('/device:GPU:0'):
    model = Sequential()
    model.add(resnet50)
    model.add(Flatten())
    model.add(Dense(nb_classes, activation='softmax'))
    model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])


    food = model.fit(X_train, y_train, batch_size=64, epochs=100, validation_split=0.1)

모델은 이렇게 작성했습니다. 

 

그리고 보기 편하게 그래프를 만드는 코드는 아래와 같습니다.

%matplotlib inline
import matplotlib.pyplot as plt

fig, loss_ax = plt.subplots()

acc_ax = loss_ax.twinx()

loss_ax.plot(food.history['loss'], 'y', label='train loss')
loss_ax.plot(food.history['val_loss'], 'r', label='val loss')

acc_ax.plot(food.history['accuracy'], 'b', label='train acc')
acc_ax.plot(food.history['val_accuracy'], 'g', label='val acc')

loss_ax.set_xlabel('epoch')
loss_ax.set_ylabel('loss')
acc_ax.set_ylabel('accuray')

loss_ax.legend(loc='upper left')
acc_ax.legend(loc='lower left')

plt.show()

 

그래서 정확도는 평균 94%가 나왔습니다.

 

CNN보다 더 떨어졌습니다. 분명히 ResNet은 CNN보다 성능이 좋다고 했습니다. 혹시 층의 개수가 적어서 그런게 아닐까라는 생각이 들어서 ResNet101, ResNet152까지 실행시켜 봤습니다.

 

ResNet101

 

ResNet101은 평균 정확도가 92%로 더 떨어졌습니다. 게다가 그래프 수치도 더 안좋아 보입니다.

 

 

ResNet152

 

 

결론

저는 왜 층의 개수를 늘리면 늘릴 수록 정확도가 더 떨어지는 지 알아보다가 한 포스팅을 보고 이유를 알았습니다. 

https://oi.readthedocs.io/en/latest/computer_vision/cnn/resnet.html

CNN을 진행하면서 조심해왔지만 간과했던 "과적합"이 문제였던 것 같습니다.  

제 데이터의 양은 그대로인데 층만 깊어지니 과적합이 발생해 오히려 정확도가 더 떨어질 수 밖에 없었습니다. 게다가 제 데이터의 양은 보통 CNN치고는 적은 편이었인데다 ResNet은 구조적으로 과적합을 방지할 수 있지만 데이터의 양이 적으면 과적합을 피하기 어렵습니다.

 

그러니, 데이터 양에 맞게 layer 수를 조절할 것, 무작정 좋다는 알고리즘을 사용할게 아니라 데이터셋에 알맞은 알고리즘을 사용해야 한다는 것을 배울 수 있었습니다.

'CNN' 카테고리의 다른 글

CNN 용어 정리  (0) 2020.10.03
CNN  (0) 2020.09.29

 

데이터 선정

데이터는 AI Hub에서 신청하면 무료로 받을 수 있는 한식이미지를 선정했고 총 15만개의 이미지 데이터 중 4000개만 사용했습니다.

(데이터 신청 시 서약서를 작성하는데 서약서에는 사용 기간을 명시해야 하고, 저는 사용기한이 6월 말까지였기 때문에 이미지를 따로 올리지 않는 점 양해바랍니다.)

 

개발 환경 및 라이브러리

개발 환경은 구글의 colab이며, 텐서플로우 케라스를 사용하였습니다.

 

코랩 환경 설정

이미지 데이터를 사용하기 때문에 이미지를 불러들일 필요가 있는데 저는 구글 드라이브에 이미지들을 올려놓고 사용했습니다. 

from google.colab import drive # 코랩 구글드라이브 연동
drive.mount('/gdrive', force_remount=True) 

* 참고로 새로 접속할 때마다 구글 드라이브와 연결해야하므로 한번 연결됐다고 주석처리하면 안됩니다. *

마운트 경로는 자신의 경로에 맞게 고쳐서 사용할 수 있습니다.

 

데이터 늘리기

또한 그냥 4000장만 사용했을 때는 데이터셋의 양이 작고 성능이 낮게 나오기 때문에 먼저 이미지들을 numpy 배열로 변환하고 ImageDataGenerator를 사용해 약 3만 7천개로 데이터를 늘렸습니다.

numpy배열 변환은 이 블로그(lsjsj92.tistory.com/357?category=792966)를 참고하였습니다. 코드를 그대로 사용한 게 아니라 저에게 맞게 변형하였기 때문에 제 코드를 올리기보단 블로그 주소를 남기는 것이 낫겠다고 생각하여 주소만 기입합니다.

ImageDataGenerator를 이용해 데이터셋을 늘리는 여러 코드들이 나와있지만 저는 이 블로그(jeongmin-lee.tistory.com/5)를 참고해서 경로와 데이터 생성 갯수만 수정해서 사용했습니다.

import numpy as np
import os
from os import listdir
from os.path import isfile, join
from PIL import Image
 
 
from google.colab import drive # 코랩 구글드라이브 연동
drive.mount('/gdrive', force_remount=True) 

 
np.random.seed(3)
 
from keras.preprocessing.image import ImageDataGenerator, array_to_img, img_to_array, load_img
 
 
data_datagen = ImageDataGenerator(rescale=1./255)
 
data_datagen = ImageDataGenerator(rescale=1./255,
                                   rotation_range=30, 
                                   shear_range=5.5,  
                                   # width_shift_range=0.1,
                                   # height_shift_range=0.1,
                                   zoom_range=0.,
                                   horizontal_flip=True,
                                   vertical_flip=True,
                                   fill_mode='nearest') 
 
 
filename_in_dir = [] 
 
for root, dirs, files in os.walk('/gdrive/My Drive/data/dataset/gobchang92'):
    for  fname in files:
        full_fname = os.path.join(root, fname)
        filename_in_dir.append(full_fname)
 
for file_image in filename_in_dir:
    img = load_img(file_image) 
    x = img_to_array(img)
    x = x.reshape((1,) + x.shape)
 
    i = 0
 
    for batch in data_datagen.flow(x,save_to_dir='/gdrive/My Drive/data/dataset/datagenerator/gobchang', save_prefix='gobchang', save_format='jpg'):
        i += 1
        if i > 16:
            break

 

 

CNN 구조

 

가장 단순하다고 할 수 있는 CNN 구조입니다. 코드로 작성하면 아래와 같습니다.

with K.tf_ops.device('/device:GPU:0'):
    model = Sequential()
    model.add(Conv2D(64, (3,3), padding='same', activation='relu', input_shape=(64,64,3)))
    model.add(MaxPool2D(pool_size=(2,2)))
    model.add(Dropout(0.25))

    model.add(Conv2D(128, (3,3), padding='same', activation='relu'))
    model.add(MaxPool2D(pool_size=(2,2)))
    model.add(Dropout(0.25))

    model.add(Conv2D(256, (3,3), padding='same', activation='relu'))
    model.add(MaxPool2D(pool_size=(2,2)))
    model.add(Dropout(0.25))

    model.add(Conv2D(512, (3,3), padding='same', activation='relu'))
    model.add(MaxPool2D(pool_size=(2,2)))
    model.add(Dropout(0.25))

    model.add(Conv2D(1024, (3,3), padding='same', activation='relu'))
    model.add(MaxPool2D(pool_size=(2,2)))
    model.add(Dropout(0.25))

    model.add(Conv2D(2048, (3,3), padding='same', activation='relu'))
    model.add(MaxPool2D(pool_size=(2,2)))
    model.add(Dropout(0.25))

    model.add(Flatten())
    model.add(Dense(nb_classes, activation='softmax'))
    model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])

 

정확도는 5번 돌려봤을 때 95%정도가 나왔습니다.

 

'CNN' 카테고리의 다른 글

CNN 용어 정리  (0) 2020.10.03
ResNet 라이브러리 사용해보기  (0) 2020.10.03