はじめに
AtCoder上で開催されたフューチャー社主催のヒューリスティックコンテストHACK TO THE FUTURE2022(HTTF)に参加した*1。問題等詳細は以下を参照。
この問題は大きく分けて各作業者のスキル推定と作業スケジューリングという2つの要素があるが、その中でもスキル推定の方に以前から気になってたリーマン多様体上の最適化なるものが使えそうだったので試してみたというのが今回の話。実のところ自分も多様体は何ぞやとか数学的なことはよく分かっていないが、今回行った単位超球面上の最急降下法であればそこまで難しくないし、以下の資料を参考に比較的簡単に実装できる。
http://www.orsj.or.jp/archive2/or60-9/or60_9_549.pdf
結果としては割とうまく推定できるが普通の最急降下法でやった場合とスコア的にはさほど差がなく、最終的にはスコアが高く出た普通の最急降下法を採用した(誤差範囲の気もする)。
以下、具体的行ったことを書いていく。
スキル推定問題の定式化
問題全体は上記のリンク先を見ていただくとして、ここではスキル推定問題について定式化をしておく。スキルは作業者間で独立なので、ここでは1人の作業者のスキルを推定する問題を定式化する。 作業者は種類のスキルを有しており、その番目のスキルをとする*2。また、タスクの要求スキルも同様に種類あり、タスクの要求スキルをとする。そして、実際にその作業者がタスクを実行したときにかかった時間はであり、この時間はなら、ならこの値にの乱数を加えたもので得られる(この場合も以下になるならとする)。個タスクが作業者に割り振られ、が得られているので、この集合から作業者のスキルを推定したい。
ということで、このスキル推定問題を2乗誤差最小化問題として以下のように定式化する。
ここで制約付き最適化になるとややこしいので、という制約はつけず負値を取ることを許して、式の中で絶対値を取るようにしている。
通常の最急降下法でスキル推定
最終的に採用したのはこっちの方。式(1)の中にmaxやら絶対値やらが入っているので一部の人から怒られそうだが、気にせずで微分して勾配を求める*3。
ただし、とは次元のベクトルで、その番目の要素をそれぞれとすると
である。また、はアダマール積を表す。スキルはこの勾配を用いて、
という更新式を適当な回数まわして推定した。本来なら収束判定を勾配のノルムとかで行うべきだが、手を抜いてループ回数を固定している。また、ステップ幅についても本来なら線形探索などで適切な値を求めるべきだが、これまた手を抜いて適当な値に固定している。
超球面上の最急降下法でスキル推定
ここからが本題。すぐ後に示すように式(1)を少し変形するとノルム制約の最適化問題が出てくるので、そこに超球面上の最急降下法を使った。
スキルの成分分解
問題文をよく見ると真のスキルの生成方法が書かれている。これを見ると、という式で生成されている。従って、ノルムがのベクトルと実数を用いて、と書くことができる。 これを使うと式(1)は
というとに関する最適化に変換される。 この式(4)の最適化のため、を固定してを最適化する処理と、を固定してを最適化する処理を交互に繰り返す方法を取った。
の最適化
を固定すると、式(4)はについて凸な関数になる。また、は1次元の実数。ということで三分探索で最適解を求めた。ただ、タイムリミットの関係上三分探索のループは5回にしてるので、かなり粗い探索になっている。
の最適化
はノルムがという制約条件があり、これはが単位超球面上に存在する制約だといえる。 このような制約条件つき最適化問題に対しては様々なアルゴリズムが提案されているが*4、今回は冒頭で挙げた資料の通り超球面上での制約条件なしの最適化問題とみなす手法を実装した。
まずは一応式(4)のに関する通常の勾配を書いておくと、
ただし、
となる。この勾配方向に式(3)のように動かしても、超球面のことは全く考慮されていないので明後日の方向に行ってしまう可能性がある。ということで、
ということを繰り返すのが当該のアルゴリズム。以下もう少し具体的に書く。
動かす方向
今超球面上の点にあって、そこから動かす方向を決める。における接平面の法線ベクトルはである。この法線ベクトルが張る空間の直交補空間は接平面に平行な部分空間(接ベクトル空間)であり、のその部分空間へ直交射影したベクトルをとすると、
となる。これを用いて、
にまずは動く。こうすれば、とりあえずは接平面に沿った移動になるので、超球面から離れないという観点で言うと少なくとも方向に移動するよりはマシになるはず、というのが直感的な理解。なお、はステップ幅でこちらも本来は(曲線)探索するべきだが実装では手を抜いて固定値にした。
超球面へのレトラクション
式(7)で得たは、それでもやはり超球面からははみ出ている。従ってこれを超球面上に戻す必要がある。この操作をレトラクションと呼ぶ。これは単純にのノルムで割ればよい。よって、
としてを更新できる。
結果
seed=0の時のビジュアライザ動画を貼りたかったけどはてなブログに動画がアップロードできなかったので、最後の状態を画面キャプチャした画像を貼る。
うーん、どっちがいいとも悪いとも言いにくい。結局のところそこまで変わらないので、処理時間的にも短い通常の最急降下法を最終的に採用したわけだが。気持ちとしては後者の方がテクくて好きだったので何とかして採用したかった。。。
大半の人はスキル推定に焼きなましやMCMCを使っているので、実際のところそちらの方がいいのかもしれない。
あと、これを書いてて思ったが、振られたタスクの要求スキルが小さいと各スキルは過小評価されるので、最初のうちは満遍なくいろいろなタスクを振ってスキル推定の精度を向上させた方がよかったかもしれない。
ちなみに
作業スケジューリングについては、重み付き二分マッチング問題を誰かがタスクを終える度に実行して作業の割り当てを行った。この際、辺の重みは予測される作業時間に加えて、なるべくそのタスクを終えることで次に実行できるタスクが増えるように調整している。 スキル推定はそこまで重要じゃない気もするので、作業スケジューリングの方にもっと時間を割いて考えるべきだったかもしれない。
所謂ヒューリスティックコンテスト形式のコンテストはAtCoder Heuristic Contestが始まってからまともに参加するようになったが、今回のように連続最適化の手法も使えるコンテストがたまにあって中々楽しい。