機械学習の詰め合わせ

機械学習周りで考えたことやインプットしたことをまとめる場所。

バイアスパラメータは重み減衰させるべきか?

「Biasパラメータはweight decayの対象から除外すべき」という意見[1]がある。

典拠

これの根拠について明示的に議論した論文は見つけられなかったが、Pytorch Forum[1]で言及されているように、NFNetの論文[2]において「biasとgain(どちらもscalar)のパラメータをweight decayの対象から除外した」という記述がある。

Critically, weight decay is not applied to the affine gains or biases in the weight standardized convolutional layers, or to the SkipInit gains.

なぜweight decayしてはいけないか?

典拠が見つけられなかったので以下に自分なりの考えを述べる。

そもそもweight decayがなぜ導入されたかというと、「重みのスケールが無限大に発散する」ことを防ぐためだった。現代の多くのニューラルネットワークではNormalizationレイヤーが挿入されており、「重みのスケールに対して不変」という性質を持っている。したがって、重みのスケールを小さくしたとしても、後続のnormalizationレイヤーによって適切な範囲に収まるため、重みを減衰したとしてもネットワークの表現力は影響を受けないことが推察される。

一方でバイアスパラメータは重みの「大きさ」を表現する量ではなく、「中心からのずれ」を表すパラメータである。これを小さくするということは、実質バイアスパラメータの役割を弱めることにつながる。

このように、ニューラルネットワークの「重み」と「バイアス」は異なる役割を果たすため、重み減衰についても異なる考え方が適用されるべき、という解釈が成り立つ。

実装方法

pytorchのOptimizerは上記で議論したような事情は考慮しないため、このような仕様を反映させようとすると自分でコーディングする必要がある。

最もシンプルな実装としては、[1]の回答で示されているような、「"weight"という文字列を含むパラメータはweight_decayを>0に、それ以外は0にする」というものがある。 pytorchのデフォルトのモジュールの多くは重みパラメータは*.weight、バイアスパラメータは*.biasというキーを持つので、多くのケースではこの実装で十分と思われる。ただし、自前でtorch.nn.parameter.Parameter()を使ってバイアスパラメータを定義した場合は専用の処理が必要になる。

model = models.resnet152()

decay = dict()
no_decay = dict()
for name, m in model.named_parameters():
    print('checking {}'.format(name))
    if 'weight' in name:
        decay[name] = param
    else:
        no_decay[name] = param
    
print(decay.keys())
print(no_decay.keys())

参考資料

バッチサイズと学習率の関係について

「学習率をバッチサイズに比例して増やす」(ルール1)

という慣例があるが、これの根拠について説明する。

典拠

まず、このアイデアの出所は論文[1]だと思われる。 この論文では「学習率をバッチサイズに比例して増やす」というルールを適用すると幅広いバッチサイズで収束後の性能が良くなることを経験的に示した。

論文ではこの法則がうまくいく理由について、「バッチサイズがk倍になると、1epochあたりの更新頻度が1/kになる。1回の更新量が両者で概ね同じだと仮定すると、kステップ後の更新量に大きな差が出ると考えられる。後者で学習率をk倍すると、少なくなった更新量を補償することができるのではないか」といった趣旨の考察をしている("informal discussion"と断っている)。

DDPにおける学習率について

このルールはDDP(Distributed Data Parallel)における学習率についても当てはめることができる。 DDPでは仮想的なバッチサイズが全プロセスのバッチ数の総和となるため、個々のプロセスのバッチサイズをB、プロセス数をPとすると、バッチサイズはPBとなる。 バッチサイズが大きくなることで更新頻度が少なるなる、という性質は変わらないので、ルール1を適用すると、DDPにおける学習率はPBα / B=Pαとなる。つまり、1プロセスあたりのバッチサイズが一定の場合、学習率はプロセスの並列数に比例して設定することになる。

参考文献

Appendix: Adamにおける更新量について

論文[1]で扱っているのはoptimizerがSGDのケースだが、この解釈はAdamにも当てはまる。むしろ、Adamの場合はより物理的に意味のある解釈ができることを以下で示す。

まず、Adamは「signed SGD」の一種である。これは「学習率を乗じる前の更新量の絶対値が概ね1で、更新の符号のみパラメータごとに異なる」という性質を持つことに由来する。以下に示すパラメータ更新式を見れば明らかである。

つまり、Adamでは「1回の更新における変異ベクトルの絶対値が学習率に概ね一致する」と言い換えることができる。つまり「Adamにおけるkステップ後の移動量の総和はk * αである」と言える(ここでは簡単のために学習率のスケジュールは無視している)。

