temple

機械学習と周辺知識を整理する

生成型推薦は何を生成している?

1. はじめに

近年の推薦システムでは生成型推薦(Generative Recommendation) という設計パラダイムが台頭しつつあります。生成型推薦は単一のモデル構成や推薦手法を指す言葉ではなく、「生成」によって何を達成しようとするかは論文やシステムによって異なっています。

本記事では「ユーザー行動を条件としてアイテム・識別子列・行動列を直接予測する設計」を狭い意味での生成型推薦として扱い、次の二つのテーマを取り上げます。

  • Semantic ID などのコード列を自己回帰的に生成して候補アイテムを得る生成型リトリーバル
  • ユーザー行動を長い系列として逐次変換・予測する大規模行動系列モデル

なお「LLM を使えば生成型推薦と呼ぶ」というわけでもないため、LLM を生成的ではない用途で推薦システムに組み込んだ例として LLM ベースの ranker モデルも取り上げ、生成型推薦と対比してみます。

まずは従来の産業用推薦がどのようなものなのかを確認した後、それぞれの設計上の狙いを見ていきながら生成型推薦は何を生成しているのかを掴んでいきます。

2. 従来の産業用推薦システム

2.1 two-stage recommender で大規模カタログを扱う

大規模なカタログを持つオンラインサービスでの推薦では次のような two-stage recommender を構成するケースが多いでしょう。

候補抽出→ランキングを行う two-stage recommender の構成

第一段階の候補抽出では数百万件とあるカタログから数千件程度のアイテムに絞り込みます。ここでは全アイテムを1件ずつ精査するわけではなく、クエリとなるアイテムやユーザーの embedding を使って近似近傍探索(ANN: Approximate Nearest Neighbor)によって絞り込みを行います。

第二段階のランキングでは抽出された候補アイテムに対してスコア付けを行います。スコア付けの対象となるアイテムはたかだか数百〜数千件程度のため、ユーザーやアイテムのリッチな特徴量を使ってサービスの KPI を改善するように学習された機械学習モデルによって順位の最適化を行い、最終的にユーザーに提示するアイテムを決定します。

この候補抽出とランキングによる分業は高品質な推薦機能を高速に提供するため、産業用推薦システムでの実用的な構成となっています。

2.2 Two-Tower モデル

Two-Tower モデルの基本的な構成

候補抽出の代表的な手法として Two-Tower モデルがあります。Two-Tower モデルはユーザー側の特徴・行動履歴をユーザーベクトル \mathbf{u} に、アイテムをアイテムベクトル \mathbf{v}_i に別々に変換し、両者の近さをスコアとして扱います。

\displaystyle{\mathrm{score}(u, i) = \langle \mathbf{u}, \mathbf{v}_i \rangle}

アイテムベクトルを事前計算できるため、ANNインデックスと組み合わせやすいのが大きな利点です。Two-Tower モデルのユーザータワーを使ってユーザーベクトルをオンラインで計算し、ANN によって全カタログから候補アイテムを取り出すことができるため、この構成は現代の推薦システムにおいて非常に強いベースラインとなっています。

一方、候補抽出でこの分離を成立させるためのトレードオフもあります。

トレードオフ 1: 候補抽出時に相互作用を扱いにくい

ANN を使った候補抽出を行う場合、ユーザーの直近の意図とアイテムの特定属性との細かな相互作用を候補ごとに計算するには様々な工夫が必要になります。ユーザー埋め込みの各次元を通して候補アイテムとの関係性を一定考慮できますが、結局は内積計算で表現できる相互作用に限定されます。

後段のランキングでは交差特徴や Cross-Attention を用いて相互作用を考慮しますが、候補抽出時に同等の相互作用を扱うにはあらかじめ特徴量や表現へ織り込む必要があります。

トレードオフ 2: 計算資源を性能へ変えにくい

Two-Tower モデルを含め、多くの ID 埋め込みを用いる推薦モデルでは学習・推論コストのうち高カーディナリティな ID を Embedding Table から読み出す処理が大きな割合を占めます。この処理は大規模な行列演算よりもメモリ読み出しに律速されやすく、GPU の演算性能を十分に使い切れないことがあります。

そのため MLP などの密なネットワークを大きくしたり計算資源を増やしたりしても、それをそのまま学習スループットやモデル品質の向上へ結び付けることは容易ではありません。Transformer のように、各層でパラメータの大部分を行列演算に使う密なモデルとはスケールのさせ方が異なっています。

言語モデルではモデル規模・学習データ・計算量を増やすと損失が予測可能な形で改善するスケーリング則が観測されてきましたが、推薦でも同じような性質を得られるかは自明ではありません。

生成型推薦のうち行動系列を密なモデルで扱う系統では、モデル・データ・計算量を増やしたときに推薦性能をどこまで伸ばせるかを探る試みでもあります。

3. 生成型推薦とは

3.1 識別型と生成型の違い

従来の候補抽出やランキングに使われる推薦モデルはユーザーの属性や行動ログ、アイテムの属性などをもとに、候補アイテムごとの関連度やクリック確率をスコアとして出力します。 推薦リストを作る際にはそのスコアを比較して上位のアイテムを選びます。多くのケースでは学習時にはクリックや購入などが観測されたアイテムを正例とし、観測されなかったアイテムから抽出した負例よりも正例を高く評価するように学習します。

このような方式で正例と負例を区別するものは識別型推薦(Discriminative Recommendation)と呼ばれています。*1

これに対し、狭い意味での生成型推薦(Generative Recommendation) は候補アイテムを一つずつ採点するのではなく、ユーザーの行動履歴を入力として次に推薦するアイテムそのものやその識別子列を出力として生成します。 例として、後述する SID 型の生成型リトリーバルではSemantic ID *2 と呼ばれる ID 体系でアイテムを表現し、その ID 列を自己回帰的に生成して候補アイテムを得ます。

識別型推薦は候補ごとのスコアを計算し、生成型推薦はアイテム識別子や推薦リストなどの出力を構成する

3.2 生成型推薦を捉える三つの設計要素

KDD 2026 のチュートリアル*3では「候補アイテムを採点するのではなくユーザー行動を条件としてアイテムや行動を直接生成する推薦システム」を生成型推薦として捉え、その設計を次の三要素で整理しています。

  • Tokenization:アイテム・行動・属性をどのようなトークンとして表すか。Semantic ID はこの選択に当たる。
  • Architecture:トークン列をどのモデルで処理し、どのように次の出力を生成するか。
  • Optimization:次トークン予測、ランキング、強化学習などをどの目的で組み合わせるか。

これは生成型推薦を捉えるための近年の体系的な枠組みの一つです。本記事では既存研究を網羅的に分類するのではなく、この枠組みを手がかりにして SID 型生成リトリーバルと行動系列を系列変換として扱う方式の生成型推薦を取り上げます。

さらに、生成モデルを基盤にしていても直接生成を行わない LLM ベース推薦ランカーを対比対象として置きます。上述の三要素はどの方式にも関係しますが、以下の表では各例で特に違いが現れる設計要素を比較しています。

本稿で扱う対象 本稿で強調する設計要素 本稿での位置付け 取り上げる手法
SID 型生成リトリーバル Tokenization として SID を設計し、そのコード列を生成する 狭義の生成型推薦 TIGER*4
PLUM*5
行動系列を系列変換として扱う推薦 長い系列を処理する Architecture と学習・配信を含む Optimization 狭義の生成型推薦 HSTU*6
OneRec*7
LLM ベース推薦ランカー LLM を用いてユーザー表現を獲得し、候補集合のスコアリングを行う 生成型推薦との対比対象 LlamaRec*8
GenRec*9

この表の行は排他的ではありません。たとえば長期系列を SID で扱う生成型推薦として OneRec と呼ばれる手法がありますが、これは Tokenization と Architecture の工夫を含んでいます。

3.3 SID 型生成リトリーバル

生成型推薦では、アイテムをどのトークンで表すかが Tokenization の設計になります。このパターンは Semantic ID (SID) と呼ばれるアイテム識別子を用いてカタログ内の全アイテムを SID で表現し、そのコード列を生成することで商品の推薦を行います。

Semantic ID とは

通常のアイテム ID は item_12345 のような意味を持たない一つの識別子です。これに対して SID は 1 アイテムを複数の離散コードの組で表します。 たとえば、ある商品 A を (12, 7, 43)、商品 B を (12, 122, 99) のように表します。

通常のアイテム ID と Semantic ID の比較

