糞糞糞ネット弁慶

読んだ論文についてメモを書きます.趣味の話は http://repose.hatenablog.com

Graph Convolutional Neural Networks for Web-Scale Recommender Systems (KDD 2018) 読んだ

KDD 2018 | Graph Convolutional Neural Networks for Web-Scale Recommender Systems
著者に Jure Keskovec がいる.
Pinterest における推薦にて node の embedding を graph convolution で学習する推薦手法 PinSage を提案している.タイトルだけ読むとそのように思えるけれど,実際には Graph Convolutional Network で行われるような Graph Fourier変換にもとづく畳み込みを行っていない.この点を誤解しているまたはまともに読んでない人しかいないのではないかと思う (footnote 1 で however, the architecture we employ does not directly approximate a spectral graph convolution と言及もしている).

PinSage における Graph Convolution

Convolution

今,次のような関数を考える (論文中ではこの操作を Convolution と呼んでいる).論文中の Algorithm 1 の説明では hz が未定義の状態で登場していて完全に意味不明なので論文の主張に沿って正しいと思われるコードを書く.

# node u に対する畳込みを得る関数
# z_u  : u の現在の畳み込み表現
# z_neighbors : u の近傍ノードの畳み込み表現の集合
# alpha : 近傍ノードの重み
# Q, q : importance_pooling に渡す前のパラメタ
# W, w : 最後の ReLU に渡す前のパラメタ
def covolve(u, z_u, z_neighbors, alpha):
    n_u = importance_pooling(ReLU(Q * z_neighbors + q), alpha)
    z_u_new = ReLU(W * concat(z_u, n_u) + w)
    return normalize(z_u_new)

# vectors を element-wise に weights で重み付けして平均を取る pooling 関数
def importance_pooling(vectors, weights):
    i, j = vectors.shape
    ret = [ ]
    for dim in j:
        ret[dim] = np.mean(vectors[dim, pos] * weights[pos] for pos in range(i))

    return ret

何をやっているかというと,ある node u に対する embedding をその近傍にある node の embedding をまとめて pooling し,現在の embedding と concat した上で ReLU に通している.これを深さ K まで繰り返し適用する (論文中では k 回目の繰り返しにて得られる embedding を h^{(k)} と表現している).思ったよりシンプル.

ここだけ読むとシンプルな話でいいわけですが,論文冒頭では「 node u には visual や texual な feature が付与されている」「この手法ではそれら feature を使って embedding を学習する」と書いてある.しかし上記のコードにはそれら feature に対する言及がない."We start with input node features and then learn neural networks that transform and aggregate features over the graph to compute the node embeddings" と書いてはあるがその後の記述を読むと embedding のことを feature と呼んでいて正直に言って全く理解できない.
id:another16javac さんから「GraphSAGE [1706.02216] Inductive Representation Learning on Large Graphs が参考になる」というコメントをいただき読んだところ h^{0} を特徴量 x で初期化しているのでここで使うという話だった.そしてこの論文もよく読むと algorithm 2 で同様に h^{0}x で初期化していた.恥ずかしい.

細かいテクニック
  • Pixie で行ったように u から始まるランダムウォークによる訪問回数が上位の node を近傍として用いる.また,この時の訪問回数を重み \alpha として用いる. Pixie ではこの時のランダムウォークに用いる遷移行列を node の特徴量を謎の関数に通して重み付けしていたが,まさかこれが上記の疑問に相当する?
  • 学習はクエリ q と正例 i のペア (q, i) が与えられていると考え,負例のペアより正例のペアの embedding の内積が大きくなるように学習する.
  • またこの時,負例は negative sampling するわけですが uniform にやるとほとんど関係ない負例ばかり出てきて関数が収束しない.そこで q に似ているが正例ではない負例 を hard negative item として選ぶ.また,学習の際には epoch ごとに hard negative item を段階的に増やす curriculum training を行う.
  • 学習は MapReduce. d2.8xlarge のインスタンスを 378 台並べてクラスタを作る.

Graph の convolve は分かるけどどうやって特徴量を有効活用したのかわからない.

Sequences of Sets (KDD 2018) 読んだ

