이것 저것 하느라 블로그에 글 쓸 시간이 없었는데, 오늘 시간 내서 써봅니다.

먼저 저번 포스팅에서 데이터 수집과 라벨링까지 했었는데요. 이번에는 수집한 데이터를 가지고 custom model을 만들어 봅시다.

caffe는 설치했다고 가정하겠습니다. caffe 설치는 caffe home page 가면 자세히 나와있으니, 보고 하시면 됩니다.


1. Custom CNN을 만들자!


흠. 말 그대로 일단 Custom CNN model을 만들어야 하니 학습시킬 CNN 구조를 만들어줘야 합니다. Custom CNN 구조를 만드는 방법은 Caffe Tutorial에 자세히 나와있습니다. 하지만 이 포스팅에서는 귀찮으니 bvlc_reference_caffenet의 모델을 사용하도록 하겠습니다. caffe/models/bvlc_reference_caffenet directory에 들어가보면 deploy.prototxt, solver.prototxt, train_val.prototxt 파일이 있을겁니다. 만약 없으신분은 caffe github에서 다운받으시면 됩니다. 그럼 이 세개의 파일을 복사해서 자신이 원하는 폴더에 붙여넣기를 합니다. 저같은 경우는 caffe/models directory에 model_test_5라는 directory를 만들어서 붙여넣기를 하였습니다. 여기서 우리가 수정해줘야 할 파일은 solver.prototxt, train_val.prototxt 입니다. 먼저 train_val.prototxt를 살펴 보겠습니다.

빨간색으로 박스를 쳐 놓은 곳이 우리가 수집한 이미지로 만든 학습 데이터 경로입니다. 물론 아직 수집한 이미지를 데이터화 시키진 않았지만 수집한 이미지를 데이터화 시키는 작업은 Custom CNN의 구조와 밀접한 관계가 있으므로 train_val.prototxt 분석 먼저 하고 설명하도록 하겠습니다. (물론 진정한 CNN custom model을 만드는 작업을 하려면 이 CNN 구조도 스스로 만들어야겠죠. 하지만 여기서 그런것까지 일일히 설명하기에는 CNN에 대한 설명까지 나와야 하기 때문에 생략하도록 하겠습니다.) 

일단 위 그림에서 보면 data layer가 두개가 있죠.  위에 있는 data layer는 train data layer이고 아래에 있는 data layer는 valid data layer입니다. 빨간 박스는 위에서부터 순서대로 image mean data, train data, image mean data, valid data 입니다. image mean 값은 train data나 valid data나 같으므로 두 레이어에 모두 같은 값을 넣어주고, train layer에는 train data를, valid layer에서는 valid data를 사용하겠다고 각각 경로를 설정해 준 것입니다. 물론 이 파일들은 아직 만들어지지 않았습니다. 우리가 저렇게 설정을 했으니 train data와 valid data, image mean data를 각각 저 경로에 만들어 줘야겠죠? 그리고 각각 layer에 data param을 보면 batch_size라는 parameter가 있는데, 저 값이 의미하는 바는 한번에 처리하려는 input의 갯수입니다. 또 backend는 data layer source로 LEVELDB를 사용할지 LMDB를 사용할지 선택하는 것입니다. Default값은 LEVELDB입니다. 우리는 LMDB를 사용할 것이므로 저렇게 설정되어 있습니다. 흠... 하나하나 설명하려니 점점 설명해야 하는게 늘어가는 군요. 직접 CNN을 만드실려면 Caffe Tutorial을 참조하세요. 나중에 시간나면 하나하나 자세히 설명하는 시간을 가지도록 하겠습니다.(언제가 될지는 확실하지 않습니다.) 어쨋든 우리는 caffenet model을 그대로 사용할 것이기 때문에 그냥 mean_file과 source 값만 바꿔줍시다. 

마지막으로 여기서 한가지 더 짚고 넘어갈 부분이 있습니다. train_val.prototxt의 마지막 InnerProduct layer를 보면 output number가 1000으로 되어 있는데 이는 이 CNN은 imagenet의 data set에 맞춰서 설계되었고, imagenet data set의 class가 1000개이기 때문입니다. 우리가 수집한 데이터의 class가 몇개인지는 모르겠지만 어차피 나중에 synset_words.txt만 수정해주면 되므로 그냥 pass합시다. 자신이 학습시킬 모델의 class 갯수에 맞추어 CNN을 디자인 하는 것이 옳지만 저 output number 값을 바꿀거면 그냥 CNN을 직접 설계하는게 나을듯 합니다. 그대로 써도 어느정도 성능은 나옵니다. (물론 over fitting이 될 확률이 있지만...)

deploy.prototxt는 바꿀 필요가 없습니다. 당연히 deploy.prototxt도 output이 1000개 입니다. (train_val.prototxt는 학습을 시키기 위한 구조고, deply.prototxt는 학습이 완료된 모델을 이용하여 classifying 할때 쓰는 구조입니다.)

