AI RUSH2019(LINE主催の機械学習コンペ)に参加してきました

LINE/Naver社が主催する機械学習コンペに参加してきたので久々にブログを書きます。

なお、コンペのソリューションについては秘密保持義務に違反する可能性があるのでこちらの記事では特に言及しません。(故に7割方単なる韓国旅行記となります)

コンペ概要

https://ai-rush.com/

コンペの内容は上記のサイトに記載がありますが、こちらでも簡単に概要を書いておきます。

  • 1~3名のチームで参加
  • 予選と決勝の2 roundで構成
  • 予選はImage Classificationタスクで、100チーム中上位30チームが決勝に進出
  • 決勝はCTR予測タスクで、コンペ期間11日間のうち最後の4日間は韓国にあるNaverの研修施設でコンペに参加
  • 優勝賞金は1万ドル

我々のチームはtakuokoさん(Kaggle Master・激強人材)とYusakuさん(Kaggle Master・激強人材)そしてという3人構成でした。

コンペインフラ

今回のコンペではローカルにデータをダウンロードすることは出来ず、Naver社が保有するNSML(Naver Smart Machine Learning)という機械学習プラットフォーム上で全ての計算を実行します。

f:id:naohachi89:20190907153031p:plain
NSML: A Machine Learning Platform That Enables You to Focus on Your Modelsより引用

NSMLはざっくり言うと機械学習に必要なリソース(GPU/CPU等)の管理機能と、実験の管理に必要な諸々の機能(e.g. ソースコードのバージョン管理、モデルの保存、学習結果・過程の可視化等)を提供してくれるプラットフォームです。

私が知る限りだとcomet.mlMLflowあたりのツールが少し近いですが、NSMLの方がより多機能で、且つ学習の再現性を担保する為の仕組みが強力という印象です。

ただ、このNSMLが中々曲者で、コマンド一つポチるだけでよしなにリソースを割り当ててコードを実行してくれる点(=インフラの面倒を見なくて良い)と実験の再現性が高い点は良かったのですが、

  • pythonのnsml packageの学習コストがそれなりに高い
  • notebook/REPL環境が用意されていないためにトライアンドエラーを繰り返しにくい
  • 参加者数に対してリソースが不足気味で計算が思うように回せない

など、割と苦戦を強いられました。

Issue(コンペに関する質問や要望がある場合はgithub上でIssueを立てる)やコンペ終了後の懇親会で聞いた中でも似たような声は多く、NSML is ツライというのは恐らく参加者間の共通認識だったように思います。

今回のAI RUSHは基本的にとても良いコンペだっただけに、もし次回開催されることがあるならこの辺りが改善されているとよりコンペが有意義なものになるかと思いました。(と、コンペ終了後のアンケートにも書きました)

韓国滞在について

前述の通り最後の4日間は韓国に滞在しました。ちなみに往復の航空券や滞在費用は全てLINE/Naver社負担という太っ腹っぷりです。

滞在中はNaver社の研修施設に宿泊したのですが、この施設が本当に素晴らしかったです。

  • 建物が綺麗
  • 施設からの眺めも綺麗
  • 社内のカフェテリアで無料でご飯が食べられる(しかも全て美味しい)
  • 体育館・トレーニング設備・トランポリン・フットサルコート完備
  • (プレイしなかったけど)多種多様なボードゲーム完備

f:id:naohachi89:20190907235448j:plain
隈研吾みが迸る外観

f:id:naohachi89:20190907235723p:plain
カフェテリアで提供されたサムギョプサル(美味しい)

f:id:naohachi89:20190908000015j:plain
会場から見た風景(晴れた日に撮影できなかったが本当はもっと綺麗)

f:id:naohachi89:20190908000142j:plain
会場

f:id:naohachi89:20190908000634j:plain
会場に置いてあったタペストリー的なやつ

