Kaggle

Kaggle : What’s Cooking?

Kaggle에 대해 알게 된건 올해 초 쯤이었던 것 같다. Kaggle은 일종의 데이터 사이언스 대회 사이트인데, 특정 문제가 주어지면 그 문제를 해결하기 위해 전 세계의 데이터 과학자들이 각자 가지각색의 알고리즘을 통해 문제를 해결하고, 그 성능을 경쟁한다. PS 분야에 Codeforces가 있다면, 데이터 사이언스 분야에서 이 사이트가 비슷한 역할을 하고 있다고 할 수 있겠다. 과제로 주어지는 문제의 종류는 굉장히 다양하며, 개중에는 데이터 분석이 필요한 기업들에서 상금을 걸고 대회를 주최하는 경우도 있다. 이 대회들에 참가하는 사람들은 처음 데이터 사이언스 공부를 시작하는 학생들뿐만 아니라, 관련 대학원생들이나 실제 현장에서 일하는 전문가들까지 굉장히 다양한 사람들이 대회에 참여하고 있다.

Kaggle에 대해 처음 알았을 때부터 굉장히 흥미가 생겼던 것이, 고등학교 때부터 내가 이 분야에 대해 공부하면서 최종적으로 하고싶었던 것들이 이렇게 ‘언뜻 보면 어떻게 해결해야할 지 모르겠는 고난도의 real-life 문제들’ 을  기계 학습 등의 방법을 통해 분석하고, 해결하는 것이었기 때문이다. Kaggle에서 주어지는 문제들은 이러한 나의 흥미에 딱 들어맞았다. 처음 Kaggle에 대해 알게 되었을 때는 관련 지식이 전혀 없었기 때문에, 문제를 풀 방법이 없었다. 그러나 1년간 기계 학습에 대해 공부하면서 이 분야에 대해 아직 미흡하지만 문제들에 도전은 해볼 정도의 지식은 생긴 만큼,  이제 갖가지 Kaggle 대회들에 실제로 참여해보면서 실제 문제들을 해결해보려고 한다.

처음으로 참여한 Kaggle 대회는 ‘What’s Cooking?‘ 이라는 대회이다.  이 대회는 얼마 전인 12월 20일에 종료되었는데, 이 대회에 대해 알게 되고 실제로 참여한 것이 12월 17일이었다. 4일이라는 시간이 다소 짧아 많은 것을 시도해보거나 좋은 성과를 이루어내지는 못했지만, 그래도 이 동안 어떤 식으로 문제에 접근했는지 정리해보고자 한다.

Problem Description

이 문제에 대한 자세한 설명은 위에 첨부한 대회 페이지에서 자세하게 볼 수 있다.
문제의 전체적인 개요는 ‘어떤 음식을 만들기 위한 재료의 목록이 입력되었을 때, 이 음식이 어느 나라(지역)의 음식인지 분류하는’ 것이다. 재료는 양이나 넣는 순서 등은 주어지지 않고 단순히 재료의 이름만이 주어지며, 재료들의 이름이 깔끔하게 주어지지도 않는다(‘salt’, ‘sugar’, ‘eggs’ 등의 단순한 이름도 있지만, ‘eggland’s best® eggs’, ‘reduced-fat sour cream’ 등 브랜드나 부가적 설명이 붙은 재료들도 있고 typo가 있는 재료들도 있다). 이 재료들의 목록을 바탕으로 음식의 ‘cuisine(특정 지역, 나라의 음식)’ 을 분류해야 하는데, cuisine은 southern-us, spanish, french, korean, japanese, brazilian .. 등 20 종류가 있다. 문제를 해결하기 위해 약 4만 개의 음식에 대한 재료 정보를 담은 training data가 주어진다.

Methodology Part #1

이 문제를 보고 가장 기본적으로 떠오르는 접근법은 training data를 돌면서 ingredient의 dictionary를 만든 뒤, 재료 목록을 bag-of-ingredients 등으로 표현한 뒤 Naive Bayes나 Neural Network 등의 분류기를 사용하는 방법일 것이다. 그러나 나는 보다 재료들의 ‘본질적인 특성’ 에 대해 알 수 있는 방법이 있을 것이라고 생각했고, 재료들의 특성을 보다 수치적으로 표현할 수 있다면 이 정보를 이용하여 보다 정교한 분류가 가능할 것이라고 생각했다. 이에 분류에 앞서 각 ingredient의 정보를 수치화하는 방법이 필요하였고, 여기서 떠오른 것이 word2vec 이었다.

word2vec은 자연어처리(NLP)에서 사용되는 방법으로, 특정 단어의 직접적인 의미를 파악할 수 없었던 기존 자연어처리 기법을 비약적으로 발전시킨 방법이다. 이 방법에서는 각각의 단어들을 고차원의 숫자 벡터로 나타내어 단어 자체를 ‘특성화’ 시킨다. 이 방법을 이용하면 이 벡터들을 가지고 더하고 빼는 등 하면서 단어에 대한 추론이나 단어 사이의 관계도 쉽게 다룰 수가 있게 된다. word2vec에 대한 정보를 더 알고싶다면 이 블로그를 참조하면 될 것 같다.

