본문 바로가기

MOBILE/ios

[iOS] coreML 사용하여 multi class classification 모델 생성 및 프로젝트 반입하기

프로젝트를 진행하던 중 multi class classification을 해야할 일이 생겼다.

프로젝트가 아직 진행 중이라 다 말할 수는 없지만 사용자의 선택지에 따라 선택에 맞는 결과를 분류하여 class 중 하나를 보여줘야 하는 것이 목표다.

기계학습에서 배운 지식을 활용하면 multi class classification에는 여러 가지 모델을 사용할 수 있다. logistic regression, MLP, SVM 등등이 있다. 그런데 apple에서는 coreML이라는 것을 제공하는데 이 안에 tabular 데이터를 classification 해주는 라이브러리가 있다. 사실 공개된 swift ML 라이브러리도 많고, 직접 구현하는 것도 재미가 있지만 이미 있는 걸 최대한 활용하는 것이 개발자의 덕목(?)이기 때문에 coreML을 통해서 classification 모델을 생성하고 이를 프로젝트에 반입해보기로 했다.

 

전형적인 머신 러닝 모델을 만드는 순서로 진행했다.

1. 문제 정의

2. 데이터셋 준비

3. 모델 학습

4. 평가

5. ios 프로젝트에 반입

6. 오류 해결

 

1. 문제 정의

입력 특징 벡터

a b c d e

출력 벡터 (class 1인 경우)

1 0 0 0 0 0

현재 입력 특징 벡터의 dimension은 5차원이다. output 벡터는 Multi class이기 때문에 One-hot-coding으로 표현해야 한다. 현재 프로젝트에서 결과 class의 종류는 6가지 이므로 output vector의 dimension도 6이다. 데이터 형태를 matplotlib이나 Pandas로 확인하지도 않았지만 당근 선형 분리 안될 것 같다. 원래 mlp나 svm을 사용하면 선형 분리 되는 특징 공간으로 변환시켜서 풀어야 하는데 이 변환 과정을 coreML에서 해주는지는 잘 모르겠다... 더 알아봐야할듯 (애초에 coreML classification은 무슨 모델을 쓰는거지)

 

 

2. 데이터 셋 준비

 현재 입력 벡터의 값은 range가 좁은 편이다. 게다가 정수형에 한정되어 있다. 심지어 a+b+c+d+e = 13 이라는 subject도 있다.

따라서 나올 수 있는 경우의 수가 한정적이다. 이에 대해서 유효한 데이터를 모으면 다음과 같이 500개 정도가 생긴다.

 학습시키기에는 데이터 자체가 엄청 작은 양이다. 이걸 다 training set으로 쓰는게 아니라 validation set과 test set도 모두 여기서 나눠 가져야 하기 때문이다... 그래도 현재 게임에서 챕터 업데이트를 하지 않는 한 가능한 모든 경우의 수이기 때문에 일반화 성능은 나쁘지 않을 것이다.

 

데이터 가공은 수작업이 최고다 근데 귀찮아

 

사실 데이터 set 자체가 규모가 크지 않고 range도 한정적이기 때문에 굳이 머신 러닝을 써서 분류할 필요는 없지만 이를 쓰는 이유는 바로 사용자 업데이트를 위해서이다. 지금 label은 입력 벡터에 따른 class를 임의로 정해둔 것이고 실제 사람들의 평가와는 다를 수 있다. 따라서 나중에 게임이 인기가 많아진다면! class 분류 결과에 대한 사용자의 피드백을 받아 이를 업데이트 할 때 그 경향성을 파악하기 위해서 ML을 사용하는 것이다. 물론 인기가 많아지고 업데이트를 꾸준히 할 수 있다면 말이지..

아무튼 500개 데이터 중에서 350개는 training set으로 사용하고 50개는 validation set, 남은 100개는 test set으로 사용할 것이다.

 

3. 모델 학습

coreML 프로젝트를 생성한다. 이때 template을 tabular classification으로 선택한다.

 

 

tabular 데이터는 정형 데이터이다. 그냥 표 형태의 데이터라는 뜻이다. CSV 파일을 준비하면 된다.

 

template을 선택하여 프로젝트를 생성하면 다음과 같다.

training data 영역에 미리 준비해둔 CSV 데이터셋을 넣어주면 알아서 feature label을 파악해준다.

 

 

심지어 validation set도 training set의 일부로 떼와서 써준다... 진심 감사

 

multi class classification model 종류도 선택 가능하다.

 

 

기본적으로 선형 분리 안되는 문제는 은닉 노드 여러개 둬서 푸는 것 같다. SVM도 커널 매핑을 알아서 해주는 듯하다... 내부 동작을 모르니까 좀 답답하긴 한데 결과가 잘 나오니까 상관없을 듯.

일단 나는 Automatic으로 선택했다. 알아서 model selection을 해주는 듯 하다. (model 다 비교해서 제일 성능이 높은 걸 선택하는 듯하다.)

 

다음에 feature 벡터는 어떤걸로 할지 선택하면 된다.

 

 

