이제 합성곱 신경망은 이미지 분류 - 물체에 대한 사진이 주어지면, 해당 물체가 1,000개의 카테고리 중 어디에 속하는지를 보여주는 것 - 등의 컴퓨터 비전 작업에서는 인간못지 않은 성능을 보여주고 있다. 여기서는 VGG 합성곱신경망을 이용하여 위와 같은 이미지 분류를 해보도록 하자. 아래와 같이 4개의 파트로 나눠서 다루도록 한다.
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-x 2 founder founder 4096 Jan 15 08:36 . drwxrwxr-x 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 |
1 2 3 | from keras.applications.vgg16 import VGG16 # load the model model = VGG16() | cs |
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 |
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=(224, 224)) # 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/