이제 solver.prototxt를 봅시다. solver.prototxt는 두 곳만 수정하면 됩니다.

먼저 net은 학습시킬때 사용할 CNN의 경로를 적어주면 됩니다. 바로 금방 전까지 다룬 파일의 경로를 위와 같이 적어줍니다. snapshot_prefix는 중간 중간 학습시킨 모델들을 저장할때, 어디에 앞에 어떤 이름으로 저장할지 설정하는 것입니다. snapshot 이 10000으로 설정되어 있는데, 이는 iteration이 10000번 돌때마다 그때까지 학습시킨 모델을 저장하겠다는 것입니다. max_iter은 말 그대로 iteration의 최대값입니다. 즉, iteration이 450000을 돌면 학습을 그만 두겠다는 거죠. 이 solver.prototxt file을 가지고 학습을 시키면 caffe/models/model_test_5 directory에 model5_train_iter_10000.caffemodel, model5_train_20000.caffemodel ~ model5_train_iter_450000.caffemodel이 저장되겠죠.(solverstate도 같이 저장됩니다.) solver_mode는 gpu로 연산하겠다는 것입니다. cpu로 하면 엄청 오래 걸리니까 gpu로 하시는게 좋습니다.



2. 수집한 Image data를 이용해 LMDB를 만들자!


이제 우리가 수정한 CNN에 학습시키기 위해 수집한 image를 LMDB 파일로 만들어야 합니다. 앞선 train_val.prototxt에서 data layer의 layer type이 data고, backend값이 LMDB이기 때문입니다. 물론 Data layer의 layer type을 ImageData로 설정하고 source를 학습시킬 image의 filename이 적혀있는 text file로 설정을 했으면 이 단계가 필요 없지만, 그러지 않았기 때문에 image data들을 LMDB file로 만들어야 합니다. (나중에 시간이 나면 layer type들에 대하여 설명해 드리도록 하죠. 궁금하신 분은 caffe layers를 보시기 바랍니다.)

다행스럽게도 caffe에서 create_imagenet.sh라는 파일을 제공해 주고 있습니다. 보통 caffe/examples/imagenet/create_imagenet.sh에 있으며 만약 없다면 BVLC/caffe github에서 다운받으시길 바랍니다. caffe/examples/imagenet directory를 보면 create_imagenet.sh, make_imagenet_mean.sh, train_caffenet.sh, resume_training.sh가 있습니다. create_imagenet.sh는 LMDB 파일을 만드는 bash file이고 만약 image를 resize하지 않았다면 이 파일을 통하여 resize도 할 수 있습니다. (정확히 말하면 convert_imageset이 하는거지만 그냥 각 bash file의 기능만 말하겠습니다.) make_imagenet_mean.sh는 말 그대로 image의 평균값을 계산해 주는 파일입니다. 마지막으로 train_caffenet.sh는 CNN을 training시키는 기능을 합니다. 저는 이 세 파일들을 caffe/examples/model_test_5라는 directory를 만들어 복사했으며, 이 전 포스팅에서 만든 train.txt와 val.txt는 caffe/data/model_test_5 directory에 넣어놨습니다. 그럼 create_imagenet.sh를 보겠습니다.

먼저 EXAMPLE 경로와 DATA 경로를 수정해야합니다. LMDB는 EXAMPLE 경로에 만들어지며, DATA는 train.txt와 val.txt가 있는 경로로 설정해 주면 됩니다. TOOLS는 convert_imageset이 있는 경로입니다. TRAIN_DATA_ROOT와 VAL_DATA_ROOT 값도 살포시 변경해줍니다. train.txt에 라벨링한 학습할 이미지 경로는 n0/n_*.JPEG로 작성했었습니다. 저는 train image 파일들을 caffe/imageSet/train2에 넣었으므로 이 이미지 파일들을 제대로 참조하려면 TRAIN_DATA_ROOT값을 imageSet/train2/로 설정해줘야 n0/n_*.JPEG와 합쳐져 온전한 경로가 될것입니다. (절대 경로로 써도 당연히 됩니다.) RESIZE는 256*256 size로 resize 할 것인가 설정하는 것인데, 현재 제가 모은 image들은 크기가 제각각이므로 이 값을 true로 설정했습니다. default는 false로 되어있습니다. image들을 어떤값을 어떤 순서로 데이터화 시키느냐에 따라서 모델의 성능이 은근히 달라지기 때문에 BVLC에서는 각자 알아서 data 변환 하는것을 추천하는 편입니다. 하지만 여기선 그냥 resize합니다. 마지막으로 $EXAMPLE/model5_train_lmdb와 $EXAMPLE/model5_val_lmdb로 값을 변경해줬습니다. 저는 train_val.prototxt에서 위와 같은 directory로 경로를 설정했기 때문입니다. --shuffle은 학습시킬 이미지들을 섞겠다는 건데, train.txt 작성할때 그냥 순서대로 써서 --shuffle은 그냥 놔두는게 좋습니다. train.txt 와 val.txt 작성할 때 shuffle을 했다면 저 option은 지워도 상관 없습니다. (shuffle을 안해주면 학습이 제대로 안될수도 있습니다. 이게 무엇인지 계속 학습시키다가 그다음 이게 무엇인지 계속 학습을 시키면 어느 한 class에만 over fitting 될 수가 있기 때문입니다. 때문에 그 다음에 학습시키는 class들이 제대로 학습되지 않을 수 있습니다.)

