[Mangakiチャレンジ] アニメ・マンガの推薦のモデル

Kento Nozawa
01 October 2017

はじめに

ビッグデータ大学っていう日本のアカデミアの人が運営している機械学習のコンペサイトがあります。

約3ヶ月の間、マンガ・アニメを推薦するタスクがあったので、やってみました。 2位でした。 残念。

タスク内容

データは3種類:

  1. ユーザが作品を見たいか見たくないか
    • ユーザ \(\times\) 作品の3値行列(見たい、見たくない、欠損)
  2. ユーザによるマンガ・アニメの評価値
    • ユーザ \(\times\) 作品の5値行列(love, like, neutral, dislike, 欠損)
    • 1.と比べてたくさんある
  3. 作品の英名タイトルと作品カテゴリ(3値)

1のテストデータがあり、見たいになる確率値を推定し、AUCで評価値。 ただし、これ以外のデータも自由に使ってよい。

以下、時系列にやったこと。

1.のデータだけ

入力が離散値、出力が分類/確率値のとき、fasttextのsupervisedがベースラインになるという信条を持っているので、それを使う。 1. のデータだけで 0.8 出たので、これを使うことに決定。

ビッグデータ大学が、カラムが1つ多くても評価して焦る。

2. 評価値

補助情報の使い方が重要なので、評価値の使い方を考える。 Kaggleで近傍のデータをいれるといいという話を見たことがあったので、それを試した。

まず、評価値は離散値なので雑に

  • dislike : -1.0
  • neutral : 0.0
  • like : 0.6
  • love : 1.0
  • 欠損: 0.0

とした行列を作る。 一応値を変えてみたけど、これが良かった。 離散値を実数値に変換した行列をもとに、cosine similarityを計算し、各ユーザと各アイテムについて20近傍を計算。 これを使って入力を

  • 作品w
  • ユーザu
  • 作品wの20近傍の作品集合
  • ユーザuの20近傍のユーザ集合

とする。

これを以下のモデル(Keras)の入力とする。

emb_dim = 128
top_k = 20

user = Input((1,))
work = Input((1,))
user_emb= Embedding(num_users, emb_dim)(user)
work_emb= Embedding(num_works, emb_dim)(work)

topk_users = Input((top_k,))
topk_items = Input((top_k,))
top_k_users_emb = Embedding(num_users, emb_dim)(topk_users)
top_k_works_emb = Embedding(num_works, emb_dim)(topk_items)

avg_top_k_users_emb = GlobalAveragePooling1D()(top_k_users_emb)
avg_top_k_works_emb = GlobalAveragePooling1D()(top_k_works_emb)

main = Add()([user_emb, work_emb])
aux = Add()([avg_top_k_users_emb, avg_top_k_works_emb])
aux = Reshape((1, emb_dim, ))(aux)

x = Concatenate()([main, aux])
x = BatchNormalization()(x)    
x = Dropout(0.5)(x)
x = Dense(emb_dim, activation=K.cos)(x)

y = Dense(1, activation='sigmoid')(x)

model = Model(inputs=[user, work, topk_users, topk_items], outputs=[y])
model.compile(loss='binary_crossentropy', optimizer='adadelta')

x = Dense(emb_dim, activation=K.cos)(x) を最初reluにしていたが、MNISTでcos性能がいいのを思い出したので、使ってみたら0.83を超えた(reluだと0.82)。

optimizeradamだと3 epochくらいでoverfitして使えなかったのでadadeltaを使っていた。

3. 作品の補助情報

いきなり増えたデータ。

色々あって試せなかった。 締め切り直前にやった感じでは、単語をそのままEmebeddingsにいれても微妙で、 カテゴリをEmbeddingsにしたら0.84いけそうだった(学習中に締め切りがきたので未提出)。

おわりに

1位の方のスコアを見ると、仮に提出できていても2位のままなので、もっと別の工夫が必要だと思いました。