現地に行くまではどんな場所なのか不安を抱いていたのですが、いざ赴くと施設も綺麗で思っていた以上に準備に気合が入っていて不安が消し飛びました。 社員の方に聞いたところNaverの新入社員は最初の三ヶ月ほどの研修期間をこの施設で過ごすそうです。めっちゃ羨ましい。

滞在中のスケジュール

1日目

ほぼ移動日で、朝に家を出て大体20時頃にNaverの研修施設(会場兼宿泊施設)に到着。

到着後は夕食を食べて少しだけ作業をして就寝。

ちなみにチームメイトのYusakuさんは普段はアメリカで働いているのでここで初めてのご対面でした。

2日目

作業 & ご飯 & たまにミニゲームといった感じでした。

ミニゲームは運営の方々が主催してくれていて、大体2時間に1度、一日に5~6回程度の頻度で開催されました。

ミニゲームの内容はクイズ・王様ジャンケン・ビンゴ等で、勝つと景品を貰うことができます。

 

f:id:naohachi89:20190907160219j:plain
ゲットした景品たち(かわいい)

LINEのキャラクターは個人的にも大好きなのでグッズをゲット出来たのは普通に嬉しいです。東京は未だに暑いので携帯扇風機は我が家で大活躍してくれています。

3日目

2日目同様に作業 & ご飯 & たまにミニゲームでしたが、コンペはこの日の17:30に終了したのでその後表彰と懇親会がありました。

ちなみに我々のチームは1位でした。

2位は東大の修士の学生チームで、3位は韓国の(確か)大学院生のチームでした。

コンペ期間中はなんだかんだで余裕がないのと、ソリューションについては話せないのでコンペが終わったこのタイミングの懇親会でようやく他の参加者の方々とゆっくり自由に話すことが出来ました。

コンペ直後の懇親会で参加者が顔を合わせて話せるというのは、Kaggle等にはないオンサイトコンペの良さですね。

4日目

4日目は

  • 朝ごはんを食べる
  • レールバイクに乗る
  • 昼ごはんを食べる
  • 帰国する  

という感じでした。 最終日はコンペも終わっているので、LINE社/Naver社の方にアレンジして頂いたレールバイクというアクティビティを堪能しました。 これは複数人で大きめの自転車に乗って鉄道線路上を爽やかに駆け抜けるというアクティビティです。

これだけ聞くと単調で面白みのないもののように思えるかもしれませんが、豊かな自然をハイスピードで駆け抜けるのは中々に気持ちが良く、要所要所でネオン煌きクラブミュージック流れるトンネル等のアクセントも配置されており、非日常的な体験が出来て存外楽しめました。

韓国に行かれる機会がある方はぜひ行ってみてください。オススメです。

f:id:naohachi89:20190907231656j:plain
レールバイク

f:id:naohachi89:20190908024614p:plain
クラブと化したトンネル

おわりに

振り返ってみると今回のコンペはトータルでは非常に満足度が高かったです。 韓国滞在中の体験は控えめに言って最高でしたし、詳細は書けないのですが各roundのタスクもチャレンジングで解き甲斐のあるものでした。

懇親会等で社員の方と話したところコンペの準備はかなり大変だったそうで、運営の方々には感謝してもしきれません。本当にありがとうございました!

一方で、一参加者としては最高に楽しかったので、準備が大変というのは知りつつも次回の開催を心待ちにしています...!

おまけ

今回final roundでtakuokoさんのモデルのweightが100だったので記念にweight 100 Tシャツを作成しました。

現在UT me!で出品審査を出しているところで、審査が降りた暁には「我weight100ぞ?」というkagglerの方々、是非お買い求めください。(万が一売れたら売上金はどこかに良い感じに寄付でもします)

f:id:naohachi89:20190908024838j:plain
weight 100

追記

weight 100 Tシャツの出品審査通りました。 utme.uniqlo.com

MLCT 8で発表してきました

www.slideshare.net

 