さて、元の学習率の議論に戻り、ルール1を当てはめると、以下のような設定となる。

  1. バッチサイズがBで1epochあたりのステップ数がN/B、学習率がα
  2. バッチサイズがkBで1epochあたりのステップ数がN/kB、学習率がkα

ここで1、2のケースで1epochあたりのパラメータの移動量の総和を計算すると、どちらのケースの場合もαN/Bとなることがわかる。つまり、Adamの場合は「学習率をバッチサイズに比例して増やすと、パラメータ空間における移動量が不変となり、バッチサイズに比例しなくなる」と言える。

このように、ルール1はAdamの場合は物理的に意味のある解釈ができる。

StratifiedGroupKFoldの実装を読んだ

有名なアルゴリズムの実装を読む シリーズの第二回。 今回はscikit-learnのStratifiedGroupKFoldの元のなったKaggle Notebookの実装を読んだ。といっても43行のとても短いコードである。

表記

  • n_fold: フォールド数
  • n_groups: ユニークなグループ数
  • n_labels: ユニークなラベル数

処理の概要

まず、StratifiedGroupKFoldは、以下の制約を満たすようなFold分割アルゴリズムである。

  • 各foldに割り当てられたラベルの分布が全体のラベルの分布になるべく一致する
  • 各foldに固有のグループが割り当てられるようにする。すなわち、異なるfoldには同一のグループに所属するサンプルが存在しない

これを実現するために、以下の処理を行っている。

  1. グループごとにラベルの頻度分布を計算する(n_groups x n_labels)
  2. 各グループについて、ラベルの頻度のばらつき(具体的には標準偏差)が大きいものから順にfold割り当て処理を行う

fold割り当て処理

  1. 各グループのラベルの頻度分布を試しに各foldに割り当ててみる
  2. fold割り当て後の評価値が最小になるfoldにそのグループを割り当てる

評価値は以下のように定義している。

  • 「各foldのラベル頻度と元のラベル頻度の比」の標準偏差の平均値

コストの大きいものから、評価値(=元の分布からの隔たり)が小さくなるように割り当てていくので、貪欲法のアルゴリズムの一種である。

計算量はO(n_fold * n_groups * n_labels)である。

scikit-learnの実装

scikit-learnの実装はこの実装をより汎用的に使えるようにするための処理が追加されている。 少数グループが割り当てられなかったfoldがあった場合に警告を出したり、乱数でshuffleかどうかを切り替える機能などが追加されている。

なお、shuffleした後で結局コストの大きいものから順に処理しているので、shuffleの効果はのグループ内でラベル頻度の標準偏差が一致するものの処理順序が変わる程度の効果しかない。

scikit-learn-extraのKMedoidsの実装を読んだ

概要

scikit-learn-extraのKMedoidsの実装を読んだので備忘録として残しておく。

KMedoidsとは

KMeansと同種のクラスタリングアルゴリズムで、クラスタの代表点としてクラスタの重心(centroid)でなくメドイド(medoid)を使う。メドイドは1次元における中央値(median)を多次元に拡張した概念で、「全サンプル点との距離の総和が最小となる点」として定義される。

$$\text{Medoid}=\min_{x_i} \sum_i | x - x_i |$$

アルゴリズムの概要

KMedoidsのアルゴリズムにはいくつか存在するが、ここではPAMというアルゴリズムについて説明する。

  1. BUILD: greedyなアルゴリズムを使って初期値を選択する。
  2. SWAP: クラスタの代表点以外の点の集合のうち、代表点のいずれかと交換することでコストが最小になるものを見つける。この点と代表点を交換し、クラスタの再割り当てを行う。この処理を収束するまで繰り返す。

以下ではSWAP処理について説明する。

SWAP

タスクを書き直すと、「(代表点、非代表点)のペアの集合から、両者を交換することでコストが最小になる点を見つける」となる。コストは「代表点とクラスタ内の全点との距離の総和」で定義される。したがって、計算量は O(k(N-k)2) となる(N: サンプル数、k: クラスタ数)。KMeansがサンプル数に比例する計算量なので、KMeansよりも計算コストが高い。

python擬似コードを書くと、以下のような3重のforループを使って計算する。

for h in non_medoid_points:
    for i in medoids:
        for j in non_medoid_points:
            ....

