본 내용은 딥러닝 부트캠프 with 케라스 라는 책의 내용을 따라해본 것을 정리한 것이다.

소프트웨어 개발 관련 중에서 특히 딥러닝 분야의 책들이 늘 그렇듯 출판된지 조금만 지나도 업데이트가 빠르게 이루어지다 보니 책의 내용이 최신 버전을 반영하지 못하는 부분이 있다. 

이 책 역시도 Keras 1 버전에 예전 Theano 버전을 기준으로 작성되다 보니 일부 코드가 실행되지 않는 문제가 발생하여 여러 삽질을 겪어야 했다.

특히 GPU를 활용하는 부분이 아직 사용하기 어렵다.


코드 다운로드 하기

해당 책에서 공식적으로 제공하는 소스코드는 https://github.com/gilbutITbook/006959 에서 받을 수 있다.

최신 버전을 반영하기 위해 수정한 코드는 https://github.com/kyuhyong/deep_learning_keras 에서 받으면 된다.

위 소스코드를 git clone 하여 다운로드 한다.


프로젝트 구성

폴더 구성은 다음과 같다.


/deep_learning_keras/pycode/classification <-- 이미지 분류 관련 코드

/deep_learning_keras/data/                          <-- 훈련, 테스트, 평가할 데이터 셋


데이터 셋 다운로드 하기

이미지 분류를 진행하기 위해 데이터 셋을 다운로드 한다.

여기에서는 Caltech 101 이라는 데이터셋을 사용한다.

http://www.vision.caltech.edu/Image_Datasets/Caltech101/ 에서 다운로드할 수 있다.



101_ObjectCategories.tar.gz 라는 파일을 다운로드 하고 프로젝트 폴더의 data 폴더에 압축 해재한다. data 폴더가 없으면 생성한다.

$ cd ~/deep_learning_keras/ $ mkdir data $ tar xvf ~/Download/101_ObjectCategories.tar.gz data/

데이터셋의 구성은 다음과 같다.

/deep_learning_keras/data/Caltech-101

. label.csv

/test            <--테스트셋 데이터 폴더

  /0            <-- 클래스 airplanes

  /1            <-- 클래스 Motorbikes

  /2            <-- 클래스 Faces_easy

  /3            <-- 클래스 watch

  /4            <-- 클래스 Leopards

  /5            <-- 클래스 bonsai

/train        <-- 트레이닝 데이터 폴더

  /0            <-- 홀드아웃 1

  /1            <-- 홀드아웃 2

/train_org    <--복사한 6개의 카테고리 데이터

  /0            <-- 클래스 airplanes

  /1            <-- 클래스 Motorbikes

  /2            <-- 클래스 Faces_easy

  /3            <-- 클래스 watch

  /4            <-- 클래스 Leopards

  /5            <-- 클래스 bonsai 

/valid           <-- 벨리데이션 데이터셋 폴더

  /0            <-- 홀드아웃 1

  /1            <-- 홀드아웃 2


데이터 셋에는 총 6가지의 클래스로 구분된 폴더가 각각 존재한다. 

데이터셋 확장하기

기본적인 데이터의 양이 많지 않기 때문에 이미지를 회전, 확대, 축소, 늘리기, 노이즈 추가 등의 작업을 통해 데이터를 늘리는 작업이 필요하다.

pycode/classification/의 data_augmentation.py 은 파이썬의 sckit-image 라이브러리를 사용하여 이러한 작업을 수행한다.

확장된 데이터는 다음과 같다.

/deep_learning_keras/data/Caltech-101

. label.csv

/test            <--테스트셋 데이터 폴더

  /0            

  /1            

  /2            

  /3            

  /4            

  /5            

/train        <-- 트레이닝 데이터 폴더

  /0            <-- 홀드아웃 1

     /0        <--확장된 데이터 클래스

     /1

     /2

     /3

     /4

     /5

  /1            <-- 홀드아웃 2

  /all           <-- 홀드아웃 1+2

/train_org   

/valid           



모델 만들기

keras 에서 지원하는 9층 합성곱 모델을 작성한다. 책의 내용은 keras 1 버전의 내용을 담고 있어서 keras 2 를 지원하기 위해 일부 호출되는 함수 명, 계층 명칭을 수정하였다.