従来のリトリーバルではユーザー表現と各候補アイテムの表現を元にして、候補アイテムごとのスコアを計算します。これに対して SID 型では、ユーザー履歴を条件として「次に推薦するアイテムの SID を構成するコード」を一つずつ出力します。 候補ごとに採点するのではなく、アイテムを表すコード列そのものを出力として生成することが、この系統で「生成型」と呼ばれる理由です。

なぜ SID を使うのか

SID を使う一番の理由は、数千万件以上になるアイテムのカタログをそのまま出力語彙として扱うことを避けるためです。アイテムごとに一つのトークンを割り当てる場合、モデルの出力層にはカタログ中の全アイテムに対応するパラメータが必要になり、また次アイテムの確率分布を計算する際には全アイテムを出力候補として比較することになります。

大規模なサービスでは推薦候補が数千万〜数億件に達することもありますが、この場合、言語モデルの一般的なサブワード語彙数である十数万トークンよりはるかに大きい出力空間を扱うことになります。その結果、出力層のパラメータや計算コストが大きくなるだけでなく、出現頻度の低いアイテムは個別トークンとして十分な学習信号を得にくくなってしまいます。

これに対して SID では、各段の語彙サイズを K、コード長を L とするコード列でアイテムを表し、各段の語彙サイズが全て K の場合に表現可能なコード列は K^{L} 通りとなります。実在アイテムの数に絞れば全ての組合せを使うわけではありませんが、比較的小さな語彙を組み合わせて非常に大きなアイテム空間を表現できます。

生成時は SID を構成するコード列を左から順に出力していきます。例えばユーザーのコンテキスト X を入力として、[BOS] → "12" → "7" → "43" → [EOS] のようにコード列を出力し、(12, 7, 43) に対応する商品を逆引きします。

このように SID は出力語彙数を減らしながら大規模なアイテム空間を扱えるようにするアイデアですが、以下ではこの SID をどのようにして推薦タスクに適用しているのかを見ていきます。

TIGER (NeurIPS 2023)

コンテンツ特徴から Semantic ID を作り、その系列から次アイテムの Semantic ID を生成する。Rajput et al., Fig. 2 より引用。

論文: Rajput et al., "Recommender Systems with Generative Retrieval", NeurIPS 2023

TIGER は SID そのものを提案した論文で、SID で学習させた Transformer によって推薦を行う例を示しています。

TIGER ではアイテムのタイトル、価格、ブランド、カテゴリなどのコンテンツ情報から作った埋め込みを Residual Quantized VAE(RQ-VAE)*10 で複数段に量子化して SID を作っています。

RQ-VAE は元の埋め込みに近いコードを一つ選び、そのコードで表し切れなかった差分(残差)を次の段のコードで近似することを繰り返し、粗い近似から細かな近似へと複数のコードを積み重ねます。各コードが人間に解釈可能なものになるとは限りませんが、たとえば「コード 11 を持つアイテムは夏物っぽい」といった具合で、同じコードを共有するアイテムは元のコンテンツ埋め込みにおける近さが反映されることを期待しています。

SID は商品を表すため、TIGER ではユーザーの行動履歴を SID の系列へ置き換えて encoder-decoder 構成の Transformer に入力します。デコーダは前述の通り次アイテムの SID を左から右へ出力します。すなわち、従来の識別型推薦のように候補アイテムを一件ずつ採点するのではなく、12 → 7 → 43 のようなコード列を生成してそれに対応するアイテムをカタログから取得します。

\displaystyle{p(c_1, c_2, \ldots, c_L \mid \text{history}) = \prod_{l=1}^{L} p(c_l \mid c_{\lt l}, \text{history})}

c_l は SID を構成する l 番目のコードで、コード列全体が次に推薦するアイテムの識別子となります。

このようにして生成されたコード列の組合せにはカタログに対応しないものも含まれる可能性があるため、TIGER ではビームサーチで複数の SID を生成し、カタログに存在しない SID をフィルタリングして候補を得ます。また、複数アイテムが同じ SID にマッピングされてしまう可能性もあるため、アイテムをユニークにするための追加コードを付けて全アイテムで一意になるようにしています。

TIGER 以後には、SID の作り方や生成器、探索方法を改良・検証する研究が数多く続いています。TIGER 型のパイプラインを構成要素ごとに再実装し、RQ-VAE、SID の長さ、ユーザートークン、制約付き探索といった要素を系統的に検証した論文として GRID*11 が参考になります。

PLUM (WWW 2026)

マルチモーダル入力を残差量子化して SID-v2 を作り、共起する動画を近づける対照損失を加える。He et al., Fig. 1 より引用。

論文: He et al., "PLUM: Adapting Pre-trained Language Models for Industrial-scale Generative Recommendations", WWW 2026

PLUM は YouTube に TIGER の定式化を導入して成果を挙げた例です。PLUM では TIGER で提案された SID を改良して SID-v2 として、より産業用推薦の用途にフィットさせています。

TIGER の論点 PLUM の対応 狙い
コンテンツ埋め込みだけで SID を作るため、ユーザー行動の協調信号を反映していない テキストメタデータ・映像・音声を統合し、動画共起を近づける対照学習を SID の学習に加える 内容と協調信号の両方を SID へ反映する
各段の codebook が同じ大きさで、使われないコード列が多くなりやすい l 段の codebook サイズを \displaystyle{\frac{2048}{2^{l-1}}} とし、2048 → 1024 → 512 → 256 → ... と段ごとに半減させる 粗いコードから細かなコードへ情報を割り当て、未使用コード列を減らす
事前学習済み LLM は SID や推薦文脈を扱えない SID を語彙へ追加し、CPT と SFT で推薦タスクへ適応する 動画内容・行動文脈を条件に次動画の SID を生成できるようにする

SID は事前学習済みの LLM(decoder-only Transformer)の語彙として追加し、動画メタデータやユーザー行動系列から構成したプロンプトで Continued Pre-training(CPT) を行います。その後、ユーザー履歴・特徴・現在閲覧中の動画の情報をプロンプトにして、ターゲット SID を生成するよう Supervised Fine-Tuning(SFT)することで、事前学習済みの LLM に対して「ある閲覧履歴を持つユーザーがあるアイテムを消費している場合にはこういう SID を提示すべき」と学習させます。

推論時は SFT した時と同様にユーザーの特徴と閲覧情報を元にしたプロンプトを入力として、次に閲覧すると推測される SID を事前学習済み LLM で逐次的に生成します。

PLUM は実際に YouTube で数十億ユーザー規模のリトリーバルへ展開されており、長尺動画では視聴ユーザー数が +0.07%、Panel CTR が +0.76%、Shorts ではそれぞれ +0.28%、+4.96% 改善したと報告されています。なお、これは既存のリトリーバル手法を完全に置き換えた結果ではなく、既存手法の候補数を増やすパターンと PLUM を併用するパターンでの比較を行った結果である点に注意が必要です。

一方で、SID を作る段階に協調信号や推薦目的をどのように反映するか、また SID の生成尤度だけで最終的なアイテムの関連度をどこまで表せるかは、引き続き重要な論点です。前者を扱う LETTER*12 や SID の生成と dense retrieval を組み合わせる COBRA*13 は SID 型生成リトリーバルをさらに掘り下げる際の参考になるでしょう。

3.4 行動系列を系列変換として扱う生成型推薦

SID 型生成リトリーバルでは主に巨大なアイテム空間をどのトークンで表現して出力するかを扱うのに対し、この系統は長いユーザー行動履歴を系列としてどのようにモデル化し、学習と計算資源をどのように推薦性能へ結び付けるかに焦点を当てています。

何を「生成」するのか

たとえば、あるユーザーが 動画Aを表示 → 動画Aを最後まで視聴 → 動画Bに「いいね」 → 動画Cをスキップ という行動系列を持つ場合、従来の識別型推薦では履歴やユーザー属性を特徴量へ集約し、推薦候補となっている動画ごとにクリック率・視聴確率などのスコアを計算します。

これに対して大規模行動系列モデルでは表示された動画、その動画に対する反応、時刻、作者、ユーザー属性といった情報を時系列に沿った一つのトークン列として扱います。そしてある時点までの列を条件に、その後に起きる反応や次に正の反応を得る動画を予測します。

行動・属性を時系列として扱い、履歴中の複数の位置から反応予測と次コンテンツ予測の学習信号を得る

概念的には、時刻 t までに観測された行動列 x_{\leq t} を条件として、次に起きる反応やコンテンツ y_{t+1} の確率を学習します。

\displaystyle{p(y_{t+1} \mid x_{\leq t})}

出力は必ずしも次のアイテム IDだけではないのが特徴で、たとえば次のアイテム ID に対してクリック、いいね、スキップといったアクションを予測させることもあります。