내가 준비한 데이터셋에서는 모든 column이 유효한 feature였기 때문에 다 선택했다.

사실 이렇게 feature를 선택할 수 있으면 데이터 이상치 sample만 걸러준다면 가공을 직접할 필요가 없을듯하다...

Open data 가져와서 쓸 때 편할듯

 

그리고 Xcode build 버튼처럼 생긴 Train 버튼을 눌러서 학습을 시켜준다.

epoch은 기본이 10으로 설정된듯 하다. 아마 조정 가능할듯.

모델 선택을 자동 사냥 돌려놨더니 트리 앙상블로 선택된듯 하다. (boosted tree)

 

 

epoch이 10밖에 안되는데도 생각보다 evaluation 결과가 괜찮아서 그냥 멈췄다.

 

Evalutaion 탭에서는 학습 결과를 확인할 수 있다. 

 

 

분류되는 클래스의 종류(Count)와 정밀도(Precision)를 볼 수 있다. 이때 재현율(Recall)은 실제로 true인 데이터 중에서 true로 예측한 비율이다. 재현율은 accuracy가 통계적으로 신뢰할 수 없을 때 사용할 수 있는 수치이다. 예를 들어서 비가 내린다 vs 내리지 않는다 를 예측한다고 할 때 평균적으로는 비가 내리지 않는 날의 비율이 더 높다. 이 경우 항상 비가 내리지 않는다고 예측해버리면 accuracy는 높지만 이 예측 모델은 걍 쓰레기 그 자체이다... 이럴 때 Recall 수치로 모델을 평가하면 0이 되기 때문에 쓸모 없음을 확인할 수 있다. F1 score는 Precision과 Recall의 조화 평균이다.

 

 

4. 평가

위에 나온 결과를 봐도 정확도가 대부분 99%~100% 정도이다.

Preview를 써서 실제로 데이터를 넣었을 때 어떻게 결과가 생성되는지 볼 수 있다.

부서 배치가 1이 되는 데이터를 넣을 경우 다음과 같이 86%의 confidence를 가지고 class1로 분류된다.

 

 

이렇게 학습된 mlmodel 파일을 프로젝트에 반입해보자

 

 

5. ios 프로젝트에 반입

.mlmodel 파일을 그냥 프로젝트에 끌어서 추가하면 다음과 같이 내부 클래스를 자동으로 생성해준다.

 

 

 

이 클래스를 가져와서 코드에서 사용해야 한다.

기본 코드는 다음과 같다.

클래스 명은 mlmodel 파일명과 동일하게 생성된다. 이를 불러오면 되는데 init 생성자가 deprecated되어서 configuration 파라미터에 MLModelConfiguration 클래스를 넣어줘서 초기화를 시켜준다.

 

 

그 다음 model의 prediction 함수를 호출해서 사용하는데 이때의 파라미터 label도 자동으로 데이터셋의 feature 이름으로 설정된다.

이제 분류가 필요한 곳에서 이 api를 호출해서 쓰면 된다!

 

 

6. 오류 해결하기

데이터 셋 정리하기

 원래 파이썬으로 classification 모델 작성하던 것처럼 one hot coding으로 target class를 표현했는데 사실 이게 아니었다.

coreML에서는 target class를 그냥 해당 클래스로 표기해주면 된다. 현재 클래스가 6가지이므로 그냥 쉽게 1~6으로 Int로 나타냈다. 따라서 수정된 데이터셋은 다음과 같다.

 

입력 벡터 (5차원) + 출력

a b c d e 1~6

 

 

사실 5번 과정 진행 중에 오류가 발생했었다.

문제는 Xcode에서 model 인식을 못하는 것이였다... 

 

 

그래서 찾아보다 보니 prediction 함수의 파라미터가 데이터셋의 feature 이름으로 자동으로 생성되는 걸 알게 되었다. 그런데 내 데이터셋의 feature 이름이 한글로!! 되어있어서 설마 설마 하면서 영어로 변경하고 다시 학습 후 반입했는데 아주 쉽게 해결했다. 하...

어쨌든 MLmodel 반입 중 Cannot find 'mlmodel' in scope 오류가 발생하면 인코딩 안되는 한글이나 움라우트 같은게 들어가있는지 제일 먼저 확인해야 한다. 영어로 써서 다른 사람들한테도 알려주자..

 

If you find [Cannot find 'mlmodel' in scope] error when importing coreML into an iOS project, you should check for umlauts or non-English or encoding problems.

 

다음을 참고하면 쉽게 코드를 작성할 수 있다.

https://developer.apple.com/documentation/coreml/integrating_a_core_ml_model_into_your_app

 

Apple Developer Documentation

 

developer.apple.com

 

 

python으로 직접 코드를 짜는게 아니라 coreML을 사용해본 건 처음이었는데 생각보다 내부 알고리즘을 알 수 없다는 것이 좋은 것은 아닌 것 같다... 그래도 동작을 잘 모르는 사람이 모델만 빠르게 만들어서 생성할 때는 좋은듯.

나중에는 그냥 ML 라이브러리를 가지고 직접 구현해야겠다.