MLCT(Machine Learning Casual Talk)という、機械学習システムの運用に関する知見を共有する会で発表してきました。

イベントのリンクはこちら

mlct.connpass.com

 

 

プレゼンで紹介した課題と解決策に関しては、モノによってはかなりdomain specificな課題を解いているとは思っていて、発表前は参加者の方々に刺さるか結構不安だったんですがTLを見る限りは概ね公表なようで安心しました。

 

MLCTには第5回から参加はしていたのですが、8回目にして漸く少しだけコミュニティに貢献することができて良かったです。

 

機械学習システムの運用はまだまだベストプラクティスが確立されていないのが現状なので、引き続きやっていきたいと思います。

Cpaw AI Competitionを連覇しました

第3回 Cpaw AI Competitionで優勝してきました。


cpaw.connpass.com


前回も優勝したので連覇になります。嬉しいです。

Cpaw AI Competitionがどのようなものかは以下の記事に詳しく記載されています。

knowledge.sakura.ad.jp

 

ざっくり概要を説明すると「短時間で複数のデータセットに対してソリューションを作成するKaggle」です。

データセットの数は毎回異なっているようで、前回は4つでしたが今回は3つでした。

それぞれのタスクは以下のとおりです。

  • 自然言語 + テーブルデータのマルチクラス分類
  • 画像のマルチクラス分類
  • ハイパースペクトル画像のマルチクラス分類

この記事では、今回行った事前準備と私のソリューションの概要について説明します。

 

自然言語 + テーブルデータのマルチクラス分類

観光地に関するデータセットで、観光地の説明文や都道府県・観光地が開かれている曜日・時間帯などの情報を使って観光地のクラス(Temple, Spa, Park, Shopなど8クラス)に分類する問題です。

私のソリューションはMulti Layer PerceptronとLightGBMのスタッキングで、各レイヤーのモデル・特徴量は以下の通りです。

  • 1段目のMLPの特徴量として、word tfidf(形態素解析MeCab + neologd)とcharacter ngram tfidfをconcatして利用
  • 2段目のLightGBMの特徴量として、上記のconcatした特徴量 + MLPの予測値 + 元データの中で型がint, floatのものを利用

データセットの中にはカテゴリカルなカラムもあったので本当はそちらも使いたかったのですが、時間がなくて断念しました。

最終的な精度は84.3%程度でした。

 

画像のマルチクラス分類

手の画像があり、指が何本(1本 or 2本 or 3本)立っているかを予測するマルチクラス分類の問題でした。

モデルは以下のCNNで、kerasのImageDataGeneratorでData Augmentationをし、50エポックほど学習させて精度は97%程度でした。

model = Sequential()
model.add(Conv2D(32, (3, 3), input_shape=input_shape))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))

model.add(Conv2D(32, (3, 3)))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))

model.add(Conv2D(64, (3, 3)))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))

model.add(Flatten())
model.add(Dense(64))
model.add(Activation('relu'))
model.add(Dropout(0.5))
model.add(Dense(class_num))
model.add(Activation('softmax'))

model.compile(loss='binary_crossentropy',
              optimizer='rmsprop',
              metrics=['accuracy'])

ハイパースペクトル画像のマルチクラス分類

ハイパースペクトル画像のマルチクラス分類問題です。すみません、解説のときにぼーっとしていたのでこれ以上詳しい説明ができません...。
そもそもハイパースペクトル画像というものを知らなかったのでぐぐってそれっぽい論文を探したり、1次元CNNを実装したりしたのですが学習がうまくいかず、
結局サンプルコードのモデルをリッジ回帰からLightGBMに差し替えたものが最も高精度で、88%程度の精度で終わりました。

Cpaw AI Competitionで勝つために大切なたった2つのこと

勿論Kaggleで求められるような機械学習やプログラミングの基礎的な能力も当然大事なのですが、個人的にはこの大会で勝つために求められる能力は微妙に異なると思っていて、特に以下の2点が重要だと考えています。

