MATHEMATICS FOR MACHINE LEARNING の読書記録

いくつかの Kaggle competitions を経験し数学の復習が必要だと気づいたので Mathematics for Machine Learning を読む。まずはトライアルで2章を読み切る。新・数学の学び方 を参考に以下のルールで読みすすめる。

  • 数式を完全に分かるまで追う。
  • 実際に手を動かして同じ式変形をする。分からない場合は覚えるまで式変形を繰り返す。
  • 記録をここに残す。
  • どうしても分からないところは誰かに質問する。
  • これがうまくいくようであれば仲間を募る?
  • https://mml-book.com

読後の感想など

数字

  • 355 ページ 12章
  • 70日
  • GoodNotes の手書きノート407ページ

なぜ読んだか

冒頭にも書いたが Kaggle Indoor コンペでチームメイトの Saito さんのやっていることが分からなかったのが直接の動機。それ以外にも Discussions で線形代数の基礎が分かっていれば深い理解が得られそうな場面もあった。 なので機械学習をからめて線形代数を網羅的に勉強したかった(正確には復習)。

何を得たか

以下の2つが大きい。

  • 70日間ほぼ毎日、数式を書く・追うことを繰り返して勘を取り戻していった(助けて下さった Twitter の皆さんには感謝しかない)
  • 網羅的に勉強したのだから大丈夫。という謎の安心感。(これはCSを網羅的に学習したときも感じた。)

Twitter での記録 (上が最新)

  • すべてのノート
  • 12章
  • 11章
  • 10章
  • 9章
  • 8章
  • 7章
  • 6章
  • 5章
  • 4章
  • 3章
  • 2章

    • 2021/6/16 朝。Exercis 2.20 終わった。 e と f の答えが合わず悔しい。どこで間違った。これにて2章読了。合計20日・ノート117ページ。サポートしてくださった。@Ak141J, @kengohirachi, @__garzon, @NeXTSTEP2OSX, @TwShotaro , @melonsode (敬称略)本当にありがとうございました。3章も挫折禁止でいきます。
    • 2021/6/15 夜。Exercise 2.20 d まで。もう少し
    • 2021/6/15 朝。Exercis 2.15 G={(a-b, a+b, a-3b)|a,b∈R} の basis の求め方が分からない。(a-b, a+b, a-3b) が basis かとも思ったが a,b∈R なので定まっていないから違う。(a-b, a+b, a-3b) = (a-b)[1 0 0]T + (a+b)[0 1 0]T + (a-3b)[0 0 1]Tと書けるから the canonical basis でよいのだろうか
      • 良くない。詳細は__garzon@さんのコメント。
    • 2021/6/14 Kengo Hirachi (@kengohirachi) さんによるヒント で Exercise 2.12 光が見えた。本当に感謝。
    • 2021/6/13 Exercise 2.12 で突然 basis of U1 ∩ U2 を求めろと言われお手上げ。そもそも intersection について言及なかったはず。
    • 2021/6/12 Exercise 2.5 まで。2.2 はぱっと見の難しさがすごい。読み解くとギリギリ分かる範囲。
    • 2021/6/11 (1) Rank Nullity Theorem の唐突感。何がうれしいのか分からず戸惑う。(2) Affine subspaces のところで間違いを見つけて errata 見たら修正されてた。(3) というわけで2章は Excercises を残すのみ!
    • 2021/6/10 Image and Kernel の Definition 2.23 まで。Basis Change は数式が多かった。おかげで飛躍が少なく理解しやすかった。Kernel/null space と書いている割に文脈によっては null space を多用しているけど ker(φ) と。面白い。
    • 2021/6/9 Theorem 2.20 (Basis Change) の途中。やりたいことの背景は分かるのであとは式を丁寧に追うだけのはず。
    • 2021/6/8 (2.94) は https://twitter.com/Ak141J/status/1401922706858135554 において @Ak141J さんが教えてくださった。方法で完全に納得しました。
      • 2021/6/10 更新。Nyoho@NeXTSTEP2OSX さんに間違いをご指摘いただいたので修正。このスレッドから追える。
    • 2021/6/5 式 (2.94) がやはり分からない。あいまいな理解を減らすために 2.7.1 を全体的に見直して 2.94 直前までは理解できたのだが分からない。明日もうすこしネットで同じ内容のものを探そう。
    • 2021/6/3 (2.94) まで。Example 2.21 がが理解出来ないので明日も続ける。任意のx∈V, y∈Wのlinear mapping について話していたのにいつの間にか basis の変換の話に。
    • 2021/6/2 (2.84)まで。generating set, basis, rank 。新しい概念がたくさん。rankは分かったような分からないような。
    • 2021/6/1 (2.76)まで。Linear Independence をクリア。定義、例、直感的な説明、手を動かしてようやく理解できた気がする。
    • 2021/5/31 Example 2.12 まで。Example 2.12 内の The intersection of arbitrarily many subspaces is a subspace itself. がしっくりこない。

      • Kengo Hirachi (@kengohirachi) さんによるコメント 参照。いつもコメントくださってありがたい。
    • 2021/5/30 事情により時間を取れず

    • 2021/5/29 式(2.64)まで。Gaussian Elimination の計算に苦労した。Group を学んでからの Vector Spaces の定義は分かったような分からないような。
    • 2021/5/28 式(2.53)まで。きちんと追えたと思う。
    • 2021/5/27 式(2.45)まで。式(2-40)から(2-43)が最初全然分からなかった。Ax=b の解 x=x' 。Ax=0 の解 x=x'' はA(x'+x'')=b を満たすので x'+x'' は Ax=b の解であることは分かる。だがなぜそれが一般解なのか。Ax=0 を満たす解を2種類求めているのはなぜなのか?が分からなかった。
    • 2021/5/26 式(2.37)まで。さすがに覚えている内容だが式をきちんと追った。
  • 1章

    • 2021/5/26 本書の読み方的な章。