KDD 2018 | Sequences of Sets
好きな研究者が何人かいて,タイトルで気になった論文の著者がその人だとちょっとうれしくなる.Cornell University の Jon M. KleinbergGoogle の Ravi KumarStanford の Jure Leskovec は気になって定期的に著者のページを見に行っている.Facebook の Lars Backstrom は久しく論文を書かなくなってしまったので悲しい.
今回の論文は Ravi Kumar が Co-Author に入っている.

集合 (set) の系列 (sequence) についてモデリングする.論文中では

  • ある人物が送信したメールそれぞれの宛先を時系列でソートしたもの
  • Stack exchange において投稿された質問に付与されたタグをユーザごとに集めてソートしたもの
  • センサーから得られた人の接触データ
  • 共著関係

を対象に分析・観察を行い,集合の系列の推定モデル Correlated Repeated Unions (CRU) model を提案している.

データの観察

  • 集合は繰り返す.多くの集合は系列において繰り返し現れるし,全く同じものだけでなく上位集合 (superset) や部分集合 (subset) も現れる
    • 系列を前から見ていった時にある集合 (と完全に同じもの | と全く要素がかぶらない集合 | の部分集合 | 上位集合) ががそれより前に現れた比率を見ると集合が繰り返して現れていることがわかる
  • 集合の要素は相関する.二つ組,三つ組の組み合わせは相関を持って現れる
    • 全集合から全ての二つ組,三つ組を数え上げるとそれらがランダムに出現する個数より多い
  • 古いものより新しいものに類似した集合が出現する
    • ある集合と,それより k 個前に現れた集合との Jaccard 係数の平均を見ると, k を大きくするほど低下する.つまり近ければ近いほど集合間の類似性は高い

CRU モデル

これらを踏まえて集合系列のモデルを提案する.
しかしここまで読むとこのモデル,系列 S_1,\cdots,S_n が観測されている状態で S_k までを用いて S_{k+1} がどのように生成されるかをモデル化している (機械学習的な外挿を行うモデルではなく,物理のように現象を理解するためのモデルのようなニュアンス).本来想定していたのは S_n までが与えられた状態で S_{n+1} を推定するモデルだったのでちょっと肩透かし.
パラメータとして長さ n であるいくつ前の集合を重視してサンプリングするかの w と集合内からサンプリングを行うための p を持つ.また, S_{n+1} の要素数も (なぜか) わかっているとする.こういう仮定のおかげで将来予測ができない.
CRU モデルの論文の説明を Python のコードで書いた.大雑把な言い方としては

  • 過去の系列をさかのぼってどの集合から要素をサンプリングするかを選ぶ
  • 選んだ集合から要素をサンプリングする
  • これが一定の大きさになるまで繰り返す

という動きをする.

# S_i の重み付き抽出に必要
from numpy.random import choice

# 長さ k の 集合の系列 S を受け取って次の繰り返し集合 R を出力するモデル
def CRU(r, w, p, S):
    R = set()
    k = len(S)
    while True:
        if len(R) == r:
            return R

        # S_i を重み w_{k + 1 - i} で抽出
        # w は重みなのでサンプリング用の確率に変換する
        p_s = [w[k + 1 - i] for i in range(k + 1)]
        p_s = [x / sum(p_s) for x in p_s]
        S_i = choice(S, p=p_s)

        # S_i から各要素を確率 p でサンプリング
        T = set()
        for s in S_i:
            if random.random() <= p:
                T.add(s)

        # この時の n は系列の「全長」 (未来の分まで含める)
        if len(R | T) > n:
            while len(R) < n:
                # T から一様に要素をサンプリング
                y = choice(T)
                R.add(y)
                T.remove(y)
        else:
            R = R | T

パラメータ推定

推定したいのはいくつ前の集合を重要視してサンプリングするかのパラメータ w (論文冒頭にて要素内からのサンプリングパラメータ p はグリッドサーチしたと言及がある).尤度の式を作ることができればパラメータの推定はできるはず.しかし集合が生成される尤度とはどういう形でしょうか.僕はすぐには思い浮かばない.
3.2 を真面目に読んでいないけれど,方針としては出力される R の部分集合すべてについてそれが生成される確率を求めてやればいい,という理解でいる.これ以上はこの論文を再実装したくなった時に読み返す.