やることの優先順位をつけること

Kaggleと比べると圧倒的にタスクを解く時間が足りないので、実装にかかる工数と期待される効果を鑑みてやることの優先順位をつけることがKaggle以上に重要になります。
Kaggleに関しては全てのdiscussionとkernelを見てtry everythingすれば良いだけなので特にやることの優先順位などをつける必要はないのですが、何せ4.5時間で3タスクを解く必要があるのでtry everythingする余裕はありません。
今回は観光地データセットにカテゴリカルなカラムが含まれていて恐らくこのカラムで特徴量を作れば精度が上がったかもしれないのですが、実装工数がかかりそうだったので見送りました。
結果的にはStackingが余り効果がなかったのでひょっとするとfeature engineeringに取り組んだほうが良かったのかもしれないのですが、この辺は結果論ですね。
データセットの各カラムのデータ型を見たときにnumericalなカラムがあったので、カテゴリカルな特徴量に対してfeature engineeringするよりはMLPの予測値とnumericalなfeatureをLightGBMでStackingした方が期待される精度向上は高そうだと考えてそちらを優先しました。

事前準備をすること

この大会ではさくらVPSのハイスペックなサーバーが各参加者に与えられるのですが、ほぼまっさらな状態で与えられるので環境構築を行う必要があります。
地味に時間がかかるので、環境構築はスクリプトで自動化しておくとだいぶ時間が節約できると思います。
私自身前回は準備をせずに行ってかなり時間を取られたので、今回はある程度環境構築を自動化できるようスクリプト化しておきました。それでもmecab周りの設定は準備できておらず、うまくサーバーの方に入っていなかったので結局手元のローカルMacでやる羽目になりましたが...。
後は、(中々そこまでのガチ勢はいないと思いますが)本気で勝つことを目指すのであれば特徴量生成などの関数を自作したり、様々なタスク(e.g. 画像のクラス分類)のテンプレート的なNotebookを作成しておくと時間が節約できると思います。

感想

前回に引き続き大変疲れましたが、とても楽しい大会でした!
4.5時間で3タスクはエグいですね。終始アドレナリンを出しながら仕事以上に集中してやってました。
KaggleもKaggleでコンペ中はとても楽しいのですが、時間がめちゃくちゃ短くてリーダーボードも所謂パブリックリーダーボードしかないのでまた別のヒリヒリ感があります。(Kaggleも1位の人とかだとヒリヒリ感があるのかもしれませんが、なったことがないので感じたことがありません😢)
最後の20秒くらいは出来ることも特になかったので、抜かれないことを祈りながら更新ボタンを押してました。
運営的にはかなり大変(データセットの作成は本当に大変だと思います。いつもありがとうございます)だと思いますが、とても楽しい大会なので是非今後も続けて頂けると嬉しいです。
運営(Cpaw)の皆様、スポンサーの皆様(サイバーエージェント様・さくらインターネット様)、素晴らしい会を開いて頂いてありがとうございました!

GW 1日目日記

今年もGWがやってきたので日記を書きます。

去年は途中で力尽きましたが、今年はどこまでいけるか。

 

やったこと

WikipediaのダンプデータをAmazonのElasticsearchに載せた。

ざっくり手順

  • Wikipediaのダンプを落とす
  • WikipediaExtractorで中身をパースし、分割して出力する 
  • 分割して出力したファイルをpyhton(Beautifulsoup4)で読んで、Elasticsearchモジュールで記事をindexに追加

ググってみても、Wikipediaの日本語のダンプデータをAmazonのElastisearchに載せてる人は見つからなかった。(ローカルのESに載せてる人はいた) 生データは11GBくらいあるので、(ローカルのESに載せる記事だと)XMLをstream2esで載せている方法があったがAmazon Elasticsearchでこの方法を使ってもいまいちうまくいかない。 ストリームデータをAmazon Elasticsearchに載せる方法はいくつかあるみたいだが、 微妙に今回やりたいことにそぐわないのと準備に手間がかかりそうなので上記のような手順を取った。