このように、アイテム ID やアクションなど異なる種類のトークンを同じ時系列の変換問題として扱っており、「行動列の続きを条件付きで予測する」という定式化とそれを多くの時点で学習する方法がこの系統で生成型と呼ばれる理由です。

HSTU (ICML 2024)

従来の DLRM の特徴と学習手順を、単一の時系列へ統合する Generative Recommender の定式化。Zhai et al., Fig. 2 より引用。

論文: Zhai et al., "Actions Speak Louder than Words: Trillion-Parameter Sequential Transducers for Generative Recommendations", ICML 2024

Meta の HSTU では、画像や動画などのコンテンツに対する視聴・スキップ・いいね・シェアといった行動をモデル化し、次に正の反応を得るコンテンツの予測(retrieval)と、提示された対象コンテンツに対する行動の予測(ranking)を系列変換タスクとして定式化しています。ポイントになるのは、カテゴリ特徴を系列データの一部として組み込み、十分な系列長・表現力・target-aware な定式化によって、手作業で作る数値集計特徴への依存を減らすことを狙っている点です。

例えばユーザーの行動ログが以下のようになっていたとします。

10:00 動画Aを視聴
10:02 動画Aの視聴完了
10:10 クリエイターXをフォロー
10:13 動画Bをスキップ
10:14 動画Cを視聴・いいね

これを以下のような系列データに落とし込みます。

[language:ja]
[city:tokyo]
10:00 [video:A] [action:watch]
10:02 [video:A] [action:complete]
10:10 [creator:X] [action:follow]
10:13 [video:B] [action:watch] [action:skip]
10:14 [video:C] [action:watch] [action:like]

系列の冒頭には [language:ja]、[city:tokyo] というユーザーの使用言語と居住地に関するメタデータの情報が挿入されています。このような変化頻度の低いカテゴリ特徴は値が変わった時だけイベントとして挿入します。一方で、頻繁に変化するカウンタや比率のような数値特徴をすべて逐次的に計算して挿入することは計算量や保存量の面から現実的ではありません。そのため HSTU では行動・カテゴリ特徴を一つの系列として扱い、非常に長い履歴を大規模モデルで学習することで、CTR のような手作業の集計特徴への依存を減らすことを目指します。

論文で提案されている HSTU(Hierarchical Sequential Transduction Unit)は、このような長く、語彙が大きく、時間とともに分布が変化する系列を処理するための encoder です。アテンションやメモリ使用量を推薦用に最適化し、長い系列を Transformer より効率的に扱うことを狙っています。論文では数千トークンの系列での効率とオンライン A/B テストでの改善に加え、HSTU を用いた Generative Recommender が大規模ストリーミング設定で計算量に対してべき乗則的に品質を伸ばす傾向も示しています。

この結果は推薦でもモデル・データ・計算量を増やして性能を伸ばす余地があることを示唆します。

OneRec (2025)

セッション単位の生成学習と、報酬モデルで作る自己 hard negative を用いた Iterative Preference Alignment(IPA)からなる OneRec の学習手順。Deng et al., Fig. 2 より引用。

論文: Deng et al., "OneRec: Unifying Retrieve and Rank with Generative Recommender and Iterative Preference Alignment", arXiv:2502.18965, 2025

快手の OneRec は候補抽出・ランキングのように複数の段階に分かれた推薦パイプラインを、encoder-decoder による一つの生成型推薦システムとして組み直すものです。OneRec では次アイテムを一件ずつ生成するのではなく、ユーザー履歴から一つの推薦セッションを構成する複数動画の Semantic ID を自己回帰的に生成します。生成の単位を単一のアイテムから推薦リストへ広げつつ、候補抽出とランキングに分かれた多段パイプラインを単一の生成モデルで直接最適化しようとする点が特徴です。

OneRec も動画を Semantic ID で表現しており、その点だけを見れば 3.3 の SID 型生成リトリーバルと重なります。ただし、TIGER や PLUM が次の一件を得るために SID を生成するのに対し、OneRec は一つのセッションを構成する複数動画の SID を生成します。

OneRec では decoder で Sparse MoE を用いてモデル容量を拡張しつつ、生成した複数の推薦リストを外部の報酬モデルで評価します。評価が最も高いリストと低いリストから選好データを作り、NTP(Next Token Prediction)損失と DPO(Direct Preference Optimization)損失を組み合わせて decoder を学習します。 こうした「Sparse MoE でモデル容量を拡張する」「生成モデルの出力を外部評価に基づいてアライメントする」という構造は、LLM のスケーリングや post-training で発展してきた知見を、推薦の生成モデルへ応用したもの と捉えられます。

論文では、快手のメイン画面の動画推薦で既存の多段推薦システムと比較したオンライン A/B テストを行い、OneRec-1B+IPA は総視聴時間を +1.68%、平均視聴時間を +6.56% 改善したと報告しています。また、0.05B から 1B へのモデル拡大で性能が一貫して改善する傾向も示しています。

OneRec が生成しているものは SID 型リトリーバルと同じく動画を表す Semantic ID ですが、LLM の発展で培われた設計を推薦タスクに取り込んでいる点に OneRec の面白さがあります。

HSTU と OneRec ではともにモデル規模の拡大に伴って性能が改善する傾向を報告しており、これは LLM で観測されてきたスケーリングの性質が推薦でも得られる可能性を示す興味深い結果です。ただし、まだ推薦タスク全般で成り立つ法則とまでは言えない点に注意が必要です。

3.5 LLM ベース推薦ランカー

LLM を推薦システムへ用いていれば生成型推薦、というわけではありません。ここでは LLM を使ったランカーモデル(LLM ベース推薦ランカー)を生成型推薦と対比させます。

本記事で扱う LLM ベース推薦ランカーでは、ユーザー履歴、現在の文脈、候補アイテムの情報を LLM に与え、既知の候補集合にスコア付けをして並べ替えます。後述する GenRec のように文脈表現をランキングヘッドへ渡す方式もあれば、LlamaRec のように候補インデックスのトークン確率を候補スコアとして読む方式もあります。いずれも推薦の出力は既知の候補に対するスコアであり、推論上の役割は識別型推薦のランカーと同じです。

このように事前学習された decoder-only LLM を基盤にしていても、それだけで推薦の出力が生成的になるわけではありません。ここで中心となる問いは、「従来は特徴量として与えていた情報をどのように文脈として構成し、事前学習済み LLM の表現能力をランキングへ結び付けるか」 です。この対比は、「LLM を使うこと」と「推薦対象を生成すること」を分けて考えるために重要です。

LlamaRec (PGAI@CIKM 2023)

候補抽出、プロンプト構成、verbalizer による候補ランキングからなる LlamaRec の二段階推薦。Yue et al., Fig. 1 より引用。

論文: Yue et al., "LlamaRec: Two-Stage Recommendation using Large Language Models for Ranking", PGAI@CIKM 2023

LlamaRec は two-stage recommender のランキング部分に LLM を使うわかりやすい例です。まず軽量な系列推薦モデルで候補を取り出し、ユーザー履歴と候補アイテムのタイトルをテキストとして LLM に入力します。入力テキストの構成として、候補ごとに (A)、(B)、(C) のようなインデックスを割り当て、LLM にはそのインデックスを一つ出力するよう学習させます。例えば正解が候補 (B) であれば、教師ラベルはアイテム名ではなく "B" となります。

応答位置における語彙全体の logits を z、候補アイテム i_j に対応するインデックス文字を \ell_j とします。verbalizer は z から候補インデックスの logits だけを取り出し、候補集合 C の中で正規化します。

\displaystyle{P(i_j \mid \mathrm{prompt}, C) = \frac{\exp(z_{\ell_j})}{\sum_{i_r \in C}\exp(z_{\ell_r})}}

この確率で候補を並べ替えるため、言語モデルの次トークン分布を候補のスコアベクトルとして読み出していることになります。推論時に必要なのは一回の forward pass と候補インデックスの logits の取得だけであり、アイテム名や推薦リストを逐次デコードしたりビーム探索したりする必要はありません。

ベースモデルには事前学習済みの Llama 2 7B を用いており、PLUM のように推薦データで継続事前学習を行うのではなく、既存の Llama 2 をランキングタスクへ直接適応する構成になっています。

GenRec (2026)

会員の履歴・文脈をテキスト化して1回の prefill で処理し、カタログ全体を採点する GenRec の推論パイプライン。Li et al., Fig. 1 より引用。

論文: Li et al., "GenRec: An LLM-Backed Recommendation Ranker at Netflix", arXiv:2608.10257, 2026

