こんにちは。BASE株式会社 DataStrategyに所属している齋藤(@pigooosuke)です。
先日、ショッピングアプリ「BASE」内の主要コンテンツである商品特集を自動で運用するように切り替えました。
今までは、「ワンピース特集」「ピアス特集」など、トレンド・テーマに沿った商品選定を人手で行い、全ユーザーに対して同一の配信をしていましたが、改善後はトレンドを捉えた特集コンテンツを自動で生成し、ユーザー別に最適化された特集を配信出来るようになりました。その結果、閲覧数の向上に繋げることが出来ました。
「BASE」ではレコメンドアルゴリズムを複数運用していますが、そのうち一部のモデルの応用により実現しましたので、その開発内容をお伝えしたいと思います。
特集について
「BASE」では特定のテーマに沿ってピックアップされた商品が特集としてリストアップされています。
BASEがセレクトしている今流行りの商品に出会えるコンテンツです。
要件定義
まず開発にあたって、必要事項の洗い出し・ヒアリングをしました。
リリースに向け最低限クリアしなくてはいけない条件は以下の通りでした。
- 特定のテーマに沿った特集であること
- それぞれの特集がトレンドをキャッチしていること
- 掲載商品は人気が出る商品であること
- それぞれの特集に対して、適切なタイトル文(説明文)が設定されていること
- 各ユーザーに対して、最適な特集が配信されていること
- 適切な商品・タイトルが設定されているか確認出来ること
上記を踏まえ、このようなフローなら一連の作業を代替出来るのではないかと構想・開発を進めました。 ここからは、各ステップでどのような処理をしているのか順に解説していきたいと思います。
1.商品レコメンドモデル作成
今回のレコメンドモデル作成には、LightFMのモデルを活用しています。
LightFMとは、ユーザー・商品の特徴(メタデータ)を取り込むことが出来る因子分解レコメンドモデルです。
ユーザー・商品のInteractionからユーザー・商品の潜在表現(Latent Representation)を学習して、潜在表現から評価値を復元(予測)出来るようにしています。
日本語圏で取り上げられている記事が少ないので、もう少しモデルの中身を紹介します。
ここでは、ユーザー・商品をそれぞれ, 、ユーザー・商品の特徴をそれぞれ, とします。
このモデルでは、ユーザー・商品が持つ特徴に対してembeddingを行います。
そして、全てのユーザー・商品の潜在表現はそれぞれに付与されている特徴の総和で表現されるとしています。
ユーザー・商品の潜在表現をそれぞれ, として、
同様に、ユーザー・商品のバイアス項をそれぞれ, として、
と定義されます。
(特徴表現・バイアス項は、それぞれが持っている特徴の総和であるというだけを意味しています。)
ユーザーに対する商品の評価値の予測は、の潜在表現との潜在表現の内積とそれぞれのbias項の和で計算します。
とてもシンプルな計算です。
損失関数については、WARP Loss(Weighted Approximate-Rank Pairwise loss)がサポートされており、BPRよりもこちらを活用したモデルが最も成績が良かったです。
ちなみに、WARP Lossはランク学習するための損失関数で、
まず、特定ユーザーの特定の正例に対して、それ以外の負例をランダムサンプリングします。
そこで、正例の予測値
に対して、負例の予測値
が一定のマージンを含めて超えた場合に、
商品総数に対して出現までにかかったサンプリング回数を考慮した、実際の評価と予測値の差分で重みを更新していきます。
参考資料: Learning-to-rank using the WARP loss
上で紹介したように、それぞれが持つ特徴同士の関係を踏まえ学習を進めるため、
「User-Item, User Feature / Item Featureの因子を組み合わせるので、Factorization machinesの特殊なケースとも言える。」とも論文では述べられています。
実際にこのモデルを使うメリットとしては、
- CPU環境でも高速に計算可能
- メタデータの追加が容易
- 各Interactionに対する評価値を自由に設定可能(Negative評価含め)
- 因子分解するためPureなFactorization Machinesより少ない計算量
が挙げられると思います。汎用性が高く個人的に好きなライブラリだったので利用しました。
同製作者が公開しているレコメンドシステムのフレームワークであるSplotlightにもBilinearNetとして同様の計算がGPU環境で実行出来るようパッケージ化されていますが、実際の運用ではCPUでも高速であり、モデリング時間自体がモデル更新処理全体に占める割合のごく一部にすぎないので、結果論ですがこれで十分だったと思います。
また、本番環境で運用するモデルを日々アップデートしていく中で、
どのような評価値(Rating)を、どのように学習に加えるかがレコメンドモデルでは重要ですが、今回の記事では省略します。
さらに、上記のモデルで評価値の推論を単純に行うと計算量が膨大となるので、計算量を減らす工夫も別途必要となります。
2.特集コンテンツ作成
ここでは特集に掲載する商品を選定していきます。
特集のトレンド感を出すのに利用しているのは、アプリ内検索キーワードです。
検索で上位に出てくるキーワードを元に商品群を選定しています。
(アプリユーザーが特定の特集を意図的に(不正に)生成出来ない仕組みは用意しています)
検索キーワードを元にレコメンドモデルで学習した商品群を抽出し、その中で注目度の高い商品
を特集に掲載することにしています。
つまり条件付きソートです。
ここで商品に対する注目度の高さ
という評価軸に活用したのがレコメンドモデルの学習結果です。
今回のレコメンドモデルでは、商品に対する評価値はユーザー・商品の潜在表現の内積にユーザー・商品のbias項を加えたもので推論されます。
ユーザーを特定しない場合は、ユーザー・商品間の内積とユーザーのbias項を無視することで、
商品単体としての評価値はbias項で近似されるとも言えます。
その評価値のrankと、いくつかの別の評価値を加え、注目の高い商品
として抽出しています。
ただ、「BASE」の商品群には注意すべき点があり、
「ワイドパンツ」というキーワードを元に特集を作ろうにも、それはメンズ?レディース?子供用?
また、「さくらんぼ」でも、それはフルーツ?刺繍?
といった多様な商品を掲載しているがゆえに、キーワードの属性を一意に決めることが困難なものが存在します。
そのため、各カテゴリーごとに特集を用意することにしています。
加えて様々な制御機構を経由し、最終的に200-300程度の特集を日々生成しています。
長くなりましたが、特集の中身をざっくり表現すると、トレンドキーワードの検索結果を(主に)人気順にソートしたものです。
わざわざユーザー自身でキーワードを入力せずに商品を閲覧出来る導線があるのは便利ですね。
3.特集タイトル作成
ここでは各商品群に対して最適なタイトルを選定していきます。 手元の状況を確認すると、
- 各特集にはカテゴリーとキーワードが付与されている
- 過去掲載してきた特集が十分蓄積されているとは言えない
- アノテーション済みデータもない
- 単語辞書もあまりない
- 特定ジャンルに特化しているサービスでもない(取り扱い商材はファッションからインテリア、エンタメまで)
ということで選択したのは、条件分岐生成です。 これまで過去、コンテンツ担当者が生み出してきたキャッチーなタイトルを参考に単語の置き換えでタイトルを作ることにしました。
タイトル選定する手順は以下の通りです。
- モデル作成時に、各特集で使われたキーワードがTableに追加されてきます。まだカテゴリー分類されていない未知語に関しては、オリジナルのラベルを付与していきます。
- 特定のタグが埋め込めているテンプレートには、どのキーワードカテゴリーに対応するかが設定されており、目的のキーワードに対して最適なテンプレートが選択されます。
- テンプレートに含まれているタグに対しても別途テンプレートタグ専用のアノテーションデータを用意してあり、指定のタグを埋めていきます。様々なタグを用意することで表現の幅を広げられるようにしています。
他にも出力制御機構を用意してありますが、基本的な仕組みはこの通りです。
特集タイトルのデータ管理は専用のDashboard画面(Vue.js + Django)で運用されています。
キーワード管理画面
4.配信最適化
最後に、どの特集を誰に配信するかを決めます。
ここでまたレコメンドモデルの推論に戻ります。
既に各ユーザーの各商品に対する評価値を推定する準備は出来ているので、
全ユーザーに対して各特集に含まれる全商品の評価値を計算&比較し、好まれやすい特集を上位に表示するようにしています。
レコメンドモデルのデータセットに含まれなかった(予測が出来ない)ユーザー向けの表示も別の属性を利用して計算しています。
5.運用
ここでは特集コンテンツ管理をどのように運用しているか紹介します。
(データ配信基盤の説明に関しては今回省略します。いつか誰かが投稿してくれるかもしれません。)
特集内容の詳細については、専用のDashboard画面で各種監視出来るよう整備してあります。 不適切な商品・タイトル文が生成されていた場合に、画面操作で表示条件の切り替えが可能です。
運用成績については、Redashで集計・計測しています。
具体的な数字は今回公開しませんが、リリース前後で閲覧状況の改善を達成することが出来ました。
終わり
以上の内容を踏まえて、各処理を振り返るとこのような構成になっています。
今回の実装を終えて振り返ってみると、
- レコメンドモデルの改善
- ユーザー別に特集構成商品の切り替え
- 特集テーマ・トレンド検知モデルの置き換え
- 各特集に掲載する商品フィルターの改善
- テンプレートで使っている単語に対するカテゴリー分類の自動化
- アノテーションデータを揃えて、テンプレートに対する単語の埋め込み学習
など、まだまだ各処理の最適化&統一を行う余地があるので、
今後の運用状況を観察しつつ改善をしていきたいと思います。
大層な書き方をしていますが、個々の処理で利用している要素技術は非常に単純なものです。
レコメンドモデルに関しても、今回紹介したものを活用しないと出来ないものでもありません。
必要に応じて様々なアイディアを組み合わせた機能開発が出来るのもBASEのDSチームの醍醐味だと思います。
設計レビューやリリースのサポートして頂いたエンジニアの方々ありがとうございました。
今後も精度向上や機能追加を行い、使いやすいサービスを作って行きたいと思います。楽しみにして頂ければ幸いです。
BASEでは一緒にネットショップ作成サービスを開発・改善するエンジニアを募集してます。 機械学習チームでは、様々なデータや技術を使ってECならではの開発を続けています。 ご興味のある方はぜひ遊びにきてください!!