word2vec이 단어 자체를 특성화하듯이, 나도 같은 방법으로 재료 자체를 특성화할 수 있다. 특히 이 문제에서 요리라는 것은 결국 재료의 선형적인 결합이라고 근사화할 수 있다고 생각하였기 때문에, 이렇게 재료를 수치화하여 분석한다면 좋은 결과를 얻을 수 있을 것이라고 생각하였다. 이를 ingredient를 vector로 바꾸는 과정이므로 ing2vec이라고 부르겠다. ing2vec의 학습에는 word2vec의 학습 방법 중 skip-gram을 이용하였는데, word2vec의 학습 자료인 ‘글’과는 달리 요리의 재료에는 딱히 정해진 순서가 없다. 따라서 특정 요리의 특정 재료에 대해 함께 등장하는 재료들을 랜덤하게 고른 다음, 이를 이용하여 학습을 진행하는 방법을 사용하였다. 또한 word2vec 학습에서의 ‘글’과 이 training data가 다른 점은, 글을 학습하는 과정에서는 실제 의미를 알 수 없는 반면 이 training data의 경우에는 cuisine이 무엇인지에 대한 답이 주어진다는 점이다. 이에 착안하여, skip-gram의 중간 hidden layer에 별개로 hidden layer #2 – output layer를 달아주어 cuisine classifying layer를 따로 달아주었다. 이를 이용하면, 각각의 ingredient의 unsupervised feature 말고도 각각의 재료의 ‘cuisine’ 의 특성을 반영하는 요소도 넣어줄 수 있을 것이라고 생각하였다. 결국 ing2vec에서 사용한 네트워크 구조와 학습법은 대충 다음과 같다.

Diagram
– Layer Structure and Cost Definition for ing2vec training.

 레이어 구조와 학습은 theano를 이용하여 구현했는데, 나는 네트워크 크기가 그렇게 크지 않고 학습 데이터도 word2vec의 데이터 사이즈에 비하면 굉장히 작기 때문에 학습이 빠르게 진행될 것이라고 생각하여 negative sampling 등의 방법을 사용하지 않고 굉장히 naive하게 구현하였다. 그런데 생각보다 학습 속도가 느려서, 밤새 학습을 진행했는데도 5 epoch밖에 진행하지 못했다 (물론 실험을 진행한 환경이 열악하기도 했지만).

 이렇게 naive하게 구현하게 ing2vec을 구현하였고, 학습이나 hyperparameter 선정도 제대로 진행되지 못하여 과연 vectorize가 제대로 되었을 지 의문이 들었지만 학습된 결과를 가지고 몇 가지 실험을 진행해보니 어느 정도는 학습이 제대로 진행된 것을 확인할 수 있었다.

coffee, gochujang
Top 10 Closest Ingredients to Target : (1) Coffee, (2) Gochujang Base

 위는 ‘coffee’ 와 ‘gochujang base’ 재료에 대해 가장 가까운 10개의 재료들을 나열한 결과이다. 가깝다는 기준으로는 cosine similarity를 사용하였다. 보다시피 두 결과 모두 유사한 느낌의 재료들이 모여있는 것을 확인할 수 있다. coffee의 경우 espresso, coffee liqueur 등이 있으며, gochujang base의 경우 gochugaru, kimchi, korean chile flakes 등이 있다. 특히 이 ing2vec training은 cuisine의 정보를 가지고도 training 된 만큼, 많은 나라의 음식에서 등장할 수 있는 coffee보다 거의 korean cuisine에만 등장할 gochujang base와 관련 재료들이 훨씬 높은 cosine similarity를 가지고 잘 모여있는 것을 확인할 수 있다.

icecream+coffee
Top 10 Closest Ingredients to ‘Ice cream + Brewed Coffee’

 위 결과는 ice cream과 brewed coffee의 벡터 두개를 합친 벡터에 대해 가장 가까운 10개의 ingredient를 확인한 결과이다. 원래의 두 재료가 1, 2위이며, 3위에는 ‘coffee ice cream’ 재료가 있다. 즉, 벡터를 수치화하여 더해서 새로운 벡터를 만들어도 새로운 재료의 특징을 잘 나타낼 수 있다는 결과를 확인한 것이다(물론 모든 경우에 대해 좋은 결과가 표현되는 것은 아니었다).

Methodology Part #2

