2015년 10월 25일 일요일

Pose estimation

입력 rgb채널을 9개로 해서 3개의 연속 영상을 입력(temporal information 고려)
마지막 fc층은 regressor로 사용 시 학습율을 다른 층과 달리해야 함
pooling, local response normalization, ReLU, dropout 적용된 convnet 사용
Video-specific learning으로 기존에는 주로 전체 학습 영상 평균을 제거. 여기에서는 per-video mean 제거.
data aug은 N(가로)x256(높이)로 만들고, 여기서 248x248를 random하게 추출, flip+rgb jitter적용 후, 좌표는 [0,1]로 정규화.  scratch후 학습율은 10^-2, 10^-3(80k), 10^-4(90k). 110k에서 stop.
ImageNet과 같은 classification learning은 학습 샘플 내부 객체의 세부적 위치 변화에 insensitive하게 학습이 되므로 pose 추정에는 부적합
ImageNet 분류기 결과에 BBC db(pose)를 fine tuning해도 결과는 별로 개선 안됨. 분류와 자세 추정은 서로 다른 weight를 요구할 만큼 다른 작업임
ImageNet의 표준 배경 이미지 사용 시 성능 악화 (학습 data의 배경에 overfitting된 경우임. 따라서 per-video배경 제거 필요)
표 1의 Scratch 의미는 랜덤하게 weight처리(?) 후 학습 의미
-DeepPose에서 배경처리?

Ref.
[1] T Pfister et al., Deep convolutional neural networks for efficient pose estimation in gesture videos, 2015.


2015년 8월 5일 수요일

Windows에서 Theano 설치

첫 번째 방법

Windows7 64bit 와 vs2013 사용 환경에서 설치


1. Anaconda(python) 설치.  https://store.continuum.io/cshop/anaconda/

>conda update conda // update 해줌
>conda install mkl  // intel math kernel lib, blas 중 하나
>conda install libpython // gcc, g++ 컴파일러 설치, gcc는 theano 컴파일에 필요

libpython 설치 후에도 gcc가 실행되지 않으면, 아래에서처럼 MinGW, MSYS를 직접 설치할 수 있다.  MinGW와 MSYS는 windows 환경에서 Linux 환경을 사용 가능하게 해 줌.
또 다른 자료에는
>conda install mingw libpython
잘 동작 한다고 하나 시도해보지 않았음.


2. Visual studio 2013 설치.
설치 후에 vs의 cl.exe(ms의 c/c++ 컴파일러/링크 제어 명령)를 사용해야 하므로 path를 설정해야 함.  "시작 버튼->내컴퓨터->오른쪽 클릭->속성->고급시스템설정->환경변수->'시스템변수'->'Path'->편집 버튼" 에서 경로 추가.  보통 cl.exe는 C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\bin에 있음.

windows 64bit를 사용하므로 cmd창을 열고 cl이 있는 위치로 가서 x64 설정:
>cd C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC
>vcvarsall.bat amd64

설정 후, cmd 창에서 cl입력해서 x64(64bit compiler/link)인지 확인. cl은 cuda 컴파일에 필요


3. cuda 설치 (7.0버전)


4. Theano 설치
기 설치된 anaconda의 console을 하나 open한다. cl.exe의 64bit 옵션은 현재 오픈된 해당 console에서만 유효하므로 x64로 변경 후

> where cl
> where gcc 
> where nvcc
> where g++

로 여러 컴파일러들이 문제 없이 동작함을 확인한다.

> pip install theano 

로 theano 설치 (제거 시에는 >pip uninstall theano, 기 설치의 upgrade는 >pip install --upgrade theano). 혹시 더 필요한 lib가 있다면 이런 방식으로 설치나 제거해준다.


5. Theano 설치 후

cmd 창에서 

>echo %USERPROFILE%

해서 위치 확인하고 거기로(user 디렉토리임) 가면 ".theanorc.txt' 파일이 있다. 이것을 아래처럼 수정. 없다면 새로 만듬.
---------------
[global]
device = gpu
floatX = float32

[nvcc]
flags=--use-local-env --cl-version=2013
----------------



6. Test 1

> python

실행 후 

>> import theano
>> theano.test()

명령 입력. 두번째 명령은 theano 실행에 필요한 여러 소스를 알아서 컴파일 한다(상당히 오래 걸림). 미리 컴파일 해놓지 않으면 iphython notebook 등에서 theano 실행 시 오래 걸리거나 오류 발생 (실행전 cl의 x64 체크).



7. Test 2
아래 두 번째 방법의 6번 수행.
(일단 새 console 창 열면 무조건 cl을 x64로 설정해 줘야 함)


8. Test 3 [1]
interactive python(ipython ) notebook 실행 후 theano 사용과 graph 출력:

%matplotlib inline
import numpy as np
import matplotlib
import matplotlib.pyplot as plt

import theano
import theano.tensor as T





MinGW와 MSYS의 직접 설치

만일 gcc가 제되로 실행되지 않는다면 다음처럼 mingw와 msys를 설치한다.

1. 64bit MinGWMSYS를 설치한다. (둘 다 설치 파일 MinGW-w64 installer.exe 와 MSYS-1.0.11.exe를 받아 실행)
-MinGW: Architecture(x86_64), Thread(posix), Exception(Seh)로 설정. 설치 directory는 "c:\MinGW"로 간략하게 함. 설치 중간 옵션 중에 g++ compiler 선정.
-MSYS: 설치 경로를 "c:\MSYS"로 단순하게 함. 설치 중간에 물음에 y선택 2번, MinGW 경로 요구는 "c:/MinGW"(MinGW설치 경로. 이 밑으로 bin 등이 있어야 함) 설정.


