映画の好みを予測しますか?オートエンコーダを使用して協調フィルタリングを実装する方法

映画の好みを予測しますか?オートエンコーダを使用して協調フィルタリングを実装する方法

推奨システムは、協調フィルタリングを使用して、ユーザーの好み情報を収集し、特定のユーザーの興味を予測します。協調フィルタリング技術の基本的な前提は、ユーザー A が特定の問題に関してユーザー B と同じ趣味や意見を持っている場合、他の問題に関しても A は B と同じ意見を持っている可能性が高いというものです。

この記事では、ユーザーの好み、視聴履歴、同じ映画や他の映画を見た他のユーザーのレビューに基づいて、ユーザーの映画の評価を予測する方法を説明します。

[[229848]]

1. はじめに

オートエンコーダーは、協調フィルタリングの分野で最先端のパフォーマンスを実現するディープラーニング ニューラル ネットワーク アーキテクチャです。この記事の最初の部分は理論的な概要であり、単純なオートエンコーダとディープオートエンコーダの基本的な数学的概念を紹介します。パート 2 では、実用的な側面を詳しく説明し、この手法を TensorFlow で段階的に適用する方法を説明します。この記事では、モデルの最も重要な部分のみを取り上げ、評価します。

モデル全体の入力パイプラインと前処理は、対応する GitHub で確認できます。

https://github.com/artem-oppermann/Deep-Autoencoders-For-Collaborative-Filtering

2. ディープオートエンコーダ

1. オートエンコーダ

ディープオートエンコーダーについて説明する前に、まずは少しシンプルなバージョンを紹介しましょう。オートエンコーダーは、入力データのセットの表現 (エンコーディング) を学習するために使用される人工ニューラル ネットワークであり、次元削減を実現するために使用されることがよくあります。

構造的には、オートエンコーダは、入力層、隠れ層、出力層で構成されるフィードフォワード ニューラル ネットワークの形式をとります (図 1)。出力層には入力層と同じ数のニューロンがあるため、オートエンコーダは教師なし学習であり、ラベル付きデータは必要ありません。入力と出力のペアではなく、入力データのセットだけが必要です。

図1. 典型的なオートエンコーダアーキテクチャ

オートエンコーダの隠し層は入力層よりも小さいため、モデルはデータ内の相関関係を学習して、隠し層内のデータの圧縮表現を作成できます。

入力層から隠れ層への変換はエンコード手順と呼ばれ、隠れ層から出力層への変換はデコード手順と呼ばれます。これらの変換をマッピングとして数学的に定義することもできます。

このマッピングは、入力データ ベクトルに重み行列を乗算し、バイアス項を追加し、結果のベクトルをシグモイド、tanh、または正規化線形単位などの非線形演算に適用することによって実現されます。

2. オートエンコーダのトレーニング

トレーニング中、エンコーダーは入力データ サンプル x を受け取り、それをいわゆる隠し層または潜在表現 z にマッピングします。次に、デコーダーは z を出力ベクトル x' にマッピングします。これは (最良の場合) 入力データ x の正確な表現です。一般に x を正確に再構築することは不可能であることに注意してください。

出力x'を使用したトレーニングは、平均二乗誤差などの所定の損失を最小化するために確率的勾配降下法を適用することから構成されます。

3. ディープオートエンコーダ

シンプルなオートエンコーダの拡張バージョンがディープオートエンコーダです (図 2)。図 2 からわかるように、単純な対応部分との唯一の違いは、隠し層の数です。

図2. ディープオートエンコーダのアーキテクチャ

追加の隠し層により、オートエンコーダはデータ内のより複雑な基礎パターンを数学的に学習できるようになります。ディープオートエンコーダの最初のレイヤーは、生の入力内の一次特徴(画像内のエッジなど)を学習できます。 2 番目のレイヤーは、1 次特徴の外観のパターンに対応する 2 次特徴を学習できます (たとえば、どのエッジが一緒に発生する傾向があるか、たとえば輪郭やコーナー検出器を形成するかなど)。ディープオートエンコーダのより深い特徴は、多くの場合、より高次の特徴を学習できます。

まとめると、協調フィルタリングで使用するデータのような、より複雑なデータを処理するには、より多くのレイヤーが必要になります。

3. 実装

前述したように、ユーザーが映画に与える評価を予測する方法を学びます。この目的のために、有名なMovieLensデータセットを使用します。

