前提
以下に示すようなことを機械学習を使って行っているのですが、なかなか精度が上がりません。
似たような事例が過去にKaggleや何かで出ていないでしょうか。その時の優勝者のコードなどを参考にしたいと考えています。
もしくはこうしたらいいんじゃない?というアイデアも欲しいです。
どうしたらいいかひたすら考えている一方、こういうタスクって絶対他にも過去にあったんじゃないのかなという気がします。
機械学習やデータサイエンスは本業ではないので、正直過去の事例や機械学習のことに関してかなり疎いです。なので皆さんの知識をお借りしたいです。よろしくおねがいします。
実現したいこと
- ランク学習で扱うような、クエリとそれに対応する複数の文書のデータセット。
- 特徴量は画像ではなくすべて数字で与えられるデータ。
- 各クエリの持つ文書たちが正解ラベルとして取りうる値は、0,1の2値。
- 各クエリ内のほとんど全ての文書の正解ラベルは0。
- 各クエリの持つ文書の中に正解ラベルが1の文書は1個あるかないか。
- 各クエリ内で、正解ラベル1の文書に対し、一番高い出力(予測確率など)を与えたい。
- 正解ラベル0の文書の順番や出力の値は全く気にしない。とにかく正解ラベル1の文書を各クエリ内で1位にしたい。
- 機械学習モデルの出力の値の大きさや文書間の値の差などは気にしない。とにかく各クエリ内の文書リスト順位の1位に正解ラベル1の文書が来てほしい。
- 当然、全ての文書に同じ出力を与えてしまうと、正解ラベル1の文書は1位にはなれるが、同率1位の他の文書だらけになってしまい、これだと意味がない。
試したこと
初めはクエリごとに見ずに、単純な2値分類として扱って、未知データに対し正解ラベルが1っぽいか否かを当てるようにしていました。ただ、クエリごとに見たときの順位が大切なので、正解ラベル1の文書を1だと予測できても、同じクエリ内の正解ラベル0の文書を、より高い予測確率で間違えて1だと判定してしまうことがあり、これが課題点でした。
この問題を解決するために現在はランク学習を用いています。
直面している問題
ネットなどで記事を見ても、扱うデータがバイナリーというケースが見当たらず、どうしようかと露頭に迷ってる状況です。
具体的には、LightGBMでのランク学習、PyTorchでのランク学習を試しています。NDCGで損失関数(クロスエントロピー)の勾配をスケーリングするLambdaRankという手法(正解ラベル1が高い順位になるようにというのを期待している)を行っているのですが、現在以下のような問題に直面しています。
- 各クエリ内のほとんど全ての文書の正解ラベルが0であるため、全て0と予測してしまえば損失関数を低くでき、かつクロスエントロピーの勾配はほとんど0であるため、そこから学習が進まない。このとき全ての文書が同率1位
- (PyTorchで)学習エポックの1回目の結果で学習の進み方が大きく変わる。殆どの場合一回目から上記のようにすべて0と予測してしまい、勾配もほぼ0のため、そこから動けない。たまに1回目で何故か全クエリの1割くらいはうまく予想できている時があり、そのときは学習が進む。だけどLightGBMの結果には及ばない。(optimizeの問題なのか根本的にアルゴリズムの得意不得意なのか)
- (PyTorchでは未確認)学習がうまく進むと多くのクエリで1位に正解ラベル1の文書を持ってこれるが、クエリの中にはそもそも正解ラベルが0の文書しか持たないクエリもある。このようなクエリを切り捨てたいが、モデルの出力(予測確率など)でカットをかけてもあまり改善しない。ランク学習はクエリ内で文書の順番が正しくなるようにモデルの出力を与えるが、異なるクエリ間でモデルの出力に一貫性はない?(例えばモデルの出力が、クエリ1[文書A:0.9 文書B:0.6 文書C:0.1]), クエリ2[文書D:0.7 文書E:0.3]であったとき、クエリ1の文書Aとクエリ2の文書Dとでは、文書Aのほうがより正解ラベルが1らしいと言えるか?)
まだ試していないけどアイデア
- ほとんどの文書の正解ラベルが0であるせいで学習が進まない→Focal Lossのような損失関数を使う。/正解ラベル1の文書の予測確率での損失関数の勾配をモデルのパラメータ更新に使う。
- 同率1位が邪魔→1位の文書の数を減らすような自作メトリックを考える。/正解ラベル1の文書に対するモデルの出力と、他の文書の中で最も高い出力を持つ文書とを比較して、正解ラベル1の文書が、その他の文書の中での1位より高い出力を得られるような自作メトリックを考える。/これらのメトリックはおそらく離散的で微分不可能なので直接損失関数にはできないが、NDCGの代わりにこれらでクロスエントロピーの微分をスケーリングしたら損失関数に組み込める?
あなたの回答
tips
プレビュー