このコードはメドイドiを非メドイド点hと交換した場合のコストを(h, i)の全ての組み合わせについて計算している。jのループについては、「h, iを交換した場合のコストの変化の総和」を計算している。このコストの変化の総和が負の値になる場合はコストが現在よりも下がるということなので、交換する候補になる。最終的に(h, i)の全ての組み合わせについて、交換によるコストが負の最小値になるような組み合わせについて(h, i)を交換する。

なお、ナイーブに実装するとコストの計算に距離の計算が重複して計算してしまい、計算量が増加する。これを避けるために、scikit-learn-extraの実装では1度だけ計算すれば良いような工夫がされている。

まず、以下の3つの値を計算しておく。

  1. サンプル点のうち任意の2点間の距離: D_i, j (N, N)-行列
  2. サンプル点と、一番近いメドイドとの距離: C_i, j (N,)-行列
  3. サンプル点と、2番目に近いメドイドとの距離: S_i, j (N,)-行列

これらの3つの値を使って、「hとiを交換した場合のコストの変化」を以下のように場合分けして計算する(図1 (a)-(c))。

  1. jがiのクラスタに所属し、かつ、hがjの二番目に近いメドイドとの距離よりも近い場合
  2. jがiのクラスタに所属し、かつ、hがjの二番目に近いメドイドとの距離よりも同じか遠い場合
  3. jがiのクラスタに所属せず、かつ、hがjの最も近いメドイドとの距離よりも近い場合

上記以外の場合は交換によりコストの変化が生じないのでコストの変化は0となる。

最後に、iとhを交換することにより、新たにiが非メドイド点に変わるため、新たにiとメドイドとの距離がコストとして追加される。この時のコストの変化を以下のように場合わけして計算する(図1 (d)-(e))。

  1. hがiの2番目に近いメドイドとの距離よりも近い場合
  2. hがiの2番目に近いメドイドの距離よりも同じか遠い場合

a-eのそれぞれのケースにおけるコストの変化量は以下のようになる。

  1. D(j, h) - Cj
  2. Sj - Cj
  3. Cj - D(j, h)
  4. D(i, h)
  5. Sj

図1. コスト変化の場合分け

参考

本記事におけるKMedoidsの実装はscikit-learn-extraのものを参考にした。

github.com

8日目: 決意表明

100日後にCompetition Masterを目指す

Ottoコンペは残念ながらメダル争いの圏外だった。 とはいえ良い事もあって、GBRの時のように燃え尽き症候群が発生していない。 精神的にも体力的にも次のコンペに参加する余力が残っている。

というわけで次に参加するコンペを考えていたのだが、ここに来て1日目のブログで書いていた方針を変更しようと思う。「100日後にCompetition Masterになることは本気で目指していない」と書いたが、本気で目指してみようと思う。

理由は以下の通りだ。

  • 目標を明確にしたほうがコンテンツとして面白い
  • 同じコンテンツを惰性で続けるのはモチベーションが低下する可能性がある

このブログは筆者の脳内にある考えを言語化することが主な目的だが、読者にとっては一種のエンタメのような側面もある。エンタメとしてやる以上は、最初に目標を決めて最後どうなったかをお知らせする方が、良い結果になった時もそうでなかった時も、どっちに転んでもコンテンツとしての面白さがある。変に予防線を張って逃げるよりは、ちゃんと「有言実行した」あるいは「宣言したのにできなかった」自分を見せた方が良いと考えた。

また、そもそも「100日後に...」というタイトルにしたのは筆者自身がブログを続けるモチベーションを保つためだったが、いつまでも同じコンテンツを惰性で続けているとそれはそれでモチベーションが低下していくように思える。さっさと目標達成して次に進めるインセンティブを与えた方が、長期的にモチベーションが保てると考えた。

今後のコンペ参加方針について

また、コンペの参加の仕方についても、少し方針転換する。

これまでは、次のような方針だった。

  • 2-3ヶ月のコンペに初期から最後まで参加する
  • チームアップは基本しない

今後は次のような方針でコンペに参加するつもりである。

  1. 1ヶ月単位くらいの短いスパンでできるだけ多くのコンペに参加する
  2. ソロ銀以上のポジションにいる時に限りチームアップも検討する
  3. 単にメダルを取るのが簡単そうだからという理由でコンペを選ばない。できれば日本人Kagglerが大勢参加しているようなメジャーなコンペに参加する

1点目について、約3ヶ月の間にメダルを獲得しなくてはならないので、チャンスはなるべく多い方が良いと考えた。また、短いスパンで情報にキャッチアップしたり素早く実装することが求められるので、それはそれである種の訓練にもなる。