2. 시스템 속성 변경

환경변수->시스템변수.에 와서 '새로만들기' 선택.  변수명(MINGW), 변수값(c:\\MinGW). 또, 변수명(MSYS), 변수값(c:\\msys) 입력.
'Path' 항목 찾아 편집 버턴을 눌러 %MINGW%\bin;%MSYS%\bin; 추가 후. 클릭.

완료 했으면 cmd창을 열어서 다음을 입력하여 확인.
>make
>gcc --version

 
cuda, cl, gcc, g++ 설치가 잘 되었는지 확인 방법: cmd창 열어
>where cl
>where gcc
>where g++
>where nvcc






두 번째 방법

1. 먼저 libpythonxx.a 파일을 만들어야 한다. 일단 pythonxx.dll(2.7 version의 경우 python27.dll. c:\anaconda밑에 있다)을 찾아서 임시 directory에 복사.

2. 다음 명령을 실행(여기서 XX는 버전 정보 27)
>gendef pythonXX.dll
>dlltool --as-flags=--64 -m i386:x86-64 -k --output-lib libpythonXX.a --input-def pythonXX.def

3. 이렇게 만들어진 libpythonxx.a 파일을 파이썬을 설치한 directory의 libs 아래에 복사.  여기서는
c:\anaconda\libs 밑에 복사.

4. https://github.com/Theano/Theano에 가서 Theano의 zip파일을 다운 받아서 압축을 푼다. Theano 코드가 있는 directory에서
>pip install .


5. cmd창에서
>echo %USERPROFILE%
해서 위치 확인하고 거기로(보통 user 디렉토리임) 가면 ".theanorc.txt'파일이 있다. 이것을 수정. 없다면 새로 만듬.
---------------
[blas]
ldflags =

[gcc]
cxxflags = -shared -I[MinGW 디렉토리]\include -L[파이썬 디렉토리]\libs -lpython34 -DMS_WIN64
----------------


직접 설정한 예는 다음과 같다:
----------------
[blas]
ldflags =

[gcc]
cxxflags = -shared -I%MINGW%\include -LC:\Anaconda\libs -lpython27 -DMS_WIN64

[global]
device = gpu
floatX = float32

[nvcc]
flags=--use-local-env --cl-version=2013
-----------------

device는 cpu나 gpu로 바꿀 수 있다.



6. 테스트를 위해 Anaconda command prompt를 하나 열고
>python test.py

해보면 된다.
test.py파일은 http://hugman.re.kr/static/media/uploads/codes/test.py 에 있다.

---------------------------------
import numpy as np
import time
import theano
A = np.random.rand(1000,10000).astype(theano.config.floatX)
B = np.random.rand(10000,1000).astype(theano.config.floatX)
np_start = time.time()
AB = A.dot(B)
np_end = time.time()
X,Y = theano.tensor.matrices('XY')
mf = theano.function([X,Y],X.dot(Y))
t_start = time.time()
tAB = mf(A,B)
t_end = time.time()
print "NP time: %f[s], theano time: %f[s] (times should be close when run on CPU!)" %(
                                           np_end-np_start, t_end-t_start)
print "Result difference: %f" % (np.abs(AB-tAB).max(), )
----------------------------------

실행 하면 다음과 같은 결과가 나온다:

2015년 8월 2일 일요일

Color data augmentation in Alexnet

clc; clear all;
im=imread('painter.jpg'); % 이미지 입력
imd=double(im)/255.0; % 픽셀 값을 0~1사이의 실수 값으로 만듬

m = size(imd,1); % 이미지 폭
n = size(imd,2); % 높이. 한번에 [m,n] =size(imd);로 해도 됨
im1=reshape(imd(:,:,1),[1,m*n]); % r 행렬을 벡터로 변환
im2=reshape(imd(:,:,2),[1,m*n]); % g
im3=reshape(imd(:,:,3),[1,m*n]); % b

m1=mean(im1); m2=mean(im2); m3=mean(im3); % r, g, b 각 채널 픽셀 값의 평균
d1=im1-repmat(m1,[1,m*n]); % r 픽셀 값에서 r 평균을 뺌
d2=im2-repmat(m2,[1,m*n]);
d3=im3-repmat(m3,[1,m*n]);

