갈루아의 반서재

이제 합성곱 신경망은 이미지 분류 - 물체에 대한 사진이 주어지면, 해당 물체가 1,000개의 카테고리 중 어디에 속하는지를 보여주는 것 - 등의 컴퓨터 비전 작업에서는 인간못지 않은 성능을 보여주고 있다. 여기서는 VGG 합성곱신경망을 이용하여 위와 같은 이미지 분류를 해보도록 하자. 아래와 같이 4개의 파트로 나눠서 다루도록 한다. 


Load the VGG Model in Keras

VGG 모델은 케라스 딥러닝 라이브러리에서 직접 로드가능하다. 케라스는 미리 훈련된 모델을 로딩하여 사용가능하도록 Applications interface 를 제공하고 있다.

해당 인터페이스를 활용하면 Oxford 그룹이 제공하는 사전에 훈련된 가중치를 사용하여 VGG 모델을 생성할 수 있다. 이를 출발점으로 삼거나 아니면 바로 이 모델을 이미지 분류에 사용해도 무방하다.  본 튜토리얼에서는 VGG 모델을 사용하여 새로운 이미지를 분류하는 것에 집중해볼 것이다. 

케라스는  VGG16 과 VGG19 클래스를 통해 16-layer 와 19-layer 버전을 제공한다. VGG16 모델을 가지고 시작해보자. 다음과 같이 모델생성이 가능하다.

1
2
from keras.applications.vgg16 import VGG16
model = VGG16()
cs

처음 실행하게 되면 케라스는 가중치 파일을 다운로드받아 아래와 같이 ~/.keras/models 디렉토리에 저장하게 된다. 

1
2
3
4
5
(base) founder@hilbert:~/.keras/models$ ls -al
total 540508
drwxrwxr-2 founder founder      4096 Jan 15 08:36 .
drwxrwxr-4 founder founder      4096 Jan 15 08:36 ..
-rw-rw-r-- 1 founder founder 553467096 Jan 15 08:37 vgg16_weights_tf_dim_ordering_tf_kernels.h5
cs

Note 보시다시피 파일크기는 약 528 MB 정도로, 다운로드시 약간의 시간이 소요될 수 있다. 가중치 파일은 한 번 다운로드되면, 이후 실행시에는 로컬에서 바로 로딩이 된다. 

모델 구조를 살펴보기 위해 표준 케라스 툴을 사용할 수 있다. 다음과 같이 네트워크 레이어의 요약정보를 출력할 수 있다.

1
print(model.summary())
cs
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
input_1 (InputLayer)         (None, 224, 224, 3)       0         
_________________________________________________________________
block1_conv1 (Conv2D)        (None, 224, 224, 64)      1792      
_________________________________________________________________
block1_conv2 (Conv2D)        (None, 224, 224, 64)      36928     
_________________________________________________________________
block1_pool (MaxPooling2D)   (None, 112, 112, 64)      0         
_________________________________________________________________
block2_conv1 (Conv2D)        (None, 112, 112, 128)     73856     
_________________________________________________________________
block2_conv2 (Conv2D)        (None, 112, 112, 128)     147584    
_________________________________________________________________
block2_pool (MaxPooling2D)   (None, 56, 56, 128)       0         
_________________________________________________________________
block3_conv1 (Conv2D)        (None, 56, 56, 256)       295168    
_________________________________________________________________
block3_conv2 (Conv2D)        (None, 56, 56, 256)       590080    
_________________________________________________________________
block3_conv3 (Conv2D)        (None, 56, 56, 256)       590080    
_________________________________________________________________
block3_pool (MaxPooling2D)   (None, 28, 28, 256)       0         
_________________________________________________________________
block4_conv1 (Conv2D)        (None, 28, 28, 512)       1180160   
_________________________________________________________________
block4_conv2 (Conv2D)        (None, 28, 28, 512)       2359808   
_________________________________________________________________
block4_conv3 (Conv2D)        (None, 28, 28, 512)       2359808   
_________________________________________________________________
block4_pool (MaxPooling2D)   (None, 14, 14, 512)       0         
_________________________________________________________________
block5_conv1 (Conv2D)        (None, 14, 14, 512)       2359808   
_________________________________________________________________
block5_conv2 (Conv2D)        (None, 14, 14, 512)       2359808   
_________________________________________________________________
block5_conv3 (Conv2D)        (None, 14, 14, 512)       2359808   
_________________________________________________________________
block5_pool (MaxPooling2D)   (None, 7, 7, 512)         0         
_________________________________________________________________
flatten (Flatten)            (None, 25088)             0         
_________________________________________________________________
fc1 (Dense)                  (None, 4096)              102764544 
_________________________________________________________________
fc2 (Dense)                  (None, 4096)              16781312  
_________________________________________________________________
predictions (Dense)          (None, 1000)              4097000   
=================================================================
Total params: 138,357,544
Trainable params: 138,357,544
Non-trainable params: 0
_________________________________________________________________
None


출력결과로 보다시피 거대한 모델임을 알 수 있다. 기본적으로 해당 모델은 입력으로  3개의 채널을 가진 224 x 224 픽셀의 이미지를 기대하고 있음을 알 수 있다. 다음과 같이 VGG 레이어의 플랏을 생성해보자. 

1
2
from keras.utils.vis_utils import plot_model
plot_model(model, to_file='vgg.png')
cs