2点目について、これまでは「自分の好きなペース・方法論でコンペをやりたい」という理由からソロでの参加に固執してきた。しかし「1人でやっていて行き詰まった時に、打開策がないままコンペ終了まで迎えるのは、ある意味学びが少ないのではないか?」とも思えてきた。チームアップによって集合知を得ることで、一人の時よりもより多くの学びを得られるのではと考えた。とはいえ、チームメイトの実力頼みでメダルを取得するのはこのブログの趣旨に反するので、チームアップの条件を「ソロ銀以上のポジションにいる時」に限定した。つまり、目標を達成した上でさらに上を目指すためのマージである。

3点目については、やはりこのブログのチャレンジがある種のエンタメであるので、いまいちなコンペでメダルを取得しても盛り上がりに欠ける。また個人的に得られる達成感も薄い。どうせなら日本人Kagglerが多く参加しているようなメジャーなコンペで戦う方が、チャレンジとして面白いし、また良い意味でも悪い意味でも自分の今のポジションを知ることができる。

以上、今日は報告だけなので内容は短めである。

Happy Kaggling!

6日目: Ottoコンペの振り返り

11月から参加していたKaggleコンペOTTO – Multi-Objective Recommender System(通称Otto)の期間中にあった出来事について振り返っておく。

全体の感想

一言で感想を言うと、全体的にかなりハードなコンペだった。特に後半は後述するcandidate-rerank modelのゲインが全く得られず、LBで他の参加者がどんどん駆け上っていくのを見たり、ディスカッションで結果が共有されるたびに、彼らと自分の違いがどこにあるのか全く分からないまま苦しむことになった。

ディスカッションを見る限り、おそらくそれなりの数の参加者がcandidate rerank modelと呼ばれていた2-stageのモデルを採用していたと思う。 一方で、コンペ終了前1週間の時点で公開ノートブックのスコアを有意に上回るゲインを得られていたユーザはわずか4.12%と非常に限られており1、このタイプのモデルをきちんと設計するのはそれなりに難しそうに見えた。

残念ながらこの記事を最後まで読んでもこれに対する解答はない。コンペ終了後に共有されるであろう各チームの解法にヒントがあることを祈る。

CVのリークについて

個人的に後半苦しんでいた理由の一つに、CVのリークがあった。 本コンペのデータは時系列なので、未来のイベントがラベルになっており、うっかり学習データに未来のデータを含めてしまうと、CVで本来得られるはずのないゲインが観測できてしまい、モデル選択を誤る危険がある。

自分は最初、学習データへの未来データのリークについてはそこまで厳密に管理していなかった。具体的に言うと、2段目のモデルの学習データの1つ(後述するco-visitation matrix)に、本来学習時点で与えられるはずのない未来のデータを含めてしまっていた。後で調査してわかったことだが、ここには正解データの時系列を直接的に予測するための情報が含まれており、それによってCVで本来得られるはずのないゲインを観測していた。このため「CVではゲインが出るがLBではでない」問題に悩まされていた。

余談だが、後述するデータ設計ではまだ未来データをモデルの学習に使っている部分がある。これは意図的にやった部分もあるが、リークあり・なしの場合の影響について確認せずに用いており、自身の経験不足を露呈する結果となった。「CVを設計する時はリーク対策に細心の注意を払うべき」というのは、頭では分かっていてもきちんと実践するのは難しい...。

データ設計について

このコンペを難しくしているもう一つの理由に、学習・評価・予測データの設計が参加者にある程度委ねられていた点も挙げられると思う。

前述したCVのリークの話とも関連するので、以下では具体的なデータ設計の内容について記載する。振り返りの内容とは逸れるので興味がなければco-visitation matrixのパートまで読み飛ばしてもらって構わない。

共通の設計

  • trainデータを1週間ごとの4つのtermに分割する(term 0-3)
  • 各termにおけるsession2をランダムに2分割し、前半をquery、後半をlabelと呼び区別する。この命名は、前半のデータが主にモデルの学習に使われ、後半をラベルとして与えることに因んでいる。

testデータはqueryのみ与えられており、test term(term 4)におけるlabelを予測することが本コンペの主な課題である。

