Deep Learning - 이미지 처리 CNN 이용한 이미지 분류 모델 구현 실습 (1)

CNN을 이용한 이미지 분류

커머스 산업에 관심이 많다보니, 커머스에서 사용할 수 있는 모델을 구상해보았고, 이미지를 통한 카테고리 분류를 한다면 하루에도 수많은 상품이 업데이트되는 커머스 플랫폼에선 자동화의 일환으로 사용할 수 있을 것이다.

Cifar10 데이터를 이용한 실습

from tensorflow.keras import datasets
from tensorflow.keras.models import Sequential, Model
from tensorflow.keras.layers import Dense, Conv2D, MaxPooling2D, Flatten

(train_images, train_labels), (test_images, test_labels) = datasets.cifar10.load_data()

# Normalize pixel values to be between 0 and 1
train_images, test_images = train_images / 255.0, test_images / 255.0
# 라벨 설정
class_names = ['airplane', 'automobile', 'bird', 'cat', 'deer',
               'dog', 'frog', 'horse', 'ship', 'truck']

keras 제공 cifar10 데이터를 이용하기 위해 불러온 뒤, 정규화를 위해 255로 나눠준다.
기본적으로 cifar10 데이터는 10개의 라벨로 이뤄져있어, 해당 라벨을 분류할 수 있도록 모델 설계를 해주면 된다.

import matplotlib.pyplot as plt
plt.figure(figsize=(10,10))
for i in range(25):
    plt.subplot(5,5,i+1)
    plt.xticks([])
    plt.yticks([])
    plt.grid(False)
    plt.imshow(train_images[i], cmap=plt.cm.binary)
    # The CIFAR labels happen to be arrays, 
    # which is why you need the extra index
    plt.xlabel(class_names[train_labels[i][0]])
plt.show()

train데이터 5만개 중 25개만 이미지를 띄워보면 위와같이 나온다. 위의 이미지를 학습하여 test 셋의 이미지를 맞추는지 실험해보도록 한다.

model = Sequential()
model.add(Conv2D(32, 3, activation = 'relu', input_shape=(32,32,3)))
model.add(MaxPooling2D(2,2))
model.add(Conv2D(64, 3, activation = 'relu'))
model.add(MaxPooling2D(2,2))
model.add(Conv2D(64, 3, activation = 'relu'))
model.add(Flatten())
model.add(Dense(64, activation='relu'))
model.add(Dense(10, activation='softmax'))

model.summary()
  • Sequential()로 model 인스턴스를 생성한다.
  • Conv2D를 통해 컨볼루션 레이어를 추가한다. 필터와 노드수, 활성함수를 정한다.
    뎁스 32, 필터 (3,3), 활성함수 relu, 인풋사이즈 (32,32에 3채널)
  • MaxPooling2D를 지정해준다. 사이즈 (2,2) > default이기도 함.
  • Conv와 Pooling을 반복한 뒤, Flatten으로 이미지를 1차원으로 변형
  • 이후 FC에 넣어 은닉층 하나를 거쳐 최종 softmax를 취해 10개 라벨을 분류한다.
[output]
Model: "sequential"
_________________________________________________________________
 Layer (type)                Output Shape              Param #   
=================================================================
 conv2d (Conv2D)             (None, 30, 30, 32)        896       
                                                                 
 max_pooling2d (MaxPooling2D  (None, 15, 15, 32)       0         
 )                                                               
                                                                 
 conv2d_1 (Conv2D)           (None, 13, 13, 64)        18496     
                                                                 
 max_pooling2d_1 (MaxPooling  (None, 6, 6, 64)         0         
 2D)                                                             
                                                                 
 conv2d_2 (Conv2D)           (None, 4, 4, 64)          36928     
                                                                 
 flatten (Flatten)           (None, 1024)              0         
                                                                 
 dense (Dense)               (None, 64)                65600     
                                                                 
 dense_1 (Dense)             (None, 10)                650       
                                                                 
=================================================================
Total params: 122,570
Trainable params: 122,570
Non-trainable params: 0
_________________________________________________________________

model.summary()를 통해 파라미터 수 변화, 인풋데이터의 shape 변화를 볼 수 있다.
위와같이 진행 후 컴파일을 해준다.

model.compile(optimizer='adam',
              loss='sparse_categorical_crossentropy',
              metrics=['accuracy'])
              
