일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- Embedded System
- I.MX6Q
- Machine learning
- Homomorphic Filter
- ARM Processor
- IOT
- CNN
- Facial expression recognition
- VGGnet
- tf.saver()
- Python
- tf.train.string_input_producer()
- Machine Vision
- cross compile
- deep-learning
- porting
- Raspberry Pi
- OpenCV
- preprocessing
- TensorFlow
- Data Load
- tf.train.match_filenames_once()
- Today
- Total
Austin's_Lab
[Tensorflow] Facial expression recognition using adaptive VGGnet19 model(2) 본문
[Tensorflow] Facial expression recognition using adaptive VGGnet19 model(2)
Ausome_(Austin_is_Awesome) 2017. 7. 18. 14:17-Tensorflow 0.12.0사용 on Ubuntu 14.04-
4학년 1학기 Embedded System과 Pattern Recognition 수업에서 병행하여 진행한 프로젝트의 일환이다.
서버는 I.MX6Q 보드에서 촬영된 얼굴 영역 이미지를 전송받아, 화남, 슬픔, 기쁨, 평상 네 가지 감정 중 어떤 감정인 지 판단하여 결과를 보드에 돌려주어야 한다. 서버를 구축하는 과정은 총 5step으로 나뉜다.
1. 데이터 수집
2. 데이터 증식 및 전처리
3. 학습 모델 선정 및 보완
4. 학습 및 테스트
5. 학습된 모델을 사용해 서버 프로그램 개발
3. 학습 모델 선정 및 보완
학습 모델을 선정하는 데 있어서 다양한 논문들을 들여다 보았다. 그 중 CNN으로 진행한 대부분의 논문들을 구현해보았는데, 논문 만큼의 성능이 나오지도 않을 뿐더러 generalization이 거의 되지 않았다. 그래서 결국 가장 간단하고 흔하게 많이 쓰이는 VGGnet 모델을 가져다 쓰기로 했다. VGGnet이 나온 이후로 여러가지 기술들이 많이 나왔기 때문에 VGGnet 이후에 새로 나온 기술들을 적용하여 조금 더 개선된 형태의 VGGnet model을 만들어보기로 했다. 여기엔 두 가지 기술이 사용되었다.
3-1. 원래 VGGnet 논문(2014년)에서는 VGG 19같은 깊은 네트워크를 학습하기 위해서 VGG 11처럼 얕은 구조로 pre-training한 다음 pre-trained된 모델에서 앞의 4개의 layer와 FC layer의 weights를 가지고 깊은 모델의 초기화를 진행한다고 써있었다.
이 때가 아직 Batch Normalization(2015년)이 나오기 전이어서 아마 parameter initialization이 되게 중요한 이슈였던 때였던 것 같다. 하지만 VGGnet 자체가 학습속도가 미친듯이 느려서 시간적 문제도 있고, Batch Normalization을 사용하면 어느정도 parameter initialization 문제에서 자유로울 수 있기 때문에 convolution 사이사이 BN을 넣고 바로 VGGnet 19 model을 사용하는 것으로 결정했다.
붉은 화살표가 있는 부분이 모두 BN이 들어간 위치이며, 아래에서 설명할 FCN 구조 때문에 Dense layer에도 BN을 사용하였다.
3-2. 확실히 구조가 깊으니까 GPU메모리가 8GB인데도 바로 OOM이 나버린다. batch size를 너무 작게하면 오히려 감당할 수 없을만큼 느려져버릴 것 같았다. 요즘 또 FC보다는 FCN(Fully convolutional networks)를 사용하는 추세라고도 하고 이게 메모리를 상당히 줄여준다고 해서 연습도 할 겸 한 번 적용해보기로 했다.
CNN의 거의 모든 parameter는 FC layer에 몰려있다. 얘네는 convolution처럼 weight을 공유하는 형태가 아니고 모든 노드가 각각 자신에게 들어오는 input의 개수만큼 weight을 갖고 있기 때문이다. 근데 사실 matrix를 flatten하여 만든 FC layer의 feature vector는 각 노드를 1x1의 feature로 보고 1x1x노드의 개수(dimension)의 1개의 feature map으로 표현할 수도 있다. 여기에 1x1 convolution을 하면 마찬가지로 weight들을 공유하면서 parameter의 개수도 줄이고, FCN을 사용하면 input이 어떤 size가 들어와도 된다. 고 이해하고 썼었는데 최근 FCN에 대해 다시 공부하다 보니 FCN은 segmentation에서 주로 많이 쓰는 것 같고...(sliding window 효과) classification 문제에서 FC를 conv로 바꾸려면 고려해야하는 사항이 조금 더 있나보다. FCN 사용의 주 목적은 메모리 사용량을 줄이는 것이 아니라 input data가 spatial feature에 대해 유효한 정보가 있다는 게 확정적일 경우, 다양한 input size에 대한 적용인 것 같다. 더 공부를 해봐야겠다. 쨋튼 이번 프로젝트에서 사용한 결과는 꽤나 성공적으로 나왔다.
원래는 flatten해서 matmul로 구현해야 하지만 모두 convolution으로 바꾸었다. 왠지 지금 보니까 이렇게 쓰는 게 아닌 것 같은 느낌이 강하게 든다...
4. 학습 및 테스트
학습은 200 epoch를 돌리는 데 하루를 꼬박 썼다. 학습기 및 테스트 코드는 여기 적기엔 너무 길어서 github에 올려두었다.
https://github.com/moon920110/Facial_Expression_Recognition.git
Tensorflow에서 이미지 데이터는 numpy array에 들어가는 것 같았다. OpenCV도 이미지를 numpy array형태로 다루기 때문에 간단하게 openCV를 이용하여 camera를 촬영하면서 얼굴 영역을 찾고, 버튼을 누를 때마다 얼굴 영역 crop -> preprocessing -> resizing & reshaping 해서 학습기에 feed해주는 형태로 테스터를 구현했다.
과장된 표정들 위주로 학습을해서 그런지 과장된 표정에 대해서는 굉장히 높은 정확도를 보인 반면, 동양인들 특유의 애매한 표정에는 조금 덜 정확한 정확도를 보였다. google에서 긁어모은 이미지와 지인들 얼굴 표정을 crop해서 모은 데이터로 class 당 100장 test set을 만들어 test한 결과, 과장된 표정에 대해서는 평균 98%정도, 덜 과장된 표정에 대해서는 평균 92%정도의 정확도를 보였다.
Linux를 HDD에 설치해서 그런지 테스트하면서 녹화하니까 굉장히 버벅거린다. 실제로는 테스트 버튼 누르면 1~2초 안에 바로바로 검출된다.
5. 학습된 모델을 사용해 서버 프로그램 개발
서버 개발은 생각보다 별 거 없었다. 서버 개발에도 두 가지 정도의 이슈가 있었는데, 하나는 binary 데이터로 오는 이미지를 바로 numpy array format으로 converting하는 법을 몰랐던 것이고, 또 다른 하나는 서버가 EOF를 몰라서인지 자꾸 다음에 오는 이미지랑 패킷이 충돌나서 서버가 죽는 것이었다.
5-1. 그냥 받은 jpg 형식의 빈 파일을 열어서 binary data가 들어올 때마다 jpg파일에 차례대로 저장하고, 파일이 완성되면 그 완성된 이미지를 openCV로 다시 불러서 이것저것 전처리 하고 사용했다.
5-2. 그때 그때 전송되는 packet size가 달라서 명확하게 EOF를 판단할 기준을 정하기가 애매했다. packet size가 다른 애를 EOF로 하자니 중간에 다를 때도 있고... 이 때문에 간혹 저장된 이미지가 망가지거나 파일 자체가 깨지기도 했다. 그래서 그냥 client에서 이미지 packet을 보낼 때 마지막에 'aaaaa'라는 문자열을 보내도록 해서 서버에서 읽을 때 파일의 끝에 'aa'라는 문자가 있으면 EOF로 판단하도록 했다.
마찬가지로 코드는 github에 있다. https://github.com/moon920110/Facial_Expression_Recognition.git