Learning and Transferring IDs Representation in E-commerce (KDD 2018) 読んだ

KDD 2018 | Learning and Transferring IDs Representation in E-commerce
EC サイトにおける商品 (item) の埋め込み (embedding) を学習する.その際,商品につけられたメタデータをまとめて学習する.

基本方針

ユーザの商品閲覧行動にもとづいて skip-gram を学習する.すなわち,窓幅を C として

\frac{1}{N}\sum_{n=1}^{N}\sum_{-C \leq j \leq C}^{1 \leq n + j \leq N,\ j \neq 0} \log p(\textrm{item}_{n + j} | \textrm{item}_{n})

を学習する.この時

p(\textrm{item}_{j} | \textrm{item}_{i}) = \frac{\exp ({e^{\prime}_{j}}^{T} e_i)}{\sum_{d}^D \exp ({e^{\prime}_{d}}^{T} e_i)}

である.e^{\prime}\, em 次元の商品の埋め込みとして得られる.

商品と属性の埋め込み

ここで,商品には様々な属性が付与されていることを考える.論文では例として

  • ある「商品」(product,例えば iPhone X) は異なる店 (store) にて異なる商品 (item) として扱われている
  • 「商品」にはブランド (brand) が付与されている
  • 「商品」には階層的なカテゴリ構造 (cate-level1, cate-level2, cate-level3) が付与されている

としている.以降, item ID, product ID, store ID, brand ID, cate-lebel1 ID, cate-lebel2 ID, cate-lebel3 ID の 7 種類を考える (これ以上増やすことも可能).また,これを「属性」と呼ぶことにする.

今, K 種類の属性があり,\textrm{IDs}(\textrm{item}_i) = [\textrm{id}_1(\textrm{item}_i), \cdots, \textrm{id}_K(\textrm{item}_K)] とする.また \textrm{id}_1 を item ID とすると,次の式がこの論文の提案手法.

p(\textrm{IDs}(\textrm{item}_j) | \textrm{IDs}(\textrm{item}_i)) = \sigma (\sum_{k = 1}^K (w_{jk} e^{\prime}_{jk})^T(w_{ik} e_{ik})) \prod_{s=1}^S \sigma (-\sum_{k = 1}^K (w_{sk} e^{\prime}_{sk})^T(w_{ik} e_{ik}))

S は negative sampling における負例集合であり, e_{ik} は 商品i における属性 \textrm{ID} k ごとの埋め込み.属性ごとに埋め込みの次元長  m_k は変わる (この時点では全ての埋め込みは異なるものとして扱う).言ってしまえば,商品ごとの全属性の内積の総和を用いて商品の出現確率を計算する.w_{ik} = \frac{1}{V_{ik}} であり V_{ik}i の属性 k を持つ商品の個数.

更に,商品とその属性との関係も学習する.すなわち

p(\textrm{item}_i | \textrm{IDs}(\textrm{item}_i)) = \sigma (\sum_{k=2}^K w_{ik} e_{i1}^T M_k e_{ik})

とする.ここで M_k は商品 i の長さ m_1 の埋め込み e_{i1} を各属性 k の長さm_k 埋め込みに変換するための行列.ここでようやく商品と属性の埋め込みが同じものとして扱えるようになる.\sum のインデックスが k=2 から始まっているのが重要.

最終的な目的関数は

\frac{1}{N}\sum_{n=1}^{N} ( \sum_{-C \leq j \leq C}^{1 \leq n + j \leq N,\ j \neq 0} \log p(\textrm{item}_{n + j} | \textrm{item}_{n}) + \alpha \log p(\textrm{item}_n | \textrm{IDs}(\textrm{item}_n)) - \beta \sum_{k}^K ||M_k||_2)

とする.[tex\alpha]は商品自身の表現に対する重みのハイパーパラメータ,\betaM_k に対する L2 正則化のハイパーパラメータ.

ユーザの埋め込み

複雑な方法はあるけれど計算が簡単なので直近 T 個の商品の埋め込みの平均をユーザの埋め込みとする.

応用

類似商品の提示