model.fit(train_images, train_labels, epochs=10, validation_data=(test_images, test_labels))
  • 옵티마이저를 설정한다. adam이 가장 범용적으로 자주 사용되는 녀석
  • 여러가지 분류를 진행할때 0과1이 아닌 숫자로 구분을 하기 위해선 categorical보다 sparse_categorical_crossentropy를 사용하도록 한다.
  • metric은 가장 기본적인 accuracy로 지정한다.
  • model fit을 진행한다.
[output]
Epoch 1/10
1563/1563 [==============================] - 11s 7ms/step - loss: 1.5798 - accuracy: 0.4221 - val_loss: 1.3096 - val_accuracy: 0.5288
Epoch 2/10
1563/1563 [==============================] - 9s 6ms/step - loss: 1.2251 - accuracy: 0.5639 - val_loss: 1.1692 - val_accuracy: 0.5920
Epoch 3/10
1563/1563 [==============================] - 10s 6ms/step - loss: 1.0634 - accuracy: 0.6261 - val_loss: 1.0515 - val_accuracy: 0.6330
Epoch 4/10
1563/1563 [==============================] - 10s 6ms/step - loss: 0.9634 - accuracy: 0.6622 - val_loss: 1.0322 - val_accuracy: 0.6387
Epoch 5/10
1563/1563 [==============================] - 10s 6ms/step - loss: 0.8922 - accuracy: 0.6886 - val_loss: 0.9355 - val_accuracy: 0.6719
Epoch 6/10
1563/1563 [==============================] - 10s 6ms/step - loss: 0.8331 - accuracy: 0.7113 - val_loss: 0.9039 - val_accuracy: 0.6864
Epoch 7/10
1563/1563 [==============================] - 9s 6ms/step - loss: 0.7868 - accuracy: 0.7243 - val_loss: 0.8952 - val_accuracy: 0.6916
Epoch 8/10
1563/1563 [==============================] - 9s 6ms/step - loss: 0.7464 - accuracy: 0.7376 - val_loss: 0.9186 - val_accuracy: 0.6839
Epoch 9/10
1563/1563 [==============================] - 9s 6ms/step - loss: 0.7063 - accuracy: 0.7518 - val_loss: 0.8898 - val_accuracy: 0.6986
Epoch 10/10
1563/1563 [==============================] - 9s 6ms/step - loss: 0.6677 - accuracy: 0.7668 - val_loss: 0.9407 - val_accuracy: 0.6927
# 수행
test_loss, test_acc = model.evaluate(test_images, test_labels, verbose=2)
[output]
313/313 - 1s - loss: 0.9407 - accuracy: 0.6927 - 913ms/epoch - 3ms/step

val_accuracy가 높게 나오진 않았지만, 레이어를 늘리거나 학습을 더 하면 좀 더 높아진다.(과적합조심)

import matplotlib.pyplot as plt
plt.figure(figsize=(10,10))
for i in range(5):
    plt.subplot(5,5,i+1)
    plt.xticks([])
    plt.yticks([])
    plt.grid(False)
    plt.imshow(test_images[i], cmap=plt.cm.binary)
    # The CIFAR labels happen to be arrays, 
    # which is why you need the extra index
    plt.xlabel(class_names[test_labels[i][0]])
plt.show()


위와같이 테스트 셋의 다섯개 이미지를 분류해본다.

plt.figure(figsize=(10,10))
for i in range(5):
  x = np.expand_dims(test_images[i], axis=0) # 이미지의 차원을 맞추기 위해 늘려줘야한다.
  predictions = model.predict(x) # 예측을 진행한다.
  predicted_ids = np.argmax(predictions, axis=-1)
  predicted_class_names = class_names[predicted_ids[0]]
  plt.subplot(5,5,i+1)
  plt.xticks([])
  plt.yticks([])
  plt.grid(False)
  plt.imshow(test_images[i], cmap=plt.cm.binary)
  plt.title(predicted_class_names)


결과를 보면 5개 모두 화질지 좋지 않음에도 잘 맞춘것을 볼 수 있다. 이러한 방식으로 상품이미지에 대한 카테고리 라벨을 학습시켜 이미지 특징으로 카테고리를 구분할 수 있는 인공지능을 만들어 봐야겠다.

좋은 웹페이지 즐겨찾기