学習スキーム(candidate generator; 1段目)

  1. 2段目学習用の特徴/ラベル生成: term0-2のqueryおよびterm0-1のlabelを使ってco-visitation matrix(後述)を作成する
  2. 2段目評価用のラベル、および2段目の予測モデルの学習用の特徴/ラベル生成: term0-3のqueryおよびterm0-2のlabelを使ってco-visitation matrixを作成する
  3. 2段目の予測用の特徴/ラベル生成: term0-4のqueryおよびterm0-3のlabelを使ってco-visitation matrixを作成する

学習スキーム(candidate reranker; 2段目)

  1. 評価用モデルの学習: term2-3のqueryを特徴量抽出に用い、term2のlabelで学習する
  2. 評価: term2-3のqueryを特徴量とし、term3のlabelを予測する
  3. 予測用モデルの学習: term3-4のqueryを特徴量抽出に用い、term3のlabelで学習する
  4. 予測: term3-4のqueryを特徴量とし、term4のlabelを予測する

1, 3では2段目のモデルの学習を2回行っているが、これらは一般的な機械学習タスクにおけるcross fold学習と全データ学習にそれぞれ対応するものである。すなわち、1はモデルのハイパーパラメータ選択のための学習であり、3は課題ラベルの予測用の学習である。一般的に、時系列モデルは予測対象のデータと学習に使用したデータの時系列が近い方がドメインシフトの影響が小さいと考えられるためこのようなアプローチを用いた。

なお、前述したように1, 3において特徴量抽出に未来のデータを使っているが、これは本来望ましい方法ではない。「学習時と予測時で特徴量の意味を同じにしたい(変にドメインシフトさせたくない)」ということを意図してやったことでもあるが、コンペ終盤にサブミッション数も足りなかったこともあってリークのあり・なしの影響についてはは未確認であった。このように論理的に間違った手法を効果の確認できないまま実験で使用するのはただのギャンブルなのでやめておいた方が良い。

Co-visitation matrixについて

1段目のモデルにおけるco-visitation matrixについて説明する。この手法は[Vladimir Slaykovskiy]で提案されたもので、「あるユーザが期間Tの間に2つの商品を同時に参照・購入される頻度」をカウントしたものである。形式的には条件付き確率P(j | i; abs(ts(j) - ts(i)) < T)をモデル化したものとみなすことができる。これは言語モデリングでいうバイグラムに似た概念である。バイグラムが隣接する2単語の出現頻度をカウントするのに対し、co-visitation matrixは一定期間の間に同時に参照・購入した頻度をカウントする。このco-visitation matrixが非常に強力で、[Chris Deotte]ではこれを使った予測モデルでLB0.575のスコアを出しており、コンペ中盤〜終盤において多くの参加者のモデル設計の手本となった。

この手法は時系列におけるイベント間の関連を単純にモデル化したものであるが、Ottoコンペのような大規模なテーブルデータの分析タスクにおいて「計算コストが小さい割にそこそこ有効な手法」として効果が実証された。同様の時系列を予測するタイプのタスクで試す「最初の一手」の一つに加えて良いだろう。

プライベートシェアによるチート疑惑

一部のTwitterユーザはタイムラインの祭り状態で認知されたかもしれないが、本コンペではあるユーザが所属する複数のチームから「特定のチームメイトが不正に関与している疑いがある」という報告があった3, 4, 5

これらの報告から明らかになった不正行為の実態は以下のようなもと推察する。

  • 一部のチーター同士で協定が結ばれており、それぞれが別々に一般のユーザによるチームに紛れ込んで所属している
  • チーター自身は何もせずに、チームメイトの作ったコードや提出ファイルをチーター仲間からシェアしてもらい、所属するチームにはあたかも自分で作ったものであるかのように振る舞う。またチームメイトの作成したコードや提出データをこっそり他のチーター仲間に横流しする。
  • チーターは場合によっては単独でコンペに参加し、チーター仲間からシェアされたコードや提出ファイルを使ってソロメダルを獲得する
  • 上記の行動を各コンペごとに行い、メダルや賞金を荒稼ぎする

今回不正の疑惑がかけられた2名のユーザはそれぞれmasterとgrand masterの称号を有しており、特に後者は最高総合順位が11位という上位ユーザである。不正の報告が事実だとすると、これらのユーザは数年間にわたって不正を繰り返してきた可能性が高く、不正が行われていた期間と不正に(意図的、無視式的に)関わったユーザの数からしておそらくKaggle史上最悪のものになる可能性が高い。

その他のトピック

他にもコンペ開催期間中に個人的に以下のようなトピックがあったが詳細は省く。それぞれTweetのリンクになっているので、興味のある方は参照していただければ幸いである(といっても大したことは呟いていないので恐縮だが...)。

