Tensorflow Recommenders fit Expected string, but got Tensor("IteratorGetNext:0", shape=(None,), dtype=string) of type 'Tensor'

Viewed 33

I am trying to follow the tutorial on the Tensorflow quickstart page here. However, instead of using the movie-lens data used I am trying to use the Movie Dataset found at Kaggle Here. When I try to fit the model I get the following error

Epoch 1/3
WARNING:tensorflow:Layers in a Sequential model should only have a single input tensor. Received: inputs={'movieId': <tf.Tensor 'IteratorGetNext:0' shape=(None,) dtype=int64>, 'userId': <tf.Tensor 'IteratorGetNext:1' shape=(None,) dtype=string>}. Consider rewriting this model with the Functional API.
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-33-b20246ea89fa> in <module>
      4 
      5 # Train for 3 epochs.
----> 6 model.fit(ratings_tf.batch(4096), epochs=3)
      7 

3 frames
<ipython-input-31-50917ec57dbf> in compute_loss(self, features, training)
     23 
     24     user_embeddings = self.user_model(features["userId"])
---> 25     movie_embeddings = self.movie_model(features) #movie_embeddings = self.movie_model(features["title"])
     26 
     27     return self.task(user_embeddings, movie_embeddings)

TypeError: in user code:

    File "/usr/local/lib/python3.7/dist-packages/keras/engine/training.py", line 1160, in train_function  *
        return step_function(self, iterator)
    File "/usr/local/lib/python3.7/dist-packages/keras/engine/training.py", line 1146, in step_function  **
        outputs = model.distribute_strategy.run(run_step, args=(data,))
    File "/usr/local/lib/python3.7/dist-packages/keras/engine/training.py", line 1135, in run_step  **
        outputs = model.train_step(data)
    File "/usr/local/lib/python3.7/dist-packages/tensorflow_recommenders/models/base.py", line 68, in train_step
        loss = self.compute_loss(inputs, training=True)
    File "<ipython-input-31-50917ec57dbf>", line 25, in compute_loss
        movie_embeddings = self.movie_model(features) #movie_embeddings = self.movie_model(features["title"])
    File "/usr/local/lib/python3.7/dist-packages/keras/utils/traceback_utils.py", line 70, in error_handler
        raise e.with_traceback(filtered_tb) from None

    TypeError: Exception encountered when calling layer "string_lookup_1" "                 f"(type StringLookup).
    
    Expected string, but got Tensor("IteratorGetNext:0", shape=(None,), dtype=int64) of type 'Tensor'.
    
    Call arguments received by layer "string_lookup_1" "                 f"(type StringLookup):
      • inputs={'movieId': 'tf.Tensor(shape=(None,), dtype=int64)', 'userId': 'tf.Tensor(shape=(None,), dtype=string)'}

The data I am using includes the ratings_small.csv, links_small.csv and `movie_metadata.csv'. The output of the datasets can be found below

enter image description here

enter image description here

The code I have so far is below.

movies_df = movies_df.dropna()
movies_df['release_date'] = pd.to_datetime(movies_df['release_date'])
movies_df['year'] = movies_df['release_date'].dt.year

# Select the basic features.
ratings_tf = ratings[['movieId', 'userId']] #['movie_title'] #= 
ratings_tf['userId'] = ratings_tf['userId'].astype(str)
movies_tf = movies_df.dropna().drop('year', axis=1)['title']

years = []
for movie in movies_tf :
  yr = movies_df[movies_df['title']==movie]['year'].values[0]
  id = movies_df[movies_df['title']==movie]['id'].values[0]
  years.append(yr)

for i in range(len(movies_tf)) :
  movies_tf.reset_index()[i] = (movies_tf.reset_index(drop=True)[i] + ' (' + str(years[i]) + ')')

indexes = movies_tf.index
movies_tf = [movies_tf.reset_index(drop=True)[i] + ' (' + str(years[i]) + ')' for i in range(len(movies_tf))]
movies_tf = pd.DataFrame(data=movies_tf, columns=['title']).set_index(indexes)
movies_tf = movies_tf[['title']]

movies_tf = tf.data.Dataset.from_tensor_slices(dict(movies_tf))
ratings_tf = tf.data.Dataset.from_tensor_slices(dict(ratings_tf))

movies_tf = movies_tf.map(lambda x: x["title"])

ratings_tf = ratings_tf.map(lambda x: {
"movieId": x["movieId"],
"userId": x["userId"]
 })

user_ids_vocabulary = tf.keras.layers.StringLookup(mask_token=None)
user_ids_vocabulary.adapt(ratings_tf.map(lambda x: x["userId"]))
movie_titles_vocabulary = tf.keras.layers.StringLookup(mask_token=None)
movie_titles_vocabulary.adapt(movies_tf)

class MovieLensModel(tfrs.Model):
  # We derive from a custom base class to help reduce boilerplate. Under the hood,
  # these are still plain Keras Models.

  def __init__(
      self,
      user_model: tf.keras.Model,
      movie_model: tf.keras.Model,
      task: tfrs.tasks.Retrieval):
    super().__init__()

    # Set up user and movie representations.
    self.user_model = user_model
    self.movie_model = movie_model

    # Set up a retrieval task.
    self.task = task

  def compute_loss(self, features: Dict[Text, tf.Tensor], training=False) -> tf.Tensor:
    # Define how the loss is computed.

    user_embeddings = self.user_model(features["userId"])
    movie_embeddings = self.movie_model(features) #movie_embeddings = self.movie_model(features["title"])

    return self.task(user_embeddings, movie_embeddings)

 Define user model
user_model = tf.keras.Sequential([
    user_ids_vocabulary,
    tf.keras.layers.Embedding(user_ids_vocabulary.vocabulary_size(), 64)
])

# Define movie model
movie_model = tf.keras.Sequential([
    movie_titles_vocabulary,
    tf.keras.layers.Embedding(movie_titles_vocabulary.vocabulary_size(), 64)
])

# Define the objectives.
task = tfrs.tasks.Retrieval(metrics=tfrs.metrics.FactorizedTopK(
    movies_tf.map(movie_model)
  )
)

# Create a retrieval model.
model = MovieLensModel(user_model, movie_model, task)
model.compile(optimizer=tf.keras.optimizers.Adagrad(0.5))

# Train for 3 epochs.
model.fit(ratings_tf.batch(4096), epochs=3)

Any and all help would be appreciated! Thanks!

0 Answers
Related