Deep Karmaning

技術系の話から日常のことまで色々と書きます

【自作パッケージ】BPMFというJuliaでbayesian probabilistic matrix factorizationができるパッケージを公開しました

概要

タイトルの通りjuliaでbayesian probabilistic matrix factorizationができるBPMFというパッケージを公開しました。

github.com

インターフェースはpythonのscikit-learn風でとても使いやすくできたかなと個人的には思います。

そこで今回はこのパッケージに関して紹介していきたいと思います。

アルゴリズムに関して

bayesian probabilistic matrix factorizationの実装には色々なアルゴリズムがあるのですが今回実装したのは2つです。

1. Gibbs sampling

Gibbs samplingはMCMCの手法の一つです。

具体的なアルゴリズムは、以下の論文に書かれている通りの内容です。

https://www.cs.toronto.edu/~amnih/papers/bpmf.pdf

2. Variational inference

Variational inferenceは日本語だと変分推論と呼ばれますが確率分布の近似手法です。

変分推論は最適化問題を解くことで未知の確率分布の近似的な表現を得ることを目標としている手法です*1

具体的なアルゴリズムは、以下の論文に書かれている通りの内容です。

https://www.cs.uic.edu/~liub/KDD-cup-2007/proceedings/variational-Lim.pdf

ただし、現状ELBO(evidence lower bound)による計算の収束判定部分は実装せず、指定した回数分計算を繰り返すようにしています*2

パッケージ使い方

ではパッケージ使い方を説明します。

まず以下のようにパッケージを読み込んでダミーのデータを生成します。

using BPMF

#data
R = [
    0 0 7;
    0 1 6;
    0 2 7;
    0 3 4;
    0 4 5;
    0 5 4;
    1 0 6;
    1 1 7;
    1 3 4;
    1 4 3;
    1 5 4;
    2 1 3;
    2 2 3;
    2 3 1;
    2 4 1;
    3 0 1;
    3 1 2;
    3 2 2;
    3 3 3;
    3 4 3;
    3 5 4;
    4 0 1;
    4 2 1;
    4 3 2;
    4 4 3;
    4 5 3;
]

データは1列目にユーザーのID、2列目にアイテムのIDといったイメージで用意してください。

次に学習ですがGibbs sampingの場合は以下です。

β₀ = 2
μ₀ = 0
D = 3
ν₀ = D
W₀ = one(zeros(D, D))
α = 2
T = 100 #number of iterations
U = []
V = []
N = length(unique(R[:, 1]))
M = length(unique(R[:, 2]))

#learning
gibbs_model = BPMF.GBPMFModel(R, N, M, D, T, U, V, α, β₀, μ₀, ν₀, W₀)
BPMF.fit(gibbs_model)

#predict new data
BPMF.predict(gibbs_model, R, 10) #burn-inとして10個のサンプルは除去

このようにscikit-learn風なインターフェースで使うことができます。

最終行では学習データ自体を予測していますが、予測したいデータを学習データと同じフォーマットで入れればば予測可能です。

Variational inferenceの場合はパラメータの数が異なりますが、データのフォーマットは同様で以下のとおりです。

N = length(unique(R[:, 1]))
M = length(unique(R[:, 2]))
D = 3
τ² = 1
L = 10 #number of iterations
U = []
V = []
σ² = []
ρ² = []

#learning
variational_model = BPMF.VBPMFModel(R, N, M, D, L, U, V, τ², σ², ρ²)
BPMF.fit(variational_model)

#predict new data
BPMF.predict(variational_model, R)

予測も同様ですがburn-inがないので若干引数が異なっていますので注意してください。

各種アルゴリズムの精度・速度比較

最後にGibbs samplingとVariational inferenceの精度(RMSE)と速度をMovieLens 100Kのデータセットを用いて比較したいと思います。

それではまず諸々の準備です。

using BPMF
using DataFrames
using CSV
using Random
using StatsModels
using Statistics
using Plots

#設定を変えて繰り返し実行するために関数を準備
function gibbs(train_df, test_df, D, t)
    β₀ = 2
    μ₀ = 0
    ν₀ = D 
    W₀ = one(zeros(D, D))
    α = 2
    N = user #ユーザー数
    M = item #アイテム数
    U = []
    V = []
    
    gibbgs_model = BPMF.GBPMFModel(train_df, N, M, D, t, U, V, α, β₀, μ₀, ν₀, W₀)
    BPMF.fit(gibbgs_model)
    
    return sqrt(mean((test_df[:, 3] - BPMF.predict(gibbgs_model, test_df, Int64(ceil(t / 10)))) .^2 )) #RMSE
end

function variational(train_df, test_df, D, t)
    N = user
    M = item
    τ² = 1
    U = []
    V = []
    σ² = []
    ρ² = []

    #learning
    variational_model = BPMF.VBPMFModel(train_df, N, M, D, t, U, V, τ², σ², ρ²)
    BPMF.fit(variational_model)
    
    return sqrt(mean((test_df[:, 3] - BPMF.predict(variational_model, test_df)) .^2 )) #RMSE
end

そしてデータの読み込みと学習・検証用にデータを分けます。

#データ読み込み
df = CSV.read("../data/ml-100k/u.data", header = false, delim = '\t')

#配列化
df = convert(Array{Int64}, df[:, 1:3])

#オフセット idの最小値を0にする
df[:, 1, :] = df[:, 1, :] .- 1
df[:, 2, :] = df[:, 2, :] .- 1

#ユニークユーザー、ユニークアイテム
user = length(unique(df[:, 1]))
item = length(unique(df[:, 2]))

#シャッフル
df = df[shuffle(1:end), :]

#学習データとテストデータ分割
N = size(df)[1]
train_size = Int64(N * 0.8)
train_df = df[1:train_size, :]
test_df = df[train_size:N, :]

そして学習します、今回はiterationの設定を10~30にしたときの比較します。

#計測
x = zeros(1000)
loss_gibbs = zeros(1000)
loss_variational = zeros(1000)
time_gibbs = zeros(1000)
time_variational = zeros(1000)

for t = 10:30
    ind = t - 9
    x[ind] = t
    loss_gibbs[ind], time_gibbs[ind] = @timed gibbs(train_df, test_df, 10, t)
    loss_variational[ind], time_variational[ind] = @timed variational(train_df, test_df, 10, t)
end

精度は以下のグラフの結果になりました。

f:id:rf00:20180921183004p:plain

青がGibbs samplingで赤がVariational inferenceとなりますが、iterationが少ないときはVariational inferenceが精度が良いです。

一方でiterationが多くなるほどGibbs samplingのほうが精度がよくなっています*3

一般に言われている結果が見られました。

計算にかかった時間は以下のグラフのとおりです。

f:id:rf00:20180921183553p:plain

Variational inferenceのほうがGibbs samplingに比べて同じiterationなら断然早くなっています。

こちらも一般的な結果だと思います。

したがってデータのサイズが大きく、計算時間をあまり取れないような状況であればVariational inferenceが良さそうですが、基本的にはGibbs samplingを使うのがいいのではないかなという個人的な印象です。

まとめ

今回はjuliaでbayesian probabilistic matrix factorizationできるパッケージを紹介しました。

まだまだ改善の余地はあるのですがぜひ使って見ていただき意見をもらえたら嬉しいです。

よろしくお願いします!

*1:ベイズ推論による機械学習推論入門 p124より

*2:今後追加していく予定です

*3:Variational inferenceがiterationを重ねるほどに精度が悪くなっているのは、本当であればELBOで収束判定しなければならないところをしていないからだと思います