🐕

RaggedTensorで可変長データをレコメンドに組み込む方法

に公開

はじめに

レコメンデーションシステムを構築する際、可変長データの扱いは常に課題となります。例えば、ECサイトの商品に紐づくタグや、ニュース記事のキーワードは、その数が商品や記事ごとに異なります。

自分は主にTensorFlowで画像データしか扱ってこなかったため、可変長データには苦手意識がありました。しかしRaggedTensorを利用すると、データの読み込みからモデル学習まで簡単に可変長データを扱えてとても感動したのを覚えています。

今回は、このRaggedTensorを使ってレコメンドシステムに可変長の商品タグデータを組み込む方法を解説します。

RaggedTensor

日本語公式ドキュメント https://www.tensorflow.org/guide/ragged_tensor?hl=ja

通常、TensorFlowでは全てのデータが同じサイズである必要があります。そのため、異なる長さのシーケンスを扱う際には、パディング(短いシーケンスにゼロを詰める処理)を行うのが一般的です。

しかし、パディングには以下のような問題があります。

  • メモリの無駄: 非常に長いシーケンスがある場合、他の短いシーケンスもそれに合わせて大量のゼロでパディングする必要があり、メモリ効率が悪化します。
  • 計算の無駄: パディングされたゼロも計算の対象となるため、不要な計算が発生します。
  • パディング値の扱い: パディング値(通常は0)がデータ内の有効な値と区別できるように、mask_zeroなどの工夫が必要です。

RaggedTensorは、これらの複雑な処理を気にせず、四則演算やモデル学習/推論が行える便利な行列です。

RaggedTensorを利用した商品タグのエンべディング

サンプル行列の生成

今回は、簡単に3つの商品とそれに紐付く6つの商品タグを想定してエンべディングする処理を紹介します。

product_tags = tf.ragged.constant([
    [1, 2, 3],       # 商品1のタグID
    [1, 4, 5, 6],    # 商品2のタグID
    [3]              # 商品3のタグID
])
print(product_tags.shape)
product_tags

> (3, None)
> <tf.RaggedTensor [[1, 2, 3], [1, 4, 5, 6], [3]]>

行列の第二要素は可変長なので、第二要素のサイズはNoneになります。

商品タグのエンべディング

上記生成した商品タグ情報をニューラルネットワークモデルを利用してエンべディングします。

# input_dim: 商品タグのユニーク数 + 1
model = tf.keras.Sequential([
    tf.keras.layers.Embedding(input_dim=6+1, output_dim=32),
])
print(model(product_tags).shape)
model(product_tags)

> (3, None, 32)
> <tf.RaggedTensor [[[-0.031056559, 0.024490546, 0.03279623, 0.0091146715, -0.0350057, 0.042567458, -0.023720741, -0.039300144, -0.03181832, -0.025277866, -0.014838316, 0.0047158115, -0.0027456172, 0.033559907, 0.019823913, 0.022146713, -0.044504333, -0.02563945, 0.010793496, -0.031009674, 0.015534785, 0.041406777, -0.028139818, 0.020408403, 0.023775447, -0.037063517, 0.013013069, -0.039831378, 0.03136963, -0.035819672, 0.030923035, -0.040919077], [0.00026751682, 0.024028633, 0.048152912, -0.0037948713, -0.010998167, -0.017960332, 0.002881907, 0.026490632, 0.019711722, 0.0029380322, -0.03048463, -0.038111806, 0.045973863, 0.018287543, 0.049590673, -0.04622246, 0.04137719, -0.017893314, 0.040523436, 0.0019658208, 0.023592863, 0.010118831, 0.03830317, 0.026624028, 0.020709183, -0.029317582, -0.049214136, -0.0077725872, -0.035389055, 0.040477004, 0.033148218, -0.0039511435],...

まずは、それぞれの商品タグを個別にエンべディングします。サイズを見ると3つの商品の可変長データに対して32次元のエンべディングが生成されていることがわかります。

ただ、これだと1つのアイテムとして見たときに可変長でエンべディングが複数ありデータが扱いにくいため、tf.keras.layers.GlobalAveragePooling1Dを利用して商品ごとに平均を取り、商品タグ情報からのアイテムベクトルを取得します。

model = tf.keras.Sequential([
    tf.keras.layers.Embedding(input_dim=6+1, output_dim=32),
    tf.keras.layers.GlobalAveragePooling1D(),
])
print(model(product_tags).shape)
model(product_tags)

> (3, 32)
> <tf.Tensor: shape=(3, 32), dtype=float32, numpy= array([[-0.01235485, -0.01013283,  0.00388598,  0.01698468,  0.00463949, 0.01803677,  0.03121398, -0.03432863,  0.04003876, -0.02561267, -0.02822419, -0.00375384, -0.02085863,  0.01921872, -0.00524479, -0.01528156, -0.00844664,  0.02474038,  0.01040525, -0.02322186, -0.01112638,  0.03416611, -0.00829275, -0.02334791,  0.01820746, 0.03213282,  0.01558225,  0.0008272 ,  0.0165509 , -0.02307737, 0.0073213 ,  0.00122011],...

これにより、アイテムごとの商品タグ情報から32次元のエンべディングを取得することができました。

終わりに

RaggedTensorは、可変長データを効率的に扱い、モデルへの入力をシンプルにします。パディングやマスキングの煩雑な処理から解放され、モデル構築に集中できるのが最大のメリットです。

レコメンドシステムにおいて、商品メタデータのような可変長データを効果的に扱うことは、モデルの精度向上に直結します。ぜひ、皆さんのプロジェクトでもRaggedTensorを試してみてください!

DMM Data Blog

Discussion