最後に近況として、Twitterでも呟いたが、チート行為に関わる一連のコメントとディスカッションでメダルを貰えたこともありdiscussion masterになった。一方、コンペではmasterにはなれない見込みなのでこのブログのタイトルはそのままになる予定である。

それでは、Happy Kaggling!

1日目: Kaggleをやる動機

はじめに

ブログが続かないので、何かテーマを決めて書き始めることにした。ちょうどKaggle Masterまであと銀メダル1個なので、「3ヶ月あればワンチャンいけるか?」ということで、このブログのタイトルを『100日後にKaggle Masterになるトカゲ』に変更した1

Kaggle Masterになるまでに考えたことやインプットしたことについて言語化する場所としたい。

Kaggleをやる動機

本日のテーマであるKaggleをやる動機について書く。

データコンペを始めたての頃は、「ワンチャン賞金取れたらいいな」という動機が何割かあった。 しかし、最近はメダルや賞金といった外発的な動機とは別に、内発的な動機でやる方が続くのでは?と考えるようになった。メダルや賞金を目標にすると、実現しなかった時に精神的にきついとか、労力に対して割に合わないと感じることが多くなって継続できなくなると感じたからだ。

自分にとってのKaggleをやる内発的動機は以下のようなものだ:

  1. 競合相手もいる中で、自分が「どの程度頑張れる人なのか」を確認するため
  2. 公開ノートブックやディスカッションから刺激を得るため
  3. 問題解決プロセスの訓練の場として利用する

以下それぞれにの項目について説明する。

1. 自分が「どの程度頑張れる人なのか」を確認する

Kaggleをある程度の時間を確保して本気で取り組んだことがある人は経験済みかもしれないが、Kaggleでそれなりの結果を出そうと思うと、作業時間的にも認知リソースの消費的にもかなりハードである。正直、最初の頃は関連資料を調べたり公開ノートブックをいくつか読んだだけでサブミットまでいかなかったり、途中でやめてしまうことがあった。 これではいけないと考え、途中から「とりあえず最後までやり切る」ということを目標に取り組むことにした2。 というわけで、数ヶ月の間モチベーションを維持し、それなりの結果を残せるということは、それだけ「頑張れる人」であると言って良いと思うのでそれを目標にすることにした。

2. 公開ノートブックやディスカッションから刺激を得るため

これは他の多くの人も言っていることなので詳細は書かない。一言で言うと、Kaggleは他のコンペと比較しても群を抜いて集合知の恩恵が得られる場であると感じる。

3. 問題解決プロセスの訓練の場として

これまでに取得した金、銀メダルがなぜとれたかを考えると、次の2点に集約される(と思う)。

  • 競合相手よりも作業に充てられる時間が多かったこと
  • 競合相手よりもインプットの量が多かったこと

まず現在の自分は(幸運なことに)それなりの期間Kaggleにフルタイムで取り組むだけの時間的、金銭的余裕がある。このことは、会社や学業の合間で取り組んでいる競合相手と比べて優位な条件である。さらに、関連手法に関する学術論文やオープンソースのツールのソースコードについてそれなりの時間をかけて読むことができたので、インプットの面で公開ノートブックを少しいじった程度の競合相手と差をつけることができたのだと思う。

ところがこれらの要因はKaggleでさらに上を目指すには十分でないとも感じている。 上記に足りない観点は、Kaggleのタスクが本質的に「試行錯誤による問題解決」を必要とするタスクであることだ。つまり、既知のオーソドックスな手法を網羅的に適用したり、単に時間を多くかけるだけでは十分な競争力を得られないようなものが多いと感じる。

自分はこれまで企業で働いてきた経験を踏まえて考えても、特にこの辺りの成功率に課題を感じているので、Kaggleコンペに取り組むことで、そういった状況における問題解決の訓練をしたいと考えている。

まとめ

この投稿では自分がKaggleのコンペに取り組む動機について言語化した。最初なので少し頑張って書いたが、おそらく毎日この分量でやると続かないので、今後は適宜サボりながら継続していくと思う。

では、Happy Kaggling!


  1. ただし、後述するように100日後きっかりにKaggle Masterになることは本気で目指していない。もし100日後に実現しなかった場合は『N日後に...』とタイトルを変更する。
  2. なお、コンペ終了後にラベルの品質について議論が醸されたコンペだったので順位は参考でしかないが、そのコンペではPrivate LBで9位(ソロ金)の結果を残すことができた。継続が思わぬ結果をもたらすこともある。