make_imagenet_mean.sh에서도 EXAMPLE, DATA 경로를 바꿔주고, $EXAMPLE/ilsvrc12_train_lmdb값을 앞서 설정한 train_lmdb 경로로 바꿔주면 됩니다. 저 같은 경우는 EXAMPLE = examples/model_test_5, DATA = data/model_test_5, $EXAMPLE/ilsvrc12_train_lmdb -> $EXAMPLE/model5_train_lmdb가 되겠군요. 

train_caffenet.sh는 solver의 경로만 바꿔주면 됩니다. 저같은 경우는 --solver = models/bvlc_reference_caffenet/solver.prototxt -> --solver = models/model_test_5/solver.prototxt가 되겠군요.

이제 create_imagenet.sh, make_imagenet_mean.sh, train_caffenet.sh를 순서대로 실행시켜주시면 됩니다. 저는 이마저도 make_model.sh라는 파일을 만들어서 했습니다. 어쨋든 $bash examples/model_test_5/create_imagenet.sh를 하면 다음과 같이 LMDB 파일이 만들어 집니다.

/home/san/caffe/examples/model_test_5

create_imagenet.sh를 실행시킨 모습

잘못된 image file들이 몇개 있네요.

graphic memory 사용량


$bash examples/model_test_5/make_imagenet_mean.sh를 하면 mean값이 금방 계산됩니다. 마지막으로 train_caffenet.sh를 실행합니다.

train_caffenet.sh를 실행한 모습

graphic memory 사용량


이제 그냥 컴퓨터 켜놓고 다른거 하시면 됩니다. 제 컴퓨터 성능으로는 450000 iteration 도는데 36시간 정도 걸리더군요. 시간 없으신 분들은 solver.prototxt 에서 max_iter를 50000 정도만 해서 학습시키세요. class가 적으면 50000번만 돌아도 그럭저럭 학습이 됩니다. 어쨋든 학습이 완료되고나서 models/model_test_5에 가면 다음과 같이 학습된 caffemodel file들이 저장되어 있는 것을 확인할 수 있습니다. 그러면 이제 인터넷에서 이미지를 하나 다운받아서 정말 분류가 되나 확인해봅시다. 

먼저 output의 갯수가 1000이므로 output되었을때 출력될 word들도 1000 라인이어야 합니다. 저같은 경우는 총 12개의 class를 학습시켰는데, CNN은 caffenet의 구조를 그대로 사용했으므로 output node가 1000개가 되어 버렸습니다. 물론 학습시키지 않은 output이 나올리가 없지만 그래도 output이 1000개 이므로 word들도 1000로 맞춰줘야합니다. 저는 제가 학습시킨 class에 대해서는 직접쓰고 나머지는 synset_words.txt에서 복사 붙여넣기 해서 1000라인을 채웠습니다.

1번째 줄에서 12줄 까지는 제가 학습시킨 class들이기 때문에 직접 해당하는 node 번호에 맞춰서 출력할 text를 써주고 나머지는 아무렇게나 채웠습니다. 이제 분류기를 이용해서 image 분류를 해봅시다.

분류는 caffe/build/examples/cpp_classification.classification.bin file을 이용해서 합니다. 사용방법은 다음과 같습니다.


~/caffe$ ./build/exaples/cpp_classification/classification.bin deploy.prototxt network.caffemodel mean.binaryproto labels.txt img.jpg

제 경우는 다음과 같이 사용합니다.


~/caffe$ ./build/exaples/cpp_classification/classification.bin ./models/model_test_5/deply.prototxt 
             ./models/model_test_5/model5_train_iter_450000.caffemodel
             ./data/model_test_5/imagenet_mean.bynaryproto 
             ./data/model_test_5/sysset_words2.txt 
             ./imageSet/test/1.JPG

결과


뭐 그럭저럭 학습이 된거 같긴 하네요. 분류율을 높이기 위해서는 CNN을 잘 만들고, 학습 데이터도 잘 모으는 등 여러가지 인자들을 바꿔가며 좋은 모델을 만들어야 합니다. 언제가 될지 모르겠지만 내킬때 caffe tool에 대하여 자세히 이야기 하도록 하겠습니다. caffe tool에 대하여 자세히 설명하려면 어쩔 수 없이 CNN에 대하여 설명을 하면서 진행해야 겠네요. 이 포스팅이 도움되실 분들이 얼마나 있을지 모르겠지만 몇몇 분들에게라도 도움이 되길 바라면서 이번 포스팅은 여기까지입니다.

+ Recent posts