ファイルを分割する部分に関しては別にWikipediaExtractorを使う必要はないのだけど、巨大なXMLを分割して読み込み・出力するスクリプトを1から書くのが手間がかかりそうだったので利用させてもらいました。

上記のような手順を経て、どうにかAmazonのElasticsearchにwikipediaのデータをロードすることができました。

TensorFlowのエラー解消

kerasでGANのexampleを動かそうとしたら下記のエラーが出た。

TypeError: sigmoid_cross_entropy_with_logits() got an unexpected keyword argument 'labels'

調べたらどうも下記のIssueと同一のエラーな模様。 下記Issueはpython2系のもので、自分の環境はpython3系だけど同一のエラーが発生していた。

https://github.com/carpedm20/DCGAN-tensorflow/issues/84

Issueのコメントに従って、tensorflowのバージョンを最新(1.3.0rc2)に上げたところエラーが解消された。 アップデートに際しては下記リポジトリのREADMEに記載されているリンクから最新バージョンのtensorflowをDLし、その後下記コマンドを実行した。

リポジトリ: https://github.com/tensorflow/tensorflow#installation

コマンド: sudo pip install --upgrade tensorflow-1.3.0rc2-py3-none-any.whl

元々tensorflowのバージョンは最新のものに挙げたつもりだったのだけど 公式ページに書かれているものがすこし古いバージョン(1.2.1)だったようで、 どうやらそのせいでエラーが発生してたっぽい。 リポジトリのREADMEに記載されているものは最新のバージョンになっているようなので、 そちらを参照するようにした方が良さそう。

GW3日目 コードコンプリートを読んだ(途中)

CODE COMPLETE 第2版 上 完全なプログラミングを目指して

CODE COMPLETE 第2版 上 完全なプログラミングを目指して

3日目はコードコンプリートを読みつつ、A tour of Goを進めた。

コードコンプリートは6章まで読み終わった。 ソフトウェア開発におけるコンストラクション(コーディングを中心とした、詳細設計〜テストまでのプロセスのこと)に関するプラクティスが解説されている本で、現時点(6章)だと設計に関するプラクティスまでが言及されている。

今のところで印象に残っているトピックは下記

修正が遅くなるほど修正コストが増加する

要件定義の段階でミスを発見するよりもコーディングの段階でミスを見つける方が修正コストが高くなる的な話。 これは実際にやっている中でもめちゃくちゃ実感していて、既にリリースされているシステムのバグフィックスなんかだと開発段階とくらべて考慮事項が多くなるため同じ修正量であってもかかる修正コストが圧倒的に膨らむ。 だからこそ、要求段階等の早い段階でミスを見つけるのが大事。

読み進めたらまた書きます。

GW2日目 [改定第3版]Apache Solr入門を一部読んだ

[改訂第3版]Apache Solr入門――オープンソース全文検索エンジン (Software Design plus)

[改訂第3版]Apache Solr入門――オープンソース全文検索エンジン (Software Design plus)

オープンソース検索エンジン、Solrを勉強する為に読みました。 当面はSolrを運用する予定は特にないので1~4章、6章の一部、あと9章を読みました。

良かった点

  • Solrの導入方法や挙動がわかりやすく解説されている
  • githubサンプルソースが容易されていて、スムーズに読み進められる。特に躓く点がなかった。
  • 割と高度な検索エンジンの改善手法(LTRとか)をSolrに導入する方法についても言及されている。

もう少しな点

後は、検索エンジンの改善に言及するのであればモニタリングについてももう少し言及してくれるとより親切になると感じました。この点はビッグデータ分析・活用のためのSQLレシピが素晴らしかったので、検索業務に携わる人は併せて読むと良いかと。

ビッグデータ分析・活用のためのSQLレシピ

ビッグデータ分析・活用のためのSQLレシピ