Indoor Location & Navigation コンペ振り返り

Indoor Location & Navigation というコンペで9位入賞。目標だった Kaggle Master になったので振り返り。これはチームメイトである @KaggleSaito さんとの成果である。

どういうコンペか?

与えられたスマホセンサーデータ(Wifiなど)からショッピングモールでのフロアと位置を推定する。これがうまくいけば、例えばイオンモールの無印の近くにいるときに適切なクーポンをユーザーに届けられるかもしれない。

評価指標

f:id:higepon:20210518172323p:plain 大まかに言うと真の (x, y) との距離が小さければよい。何階か?を外すと大きなペナルティ。

自分のモデル

f:id:higepon:20210518172433p:plain 他のチーム同様 Wifi データをメインに LSTM/GRU のモデルで位置を推定し、post processing で精度を高めた(大きな画像へのリンク

他のチームとの差別化要因は

  • Training Data を水増しできたこと。コンペの host が提供する utility 関数に ``compute_step_postion``` という関数がありセンサーデータを人間の歩み(step) に変換できる。これを以下で述べるアプローチと組み合わせると精度が上がった。
  • Kouki さんが Shareししてくれた Wifi データを LSTMにに入力する方法の視点を変えて、より自然な waypoint ベースの training set を生成した。
  • Saito さんの提案ではじめた Pseudo Labeling がよく効いた。
  • LSTM/GRU の Stacking。
  • Saitoさん主導の Post Processing。
    • floor image を利用しての hallway map を作成。
    • hand labeling ではない waypoint の生成

試したがうまく行かなかったもの

  • Transformer
  • hallwayからハズレた場合に大きなペネルティを与える custom loss(実装大変だった)

作業環境・実験管理

  • Colab Pro のハイメモリをメインで使った。データのサイズが大きくメモリに載せるのが大変だった。ML力よりもエンジニアリング力がある自分としてはとても有利だったと思う。
  • Colab Pro は notebook 機能はほぼ使わず。安価に GPU が使える実行環境として利用した。
    • 実行環境の入出力(データセット)は API を利用して Kaggle Datasetを使う
      • 以前は Google Drive だったが圧倒的に Kaggle datasetののほうが良かった。
    • 実行ボタンを押すと、Kaggle dataset からデータダウンロード、実行 scriptを git からチェックアウト。学習が終わったら結果を Kaggle dataset にアップロード。
    • 各実験ごとに番号を振り、その notebookで実行ボタンを押せばすべてが再現するようにした。
    • コーディングは Localの Visual Studio Code on Macで。
      • Docker は非力なローカルマシンでは足枷にしかならなかったので今回はやめた。

自分が伸び悩んでいたところがわかった

自分は長らく金メダルが取れずに伸び悩んでいたのだが。どうすればよかったのかがようやく分かった。

データをよく見ること

EDA しよう。データを良く見ようとはよく言われることだ。本にも書いてある。分からないなりに EDA notebook を作り visualize したことは何度でもあるか正直ピンときてなかった。今回うまく行った方法は、他人が書いたデータプロセスコードを行レベルで完全に理解し数倍に高速化すること。その過程で「分かった」と思っていたが全然肌感覚で理解していなかったデータの関係が見えてきた。そして高速化・自分のコードに書き直したことでその先のステップに進みやすかった。

ツールや API への習熟

これも当たり前すぎるかもしれない。有名な Grand Master Abhishekさん のYouTube 動画を見たときに衝撃を受けたのを覚えている。pandas の各種機能 keyward 引数など調べずにスラスラ書いていた。一方自分はすべて検索しながらコピペしながらである。

このコンペでは上記の高速化があったので、たくさんコードを書いた。今なら何も見ずに pandas の groupby や LSTM モデル・データセットのコードを書く自信がある。

Visual Studio Code キーバインディング微調整

  • Command Palette にアクセスするキーバインドが動いていない気がする
    • ctrl + ; に割り当てた
    • when expression を空にしないと動かなかった
  • Go to Definition
    • cmd + t
  • Go Back
    • cmd + r
  • Ctrl x b が効かない。
    • Karabiner-Elements がバッティングしてた。Karabiner-Elements の設定から Ctrl-x as prefix を消した。

Riiid コンペ復習 - maskingなど

これは Riiid! Answer Correctness Prediction | Kaggle において自分が理解できていなかった部分をまとめるもの。間違いを含む可能性がある。間違いを見つけたら @higeponja にお知らせください。

Riiid はいわゆる time series コンペ。きちんと masking をしないとleakage が発生する。このあたりの自分の理解をまとめる。

未来の情報を使ってはいけない

train/infer 時のマスク

未来の情報を train/infer 時に使ってはいけない。これを厳密にやらないと leakage になる

  1. Transformer の attention で未来を見てはいけない。例)問題番号 102 の正解・不正解が分かれば、以前の問題101の予測は簡単になるかもしれない。いわゆる triu マスク。
  2. task_container_id を共有する問題は、すべての問題を解き終わらないと答えを知ることができない。これは Riiid 固有の話。そのため未来を参照しないマスクとあわせてもう1つマスクが必要。下記 task mask 参照。src_mask, tgt_mask, memory_mask すべてに同じマスクが必要。

Riiid-2

train & validation split

厳密には train/valid を split するときに task_container_id を分断してしまうと leakage が発生する。これの影響は軽微であるというコメントもあった。なぜならそれは分断面のみで起こるからデータが大きければ影響が少ないからだと思われる。

pad を参照しない

loss 計算時に pad 部分を mask する。

auc 計算

今回の Transformer 系の解法ではデータを右側に寄せる解法が多かった。これは長さの異なる input でも必ず seq[-1] が求める prediction になるから。このことから auc 計算時にはseq[-1] のみを計算対象とするべきだったようだ。

間違い、新発見があれば追記するかも。

Google Football コンペ

銅メダルでした。

  • 以前のRLコンペから学んでやらなかったこと
    • DQN などの自前実装:自分の学習のためなら良いが、自前実装はバグりやすくたくさんの罠がある。すでに動いているベースラインが運営から提供されているのでそれを使う。そうすれば reward / observation の調整などの本質に集中できる。本コンペの場合は seed_rl ベースの notebook が提供されていた。
  • 初挑戦したこと
    • seed_rl を利用することで GCP の AI Platform に詳しくなった。間違った configuration で高額課金になってしまうことを恐れていたが、きちんと document を読んでいけば怖くないよ。
  • やってよかったこと
    • 論文と関連研究の読み物。これにより成功しそうな施策のリストができた(例:difficulty を徐々に上げる adaptive learning)
    • GCP フリークレジットへの申込み。コンペの途中でわかったことだが football は GPU ではなく CPU heavy な training プロセスだった。GPU P100 1つにつき n1-standard_96 * 4 の構成で学習させる。これはクラウド以外ではほぼ不可能だった。
  • 失敗したこと
    • 失敗ではないが GCP クレジット(or お金)がもっとあれば training で試行錯誤できた。
    • seed_rl を TPU で動かすことが競争優位性となると思いがんばったが、実質不可能だった。早めに運営に質問すれば良かった。
  • 大まかな試行錯誤の流れ
    • 初期段階では自分のベースラインを作ろうと思い pfrl で簡単にデモを書いた。discussion で質問するにつれて seed_rl に勝てる部分がないことに気づき捨てた。
    • observation については以前の RL コンペから直接画像を入力するのは問題外だとわかっていたので SMM を time series で 4 つ stack したものをそのまま利用。結局 observation を変更することはなく最終日までこのままだった。ちなみに stacking することを submission コードで考慮していなかったので序盤に score が伸びず悩んだ。
    • reward はこれも score,checkpoint の両方がすでに用意されていてそれらがベースになった。kyohei さんが中盤から checkpoint reward を減衰させるコードを書いてくれた。agent が点数を入れられるようなってからは checkpoint は逆に足かせになるから。
    • 最初から hard 相手に training するよりも徐々に対戦相手を強くしていくほうが学習効率と最終的にもっと強くなるらしいので試してみた。アイデアは簡単だが実装は gym env の理解が必須だったので真面目に取り組んだ。がんばれば difficulty を動的に変更できたので良かった。
  • GCP + seed_rl でのトレーニン
    • seed_rl は強化学習フレームワークで learner (GPU) と複数の actor からなる。actor は episode を play するわけだが自分の action を決める場合の inference を自分自身では行わず GRPC で learnerで行うことで学習を scalable にするところが肝であった。
    • learner の GPU を使い切るには actors の数が物を言った。vcpu を 96 個つんだ instance を 4つかうという富豪構成。フリークレジット $1000 をもらえたとはいえかなりの制約だった。
  • team のメリット
    • kyohei さんに声をかけていただいてチームを組ませていただいた。ほぼ毎日 slack で議論して試行錯誤した。進捗の共有には dynalist を使った。チームを組むと自分に足りないものがよく見えてとても勉強になった。自分はもっと深くものを考えないといけない。つい浅はかな考えを元に手を動かしてます。
    • もう一つのメリットはやはり心が折れないこと。仲間がいるとがんばれる。

Visual Studio Code + Docker for Kaggle

Kaggle 用の docker image が公開されているのでそれを Mac 上の Visual Studio Code 使う。

  • やったこと
    • Remote-Containers という拡張を入れて拡張経由で docker を使う。これは host と container 内の両方で Visual Studio Code を起動するので開発環境=実行環境になりうれしい。
    • devcontainer.json に Container で起動する Visual Studio Code にインストールしたい拡張の記述
  • 諦めたこと
    • Container 内で GitHub に push などをやろうとした。.git_config の共有、credential を環境変数で渡すなど。どれもうまく行かなかったのでやめた。よく考えれば host 側のファイルシステムを mount させてhost 側で commit すれば良い
    • 非 root ユーザーでの実行。tutorial に従ったが home directory が permission error で作れなかった。深堀りはしなかった。
  • 想定する開発フロー

Karabiner-Elements

Karabiner-Elements を使っていたのだが Visual Studio Code で有効になり困っていたので入れ直す。

で教えていただいたことを元にきれいにインストールした時のメモ。

現状の問題点

macOS 上で Emacs キーバインドが使えるのは良いが、Visual Studio Code で有効になると困る。なぜならば VS Code では別途 Emacs キーバインドが用意されておりそちらを優先したい。

クリーンインストール

  • ~/.config/karabiner を別の場所に退避
  • Karabiner-Elements 設定 - Misc - Uninstall Karabiner-Eelements
  • mac 再起動
  • macOS の素の状態を確認
    • Ctrl-W は効かない。
    • Ctrl-F や Ctrl-B などは効く。これは macOS の機能?
  • Visual Studio Code で Ctrl-X Ctrl-F や Ctrl-X B などが効くことを確認。
  • Karabiner-Elements を公式サイトからインストール

設定

  • 起動
  • Version 13.1.0
  • Complex Modifications - Add Rule - Import more rules from the Internet
  • Emacs key bindings (rev 12) の上4つを有効にする。

f:id:higepon:20201108155433p:plain

追記

number1cruncher.com にある mark region とか ctrl-y を取り込む。 https://github.com/higepon/dotfiles/commit/c912fdd6624354d373426c8dc3d3920658fc4f2e#diff-0dc7a7cc6b2e4051d7e9ecd928e8af90f31115dc774b182451abf6b496ba3762