(https://grouplens.org/datasets/movielens/)。 MovieLensis は、ユーザーに映画を推奨する Web ベースの推奨システムおよびオンライン コミュニティです。

具体的には、6,040 人の MovieLens ユーザーによって生成された約 3,900 本の映画に対する 1,000,209 件の匿名評価を含む ml_1m.zip データセットを使用します。必要なインポート ファイルは ratings.dat です。ファイルには 1,000,209 行が含まれており、すべて次の形式になっています: user_id::movie_id::rating:time_stamp。

たとえば、 ratings.dat の最初の行:

  1. 1::595::5::978824268

これは、ユーザー 1 が映画番号 595 を 5 つ星で評価したことを意味します。ここではスコアリング時間は使用しないため無視できます。

当社のディープラーニング モデルでは、トレーニングとテストに特定のデータ構造が必要です。このデータ構造は UxM 行列です。ここで、U はユーザー数、M は映画の数です。各行 i∈U は一意のユーザー ID であり、各列 j∈M は一意の映画 ID です。このマトリックスを視覚化したものが図 3 に示されています。

このマトリックスの各エントリは、ユーザーが特定の映画に付けた評価です。 0 を入力すると、ユーザーが映画に評価を与えていないことを意味します。例えば。上記の画像では、ユーザー 1 が映画 3 を 4 つ星で評価しましたが、映画 1 にはまったく評価がありませんでした。

このチュートリアルではディープラーニング モデルの実装に焦点を当てているため、 ratings.dat ファイルを超えて User-Movie-Matrix を使用する手順についてはここでは説明しません。このトピックに関するさらなる質問については、私のGitHubページをご覧ください。

(https://github.com/artem-oppermann/Deep-Autoencoders-For-Collaborative-Filtering/blob/master/data/preprocess_data.py)、対応する Python スクリプトを参照してください。

1. トレーニングとテストのデータセット

モデルの実装とトレーニングの前に、データに対して追加の再処理手順を実行して、データをトレーニング データセットとテスト データセットに分割する必要があります。このステップはシンプルで簡単です。これまでのところ、各行が評価のリストであるユーザー-映画マトリックスができました。リストからトレーニング セットとテスト セットを取得するには、各行から評価のサブセットを取得してトレーニングに使用し、残りのサブセットをテストに使用する必要があります。

プロセスを説明する例として、わずか 15 本の映画で構成されるはるかに小さなデータセットを考えてみましょう。特定のユーザーは次のような映画を評価するかもしれません:

  1. 映画番号: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
  2. 評価: 5 0 2 4 0 0 2 1 5 1 0 4 5 1 3

0 は映画の評価がされていないことを意味することに注意してください。ここで、最初の 10 本の映画のサブセットをトレーニング セットとして取り、残りはまだ評価されていないと仮定します。

  1. 映画番号: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
  2. 評価: 5 0 2 4 0 0 2 1 5 0 0 0 0 0 0

したがって、元のデータの最後の 5 つの映画評価がテスト データとして使用され、映画 1 ~ 10 は評価なしとしてマスクされます。

  1. 映画番号: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
  2. 評価: 0 0 0 0 0 0 0 0 0 1 0 4 5 1 3

これは、さまざまな組み合わせを取得する方法の単純なデモンストレーションです。オリジナルの MovieLens データセットでは、テストにはユーザーごとに 10 件の映画評価のみを使用し、残り (大部分) はモデルのトレーニングに使用しました。

2. TensorFlowの実装

(1)モデルアーキテクチャ

ここでは、ディープ オートエンコーダーは、推論、最適化、損失、精度などの必要な操作がすべてクラス内に含まれるクラスとして実装されています。

コンストラクターでは、カーネル初期化子が重みとバイアスを設定します。次に、ネットワーク内のすべての重みとバイアスが初期化されます。重みは平均 0.0、分散 0.02 の正規分布に従いますが、バイアスは最初は 0.0 に設定されています。

この例では、ネットワークには 3 つの隠し層があり、各隠し層には 128 個のニューロンが含まれています。入力層 (および出力層) のサイズは、データセット内の現在のすべての映画の数に対応します。

  1. クラスDAE:
  2. ''' Deep Autoencoder クラスの実装'''
  3.  
  4. def __init__(self, フラグ):
  5. 自己.FLAGS =フラグ
  6. self.weight_initializer = model_helper._get_weight_initializer () です。
  7. self.bias_initializer = model_helper._get_bias_initializer () です。
  8. 自己初期化パラメータ()
  9.  
  10.  
  11. def init_parameters(self):
  12. ''' ニューラル ネットワークの重みとバイアスを初期化します。'''
  13.  
  14. tf.name_scope('weights') を使用する場合:
  15. self.W_1 = tf .get_variable( name = 'weight_1' shape =(self.FLAGS.num_v、self.FLAGS.num_h)、
  16. 初期化子= self .weight_initializer)
  17. self.W_2 = tf .get_variable( name = 'weight_2' shape =(self.FLAGS.num_h,self.FLAGS.num_h)、
  18. 初期化子= self .weight_initializer)
  19. self.W_3 = tf .get_variable( name = 'weight_3' shape =(self.FLAGS.num_h,self.FLAGS.num_h)、
  20. 初期化子= self .weight_initializer)
  21. self.W_4 = tf .get_variable( name = 'weight_5' shape =(self.FLAGS.num_h、self.FLAGS.num_v)、
  22. 初期化子= self .weight_initializer)
  23.  
  24. tf.name_scope('biases') を使用する場合:
  25. self.b1 = tf .get_variable(名前= 'bias_1' 形状=(self.FLAGS.num_h)、
  26. 初期化子= self .bias_initializer)
  27. self.b2 = tf .get_variable(名前= 'bias_2' 形状=(self.FLAGS.num_h)、
  28. 初期化子= self .bias_initializer)
  29. self.b3 = tf .get_variable(名前= 'bias_3' 形状=(self.FLAGS.num_h)、
  30. 初期化子= self .bias_initializer)

(2)研修

入力データ サンプル x (ユーザー ムービー マトリックスの行) が与えられると、順方向パスが実行され、ネットワーク出力が計算されます。隠れ層は活性化関数としてシグモイドを使用します。最後の層には非線形性やバイアス項がないことに注意してください。

  1. def _inference(自己, x):
  2. '''1 回の前方パスを実行します。入力に基づいて出力を予測します。'''
  3.  
  4. tf.name_scope('inference') を使用する場合:
  5. a1 = tf.nn.sigmoid (tf.nn.bias_add(tf.matmul(x, self.W_1), self.b1))
  6. a2 = tf.nn.sigmoid (tf.nn.bias_add(tf.matmul(a1, self.W_2), self.b2))
  7. a3 = tf.nn.sigmoid (tf.nn.bias_add(tf.matmul(a2, self.W_3), self.b3))
  8. a4 = tf .matmul(a3, self.W_4)
  9. a4を返す

ネットワークの予測を使用して、これらの予測と対応するラベル (ネットワーク入力 x) 間の損失を計算できます。損失の平均を計算するには、ゼロ以外のラベルの数、つまりトレーニング セット内のユーザーによる評価の合計数も知る必要があります。

  1. def _compute_loss(自己、予測、ラベル、ラベル数):
  2. ''' ネットワークの入力と出力間の平均二乗誤差損失を計算します。
  3.  
  4. @param predictions: スタックオートエンコーダの予測
  5. @param labels: スタックされたオートエンコーダの入力値。同時にラベルとしても機能します。
  6. @param num_labels: 平均を計算するデータセット内のラベルの数 != 0
  7.  
  8. @return 平均二乗誤差損失 tf-operation
  9. '''
  10. tf.name_scope('loss') を使用する場合:
  11. loss_op = tf .div(tf.reduce_sum(tf.square(tf.subtract(予測値、ラベル))),num_labels)
  12. リターン loss_op

ネットワークの最適化/トレーニング手順は少し難しいように思えるかもしれませんので、ステップごとに説明しましょう。入力 x が与えられたら、対応する出力を計算します。入力 x のほとんどの値がゼロ値であることに気付いたかもしれません。これは、ユーザーがデータセット内の 5953 本の映画をすべて視聴して評価したわけではないためです。したがって、ネットワークの生の予測を直接使用しないことをお勧めします。代わりに、データ入力 x 内のゼロ値のインデックスを決定し、それらのインデックスに対応する予測ベクトル内の値もゼロに設定する必要があります。この予測操作により、ネットワークのトレーニング時間が大幅に短縮され、ネットワークはユーザーが実際に与えた評価にトレーニングの労力を集中できるようになります。

このステップの後、損失とオプションで正則化損失を計算できます。 AdamOptimizer は損失関数を最小化します。このメソッドは、精度をより正確に測定するために、平均二乗誤差 (MSE) ではなく、二乗平均平方根誤差 (RMSE) を返すことに注意してください。

  1. _optimizer を定義します(self, x):
  2. '''確率的勾配降下法によるネットワークパラメータの最適化。
  3.  
  4. @param x: スタックオートエンコーダの入力値。
  5.  
  6. @return: テンソルフロートレーニング操作
  7. @return: ROOT!! 平均二乗誤差
  8. '''
  9.  
  10. 出力= self ._inference(x)
  11. mask = tf .where(tf.equal(x,0.0), tf.zeros_like(x), x) # トレーニング セット内のゼロ値のインデックス (評価なし)
  12. num_train_labels = tf .cast(tf.count_nonzero(mask), dtype = tf .float32) # トレーニング セット内のゼロ以外の値の数
  13. bool_mask = tf .cast(mask, dtype = tf .bool) # ブールマスク
  14. outputs = tf .where(bool_mask, output, tf.zeros_like(outputs)) # 対応する入力値がゼロの場合、出力値をゼロに設定します
  15.  
  16. MSE_loss = self ._compute_loss(出力、x、num_train_labels)
  17.  
  18. self.FLAGS.l2_reg == Trueの場合:
  19. l2_loss = tf.add_n ([tf.nn.l2_loss(v) は tf.trainable_variables() 内の v に対して])
  20. MSE_loss MSE_loss = MSE_loss + self.FLAGS.lambda_ * l2_loss
  21.  
  22. train_op = tf .train.AdamOptimizer(self.FLAGS.learning_rate).minimize(MSE_loss)
  23. RMSE_loss = tf .sqrt(MSE_loss)
  24.  
  25. train_op、RMSE_lossを返す

(3)テスト

数エポックのトレーニングを経て、ニューラル ネットワークはトレーニング セット内の各ユーザーの評価と時間をすべて把握することになります。この時点で、モデルはデータ内の根本的な隠れたパターンと、それに対応するユーザーの映画評価を学習しているはずです。ユーザーが評価したトレーニング サンプル x が与えられると、モデルは出力 x' を予測します。このベクトルは、入力値 x の再構成 (予想どおり) で構成されますが、入力 x に以前はゼロだった値も含まれるようになりました。これは、モデルが評価されていない映画を評価していることを意味します。この評価は、ユーザーの好み、つまりモデルがデータから識別して学習した好みに対応します。

モデルの精度を測定するには、トレーニング データセットとテスト データセットが必要です。トレーニング セットに基づいて予測を行います。トレーニングフェーズと同様に、テストセット内のゼロ以外の値を持つインデックスに対応する出力値のみを考慮します。

これで、予測された評価と実際の評価の間の二乗平均平方根誤差損失 (RMSE) を計算できます。 RMSE は、予測値と観測値の差のサンプル標準偏差を表します。たとえば、RMSE が 0.5 の場合、平均予測評価が実際の評価と 0.5 星異なることを意味します。

  1. def _validation_loss(self, x_train, x_test):
  2. ''' 検証時間中の損失を計算します。
  3. @param x_train: トレーニングデータサンプル
  4. @param x_test: テストデータサンプル
  5. @return ネットワーク予測
  6. @return 予測評価と実際の評価の間の二乗平均平方根誤差損失
  7. '''
  8. output = self ._inference(x_train) # トレーニングサンプルを使用して予測を行う
  9. mask = tf .where(tf.equal(x_test,0.0), tf.zeros_like(x_test), x_test) # テストステート内のゼロ値を識別します
  10. num_test_labels = tf .cast(tf.count_nonzero(mask), dtype = tf .float32) # ゼロ以外の値の数を数える
  11. bool_mask = tf .cast(mask, dtype = tf .bool)
  12. 出力= tf .where(bool_mask, 出力, tf.zeros_like(出力))
  13.  
  14. MSE_loss = self ._compute_loss(出力、x_test、num_test_labels)
  15. RMSE_loss = tf .sqrt(MSE_loss)
  16.  
  17. 戻り出力、RMSE_loss

(4)研修結果

最後のステップでは、トレーニング プロセスを実行し、モデルのパフォーマンスを確認します。この時点では、データ入力パイプライン、グラフ、セッションなどの構築の詳細については説明しません。これらの手順は通常は知られているからです。このトピックに興味のある読者は、私の GitHub でこれらの手順を確認できます: https://github.com/artem-oppermann/Deep-Autoencoders-For-Collaborative-Filtering/blob/master/train.py

ここでは、最初の 50 エポックのトレーニングとテストのパフォーマンスを確認できます。 50 エポック後、テスト セットの予測評価と実際の評価の偏差は 0.929 星になります。

  1. エポック番号: 0、トレーニング損失: 1.169、テスト損失: 1.020
  2. エポック番号: 10、トレーニング損失: 0.936、テスト損失: 0.959  
  3. エポック番号: 20、トレーニング損失: 0.889、テスト損失: 0.931  
  4. エポック番号: 30、トレーニング損失: 0.873、テスト損失: 0.923  
  5. エポック番号: 40、トレーニング損失: 0.859、テスト損失: 0.925  
  6. エポック番号: 50、トレーニング損失: 0.844、テスト損失: 0.929

元の住所:

https://towardsdatascience.com/deep-autoencoders-for-collaborative-filtering-6cf8d25bbf1d

[この記事は51CTOコラム「Machine Heart」、WeChatパブリックアカウント「Machine Heart(id:almosthuman2014)」によるオリジナル翻訳です]

この著者の他の記事を読むにはここをクリックしてください

<<:  実践的なスキル: システムレベルからディープラーニングコンピューティングを最適化するにはどうすればよいでしょうか?

>>:  ジャック・マー、孫丑樹、劉強東、周紅一はいかにして「スマート時代」に突入したのか?

ブログ    
ブログ    
ブログ    
ブログ    
ブログ    
ブログ    

推薦する

AI は銀行がますます激化する詐欺の競争に勝つためにどう役立つか

今日のイノベーションのペースが競争だとしたら、世界は猛烈なスピードで変化しています。今日の世界で起こ...

人工知能の進化の限界は肉体にある

[[233888]] AIの未来は私たち自身のニューラルネットワークを複製することにある私たちは、チ...

...

メタバースの錬金術には物理の基本法則が必要です! Nvidia副社長:現実世界のデータトレーニングは不要

次のことは直感に反するように思えるかもしれません: AI が現実世界のアプリケーション シナリオに適...

人工知能とはいったい何でしょうか?人工知能の主要なテクノロジーと概念について学びましょう。

現在、人工知能が何であるかをまだよく理解していない人がたくさんいます。今日は、人工知能の主要な技術と...

GPT-175Bを例にとった大規模言語モデルの分散トレーニングの定量分析とベストプラクティス

1. Transformer 大規模言語モデルのための SOTA トレーニング技術1. 大規模言語モ...

仕事再開時に間接接触を避けるには?顔認識アクセス制御で徹底した予防と管理を実現

職場復帰の日が近づくにつれ、全国で生産や業務が徐々に再開されているが、同時に防疫活動も緩めてはならな...

GitHub Copilot の盗作が確認されました! GitHub: 私たちの AI はコードを「暗唱」しません

[[409261]] GitHub Copilot は、コードを自動生成するという強力な機能により、...

ビットコインマイニング技術: 分散データストレージ、ピアツーピア伝送、コンセンサスメカニズム、暗号化アルゴリズム...

1. 説明ブロックチェーンは、オープンなデータ操作、改ざん不可能、追跡可能性、国境を越えた分散化な...

GPT-4Vに匹敵し、120万データと8つのA100のみを使用し、トレーニングは1日で完了し、LLaVA-1.5は11のベンチマークSOTAを更新しました。

マルチモーダル大型モデル着陸の風がようやく吹いた。 12日前、OpenAIはChatGPTに画像認識...

中国初の真のAI入力方式が発表され、未来の入力方式を革新する

入力がキーボードに別れを告げ、音声、表現、動作が入力方法になると、どのような魔法のような体験になるの...

130 の大学が人工知能専攻を追加。次の「陥没穴」専攻になるのでしょうか?

大学の専攻の盛衰は、時代の発展と技術の進歩を最もよく物語る証拠でもあります。今日のいわゆる「落とし穴...

...

...

...