あるユーザが直近で閲覧したいくつかの商品について埋め込みが類似する商品を列挙すればいい.

未知の商品に対する計算

未知の商品 i があるが属性が付与されているときにその商品の埋め込みが計算できる.

p(\textrm{item}_i | \textrm{IDs}(\textrm{item}_i)) = \sigma (\sum_{k=2}^K w_{ik} e_{i1}^T M_k e_{ik})

だったことを思い出すと \sigma は単調増加なので

p(\textrm{item}_i | \textrm{IDs}(\textrm{item}_i)) \propto \sum_{k=2}^K w_{ik} e_{i1}^T M_k e_{ik} = e_{i1}^T(\sum_{k=2}^K w_{ik}  M_k e_{ik})

となる.目的関数が十分に最適化されていれば p(\textrm{item}_i | \textrm{IDs}(\textrm{item}_i)) は 1 と考えられるので式変形をすれば

e_{i1} \approx \sum_{k=2}^K w_{ik} e_{ik}^T M_k^T

で値が得られる.

異なるドメインに対する転移

ここの記述が全く理解できていない.

という手続きが説明されているが,そもそもユーザの埋め込みが共有できるということは商品の体系も共通していなければならない.揃っているならばまとめて学習すればいい(ドメインの違いは属性として特徴量に持たせればいい)のではないか.論文中では Taobao を source , Hema を target としているがそもそも EC サイトとしての性質が大きく異なるのに共通で計算できているという話もよくわからない.
「cold-start なユーザに対する推薦」という話だとしても,クラスタにそのユーザを割り振る際に計算するユーザの埋め込みはどのようにして計算できているのか,という話が理解できない(そこが計算できているならばクラスタに割り振る処理は不要ではないか).

とここまで書いたところで 5.3 にて Since new users have ho historical records に気づくが,やはりどうやって新規ユーザの埋め込みを計算したのかが謎.致命的な何かを読み落としているとしか思えない.

Trajectory-driven Influential Billboard Placement (KDD 2018) 読んだ

KDD 2018 | Trajectory-driven Influential Billboard Placement

街頭広告をどのように選ぶかに取り組む。
問題設定としては

  • 緯度経度で構成される軌跡 (trajectory) t=\{p_1, \cdots, p_{|t|}\} の集合
  • 緯度軽度とコストで構成される街頭広告 (billboard)  b の集合
  • 総予算 L

が与えられ、

  • 軌跡 t のいずれかの点が街頭広告 b の半径 \lambda に入った時、確率 pr(b, t) で影響を受ける (influenced)
  • 街頭広告集合 S に対する軌跡 t への影響を 1-\prod_{b \in S} (1-pr(b, t)) とする

とするときに影響が最大になるように広告を選ぶ問題を解く。
方針としては「実データにおける多くの軌跡は短い領域の中に存在する」という観測にもとづき、同じ軌跡になるべくクラスタが被らないように街頭広告をクラスタリングして解く。

DP の話が出てきたので読むのを止めた。
こういう話結構昔からやられてそうだけど最適化の世界はよくわからない。詳しい人に解説してほしい。 (論文中では半径を考慮しなきゃいけないところが既存手法で対応していないらしい)

Customized Regression Model for Airbnb Dynamic Pricing (KDD 2018) 読んだ

KDD 2018 | Customized Regression Model for Airbnb Dynamic Pricing

民泊サービス Airbnb において, host (部屋を提供する人,ホスト) に対して「この値段で部屋を貸すと良い」と価格を提案する機能を実装するための技術.

  • 予約 (booking) が入るかどうかの予測を行う
  • その上で最適な価格を提示する

という二つの方法を取る.
この論文の貢献は以下の二つ.

  • 価格の決定方法を評価する指標を提案していること
  • その指標にもとづき価格を提示するモデルを学習する方法を考えたこと

なぜ需要の推定が難しいか

