티스토리 뷰

728x90

저번 만든 CNN의 정확도는 60%대 ... 60%면 그냥 눈 가리고 아이유인지 수지인지 찍는 수준에 불과하다고 생각한다.
적어도 80~90% 정도는 나와야 어느 정도 구분할 줄 안다고 생각할 것이다.
정확도를 개선하기 위해 여러 가지 방법이 있다.
가장 기본적인 방법은 CNN을 더 깊고 넓게 쌓는 것. 하지만, 컴퓨터의 사양이 어느 정도 돼야 할 수 있을 것이고, training 시간도 GPU가 아닌 이상 엄청나게 오래 걸릴 것이다.
하지만 필자는 노트북으로 딥러닝을 하고 있다. 즉, GPU/좋은 성능의 컴퓨터가 아니라는 의미이다.
이런 사람들은 어떻게 해야 할까?
제목에도 써 놓았듯 'VGG16' 모델을 사용하는 것이다.

간단히 'VGG16'을 설명해 보자면.... CNN으로 이미지(고양이, 강아지, 컵......) 1000가지를 분류한 모델이다.
이미 '학습'의 과정을 걸쳐 이용자는 모델만 불러서 사용하면 끝. 간단하다. 여기까진.


VGG16을 불러와보자.

# CODE 1.
from keras import applications
model = applications.VGG16(weights='imagenet', input_shape=(image_size, image_size, 3))

이런 식으로 VGG16를 불러와 model에 저장해 주었다.
이미 '훈련'된 모델이기에 weigths는 'imagenet'을 불러와주면 되고, 본인의 이미지 사이즈에 맞춰 넣어주면 된다.
어떤 게 훈련돼있는지는 모르지만, 왜 VGG16를 이토록 설명했을까? 물론 이미지 분류를 위해서다.
여기서 '훈련돼 있다'라는 부분이 중요하다. 이미 훈련이 돼있기에 VGG16모델의 CNN은 이미지의 특징점을 아주 잘 잡아내기 때문에 필자와 같은 흙 수저에겐 엄청나게 훌륭한 모델이다.

무슨 말인가 하면... 저번 DIY CNN은 처음부터 어떤 '특징점'을 추출하기 위해 훈련했다면 VGG16은 이미 훈련이 돼있기에 훌륭하게 '특징점'을 잘 추출해 준다.
즉 아이유의 사진의 특징점과 수지의 사진의 특징점을 처음부터 아주 잘 추출할 수 있어, 이미지 분류에 걸리는 훈련의 시간이 거의 필요 없고 성능 또한 우수하다.

하지만 이 모델은 1천 개의 이미지를 분류하기에 이 모델에 당장 아이유 사진을 넣더라도 아이유가 아닌 1천개중 가장 특징점이 비슷한게 나올 것이므로 우리가 원하는 결괏값이 나올 수 있게 모델을 만들어야겠다.

# CODE 2.
top_model = Sequential()
top_model.add(Flatten(input_shape=model.output_shape[1:]))
top_model.add(Dense(256, activation='relu'))
top_model.add(Dense(2, activation='softmax')) 
#아마 VGG16은 Dense(1000, activation='softmax')로 돼있을걸?

위와 같이 CNN에서 추출한 2차원 데이터를 1차원 데이터로 바꾸는 부분을 우리들의 목적에 맞게 구성해 주면 된다.
필자는 아이유/수지 둘만 분류하면 되기에 Dense(2, activation='softmax')로 했다.(물론 2가지 구분은 binary로 해도 되지만 추후에 N 개 사진을 분류할 것이므로.. 필자는 softmax.. 알아서 바꾸길...)

결국 최종 모델은 내가 생성한 모델만 훈련시킨다고 생각하자.
VGG16모델에서 이미지의 특징점 추출 -> 추출한 특징점을 가지고 나의 모델에서 분류 훈련을 한다고 생각해 자.
여기서 중요한 건 '나의 모델만' 학습을 한다는 것이다. 기억하자. VGG16모델은 학습하지 않는다.

# CODE 3.
from keras import applications
model = applications.VGG16(include_top=False, weights='imagenet',input_shape = (image_size,image_size,3))

bottleneck_features_train = model.predict_generator( #VGG16을 통해 이미지 특징점 추출 및 저장
        generator, generator.samples // batch_size) 
# CODE 4.
model.fit(train_data, train_labels,
              epochs=epochs,
              batch_size=batch_size,
              validation_data=(validation_data, validation_labels)) 
              
# train_data , _labels validation_data, labels는 본인 상황에 맞게 바꿔야 합니다.
# 저는 이런식으로 했습니다.
# train_data = bottleneck_features_train
#    train_labels = np.array(
#        [[0,1]] * (int)(iu_train_samples) + [[1,0]] * (int)(suzy_train_samples))

결국 간단히 말하면

1. VGG16에서 특징점을 추출하여 저장해 놓는다. (CODE 3.)
2. 나만의 모델(Flatten() 구간)을 설립한다.(CODE 2.)
3. 나만의 모델에 VGG16에서 추출한 특징점을 넣어 훈련시킨다. (CODE 4.)

어떤가 생각보다 간단하다. 만들었으면 무엇을 해야 하겠는가?
바로 정확도 측정해본다. 물론 데이터 셋은 저번과 동일하다 바뀌지 않았다. 물론 훈련 환경도 똑같다.(옵티마저/배치 사이즈/에폭)

 

VGG16 + 나의모델 훈련결과

난장판이지만 정확도는 70~85% 정도 나온다. 엄청나게 훌륭하다. 저번 60%대에 비하면 복덩이다. (훈련이 잘 됐다고는 말 못 함) 이처럼 VGG16을 이용하면 간단하고 빠르게, 좋은 성능을 낼 수 있다.

이러한 방법이 Transfer-learning, 전이 학습이라고 하는 것이다. 말 그대로 이미 학습한 것을 이용하여 다른 곳에 적용하는 것이다. 이 방식은 아주 훌륭하며 나의 아이유 수지 대결에 가장 중요한 부분이 될 것이다.

 

다음에는 이 난장판인 그래프를 epoch을 높혀 좀더 그럴싸(?)하게 더 훌륭한 모델로 만들어 보겠다.

여러분들도 이미지를 학습하고자 할 때 사용하면 좋은 성과를 얻을 수 있을 것이다.

반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/12   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
글 보관함