data=[d1' d2' d3']; % 크기가 [m*n, 3] 임. 분포의 중심을 원점으로 분포 행렬 만듬
[v,d]=eig(data'*data); % 데이터의 분산이 큰 방향(v)과 크기(d) 얻음

dv=sqrt(diag(d)); % 퍼짐의 크기
val=v*(0.1*randn(3,1).*dv); % 정규분포(0.1의 분산)에서 하나의 랜덤 샘플링 값을 얻고 dv에 곱합. v 방향으로 이 크기 만큼 변형된 r, g, b 값 추출. val 값을 원 r,g,b 데이터에 더해서 color aug 이미지를 만들어 냄.



References
[1] Alex Krizhevsky et. al., ImageNet Classification with Deep Convolutional Neural Networks, 2012.



2015년 7월 20일 월요일

tiny cnn 설치

tiny cnnCaffeTheano에 비해 크기가 작은 cpp기반의 cnn library이다.
cuda-convnet이나 MatConvnet 등이 cpp library를 Matlab에서 호출하여 사용하는 것이 비해 tiny cnn은 c++전용(c++11) library이다.
설치 전에 먼저 https://github.com/nyanp/tiny-cnn 에 가서 설명을 읽어본다.
여기에 접속해서 mnist를 어떻게 학습하고 test하는지에 대한 문서를 읽어본다(꼭 읽어보기를 권한다).

tiny cnn을 실행하기 위해서는 tbb(Intel)와 boost라이브러리가 필요하다. tiny cnn은 용량을 작게 유지하기 위해 gpu(many core) 대신에 tbb(multi core)를 사용한다. 따라서 빠른 실행을 위해서는 tbb를 설치해야 한다.
아래에서 두 library를 설치하는 방법에 대한 것을 함께 설명한다.

tiny cnn 설치
(1) github에 가서 tiny-cnn을 다운 받는다.
(2) 압축을 풀어 install directory/vc로 들어가면 tiny_cnn.sln이라는 솔루션파일이 있다. visual studio 2012나 2013으로 이 파일을 열어 실행한다(여기서는 vs2013을 기준으로 설명).
(3) 컴파일 하면 error가 발생하는데 boost와 tbb가 설치되지 않아서이다.



boost설치
boost설치는 여기를 참고한다.  간단하게 요약해서 설명하면

(1) boost를 다운받고, 적당한 위치에 압축 해제 후에 cmd창 열어서 bootstrap.bat실행.
(2) 실행 후 b2.exe파일이 생기는데 이것을 이용하여 boost library를 빌드한다.
visual studio 2013에 대한 lib 빌드 명령은
b2 -j4 -a --toolset=msvc-12.0 variant=debug,release link=static threading=multi address-model=32 stage
이다.  vs버전이 달라지면 명령 중에 msvc-12.0를 수정해야 한다(예를 들면 vs2012는 msvc-11.0이다). 또 address-model=32는 visual studio의 Win32 compile 모드에 대응.

(3) 빌드가 끝나면 stage/libs 밑에 여러 lib파일이 생성된 것을 확인할 수 있다.

(4) 다시 vs2013으로 tiny cnn 솔루션을 열고(열면 두개의 project(tiny_cnn, tiny_cnn_test)가 있는데 여기서는 tiny_cnn프로젝트만 컴파일한다. 따라서 tiny_cnn_test프로젝트에서 나타나는 error는 무시하기 바란다), tiny_cnn 프로젝트에 대해 다음과 같이 설정해 보자.  tiny_cnn project의 속성을 열고

- C/C++ > General > Additional Include Directories 에 "installed location\boost_1_58_0" 추가
- Linker > General > Additional Library Directories 에 "installed location\boost_1_58_0\stage\lib" 추가

와 같이 경로를 설정한다.  다시 컴파일하면 boost에 대한 error는 없어지고 tbb가 설치되지 않았다는 error가 뜬다.



tbb설치
(1) 여기에서 tbb를 다운받는다.
(2) 적당한 위치에 압축 파일은 푼다.

(3) vs2013의 속성에 tbb의 include와 lib파일의 위치를 설정한다. tiny_cnn 프로젝트 속성에서
-VC++ directory > include directory에서  
install directory\tbb43_20150611oss_win\tbb43_20150611oss\include 경로 추가.
-Linker > General > Additional Library directories에 
install directory\tbb43_20150611oss_win\tbb43_20150611oss\lib\ia32\vc12 경로 추가
(단, vs2013은 vc12, vs2012는 vc11 등, vs버전에 따라 경로를 선택해 주어야 한다)

(4) tbb설치 directory의 bin/ia32/vc12에서 파일 tbb.dll(또는 tbb_debug.dll)을 복사하여 tiny cnn설치 위치의 vc/release(또는 vc/debug)밑에 복사한다.
또, tbb설치 directory의 lib/ia32/vc12에서 파일 tbb.lib(또는 tbb_debug.lib)을 복사하여 tiny cnn설치 위치의 vc/release(또는 vc/debug)밑에 복사한다.


위의 boost나 tbb설정은 visual studio의 두개의 컴파일 모드 release, debug에 대해 각기 해 주어야 한다.  먼저 release모드에 대해 설정하고 실행해 보기를 권한다.


설정이 완료 되었으므로 다시 컴파일하면 install directory/vc/release밑에 tiny_cnn.exe파일이 생성되며 이것을 실행하면 mnist 데이터에 대해 학습을 시작한다.
(Mnist는 학습시간이 꽤 걸림으로 빠른 실행을 위해 vs2013의 release모드에서 상기한 모든 과정을 수행할 것을 다시 한번 추천한다)

설정된 20번의 epoch 후에 최종 오차율은 98.7%에 도달 후에 종결한다. 이것은 cuda-convnet의 99.3%보다는 뒤진다.

오차율을 줄이기 위해 이런 방법이 있다.



MNIST 데이터 형식
example를 보면 mnist 데이터 형식은 idx1, idx3로 제공된다. 데이터 형식을 이해하기 위해 여기를 참고한다.
opencv 데이터 변환을 위해서는 여기 참고.




참고
[0] F:\download_2015\tiny-cnn-master\tiny-cnn-master


2015년 6월 29일 월요일

SPP net

SPP-net은 기존 conv-net과 달리 분류기(fc층)에 입력하기 위한 특징 갯수를 입력 영상 크기에 무관하게 추출할 수 있는 장점을 가진다.


기존 cnn에서 자동차나 등대는 crop 후 고정된 크기로 변경되어 conv층에 입력된다. 이는 fc 층이 항상 고정된 특징(즉, 고정된 크기의 특징맵) 수를 요구하기 때문이다.
SPP-net 에서 이미지는 크기 변경없이 그대로 입력된다. 이로 인해 fc층 직전 특징맵의 크기가 달라지는데 맵 크기가 달라져도 SPP에 의해 고정된 특징 수 추출이 가능하다.


아래에서는 물체 위치 추출 입장에서 spp 적용을 요약한다:


논문에서 R-CNN과 비교하여 주로 설명하는 이유는 물체 detection을 위한 후보 영역(window) 생성을 R-CNN처럼 Selective search를 사용하기 때문이다.

기존 R-CNN은 테스트 할 대상 이미지 내에서 2,000개 후보 영역을 생성시켜 각 영역을 검증하며, 2,000개의 영역은 중복되어 생성되기 때문에 계산량이 큰 문제가 발생한다.
각 후보 window는 227x227 크기로 만들어 net를 통해 특징을 생성하고 이 값을 SVM을 통해 분류한다.


이와 비교하여 SPP의 가장 큰 장점은 특징맵(conv-pool 반복 층에서 마지막 conv층 출력 map)$^{(1)}$ 크기와 무관하게 고정된 특징 수를 추출 한다는 것이다.  따라서, conv계산 한번 만으로 모든 후보 영역(window)에 대해 동일한 spp 특징(분류기(svm나 fc layer)에 넣기 위한) 수를 만들 수 있다.


상기 그림은 3-level spp를 사용하고 있고, bin이 4x4, 2x2, 1x1인 경우를 보여준다.  각 bin에서 max pooling을 사용한다.


R-CNN과 SPP 차이를 요약하면 R-CNN은 이미지 영역에서 직접 특징을 추출하지만, SPP는 특징 맵 영역에서 window-wise 특징을 추출한다.


만일 4-level SPP(spatial pyramid pool)를 사용한다면 (즉, 1x1, 2x2, 3x3, 6x6로 전부 50개) 3-level 보다 더 많은 수의 특징을 추출한다. 이 때 마지막 conv층 특징 map 이미지 수가 256개라면 50x256=12,800개 특징 추출이 가능하다.




위치 추출 학습에서 positive sample을 만들기 위해서는 ground-truth 윈도를 사용한다. negative sample은 약 30%정도 positive와 겹치게 추출한다. 만일 negative끼리 70%이상 겹치면 제거한다. 이렇게 만든 정/부 샘플을 SVM으로 학습하게 된다.




적용 방법은 2가지로 대상 이미지를 1-scale/5-scale 두가지로 크기 변경 후 실행하는데,
1-scale에서는 대상 이미지 작은 변의 크기(min(w,h)=s)를 688로 크기 변경 후에 실행.
5-scale에서는 s를 {480,570,688,864,1200}으로 스케일링 후 각기 적용한다.





특징 맵의 가시화



화살표는 특징 맵 내 가장 강한 응답과 이미지 내에서 해당 위치를 보여준다. Pooling을 통하여 이러한 특징을 추출한다.
차량에서는 윈도와 바퀴 부분이 강한 특징으로 추출된다. 우측은 다양한 영상 입력에 대해 강한 응답을 나타내는 영역을 보여준다. 차 윈도나 바퀴와 비슷한 외형 물체들이 표시 되었다.
두번째 그림에서는 ^ 형상 이미지 영역과 v 형상 이미지 영역에서 강한 response를 나타낸다.





이미지(또는 윈도) 크기에 무관하게 특징 갯수를 정하는 방법


주어진 스케치는 특징 맵 크기가 13x13이다. 요구된 bin이 3x3이라면 필기한 방법을 통해 얻어진 win크기 5와, stride 4를 적용하여 특징을 추출한다. 그러면 3x3개의 bin이 정의되므로 모두 9개 특징 추출이 가능하다.
여기서 a=13(맵 크기)이고 n=3(bin 수)에 대한 경우를 살펴 보았다. a가 바뀔경우라도 win과 stride만 재 계산해서 적용하면 항상 고정된 bin 수를 얻을 수 있다.



(주1) 일반적 CNN의 경우, 입력 영상 크기가 달라지면 FC층에 입력되기 직전인 마지막 conv층 맵 크기가 달라지므로 맵 크기에 따라 정의되는 특징 갯수가 달라지게 된다.




References
[1] Spatial Pyramid Pooling in Deep Convolutional Networks for Visual Recognition, PAMI 2015.



2015년 6월 3일 수요일

Multi-Box prediction

학습

물체 위치를 나타내는 출력노드가 400개(100개의 위치), 각 위치에 대한 confidence를 나타내는 출력노드가 100개인 CNN이 있다. 학습 되기 전의 CNN 내부 파라메터는 임의로 초기화되어 있다.

CNN은 하나의 학습 이미지에 대해 100개의 위치와 각 위치에 대한 100개의 conf를 출력하도록 구성된다. 이때 위치는 $p_i$, conf는 $s_i$로 표시한다. 따라서, 각 위치와 conf는 인덱스 i로 연결되어 있다.


학습 샘플은 내부에 복수 개의 물체를 가지고 있다. 따라서 ground-truth는 cnn이 예측한 위치와 일치하는 것도 있고, 그렇지 않은 것도 있을 것이다.

이때 위치가 일치하는 것 만을 학습에 반영시키기를 원한다. 즉 gt와 겹치지 않은 prediction은 학습에 기여하지 못한다.

따라서 예측된 위치가 gt 위치와 일치하는 것에 해당하는 i를 선정한다. 현 단계에서 물체 부류정보는 전혀 반영되어 있지 않다.


i=1~100이기 때문에 gt와 겹치는 위치를 가진 i만을 선정한다$^{(1)}$. 예를 들면 i={2,50,72}라고 하면 100개의 prediction 중에서 3개만 true와 일치하는 경우이다.



loss 함수의 정의는 box위치의 예측 값인 $p_i$가 true의 위치와 일치할 수록 좋고, conf $s_i$는 클 수록 좋게 구성한다.

따라서 loss함수를 수학적으로 모델링하고 이 loss함수를 minimize하도록 CNN의 파라메터들은 update된다.

학습동안 CNN의 파라메터들을 적절히 조정되서 $p_i$가 true와 가능하면 일치되도록, $s_i$는 가능하면 크지도록 갱신이 발생하게 된다.



상기한 네트웍 구조와 최적화 방법의 장점은 각 학습 sample이 입력되었을 때, 출력 값 중 true 라벨과 겹치는 prediction은 몇 개 되지 않기 때문에 갱신 연산이 빠르다는 것이다.

학습이 끝나면 새로운 이미지에 대한 출력은 prediction box위치가 가능하면 true와 잘 겹치고 conf도 큰 출력을 주게 된다.




분류

테스트할 이미지에 대해 다수의 내부 crop을 추출한다. 각 추출 crop를 CNN에 넣으면 100 개의 box와 conf 값이 출력된다.

또한 이 crop은 class를 prediction하는 부류 분류기에도 입력한다. 분류기는 crop이 무슨 물체를 가졌는지 출력을 주게된다. 따라서 각 crop은 부류에 대한 확률 값을 가지게 된다.


crop에 대한 데이터를 모으면, 각 crop에서 나온 100개 box의 위치 정보, 각 box의 conf 값, 또 각 crop은 부류에 속하는 확률 값을 가진다.


이때 특정 부류에 대한 box들을 모으고 각 box의 conf 값을 이용하여 nonmax supp하면 위치 detection이 가능하다.














각주
(1) Jaccard similarity.  두 영역의 교집합과 합집합의 비가 threshold(예를 들면 0.5) 이상인지를 평가.  $s_j(a,b)= {{a \cap b} \over {a \cup b}}$



Reference
[1] Scalable object detection using deep neural networks
[2] CVPR'2014 Tutorials




2015년 5월 13일 수요일

Vehicle place recognition

작성 중...

기 학습된 큰 규모의 CNN을 가져와서 이미 방문한 장소의 인식에 사용한다.  Overfeat를 사용하는데, overfeat는 대용량의 big data를 학습한 것이라서, 여러 사물에 대한 discriminative 능력이 뛰어날 것이라는 가정을 적용한 것이 아닐까 싶다.  이미 학습이 잘 되어 있을테니 새로운 입력 영상에 대한 특징의 분별 능력이 우수할 것이라는 가정을 사용한다.

Overfeat은 ImageNet 2012의 db를 이용하여 학습된 것인데 120만개의 이미지로 1000개의 부류를 학습하였다.

장소 인식 테스트는 Eynsham db의 9,575프레임(차량이 약 70 km을 주행하면서 얻은 데이터이다)에 대해 수행하며, 주행은 두 번으로 나누어 진행한다. 첫번째는 모델 db를 추출하는 과정, 두번째는 테스트 db를 추출해서 기 구축된 모델 db와 비교하여 장소를 인식하는 과정이다.

먼저 overfeat의 구조를 살펴 본다.
overfeat는 input층을 제외하고는 모두 21개의 층을 가진다:

Input,
conv-maxPooling-ReLU 층 2개, (6 layers)
conv-zeropadding$^{(1)}$-ReLU$^{(2)}$ 2개, (6 layers)
conv-zeropadding-ReLU-maxPooling 1개, (4 layers)
FC-ReLU 2개, (4 layers)
FC 1개(output), (1 layers)



그림 1. Overfeat의 구조. 색으로 각 layer를 표시.



장소 인식 방법은 모델 특징과 테스트 특징의 Euclidean 거리를 사용하며, overfeat에 도로 영상을 입력시켜 나온 특징(중간 층의 특징을 포함)을 상호 비교하는 것으로 인식을 수행 한다.


overfeat의 중간 층의 특징은 21개 층에서 모두 다 정의될 수 있지만 실험 결과를 보면 중간 층인 9,10 layer의 특징이 좋은 성능을 낸다.



먼저 이미지는 흑백영상으로 만들고 histogram 정규화를 해서 밝기의 variation을 줄여서 사용한다. 크기는 256x256조정해서 overfeat에 입력한다.
(overfeat 논문을 참고하면, 231x231보다 더 큰 이미지는 처리할 수 있다. 256x256으로 만들어 사용한다)


각각의 layer output을 $L_k(I),k=1,...,21$이라 하면, 비교를 위한 confusion matrix$^{(3)}$를 다음과 같이 구성한다:

$M_k(i,j)=d(L_k(I_i),L_k(I_j))$, $i=1,...,R, j=1,...,T$

여기서 $R$은 training image의 수이고, $T$는 test image의 수이다.  $M_k(i,j)$는 $i$번째 training image와 $j$번째 test image사이의 Euclidean 거리를 나타낸다.


매칭이 잘 되는 위치를 찾기 위해 거리 값이 가장 작은 특징 벡터를 가진 요소를 찾는다:

$M_k(j)=arg min M_k(i,j)$ for all $i$, and $j=1,...,T$


매칭 후보를 찾는 방법은 두 가지를 이용하는데, 첫번째는 spatial continuity조건이다.
연속된 두 테스트이미지가 주는 특징 거리의 차이가 작을 것이라는 가정이다:

$if \left\vert M_k(u-1)-M_k(u) \right\vert \le \epsilon$, $\forall u \in [j-d,j]$
여기서 $j=d,...,T$

$j$는 현재 테스트 이미지이고 $d$는 이전 시간으로 얼마 만큼 먼가를 나타낸다.

예를 들어 $d$=5라면, 현재 프레임 $j$에서 이전 5프레임 동안 두 인접 $M$값의 차이가 모두 작아야한다. 즉 traing-test 특징 값의 차이가 일정시간 동안 계속 작다면 상호 매칭으로 본다.

두번째는 매칭점 사이의 기울기 평가인데 간단하므로 논문을 참고한다.




References
[0] Convolutional neural network based place recognition, Z.Chen, M.Milford etc., 2014. Queensland Univ. of Tech.
[1] zero-padding, 이미지에 mask로 convolution연산을 하면 경계를 일부분 먹으면서 결과영상의 크기가 줄어든다. 이것을 원 이미지와 동일한 크기를 만들고 경계의 값은 0으로 채워준다.  또 다르게는 미리 경계를 0으로 두른 후에 마스크 연산을 하면 처리후 경계 부에 검은 띠 형성을 막을 수 있다.
[2] Rectifier activation function으로 $f(x)=max(0,x)$로 정의된다.
[3] Confusion matrix에서 가로(행)은 실제 부류를 나타낸다. 열은 예측된 부류를 가리킨다. 아래 표의 1행에서 실제 Cat를 Cat로 예측한 샘플은 5개, Dog로 오분류한 것은 3개, Rabbit로 분류한 것은 0이다.

(from wikipedia)










2015년 3월 8일 일요일

DNN 적용 예

Training method
mini-batch(size): 256
momentum: 0.9
weight decay: 5*10^-4
dropout ratio: 0.5
initial learning rate: 10^-2, decreased by a factor of 10(when validation set accuracy stopped improving).


Initialization of network weights
-shallow network(hidden layer 수가 작아 비교적 학습하기 용이한 구조)로 먼저 시작.
-더 깊은(복잡한) network 구조를 학습할 때 이미 학습된 shallow 구조의 weight 값을 사용.
-예를 들면, 입력 layer에 바로 붙어 있는 초기 4개의 layer와 출력단에 붙어 있는 FC(full connection) 3개는 shallow weight로 초기화하고, 중간의 나머지 layer만 random하게 초기화
-random 초기화에도 uniform이 아니라 N(0,10^-2)의 정규분포에서 weight를 샘플링


Training image의 준비
-학습에 사용할 이미지의 크기는 224x224의 고정 크기를 사용하는데 이것은 스케일 변환된 원 이미지에서 random하게 잘라낸(cropped) 샘플이다.
-학습 샘플 수를 증가시키기 위해 잘라낸 샘플을 다시 수평 flip시키고 random color shift(Krizhevsky 2012)시켜 더 많은 샘플을 만들어 낸다.


Training image size
-원 이미지를 등방성(가로, 세로방향으로 동일한 비로) 스케일링하고 여기서 학습 샘플을 추출(crop)한다. 인자 s를 scaling된 이미지의 가로, 세로 크기 중에서 더 작은 값이라 하면(즉, s=min(w,h)이다) s는 224보다는 더 커야 한다.
-s가 크다면(s>>224라면) crop image는 스케일 이미지 내의 작은 부분이 되고, 작은 물체나 물체의 부분을 표현하게 된다.


s값을 설정하는 2가지 방법
(1) 고정 크기로 s값을 사용(single-scale training): 실험에서 두개의 고정 값을 사용하였음(s=256, s=384). 먼저 s=256를 사용하여 net를 학습. s=384에서 학습 속도를 올리기 위해 s=256학습 초기치를 사용하고 더 작은 학습률(10^-3) 사용
(2) s값을 독립적으로 rescaling(multi-scale training): [s_min, s_max] 범위 사이에서 s를 랜덤하게 선택하고 이 값으로 이미지를 rescaling함. (s_min=256, s_max=512사용). 이렇게 하면 이미지 내의 물체는 각기 다른 크기가 될 수 있으므로 더 좋음.  scaling jittering(small fast variation)에 의한 training set augmentation과 유사함.
-학습 속도를 높이기 위해 먼저 single-scale model(s=384)로 학습하고 multi-scale model를 적용.





Reference
K. Simonyan and A. Zisserman, Very deep convolutional networks for large-scale image recognition, ICLR 2015.




 

2015년 2월 2일 월요일

Theano 튜토리얼

[출처] http://newsight.tistory.com/161


i파이썬 서버를 mlc서버에 있음
컨트롤 엔터가 실행
쉬프트 엔터가 다른 쉘


심볼릭 변수는, 미지수 변수 x,y등을 할당하는 것

theano.function 은 CUDA C코드를 컴파일해내는 과정이고, 여기서 최적화가 일어난다.
또한 병렬화도 자동으로 처리해준다.

theano.function(inputs, outputs)
inputs는 변수의 리스트를 넣어야한다.
outputs는 인풋들로부터 계산가능한 식이 들어옴.
outputs=f(inputs)


심볼릭 변수들에대한 연산은 그래프로써 표현됨.
심볼릭 algebra들로만 연산을 하다가,
실제로 숫자를 넣어서 계산할 때 theano.function 을 이용해야함.
(함수형 언어의 철학을 따르는 방식)
심파이, 메스메티카 등도 마찬가지의 심볼릭 알제브라를 사용함.



theano.function 은 이 그래프를 CUDA 코드로 컴파일 해주는 것임


CPU/GPU 변환은 theano코드를 실행시키기 전에 해주어야함.
그래야 theano.function 에서 컴파일을 다르게 하겠네.


print(theano.config.floatX) : default 타입 확인
#심볼릭 변수의 타입
T.scalar() : 타입을 지정하지 않는 default 타입인 float32으로 되는 듯
T.iscalar() : int 32 타입을 사용하겠다
T.lscalar() : int 64
T.dscalar() : float64


#심볼릭 변수의 차원
T.scalar() : 0차원 점
T.vector() : 1차원 직선
T.matrix() : 2차원 평면
T.tensor3() : 3차원 큐브
T.tensor4() : 4차원


x=T.matrix()
y=T.matrix()
z=T.dot(x,y)
ftnSum_mat = theano.function([x,y],z)
print(ftnSum_mat(3,4))
----- 3,4는 matrix가 아니라서 에러가 남

x=T.matrix()
y=T.matrix()
z=T.dot(x,y)
ftnSum_mat = theano.function([x,y],z)

a = np.random.random((3,3))
b = np.random.random((3,3))


print(a,b,ftnSum_mat(a,b))


---------
x=T.matrix()
y=T.matrix()
z=T.dot(x,y)
ftnSum_mat = theano.function([x,y],z)

a = np.random.random((3,3))
b = np.random.random((3,3))

print(a,b,ftnSum_mat(a,b))
#이렇게 해도 변수 타입이 넘파이는 float64인데, 씨아노는 float32라서 에러가남
따라서 아래와같이 asarray함수로 float32타입으로 바꿔주어야함.
------
x=T.matrix()
y=T.matrix()
z=T.dot(x,y)
ftnSum_mat = theano.function([x,y],z)

a = np.asarray(np.random.random((3,3)),dtype=theano.config.floatX)
b = np.asarray(np.random.random((3,3)),dtype=theano.config.floatX)

print(a,b,ftnSum_mat(a,b))

-------
결론 -> 항상 float32를 쓰도록 주의할것





python 변수는 실제로 값을 가진 변수임
symbolic 변수는 실제값이 없는 미지수 변수임
shared 변수는 심볼릭 변수인데, 값을 가지고 있는 녀석임.

GPU의 셰어드 메모리에 올라가는 변수로, theano변수가 접근 가능한
값을 가지고 있음.

--
a = np.array([[1,2],[3,4]], dtype = theano.config.floatX)
x = theano.shared(a)
#a 매트릭스가 gpu 메모리에 올라가서, theano 변수가 접근 가능함
----만약 gpu메모리가 모자라면, 여기서 올리다가 에러가 남

print(x.get_value())
x.set_value(x.get_value()+1)
print(x.get_value())


# set 은 cpu -> gpu로 메모리를 올리는 것
# get 은 gpu -> cpu로 메모리를 가져오는 것
따라서 get과 set을 최대한 안써야함.
이건 거의 디버깅 용이라고 할 수 있음.
그리고 안쓰고 어차피 function에서 한방에 계산하기때문에 필요없음
---

a = np.array([[1,2],[3,4]], dtype = theano.config.floatX)
x = theano.shared(a)
y = x**2
ftnShared = theano.function([],y)
print(ftnShared())

#
여기서는 input으로 shared변수를 전달하면 안됨.
input에는 심볼릭 변수만 전달이 가능함.
shared 변수는 함수의 인자가아님.

---


T.nnet.conv.conv2d()
함수 등에 컨벌루션 레이어가 정의되어있음.


-
x = T.scalar()
y = x**2
diff = theano.function([x],T.grad(y,[x]))
print(diff(3))
결과 : [array(6.0, dtype=float32)]
#
array가 붙은 이유는 T.grad의 반환 값이 array라서 그럼.
왜냐하면 x 하나가아니라 여러개의 변수들의 리스트로 편미분을 해서

T.grad(y,[x])
즉, y 함수를 x로 편미분하는 것임,

--
x = T.scalar()
y = x**2
diff = theano.function([x],T.grad(y,[x])[0])
print(diff(3))
결과: 6.0
[0]을 해서, 첫번째 변수로 미분한 값만 array에서 가져옴
--

x = T.scalar()
w = theano.shared(np.array(3,dtype=theano.config.floatX),borrow=True)
obj = (1 - x*w)**2
learn_w = (w, w-0.1*T.grad(obj,w))
learn = theano.function([x],obj,updates=[learn_w])
print(learn(2))

#shared memory는 보통 아주 큰 memory를 GPU에서 사용하기 위함이고, cpu에서 gpu로 shallow copy가 유용하다. borrow=True옵션은 shallow copy이다. False옵션은 deep copy.
#updates는 list of tuples로 준다: [(before, after), (before, after), ...]이고 독립 변수가 여러 개인 경우, target의 독립 변수 당 derivative를 설정할 수 있다.  표기에서 []: list(수정가능), (): tuple(수정불가) 이다.  

updates 는
learn_w = (w, w-0.1*T.grad(obj,w))
이런식으로 정의를 해주어야함.
즉 w를 매 스탭마다 바꾸어갈 식을 정의함

function의 순서가 input 에서 output을 계산하고, 그다음 update 식을 수행함

while(){
learn(2)를 해주어야 이제 계속 업데이트 하는 것임
}
---

x = T.scalar()
w = theano.shared(np.array(3,dtype=theano.config.floatX),borrow=True)
obj = (1 - x*w)**2
learn_w = (w, w-0.1*T.grad(obj,w))
learn = theano.function([x],obj,updates=[learn_w])
print(learn(2),w.get_value())
print(learn(2),w.get_value())
print(learn(2),w.get_value())
print(learn(2),w.get_value())

----
theano는 update가 뉴럴넷을 전제로 깔고 정의됨.
굳이 이걸 안 쓰고, 업데이트를 function 으로 해줘도됨



--

import theano
import theano.tensor as T

class opt_problem:
    def __init__(self):
        # optimization variables
        self.x = theano.shared(numpy.array(100.,dtype=theano.config.floatX), borrow=True)
        self.y = theano.shared(numpy.array(100.,dtype=theano.config.floatX), borrow=True)
        self.pos = [self.x, self.y]
     
        # hyperparameters
        self.lr = theano.shared(np.array(0.05, dtype=theano.config.floatX), borrow=True) # learning rate
     
        # optimization objective
        self.ftn_eqn = (self.x ** 2) + 10*(self.y ** 2)
        self.grad = T.grad(self.ftn_eqn, self.pos)
     
        # evaluating current value
        self.ftn = theano.function([], self.ftn_eqn)
     
    def plot(self, scope=20.):
        # visualizing code
        x = np.arange(-scope, scope, 0.05)
        y = np.arange(-scope, scope, 0.05)
        X, Y = np.meshgrid(x, y)
        X = np.asarray(X, dtype=theano.config.floatX)
        Y = np.asarray(Y, dtype=theano.config.floatX)
        Z = (X ** 2) + 10*(Y ** 2)
        plt.figure()
        C = plt.contour(X,Y,Z)
     
    def build_gd(self):
        self.updates = []      
        for posi, grad in zip(self.pos, self.grad):
            self.updates.append((posi, posi - self.lr*grad))
     
# zip은 pos도 리스트고, grad도 리스트인데 각각을 지퍼로 연결해서 for문을 돌림
        # 독립 변수가 2개 이므로 각 변수에 대한 tuple의 list들 만듬

        # gradient descent function
        self.gd = theano.function([], self.ftn_eqn,
                                  updates=self.updates)
     
problem = opt_problem()
problem.plot()
problem.build_gd()

Xs = []
Ys = []
Xs.append(problem.x.get_value())  # gpu로 내부적으로 shared된 x변수는 값이 계속 바뀜
Ys.append(problem.y.get_value())
for epoch in xrange(20):
    if(epoch%5)==1:
        problem.lr.set_value(problem.lr.get_value()/2)
 
    f_val = problem.gd()
    Xs.append(problem.x.get_value())
    Ys.append(problem.y.get_value())
    plt.plot(Xs, Ys, '-ro')
    print(f_val)


    ----
    numpy에서 아이겐벡터, 아이겐 벨류 계산 가능


    -
 
   matplotlib 는 매틀랩하고 거의 똑같은 인터페이스로 구성되어있음
-
뉴럴넷 짤때, 백프로퍼게이션 구현안하고 짤 수 있음.



--
x = T.scalar()
w = theano.shared(np.array(3,dtype=theano.config.floatX),borrow=True)
obj = (1 - x*w)**2

#learn_w = (w, w-0.1*T.grad(obj,w))

learn = theano.function([x],obj)

w = w-0.1*T.grad(obj,w)
m_update = theano.function([],w)

print(learn(2), m_update())
print(learn(2), m_update())
print(learn(2), m_update())
print(learn(2), m_update())

#
update따로구현해보기

2015년 1월 6일 화요일

Energy Based Model

$E(x)$는 $x$의 함수이고 $x$에 따라 크기가 결정되는 값이다.  $x$ 값을 잘 조절하면 $E$의 크기를 줄일 수 있다. , $E(x)$는 $x$의 구성(또는 배치, configuration)에 따라 크기가 결정되며$x$라는 상태에 대해 값을 부여하는 하나의 방법이다. 에너지의 크기로 이 값을 본다면, 이러한 표현방식을 EBM(Energy Based Model)이라 부른다


에너지 값을 확률 값(pdf)으로 표현하면

$p(x)=e^{-E(x)}/Z$,  $Z=\sum_x{e^{-E(x)} }$


가 되고 EBPM(Energy Based Probabilistic Model)이 된다.  $E$가 0이될 때 확률 값이 최대이다.

만일 $x$가 입력 벡터(, data)이고 $E$가 어떤 $x$와 함께 결합된 파라메터 $\theta$의 조합으로 구성(즉, $E(x)=E(x; \theta)$)되었다면 다양한 여러 입력 $x$에 대해 $E$가 최소화되도록 $\theta$를 조절할 수 있다이는 data에 따라 파라메터(모델$\theta$를 결정하는 학습(learning) 과정이 된다.


위의 확률분포를 볼츠만분포(Boltzmann Distribution)라고 부르고 물리적으로는 평형계에서 에너지가 분배될 때 가장 가능성 높은 분포(열역학적으로 입자운동에 의한 점유 분포에서 최빈 분포. 어떤 온도에서 일정 공간 내의 입자수를 볼 때 가장 흔한 입자 수의 분포)를 의미한다.  에너지가 높아지면 확률 값이 작아진다.



Reference
[1] 볼츠만분포  


2015년 1월 2일 금요일

MV References

Realtime On-Road Vehicle detection with optical flows and Haar-like feature detector
adept mobilerobots: Aqua2, underwater mini unmannedrobot company

Thrun research
Robust Vehicle Localization in Urban Environments Using Probabilistic Maps, 2010. ICRA
Map-Based Precision Vehicle Localization in Urban Environments
Towards Fully Autonomous Driving: Systems and Algorithms

Template matching References

Performance Evaluation of full search equivalent Pattern Matching Algorithm
Efficient Rotation Invariant object detection using Boosted random ferns
Grayscale template-matching invariant to rotation scale, translation, brightness and contrast