「価格を決定する」というのは非常に古典的な問題.一般的には需要関数を求めて面積が最大となるような価格 P を提案する.このとき,需要関数は価格のみの関数 F(P)である.
しかし, Airbnb では需要は価格だけではなく,時刻 t およびその物件を識別する ID id によって決まる F(P, t, id) である.それぞれの要因は次のような要素で構成される.

  • 時刻による違い
    • 季節性やイベントによって需要が異なる
    • 現在時刻と予約を予測したい時刻との差が短ければ短いほど予約されにくい (表示期間が短ければ短いほど予約されにくいという話?)
  • 物件による違い
    • すべての部屋がほぼ同じであるホテルとは異なり, Airbnb にある物件はすべて異なっている (一般的な物件に加え,城やツリーハウス,船がある).これだけでも需要が大きく変わってくる.
    • もし似たような物件に絞ったとしても,レビューが良いほうが需要が高いだろう
    • 近隣物件の需要が高まっているのなら,高評価の物件はより高い価格を提示しても利用率を下げることなく予約が入るだろう.

予約推定モデル

まずは予約されるかどうか推定するモデルを構築する.
特徴量には

  • 物件特徴量 : 物件の価格,部屋の種類,収容人数,ベッドルームやバスルームの数,アメニティ,場所,レビュー,過去の利用率,「今すぐ予約」が可能か,など
  • 時間的特徴量 : 季節性 (何月何日か,何曜日か),予約状況 (チェックインからチェックアウトまでの期間など),予測日から推定対象の日付までの差など
  • 需要・供給のダイナミクス : 近隣の予約可能な物件数,検索者数など

モデルは GBM を使う.ひとつの GBM を推定するのではなく,物件の密度に応じて区画を分け,adaptive sampling を行いながら別々の GBM を学習することで AUC がより良い値になった.

このモデルを需要関数代わりに使うとどうなるか

この予約推定モデルを価格の関数としてみなすことで需要関数として扱うことができる.この関数をそのまま使って収益最大化を A/B テストしてみたが失敗した.
この関数を需要関数としてそのまま使うことには以下の三つの問題があった.

  • データがスパースであること : データにおいて価格は大きく変化していない.たとえば 150 ドルの部屋に対して 50 ドル未満や 500 ドルを設定している人はいない.そのため,平均的な価格のデータばかり集まってしまう.
  • 物件がそれぞれユニークすぎること
  • 特徴量の依存性 : 予約推定モデルにおいて用いた特徴量のうち価格と相関を持つものがあるためうまく働かない.

価格提示モデル

最適な価格と提示価格の関係,オフラインでの評価指標

ここからがこの論文の一番おもしろいところ.
そもそも「最適な (optimal)価格」とは一体どういうことでしょうか.いま手元にあるデータには,「ある価格の物件に予約が入ったかどうか」しかわからず,このデータで学習をしてもただの「現状の価格推定モデル」が得られるだけです.「真に最適な価格」は神様しか知りません.
そこで,真に最適な価格 P_o が存在するとして,実際の価格 P とモデルによって提示する価格 P_{s} との関係を考えると以下のように整理できる.

  • もし物件が予約されて P_s < P だった場合,もしホストがモデルに従っていた場合には P_s - P 分だけ損をすることになる.なのので P_o \geq P でなければならない
  • もし物件が予約されずに P_s \geq P だった場合,もっと安ければより予約される確率が高まっただろう.よって P_o < P でなければならない.
  • もし物件が予約されて P_s \geq P だった場合,もしホストがモデルに従っていた場合 (値上げしていた場合) でも予約が入ったかどうかはわからない
  • もし物件が予約されずに P_s < P だった場合,ホストがモデルに従っていればより予約される確率が高かっただろう.しかし安すぎるとホストが損をしてしまう.

これらの関係を踏まえて,prec-recall の 表のように

  • a :  P_s \geq P かつ予約された
  • b :  P_s \geq P かつ予約されなかった
  • c :  P_s < P かつ予約された
  • d :  P_s < P かつ予約されなかった

として次の 5 つの指標を考える.これらの指標はオフラインでのモデルの評価に用いる.

  • Price Decrease Recall (PDR) : d / (b + d), 予約されなかった中で,安く提案できていた割合
  • Price Decrease Precision (PDP) : d / (c + d), 安く提案できていた中で,予約されなかった割合
  • Price Increase Recall (PIR) : a / (a + c), 予約された中で,高く提案できていた割合
  • Price Increase Precision (PIP) : a / (a + b), 高く提案できていた中で,予約された割合
  • Booking Regret (BR) :  \textrm{max}(0, \frac{P - P_{s}}{P}) の全予約での median