Netflix の GenRec は、LLM ベース推薦ランカーを大規模カタログのランキングへ適用した例です。Netflix のデータを学習した decoder-only Transformer へ、会員の視聴履歴、デバイスや時刻などの文脈、作品メタデータを文章として与えます。

ここで重要なのは context engineering の観点で、プロンプトとして与えるコンテキストの中でどの行動をどのように記述し、作品情報はどこまで詳しく記述するか、といった設計がモデル品質とコストを大きく左右します。例として、context engineering によって構成する入力の概念を以下に示します。

Member profile:
- Country: Japan
- Plan: Standard
- Member since: 2023-04

Current context:
- Surface: Home
- Device: TV
- Local time: Friday evening

Recent high-signal history:
- Completed "3 Body Problem" (51 minutes).
- Gave a thumbs-up to "Stranger Things".
- Watched "Black Mirror" for 43 minutes.

Compressed history:
- Watched several episodes of a science-fiction series over the past three days.
- Often watches suspense and science-fiction titles.

Item detail to emphasize:
- "New science-fiction drama X": released this week; genre: science fiction; synopsis: ...

Task:
- Predict the next items that the user will play or thumb up.

この例では長時間視聴や高評価のような強いシグナルを個別に残す(例: Gave a thumbs-up to "Stranger Things".)一方で、繰り返し視聴したエピソード群は要約(例: Watched several episodes of a science-fiction series over the past three days.)しています。また、新作など重要な作品にはジャンルやあらすじを補います。どの情報を残すかは単に入力を短くするためではなく、LLM に「ユーザー表現として重要な情報は何か」と「推薦文脈として何を与えるか」を決める設計です。

GenRec は入力となるテキストを decoder-only Transformer で処理し、pooling 位置の隠れ状態を文脈表現 h として利用します。これとアイテムごとの埋め込み e_i をランキングヘッド \phi へ渡し、各アイテムのスコア s_i を計算します。

\displaystyle{s_i = \phi(h, e_i)}

LLM がユーザーの履歴と文脈を表す h を作り、ランキングヘッドが既知カタログを評価するという役割分担になっており、学習時は LLM 本体とランキングヘッド、アイテム埋め込みは全て end-to-end で学習されます。

推論時は prefill-only で h を得て、catalog-aware なランキングヘッドでカタログまたは候補集合をスコアリングします。このように、GenRec では decoder-only Transformer を prefill-only で使うことでスループットとレイテンシのボトルネックになる decode 部分の実行を避けています。

GenRec が向き合うのは 「数千もの手設計特徴や複雑な特徴交差を持つ従来のランカーを、LLM が読む文脈と推薦向けの事後学習でどこまで置き換えられるか」 という課題です。論文では大規模なオンライン A/B テストで既存の本番ランカーを上回る改善を報告していますが、これは提示された候補集合を評価するランキングシステムとしての結果であり、生成型推薦としての結果ではありません。

Netflix は GenRec を "LLM-Backed Recommendation Ranker" と位置付けており、生成型推薦とは呼んでいません。本稿でも LLM ベース推薦ランカーを狭い意味での生成型推薦に含めず、SID 型生成リトリーバルや行動系列モデルとの違いを確認する対比対象として扱いました。

4. 「LLM から直接推薦結果を得る」ために

近年では目まぐるしいスピードで生成 AI の性能が改善しているため、「汎用チャット LLM にユーザーの情報を渡しておすすめアイテムを直接尋ねればよいのではないか」 という自然な発想が出てきます。

LLM に直接アイテムを出力させること自体は、専用に学習・制約した生成型推薦モデルで実現でき、SID 型生成リトリーバルや OneRec はその実装例です。

しかし、汎用チャット LLM へ「おすすめアイテムを教えて」と問いかけるだけでは大規模な推薦システムに必要な機能と性能を満たせません。チャット LLM を推薦機能の中心に置くには生成速度、カタログの正確性、履歴に基づくパーソナライズ、事業上の最適化ターゲットの要求を満たす必要があります。

実現したいこと そのままでは起きる問題 必要な仕組み
十分な生成速度 decoder-only LLM で prefill → decode をするとレイテンシとスループットのボトルネックになる ・出力コードを短くし、探索幅を制御する
・GenRec のように decode を行わない採点型ランカーを選ぶ
カタログ内のアイテムのみを出す カタログ外のアイテムやポリシーに合わないアイテムを出力してしまう ・Semantic ID やアイテム ID を出力単位にして実在するコード列だけを探索する
・生成後の post-filtering でポリシーの制約を適用する
ユーザーの嗜好に合わせる アイテム同士の協調信号や短期的な関心に基づくパーソナライズが行えない ・行動ログとカタログ情報で事前/事後学習し、推薦タスクに適したトークン化、教師信号、オンライン評価を設計する
サービスや機能の目的に合わせた最適化 短期的な関連度だけでなくGMV、広告、割引率、在庫など複数の目的と制約を考慮した推薦リストが作れない ・損失の重み付け、報酬モデル、選好最適化、再ランキングや制約フィルタを組み合わせ、サービスの目的へ整合させる

要件をすべて一つの LLM に担わせる必要はありません。たとえば候補のパーソナライズを軽量ランカーに任せたり、生成結果をカタログ内のアイテムで絞り込み・サービスポリシーに応じたアイテム除外をする構成も現実的です。生成型推薦は、こうした要件のうちどこまでを生成モデルに担わせるかを設計する試みと捉えられます。

5. おわりに

本記事では生成型推薦と呼ばれる手法として、生成型リトリーバルと行動系列をモデリングするものをいくつか紹介しました。

生成型かどうかを分ける要点は LLM を使うことそのものではなく、候補を個別採点する代わりに何を出力として直接構成・予測するかにあります。SID 型は巨大カタログの出力表現を、行動系列モデルは長い履歴の表現と学習信号を主な論点にします。

一方、LLM ベース推薦ランカーは LLM を用いていますが、候補集合に対するスコアがアウトプットであるという点では従来の識別型手法と同様です。

次回は、(気力が持てば)SID型生成リトリーバルに焦点を絞っていくつか文献紹介と実行例を示そうと思います。

LightGCN の課題と発展系モデルの改善アプローチ

1. はじめに

Graph Neural Network(GNN)はユーザーとアイテムの相互作用をグラフ構造として捉え、高次の協調フィルタリング信号を効果的に学習できることから、最近の推薦システムでは主流なモデルの一つになっています。

中でも LightGCN(He et al., SIGIR 2020)は GCN の本質的な要素である近傍集約のみを残し、埋め込みの変換や非線形活性化といった処理を削除することで、シンプルかつ高性能なモデルを実現しています。

近年の推薦モデルの研究では LightGCN をベースラインとして比較されることも多く、PyG (PyTorch Geometric) を使えば簡単に検証もでき、実験のためのエコシステムも充実しています。

本記事ではそんな LightGCN の特徴と課題を整理した上で、それらを解決するために提案された以下の発展系モデルを改善の方向性ごとに紹介します。

気力が残っていれば、後日に簡易的な実装例も追加するかもしれません、、、

2. LightGCN の特徴と課題

2.1 NGCFとの比較

LightGCN を理解するには、その前身である NGCF(Neural Graph Collaborative Filtering, Wang et al., SIGIR 2019)と比較するとその違いがよく分かります。

モデル propagation rule
NGCF \displaystyle{\mathbf{e} _ u^ {(k+1)} = \mathbf{ReLU} \left( \mathbf{W} _ 1 \mathbf{e} _ u^ {(k)} + \sum _ {i \in \mathbf{N} _ u} \frac{1}{\sqrt{|\mathbf{N} _ u||\mathbf{N} _ i|}} \left( \mathbf{W} _ 1 \mathbf{e} _ i^ {(k)} + \mathbf{W} _ 2 (\mathbf{e} _ u^ {(k)} \odot \mathbf{e} _ i^ {(k)}) \right) \right)}
LightGCN \displaystyle{\mathbf{e} _ u^ {(k+1)} = \sum _ {i \in \mathbf{N} _ u} \frac{1}{\sqrt{|\mathbf{N} _ u||\mathbf{N} _ i|}} \mathbf{e} _ i^ {(k)}}

NGCF の propagation rule は GCN の基本的な構造を踏襲しており、非常に複雑そうな計算であることが分かるかと思います。一方、LightGCN は NGCF が持つ以下の要素を排除し、シンプルな近傍集約を行う propagation rule でノードの埋め込みを計算しています。

  • 特徴変換行列: \displaystyle{\mathbf{W} _ 1, \mathbf{W} _ 2}
  • 非線形活性化: \displaystyle{\mathbf{ReLU}(x)}
  • 自己接続: \displaystyle{\mathbf{W} _ 1 \mathbf{e} _ u^ {(k)}}