def layer_9_model(): # Keras의 Sequential을 기초 모델로 사용 ---① model = Sequential() if kerasVersion > 1: # 합성층(Convolution)을 모델에 추가 ---② model.add(Conv2D(32, (3, 3), padding='same', activation='linear', input_shape=(img_rows, img_cols, 3))) model.add(LeakyReLU(alpha=0.3)) model.add(Conv2D(32, (3, 3), padding='same', activation='linear')) model.add(LeakyReLU(alpha=0.3)) # 풀링층(MaxPooling)을 모델에 추가 ---③ model.add(MaxPooling2D(pool_size=(2, 2), strides=(2, 2))) model.add(Conv2D(64, (3, 3), padding='same', activation='linear')) model.add(LeakyReLU(alpha=0.3)) model.add(Conv2D(64, (3, 3), padding='same', activation='linear')) model.add(LeakyReLU(alpha=0.3)) model.add(MaxPooling2D(pool_size=(2, 2), strides=(2, 2))) model.add(Conv2D(128, (3, 3), padding='same', activation='linear')) model.add(LeakyReLU(alpha=0.3)) model.add(Conv2D(128, (3, 3), padding='same', activation='linear')) model.add(LeakyReLU(alpha=0.3)) model.add(MaxPooling2D(pool_size=(2, 2), strides=(2, 2))) else : # 합성층(Convolution)을 모델에 추가 ---② model.add(Convolution2D(32, 3, 3, border_mode='same', activation='linear', input_shape=(3, img_rows, img_cols))) model.add(LeakyReLU(alpha=0.3)) model.add(Convolution2D(32, 3, 3, border_mode='same', activation='linear')) model.add(LeakyReLU(alpha=0.3)) # 풀링층(MaxPooling)을 모델에 추가 ---③ model.add(MaxPooling2D(pool_size=(2, 2), strides=(2, 2), dim_ordering='th')) model.add(Convolution2D(64, 3, 3, border_mode='same', activation='linear')) model.add(LeakyReLU(alpha=0.3)) model.add(Convolution2D(64, 3, 3, border_mode='same', activation='linear')) model.add(LeakyReLU(alpha=0.3)) model.add(MaxPooling2D(pool_size=(2, 2), strides=(2, 2), dim_ordering='th')) model.add(Convolution2D(128, 3, 3, border_mode='same', activation='linear')) model.add(LeakyReLU(alpha=0.3)) model.add(Convolution2D(128, 3, 3, border_mode='same', activation='linear')) model.add(LeakyReLU(alpha=0.3)) model.add(MaxPooling2D(pool_size=(2, 2), strides=(2, 2), dim_ordering='th')) # Flatten층을 모델에 추가 -- ④ model.add(Flatten()) # 전결합층(Dense)을 모델에 추가 --- ⑤ model.add(Dense(1024, activation='linear')) model.add(LeakyReLU(alpha=0.3)) # Dropout층을 모델에 추가 --- ⑥ model.add(Dropout(0.5)) model.add(Dense(1024, activation='linear')) model.add(LeakyReLU(alpha=0.3)) model.add(Dropout(0.5)) # 최종 아웃풋을 구축 --- ⑦ model.add(Dense(6, activation='softmax')) # 손실 함수와 기울기의 계산에 사용하는 식을 정의한다. -- ⑧ sgd = SGD(lr=1e-3, decay=1e-6, momentum=0.9, nesterov=True) model.compile(optimizer=sgd, loss='categorical_crossentropy', metrics=["accuracy"]) return model

학습 실행

이제 모델에 데이터셋을 넣고 훈련을 수행한다. 

원래 Theano에서도 GPU를 사용하여 훈련을 하면 빠르게 진행되는데 어쩐일인지 자꾸 메모리 오류가 발생하여 일단은 CPU만 사용하여 훈련을 진행한다.

문제 해결 방안이 있으면 알려주세요.

