SVM, LIBSVM에 대해서
안녕하세요
SVM으로 문자인식을 해보려고 합니다.
라이브러리는 LIBSVM을 다운받아서 Java 버젼을 사용하고 있는데
SVM에 대해서 아무리 찾아봐도 모르는 부분이 있어서 남기게 되었습니다..
svm은 학습과 예측 2가지가 있다고 알고 있는데, 학습부분에서는 svm_problem을 만들어서 svm_model을 리턴받으면 svm_model과 테스트 데이터 svm_node를 svm_predict 함수에 넣게 되면
예측된 class가 나온다고 합니다.
여기서 svm_parameter를 설정해야하는데 c-svm, nu-svm, 같은 svm_type과 kernel_type 등 을 어떻게 설정해야 될 지 모르겠습니다.
소스는 아래와 같습니다.
svm_problem prob = new svm_problem();
ArrayList pointsList = iv.getPointsList();
svm_node[][] nodes = new svm_node[2][pointsList.size()];
for (int i = 0; i < pointsList.size(); i++) {
float point = pointsList.get(i);
nodes[0][i] = new svm_node();
nodes[0][i].index = i;
nodes[0][i].value = point;
}
for (int i = 0; i < pointsList.size(); i++) {
float point = pointsList.get(i);
nodes[1][i] = new svm_node();
nodes[1][i].index = i;
nodes[1][i].value = point+5;
}
prob.l = 2;
prob.y = new double[] { 1, 2 };
prob.x = nodes;
svm_parameter param = new svm_parameter();
libsvm.svm.svm_check_parameter(prob, param);
svm_model model = libsvm.svm.svm_train(prob, param);
System.out.println(libsvm.svm.svm_predict(model, nodes[1]));
svm에 대한 이해할 수 있는 자료가 많이 없고 svm_parameter에 대한 자료가 많이 없네요..아니면 제가 이해를 못하고 있는 것 같습니다.
value는 x값과 y값을 for문 돌면서 순차적으로 넣습니다.
고수님들 답변 부탁드립니다..
SVM
아쉽게도.. SVM 국내 자료는 찾기 힘든 것 같습니다.
질문자께서 올린신 본문 내용만으로는 svm_parameter의 세부 항목들을 다 알긴 힘들군요.
c-svm, nu-svm, svm_type과 kernel_type 에 대해서 추측을 더해서 설명드리자면,
kernel 이라는 건 svm_model 을 만들 때에서 train data로 부터 어떤 예측 함수(predict function) 모양을 기본으로 하는지 세팅하는 거구요.
(http://en.wikipedia.org/wiki/Kernel_trick)
제가 대학원 수업으로 Polynomial 이랑 Gaussian Kernel을 대표적으로 배웠는데,
속도가 문제없다면 Gaussian Kernel이 좀 더 나은 결과를
속도가 빨라야한다면 Polynomial Kernel이 좋습니다.
그런데 제 경험으로 Gaussian Kernel이 엄청 느리고 결과는 콩알 만큼 좋아졌던 기억이... 근데 이건 데이터와 다른 파라미터 값에 따라 다르니까요.. ㅎㅎ;;
svm_type 은 아마 SVM 변형 중에서 하나를 고르는게 아닐까요.
SVM 에서 regression, structed.. 라고 접두사가 붙는 변형들이 꽤 됩니다.
어떤 종류를 지원하는지는 lib 매뉴얼을 읽어보셔야 할 듯 싶습니다.
c-svm, nu-svm은 저도 뭘 의미하는지 모르겠습니다. ㅎㅎ
그래서 검색해봤더니 혹시 질문자께서 LIB를 아래 사이트에서 받으셨나요?
http://www.statsoft.com/textbook/support-vector-machines/
c-, nu- 는 error function 에 대한 표기인 것 같습니다.
뭐의 약자인지는 알 수가 없군요 ;;
자세한 설명은 제가 적는 것보다 영문 위키피디아를 참고하시구요.
SVM을 이해하기 위한(그리고 여러가지 테스트 및 가지고 놀기 좋은) 제가 추천 드리는 방법은 MatLAB을 사용하시는 겁니다.
http://www.mathworks.co.kr/help/toolbox/bioinfo/ref/svmtrain.html
스크립트 작성하듯이 바로바로 커맨드 창에서 작성하고 그래프 찍어보시면 감이 오실 것 같습니다 :)
SVM 이 black-box 인건 사실이지만 어느정도
SVM 이 black-box 인건 사실이지만 어느정도 기초적인 공부는 하셔야 쓸 수 있으실 겁니다.
SVM 은 기본적으로 binary classifier 입니다. 즉 SVM 을 하나 만들면 문자 인식이라면 a 와 b 만 구분할 수 있습니다.
a 에 해당하는 인풋 이미지들을 이미지 하나당 점으로 표현해 보고
b 에 해당하는 인풋 이미지들도 이미지 하나당 점으로 표현해 보고 그래프를 찍어보니
a에 해당하는 애들은 다 왼쪽에 몰려있고
b에 해당하는 애들은 다 오른쪽에 몰려있다 합시다.
그러면 SVM 이 하는 일은 기본적으로 둘 사이의 정 가운데다가 "줄"을 잘 긋는 것입니다.
나중엔 이 줄만 알면 새로운 포인트가 줄 왼쪽에 있는지 오른쪽이 있는지 보고 a 인지 b인지 알 수 있겠죠.
그런데 만약에 b 중의 몇개가 오른쪽에 있지 않고 왼쪽에 a 사이에 섞여 있다면?
이런 경우는 데이터 노이즈 때문에 당연히 종종 발생하게 됩니다.
이런 "몇개" 의 에러는 용인을 하고 줄을 그어야겠죠.
이걸 용인하는 애들을 soft-margin classifier 라고 합니다. 일반적으로 SVM 이라 하면 이것들을 의미합니다.
C-SVM 은 일반적으로 SVM 이라고 말하는 형태인데
C 가 penalty 를 의미합니다. C 를 크게 잡으면 (아니면 작게 잡으면 -- 식을 어떻게 쓰냐에 따라 다릅니다) 저런 "섞인 b"들에 페널티를 크게 줍니다. 즉 줄을 복잡하게 그리는 한이 있더라도 저런 애들을 최대한 없게 만드려고 합니다. 작게 잡으면 반대가 되죠. 저런 녀석들을 좀 더 용인하고 줄을 "부드럽게" 그립니다.
nu-SVM 은 같은 것을 식만 다르게 쓴 형태인데
nu 는 0 에서 1 사이 값으로 저런 녀석들을 얼마나 용인할지 fraction 의 상한을 지정하는 겁니다. 0.5 라고 치면 50% 가 저런 케이스여도 괜찮다고 설정하는 셈이죠.
그러면 kernel 이 무엇이냐 하면
SVM 은 직선밖에 못그립니다.
그럼 a 와 b 가 직선으로 나이스하게 나뉘지 않는다면?
예를 들면 팩맨이 공을 먹는 모양을 상상하면
분명 줄을 그을 수 있죠 공과 팩맨 입 사이에. 그런데 직선으로는 못그립니다.
하지만 만약에 그 데이터를 "변형" 해서 둘 사이를 떨어뜨려 놓을 수 있다면 좋겠죠. 떨어뜨려 놓은 다음에 직선을 그리면 되니까요.
그러면 그 변형된 공간에서의 "직선" 은 원래 공간에서 구불구불한 선이겠죠.
kernel 은 이 "떨어뜨리는 방법" 다시 말해서 비슷한 것끼리 "뭉치게" 하는 방법을 지정해주는 것입니다.
(정확한 설명이 아닌데 이런 용도로 쓰인다고 생각하시면 됩니다. 사실 상당히 견고한 이론적 배경이 있습니다. http://en.wikipedia.org/wiki/Reproducing_kernel_Hilbert_space )
kernel 중 가장 흔하게 쓰이는 것은 RBF (radial basis function) 이고 모르겠으면 이걸 쓰면 됩니다.
이것은 "비슷한 것끼리 더 뭉치게" 라고 생각하시면 됩니다.
즉 C-SVM 과 RBF kernel 로 시작하시면 됩니다.
이제 parameter 를 설정해야 되는데, 안타깝게도 뾰족한 수가 없습니다. 즉 C 값과 kernel width 등을 설정해야 되는데
이건 별 방법이 없습니다. 그냥 반복해보면서 가장 좋은 결과가 나오는 방법을 고르면 됩니다.
이제 남은 문제는 SVM 이 binary classifier 이기 때문에, 즉 a 와 b 만 구분할 수 있는데
알파벳 26 글자를 어떻게 구분하느냐는 거죠.
크게 두가지 방법이 있는데
a 와 a 아닌 것 SVM 하나, b 와 b 아닌 것 SVM 하나 이렇게 26 개를 만들거나
a vs b, a vs c, ..., b vs c, ... 이렇게 모든 짝에 대해 26 choose 2 개를 만드는 방법이 있습니다.
그런데 libsvm 같은 툴은 아마 둘중 하나를 자동으로 해 줄 것 같군요.
댓글 달기