ing2vec을 통해 ingredient 자체를 벡터화하는 데에 성공하였으니, 남은 과제는 이를 이용하여 요리를 분류하는 것이다. 문제는 각각의 재료의 특성을 반영하여 어떤 ‘재료의 목록’에 대한 일정한 길이의 벡터를 만들어야 하는데, 이를 정확하게 표현할 수 있는 방법에 대해 고민하고 이것저것 실험해보았지만 딱히 좋은 결과를 얻지는 못했다. 랜덤하게 특정 갯수의 재료를 뽑아서 긴 벡터를 만들고, 이를 이용하여 Simple Deep Layer Network를 만들고 실험해보았으나 이 모델은 학습 시간이 너무 길었고, 기대에 비해 좋은 결과를 얻지 못했다. 그렇다고 각 재료들에 대한 weight를 산정하여 선형적으로 더하기에는 각 재료들에 대한 weight를 얻을 적절한 방법이 떠오르지 않았으며, 각 음식마다 재료가 차지하는 비중이 크게 다를 수 있기 때문에 이 방법은 일단 배제하였다. 결국 최종적으로는 단순히 들어가는 재료들의 벡터들을 다 더하되, 너무 자주 나타나거나 sugar, salt 등의 단순한 조미료, 향신료 등은 weight를 작게 주었다. 또한, 특정 cuisine에서 자주 나타나는 일부 재료들은 weight를 크게 주어서 더해주었다. 이 vector를 같은 norm을 가지도록 normalize해준 벡터를 가지고 특정 ‘재료의 목록의 벡터’를 만들어서, 이를 이용하여 분류를 진행하였다.

분류기로 처음에 사용한 방법은 Deep Layer Network로서, 3-hidden layer짜리 Deep Network를 만들어준 뒤 Leaky ReLU, DropConnect를 적용하여 학습을 시켜주었다. 반면, 40 epoch 정도 지났음에도 불구하고 성능이 72.3%정도밖에 나오지 않았다. 이에 접근법을 달리 생각해보았는데, 이 문제가 결국 확연히 특징이 나누어지는 그룹들을 분류하는 문제인 만큼 단순한 Deep Network보다는 localization 성향이 강한 모델이 성능이 잘 나올 수 있을것 같다고 생각되어 RBFN을 사용해보기로 하였다.

RBFN에서 커널로 Gaussian Kernel을 사용하고 실험해본 결과 커널의 수가 적었음에도 불구하고 Deep Network의 결과보다 좋은 성능을 얻을 수 있었다. 이에 커널의 수를 최대한으로 늘리고 실험하여, RBFN으로 얻을 수 있었던 최대의 결과를 마지막으로 제출하였다.

Result & Discussion

내가 얻을 수 있었던 최고의 성능은 78.8%로서, 총 1416개의 팀 중 560위를 하였다. 1위 팀의 성능은 83.2%로, 나의 성능과 4.4% 정도의 차이가 난다. 솔직히 생각했던 것에 비해 성능이 많이 나오지 않아 다소 실망하긴 했다. 80% 이상의 성능을 얻고 싶었는데, 열심히 이것저것 실험해보았지만 결국 실패했다. 시간이 더 있었고 더 여유롭게 실험할 수 있었다면 80% 정도 성능은 얻을 수 있지 않았을까라고 위로를 하고싶다.

내가 진행한 것 중에 가장 미흡한 부분이 Preprocessing 부분이었던 것 같다. 시간이 많이 없다는 촉박한 느낌에 일단 모델부터 생각해야한다는 마음가짐으로 임했었는데, 일부 상위 순위를 얻은 참가자들의 방법을 보니 재료 이름을 정리하고, 세공하는 데에 많은 공을 들이고 실질적인 분류는 이미 있는 패키지들로 진행하는 방식을 사용했다. 나는 실질적으로 거의 Preprocessing을 진행하지 않아서, 이 부분에서 공을 들였다면 보다 성능이 나아지지 않았을까 싶다.

또 다른 참가자들이 분류기로 xgboost를 많이 이용하던데, 어딘가에서 분류 문제에서 실질적으로 성능이 가장 잘 나오고 가장 많이 이용하는 방법이 random forest라는 말을 얼핏 들은 것 같다. 다음에 분류 문제를 사용하는 대회에 참여할 일이 있다면 xgboost를 한번 사용해볼 계획이다.

이번 대회 및 다른 대회들의 결과를 보면서 느낀 점은 결국 어느 한계까지 이르렀을 때부터는 ensemble 방법을 이용하는 참가자가 많았다는 것이다. 내 개인적으로는 ensemble 하는 것은 아이디어나 아름다움이 있다기 보다는 계산량이나 물량으로 성능을 억지로 올리는 느낌이 들어서 싫지만 현장에선 이러한 방식으로 많이들 사용하는 것 같다. 또 ensemble 하기에는 현재 노트북으로 실험하고 있는 내 실험 환경이 따라주지가 않는데.. 본격적으로 데이터 사이언스를 제대로 해보기 위해서는 좋은 스펙을 갖춘 데스크탑을 사야되는 것인지 고민이 되기도 한다.

구현 코드는 Github의 내 Repository에서 확인할 수 있다.

Advertisements

Kaggle : What’s Cooking?”에 대한 1개의 생각

답글 남기기

아래 항목을 채우거나 오른쪽 아이콘 중 하나를 클릭하여 로그 인 하세요:

WordPress.com 로고

WordPress.com의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

Twitter 사진

Twitter의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

Facebook 사진

Facebook의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

Google+ photo

Google+의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

%s에 연결하는 중