Price Decrease は「より安く提案できていたか」すなわち予約確率をより上げられていたかについて, Price Increase は「より高く提案できていたか」すなわちホストがより収益絵を得られたかについて考えている.
BR は提案によって収益が落ちていたであろう度合いを表している.
検証したところ,これらの指標の中での PDR と BR は実ビジネスでの指標と高い相関を持つことがわかった.特に,PDR は booking gain (予約数?)と相関を持ち,低い BR による価格提案はよりホストの収益を増加させていることがわかる.じゃあ PDR と BR だけを見て最適化すればいいかというとそういうわけにもいかない.なぜなら PDR と BR はトレードオフにあるからだ (安い価格を提案すると PDR は改善するが BR は悪化する).

モデル,目的関数

まず特徴量として

  • ホストによって設定された価格 P_i
  • 予約推定モデルによる確率 q_i
  • 予約推定モデルでは捉えきれなかった市場の需要を示す変数

を入れる.
ここで,目的関数として SVR での \epsilon- insensitive loss (ε許容誤差) のように幅を持たせた新しい損失を提案する.何度も言っているように,「最適な価格」というのを我々は知ることができないけれど,ビジネス的な観点から「最適な価格はこの範囲内に入るだろう」ということはわかるのでそれを損失関数に反映する.
目的関数は次の関数の最小化である.
\textrm{argmax}_{\theta} \sum_i (L(P_i, y_i) - f_{\theta}(x_i))^+ + (f_{\theta}(x_i) - U(P_i, y_i))^+
ここで y_i は i が予約されていたかどうかを示す二値変数, f_{\theta} は推定したいモデル,(x)^+ = \textrm{max}(0, x)
L, U はそれぞれ
L(P_i, y_i) = y_i \cdot P_i + (1 - y_i)\cdot c_1 P_i
U(P_i, y_i) = (1 - y_i) \cdot P_i + y_i\cdot c_2 P_i
とする.このとき  c_1 \in (0, 1),\ c_2 > 1 である定数.
これが何を意味しているかというと,

  • 予約されている時は価格の下限を P_i,上限を  c_2 P_i とし,その範囲内であれば損失を 0
  • 予約されていない時は価格の下限を c_1P_i,上限を  cP_i とし,その範囲内であれば損失を 0

という形の非対称な損失を考える.

需要に基づく価格設定

更に価格提示のためのモデルを考える.以下のような仮説を置く.

  • 同じ物件ならば予約確率と価格には相関がある.よって予約確率で価格を変化させる.
  • 予約予測モデルでは捉えられなかった需要の兆候が容易に反映できるようにする
  • 代表的な価格を中心にしてそこからの増加・減少分を学習する

これを踏まえ次のようなモデルを作る.
P_s = P \cdot V
V = 1 + \theta_{1} (q^{\varphi_{H}^{-qD}} - \theta_2),\ D > 0
V = 1 + \theta_{1} (q^{\varphi_{L}^{-(1-q)D}} - \theta_2),\ D \leq 0
P はホストによって設定された代表的な価格,qは予約確率,D は類似した物件で作ったクラスタにおける追加の特徴量から構築した需要の度合いを正規分布で正規化したもの.
\theta_1 は価格の増減をコントロールするパラメータ,theta_2P=P_s を出す時の微調整パラメータ.\theta_1,\ \theta_2が与えられるとこの関数は q に対して単調増加する.1 < \varphi_L < \varphi_H < 2 は定数.

学習

とはいえこれだけだと値が壊れるので
 l_1 \leq \theta_1 \leq \mu_1
 l_2 \leq \theta_2 \leq \mu_2
となるような制約を加える.
また,需要が乏しい物件には
a\theta_1 + b \leq \theta_2,\ (a > 0)
という制約を加える.
あとは SGD で学習.

PDR の話のあたり,「真の値が存在しない時にどういう数字を作れば改善してるかどうか考えられるか」の話が一番おもしろかった.気力が尽きたのでP_s = SV の話のあたりはよくわかってない (例えば additional な demand signal とは何か,とか).