その結果、LightGCN での最終的な埋め込みは各層の出力の重み付き和として計算されます。

\displaystyle{\mathbf{e} _ u = \sum _ {k=0}^ {K} \alpha _ k \mathbf{e} _ u^ {(k)}}

なぜシンプルな近傍集約のみで良いのか?

ユーザー・アイテムの ID のみを使った推薦モデルの場合、メタデータのような意味のある初期特徴量を持たないのが一般的です。

LightGCN の論文中では、このような設定で推薦を行う場合に複雑な構造を持つ NGCF で以下の問題が生じると指摘しています。

  1. 入力が one-hot ID 埋め込みのみであるため、非線形変換による表現力向上の恩恵が薄い
  2. 過剰なパラメータによって学習が困難になる

NGCF は GCN を推薦タスクに応用した事例ですが、論文の著者らはそもそも GCN はノードの特徴量が豊富に存在するグラフに対して有効であり、ID 埋め込みのみを扱う推薦タスクではその利点が活かされにくいと指摘しており、LightGCN ではこうした推薦タスク特有の性質を鑑みて、IDベースの表現学習において実質的に機能していない不要な処理を排除したことが良い性能に繋がったと主張しています。

2.2 LightGCN の課題

とはいえ、LightGCN にも課題がないわけではありません。

LightGCN はシンプルな propagation rule であるが故、層を深くしても性能が向上しにくい、むしろ層を深くすると性能が低下してしまうという問題を抱えています。

LightGCN は隣接ノードの埋め込みの加重平均で propagation していくため、この操作を繰り返す(=層を深くする)と、以下のようにしてモデルの性能悪化に繋がります。

  1. ノードの情報が広範囲に伝播し、情報が均一化する
  2. ノードに伝播する情報が増えることで埋め込みが均一的になり、ノードごとの埋め込みが似通う
  3. 全てのノードで似たような埋め込みとなるため、嗜好を捉えた推論ができずモデル性能が悪化する

この現象を Over-smoothing と呼んでおり、グラフ系のモデルでは一般的なトピックです。LightGCN では浅い層数(\displaystyle{L=3} 程度)で十分、あるいは最高の性能に達するとされていますが、これは裏を返せば Over-smoothing を避ける意図でもあるでしょう。

LightGCN は線形変換のみでメッセージパッシングをして埋め込みの学習を行っている都合上、Over-smoothing が生じやすくなっていると考えられます。そのため、改善手法の多くはこの問題を回避して高い性能を目指すことを念頭に置いています。

ここで、私の主観で LightGCN の課題を以下の3つに分類し、以降のセクションではこれらの課題に対応する発展系モデルだったり改善手法を紹介していきます。*1

No. 課題 概要
1 多層化の限界 (Over-smoothing) 多層 propagation の計算コストが大きい・そもそも多層化が推奨されない
2 人気バイアスと Collapsing への対応 次数の高いノード(=人気のアイテム・アクティブユーザー)の影響が強くなりすぎる・層を通すごとに情報が希釈されてしまう
3 データの sparseness とノイズへの対処 観測データが少ない場合に十分な教師信号を得られず、グラフに含まれる誤クリック等のノイズの影響も受けやすい

3. 課題ごとの改善アプローチ

3.1 多層化の限界 (Over-smoothing)

LightGCN はモデル構造を簡素化したものの、学習時に近傍ノードの情報を集約してそれを次の層に伝播させるというメッセージパッシングは必要です。大規模なグラフ構造においては、これが非常に計算コストのかかる処理であることに変わりはありません。

このセクションでは「Over-smoothing を回避しながら多層化を目指す」という方向性ではなく、逆転の発想で「多層化せずに多層化と同等の性能を目指す」というアプローチを紹介します。

UltraGCN(CIKM 2021)

Mao et al., UltraGCN: Ultra Simplification of Graph Convolutional Networks for Recommendation, Figure 1 より引用

論文: Mao et al., "UltraGCN: Ultra Simplification of Graph Convolutional Networks for Recommendation" (CIKM 2021)

アイデア

UltraGCN は LightGCN のメッセージパッシングを完全に省略し、層を無限に深くした場合の収束状態(極限)を直接近似するというアプローチを採っています。

具体的には GCN ベースのメッセージパッシングを無限に繰り返した際の到達点を数学的に導出し、その関係性を満たすよう制約する損失関数(Constraint Loss)を定義しました。さらにこの損失関数に負例サンプリングを組み込むことで、多層化による Over-smoothing を防ぎつつ、明示的なメッセージパッシングなしでの高速かつ高精度な学習を実現しています。

手法

UltraGCN は以下の損失関数を用いて学習します。

\displaystyle{ \mathbf{L} = \mathbf{L} _ {O} + \lambda \mathbf{L} _ {C} + \gamma \mathbf{L} _ {I} }
  • \displaystyle{ \mathbf{L} _ {O} } : User-Item 間の予測損失(Binary Cross Entropy)
  • \displaystyle{ \mathbf{L} _ {C} } : サンプルごとにノードの次数を考慮した重み付きの予測損失
  • \displaystyle{ \mathbf{L} _ {I} } : Item-Item グラフにおける類似アイテムの埋め込みを近づけるための損失

解釈を加えるとすれば、\displaystyle{ \mathbf{L} _ {O} } は通常の損失、\displaystyle{ \mathbf{L} _ {C} } はグラフの構造を考慮した損失、\displaystyle{ \mathbf{L} _ {I} } は類似アイテムのスコアも上げる損失、といった具合でしょう。メッセージパッシングによる行列計算の計算コストを除外する代わりに、その複雑な機能を損失関数で表現していることがわかります。

LightGCN と UltraGCN の違いはコードで見るとよく分かります。LightGCN は self.convs によってメッセージパッシングを繰り返し行っていますが、UltraGCN では単純にユーザーとアイテムの埋め込みを内積してスコアを計算しています。

# PyG の LightGCN 実装の embedding 計算部分を一部抜粋
# https://github.com/pyg-team/pytorch_geometric/blob/44dee49ad88cf5253e8092cfce3e453c00bc8c3e/torch_geometric/nn/models/lightgcn.py#L98C1-L111C19
    def get_embedding(
        self,
        edge_index: Adj,
        edge_weight: OptTensor = None,
    ) -> Tensor:
        r"""Returns the embedding of nodes in the graph."""
        x = self.embedding.weight
        out = x * self.alpha[0]

        for i in range(self.num_layers):
            x = self.convs[i](x, edge_index, edge_weight)
            out = out + x * self.alpha[i + 1]

        return out

# UltraGCN の著者が公開している実装の embedding 計算部分を一部抜粋
# https://github.com/reczoo/RecZoo/blob/88fae23ff0b8321c60655d9c21e0a1bb1173f6af/matching/gnn/UltraGCN/main.py#L367C1-L372C47
    def test_foward(self, users):
        items = torch.arange(self.item_num).to(users.device)
        user_embeds = self.user_embeds(users)
        item_embeds = self.item_embeds(items)
         
        return user_embeds.mm(item_embeds.t())

前述した損失関数を使って学習することで無限層の GCN を近似できるため、隣接ノードの集約から次層へのメッセージパッシングといった処理は一切不要である、というのが UltraGCN の主張です。

メッセージパッシングを完全に省略しているため、実質的には重み付きの Matrix Factorization と言える形態になっています。

効果
  • LightGCN 比で +10〜76% の性能向上
  • 学習速度は 10x 以上の高速化
  • メモリ効率の大幅な改善

似たようなアプローチ: GF-CF

論文: Shen et al., "How Powerful is Graph Convolution for Recommendation?" (SIGIR 2021)

GF-CF はさらに極端なアプローチで、ニューラルネットワークによる反復的な学習自体を不要としています。

まず GCN が行っている近傍集約とは高周波(ノイズ)をカットし、低周波(ユーザーの嗜好)だけを残すローパスフィルタの一種である、と解釈できます。

そこで著者らは、LightGCN などの GCN ベースの手法が成功している本質的な理由はその構造にあるのではなく、「埋め込みの分布を適切に平滑化するローパスフィルタの機能」にあることを突き止め、この適切な平滑化をするためのローパスフィルタを数学的に導き出しました。

つまり GF-CF ではモデルの学習(バックプロパゲーション)という概念は存在せず、SVD(特異値分解)を含む事前に定義された行列計算を一度実行するだけでスコアが算出できます。

精度面では、特に大規模でスパースなデータセット(Amazon-Booksなど)においては、LightGCN と比較して 70% 近く性能を改善したことが報告されています。

