概要
今回メルカリの商品紹介文やブランドの名前などからユーザーが出品した商品の売れるであろう適切な価格を推測するというコンペにチャレンジしました。
結果は、下から40番ほどとひどい結果でした。
なぜこうなったのかkernalコンペの落とし穴とはなんなのか説明していきたいと思います。
目的
メルカリは言わずと知れた日本のフリマの会社です。
ユーザーが売りたい商品を出品し、それを買いたい人が買うというものです。
そこで今回ユーザーが入力するデータから機械学習を使って、売れそうな適切な価格を自動で判断するアルゴリズムを作ろうというコンペです。
実際使っていて、出品したものがなかなか売れないとか値下げ交渉が面倒だと思ってAIを使えばある程度売れる価格を予想できるんじゃないかと思っていましたが、実際にやってくれて嬉しいです。
データ
今回与えられたデータは英語版メルカリのデータでカラムは、
-
name:ユーザーが設定する商品タイトル
-
item_condition_id:商品の状態(1-5のどれか整数どれか)
-
category_name:商品のカテゴリの名前(例:Men/Tops/T-shirts、Women/Tops & Blouses/Blouseなど)
-
brand_name:商品のブランドの名前(例:Razer、Nikeなど)
-
price:商品のドル価格
-
shipping:配送料を出品者が負担するかどうか
-
item_description:アイテムの説明
で構成されています。
難しいのはnameとcategory_name、item_descriptionの自然言語をどう処理するのかというところです。
これだけのデータから機械学習を用いれば値段が予測できるというのはすごいですね。
今後はさらに画像による予測も混ぜていけるようにするのでしょう。
画像によって売れやすさや値段に差が出でくることは容易に予測できます。
kernelコンペとは
はじめに、カーネルとはなんなのかを説明します。
カーネルは、
-
スペックは、4core/16GBRAM/連続実行時間60分/1GBのディスク。
-
無料で使用できる。
-
情報共有が簡単。
-
pythonとRで使用でき、大抵の機械学習に用いられるモジュールが入っている。
-
dockerを使って実現している。
-
計算リソースは全てkaggle側がクラウドで提供してくれる。
kernelを使えば自分がマシンを持っていなくとも機械学習をできます。
しかし、実行スピードは、あまり早くなくGPUもないためDeep learningをするのはなかなか難しいです。
徐々にスペックが上がっていっているのでいつかGPUも使用できるようになると思います。
ここまでがカーネルについてです。
さて、肝心の今回のkernelコンペですが、これはこのカーネル上でのみ行われるコンペです。
普通は、カーネルを使っても使わなくてもよくみんな自分のローカル環境でモデルを作り、結果をだしそれを提出しますが、今回はカーネルつまり
- 4core/16GBRAM/連続実行時間60分/1GBのディスク
を使って全員が制限された同じ環境でデータを処理し、訓練し、予測して結果を提出します。
なぜこのように普段とは違うカーネルコンペにすることになったのか定かではありませんが、考えられる理由は
-
メルカリから答えとなるデータを取ってこられるため不正が行われたり、モデルの訓練にそのデータを使用する人が現れてしまうのを防ぐこと。
-
kaggleのコンペでは優勝者や上位の人の手法があまりにも複雑で実際に業務に使用できないことがあるからカーネルを使えばちょっといいノートPCレベルの環境で価格の予測ができるので十分に実際に業務で使用できるレベルであるから。
というのが私の意見です。
データの前処理
これを書いているのは、このコンペが終わった当日に書いているのでなかなか詳しい解説はできませんが、概要だけ書いていきたいと思います。
今回はカーネルをみんな使ったので情報共有されている上位の人のカーネルが多いので実際に見てみることをお勧めします。
私はそこまで自然言語処理に詳しくなく勉強中なので間違った知識があるかもしれないので信用しすぎないでください。
今回のキーとなるポイントは、商品のタイトルと詳しい説明のところの自然言語処理をどうするのかというところです。
基本的に、自然言語をベクトル化するのですがそこに使われた手法は主に3つあります。
- tfidfvectorizerとCountVectorizer
- kerasのTokenizerとEmbedding
- 外部のすでにベクトル化したデータを用いる
以上の3つです。
これらを使って自然言語をベクトル化します。
-
tfidfは、よく使われるもので、ある語が文書内で出現頻度が高く多数の文書に登場しないほど重要度が高くその文書を特徴付けるということからベクトルを生成します[1]。
CountVectorizerは、tfidfの簡易版で単語の出現頻度のみを見ている?ここに関していうとtfidfとCountVectorizerがどのように違うのかがよくわからなかったです[2]。
今回文章が長い商品の詳しい説明にはtfidf、短いその他の自然言語はCountVectorizerが使われるケースが多かったです。 -
詳しくはわからないですが、kerasには自然言語処理を簡単に行うためにTokenizerという単語それぞれにIDを割り振るものがあるそうです[3][4]。
その後、Embeddingすることでその割り振ったものをベクトルに直すことができるらしいです。 -
今回外部のデータは、主催者に許可されたものであれば使ってよく、事前に訓練された単語ベクトルであるglove達を使っている人が多かったです。
詳しいことはわかりませんが、どうやらスタンフォードで作られたwikipediaから作られた単語ベクトル、twitterから作られた単語ベクトルなどがあります[5]。
これを使えば素早く自然言語をベクトル化できそうです。
また、今回は計算時間の関係上あまり使われなかったですが,Word2Vecを使う手法もあります。
他にもレーベンシュタイン距離を使ったものもあり,これはある単語を他の単語に変換するために必要な操作の最小数を求めるものです[6]。
操作は、1文字の挿入、削除または置換、または2つの隣接文字の転置があります。
モデル
今回上位に入ったモデルは、自然言語処理なのにCNNを使ったモデルが多かったです。まだ、私は検証できていないので実際に見に行っていただきたいと思います。
毎回kaggleで上位の人とそれ以外の埋まらない差があるがこういう手法を知っているかどうかがかなり大きいのだと思いました。
私ももっと学ばなければ。
-
使われたモデルは、前処理がtfidfvectorizerとCountVectorizerを使ったものは、主にLightgbmかRidgeあるいは両方を使ったものが多かったです。
-
kerasのTokenizerとEmbeddingの場合は、そのままRNNを使ったものが多かったです。
-
外部のすでにベクトル化したデータを用いる手法をとったものは、同様にLightgbmかRidge、FTRL、FM_FTRLを使っていました。
FTRL(Follow The Regularized Leader)に関しては調べてもよくわからなかったです。
結果的にこれらの手法のうち複数をアンサンブルしてみんな競い合っていました。
上位に入るには基本的にCNNを使うのが良かったです。
Follow The Regularized Leader
結果
さて、ここまででかなりkaggleの一般的な自然言語処理の手法は網羅しました。
具体的な解説までは今回できないがかなり参考になると思われます。
最低限個人的にはこれらの手法を今後kaggleの自然言語処理コンペでは使っていきたいです。
しかし、今回私がこの記事で言いたいことはこんなことではありません。
kernelコンペの落とし穴についてです。
今回のコンペでは、2384チーム中800チームほどが失格になりました。
30%ほどの参加者が正当に評価を受けることができなかったのでということです。
普通一つのコンペに参加者はかなりの時間をかけるのですが,
これほどまで適切な評価を受けることができなかったのはとても悔しいことです。
何が起きたのか?
今回のコンペでは最終結果が出る一週間ほど前にラウンド1が終わりカーネルを提出し、以後はラウンド2となりそのカーネルは改変することができません。
しかし、ラウンド1とラウンド2では決定的に違うことがあります。
それは、テスト用データの量がラウンド2では5倍になることです。
これによって安全にカーネルがラウンド2でも動作するかの検証ができずに最終結果が出るため途中でカーネルの環境ではメモリエラーなどその他のエラーが出ることがあります。
これによって30%もの参加者がエラーとなってしまったのです。
私もメモリエラーとなってしまいました。
ラウンド1終了時点では最終日に夜10時から朝5時まで頑張って上位7%以内に入り、初めてメダル獲得が見えたのにとても残念です。
しかし、上位陣はさすがです。
結果がすごいだけでなくエラーが出ないような設計をしていたのです。
カーネルコンペは今後もっと色々改善されていくとは思いますが、今回私が言いたいことはこのような残念なことが起きないようにきちんとメモリ管理やエラー回避策を講じなくてはいけません。
まとめ
カーネルコンペでは、ありとあらゆる最悪を想定してプログラムを提出しなければとても悲しいことになります。
上位に入るにはかなりの鍛錬が必要であることがわかりました。
参考文献
[1]https://takuti.me/note/tf-idf/
[2]https://www.quora.com/What-is-the-difference-between-TfidfVectorizer-and-CountVectorizer-1
[3]https://qiita.com/yagays/items/292dd04c53cb7e0bcb5a
[4]https://machinelearningmastery.com/use-word-embedding-layers-deep-learning-keras/
[5]https://nlp.stanford.edu/projects/glove/
[6]https://en.wikipedia.org/wiki/Damerau%E2%80%93Levenshtein_distance