$ python 9_Layer_CNN.py train Using Theano backend. /usr/local/lib/python2.7/dist-packages/keras/models.py:944: UserWarning: The `nb_epoch` argument in `fit` has been renamed `epochs`. warnings.warn('The `nb_epoch` argument in `fit` ' WARNING (theano.tensor.blas): We did not find a dynamic library in the library_dir of the library we use for blas. If you use ATLAS, make sure to compile it with dynamics library. Train on 261 samples, validate on 260 samples Epoch 1/40 64/261 [======>.......................] - ETA: 1:17 - loss: 1.7578 - acc: 0.234

128/261 [=============>................] - ETA: 52s - loss: 1.7659 - acc: 0.2422

261/261 [==============================] - 142s 543ms/step

- loss: 1.7369 - acc: 0.2797 - val_loss: 1.6112 - val_acc: 0.3077

Epoch 2/40 64/261 [======>.......................] - ETA: 1:16 - loss: 1.6483 - acc: 0.375

128/261 [=============>................] - ETA: 53s - loss: 1.6038 - acc: 0.3828

261/261 [==============================] - 141s 539ms/step

- loss: 1.5719 - acc: 0.3333 - val_loss: 1.3997 - val_acc: 0.3577 Epoch 3/40 64/261 [======>.......................] - ETA: 1:16 - loss: 1.5285 - acc: 0.234

128/261 [=============>................] - ETA: 53s - loss: 1.4486 - acc: 0.3047

261/261 [==============================] - 141s 539ms/step

- loss: 1.3584 - acc: 0.4023 - val_loss: 1.1560 - val_acc: 0.5038 Epoch 4/40 64/261 [======>.......................] - ETA: 1:23 - loss: 1.0000 - acc: 0.625

128/261 [=============>................] - ETA: 55s - loss: 1.2680 - acc: 0.5391

261/261 [==============================] - 144s 551ms/step

- loss: 1.1099 - acc: 0.5862 - val_loss: 0.9709 - val_acc: 0.6615 Epoch 5/40 64/261 [======>.......................] - ETA: 1:19 - loss: 1.0750 - acc: 0.625

128/261 [=============>................] - ETA: 54s - loss: 1.0243 - acc: 0.6094

261/261 [==============================] - 142s 543ms/step

- loss: 0.9588 - acc: 0.6322 - val_loss: 0.7666 - val_acc: 0.7269 Epoch 6/40 64/261 [======>.......................] - ETA: 1:20 - loss: 0.8764 - acc: 0.687

128/261 [=============>................] - ETA: 53s - loss: 0.7606 - acc: 0.7344

261/261 [==============================] - 142s 545ms/step

- loss: 0.7319 - acc: 0.7701 - val_loss: 0.5926 - val_acc: 0.8231Epoch 34/40

...

Epoch 35/40 64/261 [======>.......................] - ETA: 1:23 - loss: 0.0206 - acc: 0.984

128/261 [=============>................] - ETA: 54s - loss: 0.0359 - acc: 0.9922

261/261 [==============================] - 144s 550ms/step

- loss: 0.0288 - acc: 0.9923 - val_loss: 0.3863 - val_acc: 0.9269 Epoch 36/40 64/261 [======>.......................] - ETA: 1:21 - loss: 0.0442 - acc: 0.968

128/261 [=============>................] - ETA: 54s - loss: 0.0636 - acc: 0.9688

261/261 [==============================] - 144s 550ms/step

- loss: 0.0698 - acc: 0.9655 - val_loss: 0.3531 - val_acc: 0.9269 Epoch 37/40 64/261 [======>.......................] - ETA: 1:17 - loss: 0.0032 - acc: 1.000

128/261 [=============>................] - ETA: 53s - loss: 0.0138 - acc: 0.9922

261/261 [==============================] - 140s 537ms/step

- loss: 0.0165 - acc: 0.9923 - val_loss: 0.3281 - val_acc: 0.9269 Epoch 38/40 64/261 [======>.......................] - ETA: 1:17 - loss: 0.0427 - acc: 0.984

128/261 [=============>................] - ETA: 53s - loss: 0.0244 - acc: 0.9922

261/261 [==============================] - 141s 541ms/step

- loss: 0.0145 - acc: 0.9962 - val_loss: 0.3111 - val_acc: 0.9385 Epoch 39/40 64/261 [======>.......................] - ETA: 1:20 - loss: 0.0261 - acc: 0.984

128/261 [=============>................] - ETA: 54s - loss: 0.0285 - acc: 0.9844

261/261 [==============================] - 142s 542ms/step

- loss: 0.0201 - acc: 0.9923 - val_loss: 0.2992 - val_acc: 0.9308 Epoch 40/40 64/261 [======>.......................] - ETA: 1:17 - loss: 0.0225 - acc: 1.000

128/261 [=============>................] - ETA: 52s - loss: 0.0157 - acc: 1.0000

261/261 [==============================] - 142s 544ms/step

- loss: 0.0116 - acc: 1.0000 - val_loss: 0.2997 - val_acc: 0.9308

Train on 261 samples, validate on 260 samples Epoch 1/40 64/261 [======>.......................] - ETA: 1:15 - loss: 1.8016 - acc: 0.078

128/261 [=============>................] - ETA: 52s - loss: 1.7970 - acc: 0.1094

261/261 [==============================] - 141s 540ms/step

- loss: 1.7858 - acc: 0.1686 - val_loss: 1.7285 - val_acc: 0.4769 Epoch 2/40 64/261 [======>.......................] - ETA: 1:23 - loss: 1.7652 - acc: 0.265

128/261 [=============>................] - ETA: 54s - loss: 1.7264 - acc: 0.3828

261/261 [==============================] - 142s 543ms/step - loss: 1.7048 - acc: 0.3602 - val_loss: 1.6120 - val_acc: 0.4308Epoch 33/40

64/261 [======>.......................] - ETA: 1:16

- loss: 0.0544 - acc: 0.968128/261 [=============>................] - ETA: 51s - loss: 0.0576 - acc: 0.9688261/261 [==============================] - 137s 527ms/step - loss: 0.0333 - acc: 0.9847 - val_loss: 0.6902 - val_acc: 0.8846 ...


Epoch 34/40 64/261 [======>.......................] - ETA: 1:18 - loss: 0.1083 - acc: 0.953

128/261 [=============>................] - ETA: 53s - loss: 0.0852 - acc: 0.9688

261/261 [==============================] - 141s 541ms/step

- loss: 0.0944 - acc: 0.9617 - val_loss: 0.6737 - val_acc: 0.8808 Epoch 35/40 64/261 [======>.......................] - ETA: 1:19 - loss: 0.0593 - acc: 0.984

128/261 [=============>................] - ETA: 53s - loss: 0.0404 - acc: 0.9844

261/261 [==============================] - 141s 541ms/step

- loss: 0.0380 - acc: 0.9885 - val_loss: 0.6246 - val_acc: 0.8846 Epoch 36/40 64/261 [======>.......................] - ETA: 1:15 - loss: 0.0090 - acc: 1.000

128/261 [=============>................] - ETA: 52s - loss: 0.0220 - acc: 0.9922

261/261 [==============================] - 140s 537ms/step

- loss: 0.0462 - acc: 0.9885 - val_loss: 0.5759 - val_acc: 0.8885 Epoch 37/40 64/261 [======>.......................] - ETA: 1:15 - loss: 0.0260 - acc: 0.984

128/261 [=============>................] - ETA: 52s - loss: 0.0265 - acc: 0.9844

261/261 [==============================] - 142s 542ms/step

- loss: 0.0229 - acc: 0.9923 - val_loss: 0.5629 - val_acc: 0.8923 Epoch 38/40 64/261 [======>.......................] - ETA: 1:21 - loss: 0.0346 - acc: 0.984

128/261 [=============>................] - ETA: 53s - loss: 0.0333 - acc: 0.9844

261/261 [==============================] - 141s 538ms/step

- loss: 0.0282 - acc: 0.9885 - val_loss: 0.5665 - val_acc: 0.9000 Epoch 39/40 64/261 [======>.......................] - ETA: 1:21 - loss: 0.0107 - acc: 1.000

128/261 [=============>................] - ETA: 53s - loss: 0.0089 - acc: 1.0000

261/261 [==============================] - 140s 535ms/step

- loss: 0.0189 - acc: 0.9923 - val_loss: 0.5851 - val_acc: 0.8962 Epoch 40/40 64/261 [======>.......................] - ETA: 1:16 - loss: 0.0290 - acc: 0.984

128/261 [=============>................] - ETA: 51s - loss: 0.0478 - acc: 0.9766

261/261 [==============================] - 139s 532ms/step

- loss: 0.0536 - acc: 0.9770 - val_loss: 0.6973 - val_acc: 0.8885


예측 실행하기 

예측을 수행하여 훈련된 모델이 잘 동작하는지 확인한다. 

실행속도를 높이기 위해 이번에는 GPU를 사용하도록 환경 변수를 등록한다.

다행히 예측하는 과정에는 메모리를 적게 사용하기 때문인지 잘 동작한다.

주의. Theano 2 에서는 device 의 이름이 gpu0 가 아니고 cuda0 로 변경되었다.

$ export THEANO_FLAGS='mode=FAST_RUN,device=cuda0, floatX=float32, optimizer_excluding=conv_dnn'

$ python 9_Layer_CNN.py test 38 27 Using Theano backend. Using cuDNN version 7005 on context None Mapped name None to device cuda0: GeForce GTX 980M (0000:01:00.0) airplanes 640/640 [==============================] - 3s 5ms/step ... 640/640 [==============================] - 3s 5ms/step 정답수  566 오답수 74 Motorbikes 638/638 [==============================] - 3s 5ms/step ... 638/638 [==============================] - 3s 5ms/step 정답수  607 오답수 31 Faces_easy 348/348 [==============================] - 2s 5ms/step ... 348/348 [==============================] - 2s 5ms/step 정답수  322 오답수 26 watch 191/191 [==============================] - 1s 5ms/step ... 191/191 [==============================] - 1s 5ms/step 정답수  119 오답수 72 Leopards 160/160 [==============================] - 1s 5ms/step ... 160/160 [==============================] - 1s 5ms/step 정답수  151 오답수 9 bonsai 102/102 [==============================] - 0s 5ms/step ... 102/102 [==============================] - 0s 5ms/step 정답수  53 오답수 49



+ Recent posts