3.2 人気バイアスと Collapsing への対応

多層構造を持つ GCN モデルは層が深くなるほど高次の関係性を捉えますが、一方で次数が高いノード(=人気のアイテム・アクティブなユーザー)の影響が強くなりすぎてしまう人気バイアスの問題に対処する必要があります。

高次数のノードは多くのノードと繋がっているため、メッセージパッシングの過程でその影響が他のノードに広がりやすくなっています。

また情報の重要度という観点では、ユーザーやコンテキストごとにどの層の情報が重要かは異なると考えられます。LightGCN の論文では層ごとに様々なバリエーションで重み付けをする実験も行われましたが、結局「全層の重みを一律にする」(=全層の平均をとる)というシンプルな形が最も良い結果を出しました。

単純に考えれば層ごとの重みを学習可能にすれば更に良くなりそうに思えますが、これには Solution Collapsing と呼ばれる、特定の層に重みが偏ってしまうという問題が発生します。

本セクションでは、情報の集約方法を工夫することで、この Collapsing を防ぎつつ人気バイアスにも対応した手法を紹介します。

LayerGCN(ICDE 2023)

Zhou et al., Layer-refined Graph Convolutional Networks for Recommendation, Fig. 2 より引用

論文: Zhou et al., "Layer-refined Graph Convolutional Networks for Recommendation" (ICDE 2023)

アイデア

LayerGCN は、LightGCN が抱えていた「層を重ねるほどノイズが混じり、特定の層への依存度が高まってしまう」という課題に対し、伝播する情報の質をその都度磨き上げるというアプローチを採っています。

この論文では、単純に層ごとの重みを学習可能にした場合、学習が進むにつれて初期層の重みが極端に大きくなってしまい、深い層の重みはほぼゼロになることを示しています。これは Solution Collapsing と呼ばれており、「深い層の情報は平滑化されているので予測の役に立たず、結局は自分自身の初期情報が最も有用である」として近傍ノードの情報を無視してしまう現象です。

そこで LayerGCN では各層で伝播する情報に自分自身の埋め込みとの差分を強調するフィルタを導入することで、動的に層ごとの重み付けを行うアプローチを提案しています。

手法

LayerGCN の新規性は以下の 2 つの仕組みに集約されます。

手法 概要
Layer refinement 各層の出力に対して、初期層(ego layer)との類似度に基づいた動的な重み付けを行う
Degree-sensitive edge pruning 次数(人気度)が高いノードほど高い確率でエッジを削除し、情報の過剰流入を抑える

Layer refinement は、各層の埋め込み\displaystyle{\mathbf{e}^{(k)}} をそのまま集約せず、初期層 \displaystyle{\mathbf{e}^{(0)}} とのコサイン類似度を用いて「その層がどれだけ信頼できるか」を動的に判定します。

\displaystyle{ \mathbf{e} _ {out} = \sum _ {k=0}^{L} \text{cos}(\mathbf{e}^{(k)}, \mathbf{e}^{(0)}) \mathbf{e}^{(k)} }

発想としては ResNet のスキップコネクションに近いですが、LayerGCN は「初期層の埋め込みから離れすぎた(類似度が低い)情報はノイズとみなして重みを下げる」というゲート機構のような役割を動的に果たしている点が特徴です。これにより深い層での情報の希釈化を防ぎ、Solution Collapsing を回避しています。

Degree-sensitive edge pruning は、人気バイアスを構造的に解消する仕組みです。高次数のノードほどメッセージパッシング時に周囲に強い影響を与えてしまうため、あえて次数に比例した確率でエッジを間引きます。一律のランダム削除よりも推薦におけるノイズを効果的に除去できるため、学習の収束が早くなることが報告されています。

効果
  • Over-smoothing, Solution Collapsing, 人気バイアスを同時に緩和
  • 学習の収束が非常に高速
  • 複数の公開データセットにおいて、当時の SOTA の性能を達成(特に dense なデータセットで精度改善が顕著)

LightGCN++(RecSys 2024)

論文: Lee et al., "Revisiting LightGCN: Unexpected Inflexibility, Inconsistency, and A Remedy Towards Improved Recommendation" (RecSys 2024)

アイデア

LightGCN では人気バイアスと Collapsing への対処として、あらかじめ以下の「固定ルール」が組み込まれています。

  1. 対称正規化:ノードの次数に応じて埋め込みの大きさを一律に調整し、人気ノードの影響力を抑制する
  2. 一様な層の統合:全層を平等に平均化することで、特定の層(ego layer)への過度な依存を防止する

1 つ目の対称正規化は、ノードの次数に応じて重みを割り引くことで人気バイアスを抑える仕組みです。また 2 つ目は、先述した Solution Collapsing を回避するための制約として機能します。

しかし LightGCN++ の著者らは、「これらの固定的なルールがデータセットごとの個性を無視した設計になっている」と指摘しています。

すべてのノードや層の影響を一律に縛るのではなく、データセットの特性に応じて柔軟に調整(スケーリング)できるようにすべきである、というのが LightGCN++ の主張です。*2

手法

LightGCN++ ではノードや層の影響度合いを「学習によって調整可能」にすることで、LightGCN 本来のポテンシャルを解放することを目指しています。

学習可能なパラメータの追加による弊害として最も懸念されるのは計算コストの増加ですが、計算コストをほぼ増やさずに以下の 2 つの仕組みを導入しました。

1. Adaptive Norm Scaling (適応的ノルムスケーリング)

メッセージパッシングの際、次数に基づく正規化項をハイパーパラメータ \displaystyle{\alpha, \beta} によって制御します。

\displaystyle{ \mathbf{e} _ i^{(k+1)} = \frac{1}{|\mathbf{N} _ i|^\alpha} \sum _ {u \in N _ i} \frac{1}{|\mathbf{N} _ u|^\beta} \mathbf{e} _ u^{(k)} }

これにより、これまでの対称正規化(\displaystyle{\alpha, \beta=0.5} 固定)によって強制的に固定されていた人気度と埋め込みベクトルの大きさの関係を、データセットに最適なバランスへ調整できるようになります。

2. Adaptive Layer Pooling (適応的レイヤープーリング)

初期層(ego layer)とそれ以降の集約層の平均を、ハイパーパラメータ \displaystyle{\gamma} を用いて統合しています。

\displaystyle{ \mathbf{e} _ i = \gamma \mathbf{e} _ i^{(0)} + (1 - \gamma) \frac{1}{K} \sum _ {k=1}^{K} \mathbf{e} _ i^{(k)} }

一律固定だった層の重みを、初期層の寄与度 \displaystyle{\gamma} によって調整可能になっています。単に重みを増やすだけでは Solution Collapsing が再発してしまいますが、前述の正規化項の調整と組み合わせることで、安定性を保ちながら柔軟な集約を実現しています。

効果
  • 行列計算のルールを微調整するだけで最大 +17.81%(NDCG@20)の性能向上
  • 追加の計算コストはほぼゼロでありながら実務上の精度改善に有効
  • Bundle 推薦や知識グラフ推薦など LightGCN をベースにした他の発展モデルにもそのまま適用可能な汎用性

3.3 データの sparseness とノイズへの対処

一般的な GNN ベースのモデルはユーザーのフィードバックを元にグラフ構造を構築し、そのグラフ構造に基づいた学習を行います。

しかし現実の推薦データは極端にスパースであり、全てのユーザー・アイテムのインタラクションが発生するわけではありません。さらに、ユーザーの誤クリックや一時的な興味など、ノイズとなる情報も多く含まれています。

この課題に対し、これまではエッジを削るなどグラフの加工(データ拡張)をして情報を水増しする手法が主流でしたが、本セクションでは対照学習を用いてノイズ耐性と表現力を高めるアプローチを紹介します。

SimGCL(SIGIR 2022)

論文: Yu et al., "Are Graph Augmentations Necessary? Simple Graph Contrastive Learning for Recommendation" (SIGIR 2022)

アイデア

データのスパース性やノイズを克服する手段として、近年注目を集めているのが対照学習(Contrastive Learning)です。

GNN × 対照学習の先駆けとなった SGL(Wu et al., "Self-supervised Graph Learning for Recommendation" SIGIR 2021)では、エッジやノードをランダムに削ることで、元々のグラフとは少し異なる「兄弟グラフ」を複数作り出します。

それらを互いに比較させ、同じユーザーやアイテムであれば「グラフの構造が多少変わっても埋め込みベクトルは一貫しているべきである」としてモデルを学習し、堅牢な表現を獲得しました。