声優統計コーパスのバランス文を男性が読み上げた音声ファイルが公開されました

声優統計コーパスのパラレルコーパスとして,東京大学猿渡研究室によるJSUT (Japanese speech corpus of Saruwatari-lab., University of Tokyo)がありました.
このたび,nico-opendata 音声読み上げデータセットDwango Media Village によって公開されました.
nico-opendata 音声読み上げデータセットDwango Media Village の男性研究員が声優統計コーパスのバランス文 100 文を読み上げた音声ファイルです.上記ページでは統計的声質変換に関するサーベイも記述されています.声質変換についてわかっていなかったので非常に参考になりました.
また,同研究員が音学シンポジウム2018で発表を行った「畳込みニューラルネットワークを用いた音響特徴量変換とスペクトログラム高精細化による声質変換」について,発表内容,ソースコード,および,統計的声質変換を実際に行ったデモ音声が公開されています.

せっかくなのでこれを機に様々な人々が思い思いの音声コーパスを公開する時代になると面白いと思います.

Pixie: A System for Recommending 3+ Billion Items to 200+ Million Users in Real-Time (WebConf 2018) 読んだ

[1711.07601] Pixie: A System for Recommending 3+ Billion Items to 200+ Million Users in Real-Time
Pinterest における推薦の論文.Jure Leskovec が last author に入っているのでとりあえず読む. WWW が WebConf に名前が変わったのが悲しい.

概要

超大規模なサービスである Pinterest においてリアルタイムな推薦を実現する Pixie について説明する.

手法

Pinterest ではユーザは Board の下にそれぞれの pin を保存する.実現したいのは直近のユーザの行動によって得られた pin と重みの集合であるクエリ Q に対して適した pin を推薦したい.
基本的な方針は pin と Board を二部グラフとみなしてそのグラフ上をランダムウォークする.

ランダムウォークの基礎

クエリ が 1 つだけで重みがない場合のランダムウォークについて考えてみると,二部グラフ上の かららスタートして 回二部グラフ上をランダムに渡り歩き,それぞれの pin を訪問回数 順に並び替えて返せばいい.
この手法を次に説明するように発展させていく.

ランダムウォークにバイアスをかける

まずはただランダムに遷移するのではなく,ユーザごとにバイアスをかけることを考える.隣接ノードを uniform に選ぶのではなく,ユーザごとの特徴量に従って遷移するノードを PersonalizedNeighbor(E, U) という関数で選ぶ.この関数についてはこれ以上の説明がないので詳細は不明.

複数のクエリと重みを扱う

クエリとして複数の pin とそれぞれの重みを扱う (重みはその pin に対してユーザがどういう行動をとったか,およびその行動が発生してからの経過時間にもとづいて決まるらしいが詳細な説明無し).
基本的には各クエリごとにランダムウォークを行い,クエリごとの pin の訪問回数 を保存する.
ここで重要なのは,各クエリにおいてランダムウォークの回数 を変えて とすることである.クエリの次数が大きければ大きいほどランダムウォークの回数は多くする.
と思ったらより効率的にするために early stopping を導入する.これは最低 個の pin に最低 回訪問したらランダムウォークを打ち切るというもの.これによって精度はそのままに計算時間が倍の速さになった.
(early stopping するなら重みの形はどうでもいいのだろう)

Multi-hit Booster

ただ足し合わせるのではなく, として複数のクエリから訪問されている pin を重く評価する.

グラフの枝刈り

グラフはそのままだと非常に大きいので枝刈りする.方針としては二つ.

雑多な Board を削除する

pin の説明文に対して LDA を適用して topic distribution を計算して topic vector とする.その後,それぞれの Board に直近で追加された複数の pin の topic vector の entropy を Board の entropy とし,これが大きい Board をグラフから削除する.

人気の pin を削除する

人気の pin を削除する.がただ削除するのではない.その pin の topic vector と Board の vector とのコサイン類似度を取って類似しているもののみ残す.

この枝刈りによってグラフの大きさを 1/6 にし,推薦の類似度を 58% 改善した.