VGG() 클래스는 다음과 같은 인수를 사용한다. 

  • include_top (True) : 출력 레이어를 포함할 것인지 여부로 개별 문제에 적합하게 되어있다면 불필요하다. 
  • weights (‘imagenet‘) : 로딩할 가중치. 처음부터 훈련시키는데 관심이 있다면 None 을 통해 사전에 훈련된 가중치를 사용하지 않아도 된다. 
  • input_tensor (None) : 서로 다른 크기의 새로운 데이터에 모델을 맞추기 위한 새로운 입력 레이어 
  • input_shape (None) : 입력 레이어를 변경할 경우 모델이 가져올 것으로 기대하는 이미지의 크기
  • pooling (None) : 출력 레이어의 새로운 세트를 훈련시킬 때 사용하는 풀링 타입
  • classes (1000) : 출력 벡터와 같은 해당 모델의 클래스의 수

그럼 로딩된 VGG 모델을 바로 이미지 분류에 적용해보자. 


Develop a Simple Photo Classifier


간단한 이미지 분류 스크립트를 작성해보자. 

1. 샘플 이미지 가져오기

분류 대상이 될 이미지를 가져와야 한다. 플리커 등에서 아래와 같이 랜덤한 이미지를 가져온다. 

이미지를 다운로드받아서  ‘mug.jpg 라는 이름으로 현재 디렉토리에 저장한다. 


2. VGG 모델 로딩

앞선 섹션에서 했던 것처럼 VGG-16 모델의 가중치를 로딩한다. 

1
2
3
from keras.applications.vgg16 import VGG16
# load the model
model = VGG16()
cs


3. 이미지 로딩 및 준비

이미지를 픽셀 데이터로 로딩하여 네트워크에 내보낼 수 있도록 준비한다. 케라스를 이와 관련한 몇 가지 툴을 제공한다. 
먼저 이미지를 로딩하고 필요한 크기인 224×224 픽셀로 조절하기 위해 load_img() 함수를 사용한다. 
1
2
3
from keras.applications.vgg16 import VGG16
# load the model
model = VGG16()
cs



케라스로 작업하기 위해 픽셀을 NumPy 배열로 변환한다.  img_to_array() 함수를 사용하면 된다. 
1
2
3
from keras.preprocessing.image import img_to_array
# convert the image pixels to a numpy array
image = img_to_array(image)
cs


네트워크는 하나 이상의 이미지를 입력으로 기대하고 있다. 이 말의 의미는 입력 배열은 4차원 - samples, rows, columns, 그리고 channels - 이 되어야한다는 것이다. 하지만 우리는 지금 하나의 샘플(하나의 이미지)만을 가지고 있으므로 reshape() 함수를 호출하여 추가 차원을 더함으로써 배열 구조를 다시 만들어야 한다. 

1
2
# reshape data for the model
image = image.reshape((1, image.shape[0], image.shape[1], image.shape[2]))
cs


ImageNet 훈련 데이터와 마찬가지로 이미지 픽셀이 준비되어야 한다. 여기서 해야하는 유일한 전처리는 각각의 픽셀로부터 훈련데이터셋에서 계산된 평균 RGB 값을 추출해내는 과정이다. 케라스는 새로운 입력을 네트워크에 주입하기 위해 preprocess_input() 이라는 함수를 제공하고 있다.

1
2
3
from keras.applications.vgg16 import preprocess_input
# prepare the image for the VGG model
image = preprocess_input(image)
cs


이제 예측을 위한 준비가 끝났다. 


4. 예측하기

1,000개의 알려진 물체의 유형 중 어디에 속할 확률을 예측하는 predict() 함수를 호출할 수 있다.

1
2
# predict the probability across all output classes
yhat = model.predict(image)
cs


이제 해당 확률을 해석하기만 하면 된다. 


5. 예측 해석

케라스는 decode_predictions() 이라는 함수를 통해 확률을 해석해낸다. 이를 통해 가능성이 높은 상위 3개의 클래스와 확률을 리스트 형식으로 반환해준다. 

1
2
3
4
5
6
7
from keras.applications.vgg16 import decode_predictions
# convert the probabilities to class labels
label = decode_predictions(yhat)
# retrieve the most likely result, e.g. highest probability
label = label[0][0]
# print the classification
print('%s (%.2f%%)' % (label[1], label[2]*100))
cs

Downloading data from https://s3.amazonaws.com/deep-learning-models/image-models/imagenet_class_index.json

40960/35363 [==================================] - 0s 5us/step
coffee_mug (75.27%)


이게 전부다. 전체 코드는 다음과 같다. 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
from keras.preprocessing.image import load_img
from keras.preprocessing.image import img_to_array
from keras.applications.vgg16 import preprocess_input
from keras.applications.vgg16 import decode_predictions
from keras.applications.vgg16 import VGG16
# load the model
model = VGG16()
# load an image from file
image = load_img('mug.jpg', target_size=(224224))
# convert the image pixels to a numpy array
image = img_to_array(image)
# reshape data for the model
image = image.reshape((1, image.shape[0], image.shape[1], image.shape[2]))
# prepare the image for the VGG model
image = preprocess_input(image)
# predict the probability across all output classes
yhat = model.predict(image)
# convert the probabilities to class labels
label = decode_predictions(yhat)
# retrieve the most likely result, e.g. highest probability
label = label[0][0]
# print the classification
print('%s (%.2f%%)' % (label[1], label[2]*100))
cs


원문출처 https://machinelearningmastery.com/use-pre-trained-vgg-model-classify-objects-photographs/