しかし、SimGCL ではこのような複雑かつ計算コストの高いグラフの加工は不要であると主張しています。

実験の結果、SGL がグラフを加工して得ていた恩恵の本質は複雑な構造の変化そのものではなく、最終的な埋め込みベクトルに適度なノイズが乗ることによる正規化効果にあることが分かりました。これを受けて SimGCL ではグラフ構造には一切手を加えず、埋め込みベクトルに直接一様なノイズを加えるだけで SGL を超える精度と効率が得られることを証明しています。

手法

SimGCL は、計算負荷の高いグラフの Dropout 処理を使用せず、埋め込みベクトルに一様なノイズを注入することで、対照学習のための「微妙に異なる 2 つのサンプル(論文中では view と表現)」を生成します。

\displaystyle{ \mathbf{e}' _ u = \mathbf{e} _ u + \Delta _ u, \quad \Delta _ u \sim \text{Uniform}(-\epsilon, \epsilon) }

このようにして生成された「微妙に異なる 2 つのサンプル」を使い、対照学習損失(InfoNCE loss)を用いて「元は同じノードであること」を学習させます。

\displaystyle{ \mathbf{L} _ {CL} = -\log \frac{\exp(\text{sim}(\mathbf{e} _ u, \mathbf{e}' _ u) / \tau)}{\sum _ {v \in \mathbf{U}} \exp(\text{sim}(\mathbf{e} _ u, \mathbf{e}' _ v) / \tau)} }

最終的な損失関数は、通常の推薦損失(BPR loss)と対照学習損失を組み合わせたものになります。

\displaystyle{ \mathbf{L} = \mathbf{L} _ {BPR} + \lambda \mathbf{L} _ {CL} }

この損失関数の組み合わせにより、モデルは \displaystyle{ \mathbf{L} _ {BPR} } を通じて「観測された履歴」を再現するだけでなく、\displaystyle{ \mathbf{L} _ {CL} } によって埋め込み空間全体の分布を最適化することを目指しています。

一様なノイズを加えても同一ノードとして識別できるように制約をかけることで、特定のグラフ構造(エッジの有無)に過剰適合するのを防ぎ、データが少ない状況であってもユーザーやアイテムの本質的な特徴を捉えた汎化性能の高い埋め込みを獲得しています。

効果
  • 複数の公開データセットにおいて、LightGCN 比で最大 +30% の精度改善
  • 兄弟グラフの再構築やサンプリングが不要なため SGL と比較してエポックあたりの学習時間を短縮(ただし LightGCN よりは低速)
  • グラフ拡張が不要であることを実証

対照学習ベースの他のアプローチ

SimGCL 以外の GNN + 対照学習ベースの手法をいくつか紹介します。

論文 概要
SGL(Wu et al., SIGIR 2021) Edge/Node Dropout によるグラフ augmentation の先駆けで、3 種類の augmentation(Edge Dropout, Node Dropout, Random Walk)を提案
XSimGCL(Yu et al., TKDE 2023) 対照学習用にノイズを含んだメッセージパッシングを繰り返し行っていたが、メッセージパッシングはせず最終層の埋め込みにノイズを加える手法に簡略化し計算コストを削減
LightGCL(Cai et al., ICLR 2023) グラフ全体を SVD で低ランクに近似し、グローバルな構造を反映した埋め込み & 通常の LightGCN の埋め込みを活用して対照学習を行う

4. おわりに

本記事では、LightGCN の基本的な仕組みとその課題、そして各課題に対応するための代表的な改善アプローチを紹介しました。

実務においては素の LightGCN をそのまま使うことはそう多くなく、何らかの改善手法が組み込まれていることが一般的かと思います。

特に大規模データを使った推薦システムでは計算コストと精度のバランスを取ることが重要になるため、今回紹介したような論文のアイデアが実務に応用されるケースが多いのではないでしょうか。

次はここで紹介した手法を実際にオープンデータセットで試してみたいです。気力が持てば…

参考文献

*1:「LightGCN の課題」と表現しているものの、LightGCN 特有の課題だけでなく GCN ベースの推薦モデル全般に共通する課題だったり推薦モデルの一般的な課題も含まれています

*2:LightGCNはシンプルさを追求したモデルですが、そのシンプルさが逆に柔軟性を欠く原因になっている、という皮肉な指摘でもあります…

Pandas でテーブルデータを読み書きする際のフォーマットごとの性能比較

動機

pandas を使うようになってからというもの、デファクトスタンダードである(と思っていた)csv形式でテーブルデータの読み書きをしていた。 最近は数GB程度のテーブルデータを扱う機会が増えてきており、データの読み書きをするだけでも相当な時間を要していることに気づいた。 「そもそもそんな規模感のデータを素の pandas で扱うな、daskを使え」などという批判も真摯に受け流しつつ、今一度 csv の代替となるフォーマットを探すべく我々はアマゾンの奥地へ向かった。

まずは結論

結論、読み書き速度とデータサイズの観点だけで言えば csv からの乗り換え先は parquet 形式ではないでしょうか。 csv 形式と比較した結果は以下。

フォーマット データサイズ read 時間 write 時間
csv 3.5 GB 1 min 145 sec
parquet 1.1 GB 1.08 sec 19.3 sec

当然データを扱う状況によって最適なフォーマットは変わり得るので盲信はよくないが、「あんまりめんどくさいことはせずにとりあえず csv から乗り換えたい!」というユースケースには適合すると思う。

比較対象フォーマット

今回 csv 形式との比較対象としたものを以下表にまとめる。

形式 選定理由
jsonl 特に深い理由はない。強いて言うなら BigQuery のデータをエクスポートする際の選択肢として存在しているから…
parquet カラムナフォーマットの代表格。GCP の各種プロダクトでサポートしていることが多い。
pickle ML モデルを保存する際のデファクトスタンダード。
joblib かつて個人的に pickle からの乗り換え先として愛用していたので。もはや pandas 関係ない。

上記のフォーマット以外にも様々な保存形式は存在するが、「極力 csv 形式からの引越しコストを抑えたい」「あまり馴染みのないフォーマットを扱いたくない」という個人的な怠慢から他のフォーマットは検討していない。 例えば TFRecord などは依存関係として tensorflow を持たせなきゃいけなかったり pandas とは異なるインターフェースでデータを扱う必要があり、データフォーマットを変えるだけでその副作用が出過ぎてしまうので候補に入れていない。

www.tensorflow.org

ちなみにフォーマットという観点以外にも cudf や dask を使うという選択肢もあるが、 cudf はまず GPU を用意するところから始まるので今までなんとな〜く csv を使っていた人がとりあえず使ってみるツールにしてはちょっとハードルが高い気がする。dask は pandas ライクに扱えるがインターフェースが違ったりハマりどころが色々あるので、しっかり腰を据えて高速化を検討するときの選択肢という印象…。

github.com

docs.dask.org

使用するデータ

以下のようにダミーデータを生成した。初めは調子に乗って 5,000 万行を float で作ろうとして普通に OOM で逝ったので控えめの integer 500万行にした。

import pandas as pd
import numpy as np

n_rows = 5_000_000
n_cols = 256
rng = np.random.default_rng()
table_df = pd.DataFrame(rng.integers(low=0, high=100, size=(n_rows, n_cols)))

path = "./table.{}"

write/read に使用するコード

保存フォーマットごとに使用したコードを記載する。

csv

# write
table_df.to_csv(path.format("csv"))
# read
table_df = pd.read_csv(path.format("csv"))

jsonl

# write
table_df.to_json(path.format("jsonl"), orient='records', lines=True)
# read
table_df = pd.read_json(path.format("jsonl"), orient='records', lines=True)

parquet

# write
table_df.to_parquet(path.format("parquet"))
# read
table_df = pd.read_parquet(path.format("parquet"))

pickle

# write
table_df.to_pickle(path.format("pkl"))
# read
table_df = pd.read_pickle(path.format("pkl"))

joblib

import joblib

# write
with open(path.format("joblib"), "wb") as f:
    joblib.dump(table_df, f, compress=3)
# read
with open(path.format("joblib"), "rb") as f:
    table_df = joblib.load(f)

(joblib だけ圧縮形式にしててズルいけど気にしない)

実行結果

jupyter notebook で%%timeマジックコマンドを使って実行した結果を表にまとめた。

フォーマット データサイズ read 時間 write 時間
csv 3.5 GB 1 min 145 sec
jsonl 11 GB N/A 177 sec
parquet 1.1 GB 1.08 sec 19.3 sec
pickle 9.6 GB 3.34 sec 42.3 sec
joblib 1.8 GB 25 sec 163 sec

jsonl は read しようとすると OOM で落ちてしまったので N/A とした。 表の通り、データサイズ・read 時間・write 時間の全項目で parquet 形式が圧勝だった。csv と比較して read は55倍、 write は7.5倍程度早くなっている。 ちなみに読み書きの速度に関しては pickle もいい線をいっているがデータサイズが csv の3倍弱になっているので、高速化の代償としては大きい気がする。

結論

csv からなんか別なフォーマットにしたいな〜という人には parquet 形式をオススメします。 なお parquet はバイナリフォーマットなので、 csv のように vim とか head でファイルの中身をチラ見できないのがデメリットでしょうか。

Feature Storeを概観する

はじめに

Feature Storeについて調べた際に日本語で資料がまとまったものがなかったのでまとめる。とはいえ、この記事もまとまってはいないかもしれない。

Feature Storeって何

端的に言うと「機械学習モデルで扱う特徴量をひとまとめにして管理し、かつ特徴量の提供も行う基盤」。これだけ聞くと特徴量専用のデータストレージを作ればいいじゃんと思うかもしれないので、Feature Storeを使うモチベーションを述べる。

より詳しく知りたい方はUberのMichelangeloというシステムの紹介記事を参照されたし。

eng.uber.com

Feature Storeを利用するモチベーション

機械学習モデルを構築し本番環境にリリース・運用しているチームでは以下のような状況になることがある。

  • 特徴量のソースがデータレイクやストリーミングデータなど様々
  • 他のプロジェクトやチームで作成した特徴量を使い回していない(使い回せない)
  • 学習時とモデルサーブ時でモデルに入力する特徴量の参照先が異なる
  • 上記に伴い、学習時とモデルサーブ時でデータを提供する仕組みが異なる

一つ二つのモデルを作って終わりならまだしもモデルを日々改善・監視しつつ更に新たなモデルを増やしたりする場合に上記の状況は深刻な問題となるので、この辺りを解決していこうというのがFeature Storeの目指すところ。

先の「特徴量専用のデータストレージを作ればいいじゃん」という意見に対しては一つのデータソースにまとめることができるならそれでいいが、本番環境に載せるモデルは往々にして色んなところからデータを取りたくなるもの。特に学習時はRDBから、サーブ時はKey-Value Storeから、といった具合に分かれる上に一度作ったシステムを使い回すのは中々に大変なので、そこにFeature Storeの大きな存在意義があると思っている。

ちなみに個人的な話で言うと、モデルを作るときに「こういう特徴量って絶対他のチームで作ったことあるよな」と思いつつモヤモヤしながら車輪の再発明をしたことがあるので、Feature Storeはモデルを作る人の作業に対する納得感を担保する一つの要素と考えている。

Feature Storeのコンポーネント

Feature Storeのマネージドサービスを提供しているTectonの以下のテックブログでは、Feature Storeを構成する5つの要素について紹介されている。

www.tecton.ai

1. Serving

f:id:f6wbl6:20210106150002p:plain

学習時と推論時で一貫したデータソースを参照して提供する。注目すべき点は学習時と推論時でほとんど同じインターフェースを利用できることで、同じようなインターフェースながらも推論時には低遅延でレスポンスが返ってくることが求められている。

この図には明記されていないが、学習時に渡しているエンティティ(entities_df)にはuser_idとデータを取得する期間が入っていて、推論時はuser_idとitem_idだけを指定してデータストレージにある最新の特徴量を暗黙的に返却するものと思われる。

インターフェースが統一できるのは割とバカにできないもので、作るモデルやプロジェクトによってデータの取得方法を思い出したりする手間が省けるから便利。データの取得先がBigQueryだったりGCSだったりBigtableだったりした時に、その度にデータの取り出し方を調べてる気がするので…。

あとは特徴量サーブで重要な概念として「タイムトラベル」があり、ある特定時点での特徴量のビューを提供する。例えば2020/12/24 21:00時点での特徴量のビューをタイムトラベルにより提供することができるため、模擬的に特徴量の状態を再現することができる。

2. Storage

f:id:f6wbl6:20210106160456p:plain

定義された特徴量を永続化する。オフラインストレージとオンラインストレージの二つから構成される。

オフラインストレージ オンラインストレージ
用途 学習/推論 推論
DBタイプ DWH, データレイク等 KVS
DB例 BigQuery, GCS Bigtable, Redis

「大きいデータはDWHやデータレイクに保存して応答性が求められるものはKVS」という至極普通の構成。Feature Storeというもので中身を隠蔽しているだけなんだけど、自前でFeature Storeと同じ仕組みを構築するとなると二つのストレージ間で同期を取ったりするのが大変そうではある。

3. Transform

f:id:f6wbl6:20210106163407p:plain

Feature Storeに入力される特徴量に対して前処理を加える。ログとして収集された生データをそのまま特徴量として使えないものに何らかの前処理を加えてから保存しようということ。

Transformの種類として以下の3パターンがある。

種類 概要 入力 特徴量の例
バッチ変換 オフラインストレージに対する処理 DWH, データレイク等 都道府県, 商品カテゴリ
ストリーミング変換 ストリーミングデータソースに対する処理 Pub/Sub, Kafka等 過去30分間でのカテゴリごとのクリック数
オンデマンド変換 リアルタイムデータソースに対する処理 APIへのリクエストパラメータ等 ユーザーの現在地

こうした処理はSparkやHadoopで実行されてオフラインストレージないしオンラインストレージに処理結果を保存してモデルに特徴量を提供するため、これらの処理を行うためのインフラなどをその都度用意する必要がなくなるのがメリットか。

確かに単純なOne-hot EncodingとかならFeature Store側でその処理を受け持って欲しいと思うが、例えばあるモデルのembedding layerといった分散表現を特徴量として使うような場合にはむしろ管理が複雑になる気もする。

4. Monitoring

Feature Storeで利用する特徴量の品質を管理する。管理観点を大まかに分類すると以下のようになる。

監視対象 項目
モデルサーブ時に提供する特徴量 Training - Serving Skew
Feature Store自体 特徴量使用率、各ストレージの容量、スループット、エラー率
外部システム Transformジョブの状態、スループット、エラー率

一つ目のTraining - Serving Skewは学習時とモデルサーブ時に提供するデータの偏りのことで、初歩的なものだと学習時とは異なるOne-hot Encodingの結果が得られた時とか。Training - Serving SkewについてはGoogleの"Rules of Machine Learning: Best Practices for ML Engineering"でも取り上げられているので気になる方は以下を参照。

developers.google.com

5. Registry

これまでに述べてきた各コンポーネントを統合してチーム間でFeature Storeを扱えるようにするための中央インターフェースのこと。レジストリを介して上に述べた各処理を実行する、というだけ。

どんなFeature Storeがあるか

Feature Storeは企業が独自に構築していたりマネージドサービスで提供していたりOSSとして存在していたりする。よく目にするFeature Storeについて分類した表が以下。

アーキテクチャ名 種別 概要
Michelangelo 内製 Uberで運用されている、Feature Storeに限らないML基盤
Zipline 内製 Airbnbで運用されているFeature Store
Tecton マネージド 大規模なMLシステム向けの商用Feature Store
Amazon SageMaker Feature Store マネージド re:Invent 2020で発表されたAWS謹製のFeature Store
Hopsworks OSS KubeflowのようなML基盤で、その中の機能の一つとしてFeature Storeがある
Feast OSS GO-JEKとGoogleCloudが共同で開発を進めているFeature Store

Feature Storeの概念自体はUberの例が初出という記事をどこかで見たが、ただ初出というだけで実際には各企業が内々で似たようなものを作っていたんだな…と思った。AWSがリリースしたものは自社で運用していたものの一部なのだろうか。GoogleCloudはFeastの開発を進めているのでGCPで利用できるマネージドFeature StoreはFeastベースになるのだろうが、どこまで使えるものになるか個人的に期待している。

ちなみにTectonは昨年11月にFeastの開発を支援する旨の声明を出していて、Feastでカバーしきれない部分をTectonでカバーし集客に繋げたい模様。

www.tecton.ai

その他のFeature Storeについては以下を参照されたし。

www.featurestore.org

まとめ

  • Feature StoreはMLモデルで扱う特徴量を管理する基盤で、学習もサーブも共通のIFで特徴量を提供する
  • Feature StoreはServing, Storage, Transform, Monitoring, Registryの5つの要素で考えることができる
  • マネージドサービスからOSSまで様々なFeature Storeがある

MLモデルを運用したことのある人なら「せやな」で終わる話ばかりだったかもしれない。

今度はOSSとして開発が進められているFeastについてまとめてみる。