[FIXED] How to save tensorflow recommenders framework model

Issue

good tuto, thank you to that, but I have a problem to save model to reuse it. I have this error

File
"C:\Users\guera\AppData\Local\Programs\Python\Python310\lib\site-packages\keras\utils\traceback_utils.py",
line 67, in error_handler raise e.with_traceback(filtered_tb) from
None File
"C:\Users\guera\AppData\Local\Programs\Python\Python310\lib\site-packages\keras\saving\save.py",
line 142, in save_model raise
NotImplementedError(NotImplementedError: Saving the model to HDF5
format requires the model to be a Functional model or a Sequential
model. It does not work for subclassed models, because such models are
defined via the body of a Python method, which isn’t safely
serializable. Consider saving to the Tensorflow SavedModel format (by
setting save_format="tf") or using save_weights.

So how to fix them?

This my source code:

import os
import pprint
import tempfile

from typing import Dict, Text

import numpy as np
import tensorflow as tf
import tensorflow_datasets as tfds
import joblib

import tensorflow_recommenders as tfrs
from src.models.movie_lens import MovieLensModel

def content_based_filtering(user_id, table1, table2, user_id_label, target_label):
    # Ratings data.
    ratings = tfds.load(table1, split="train")
    # Features of all the available movies.
    movies = tfds.load(table2, split="train")
    
    # Select the basic features.
    ratings = ratings.map(lambda x: {
        "{}".format(target_label): x[target_label],
        "{}".format(user_id_label): x[user_id_label]
    })
    movies = movies.map(lambda x: x[target_label])
    
    user_ids_vocabulary = tf.keras.layers.StringLookup(mask_token=None)
    user_ids_vocabulary.adapt(ratings.map(lambda x: x[user_id_label]))

    movie_titles_vocabulary = tf.keras.layers.StringLookup(mask_token=None)
    movie_titles_vocabulary.adapt(movies)   
    
    # Define user and movie models.
    user_model = tf.keras.Sequential([
        user_ids_vocabulary,
        tf.keras.layers.Embedding(user_ids_vocabulary.vocab_size(), 64)
    ])
    movie_model = tf.keras.Sequential([
        movie_titles_vocabulary,
        tf.keras.layers.Embedding(movie_titles_vocabulary.vocab_size(), 64)
    ])

    # Define your objectives.
    task = tfrs.tasks.Retrieval(metrics=tfrs.metrics.FactorizedTopK(
        movies.batch(128).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.batch(4096), epochs=3)

    model.save('content_model.h5')
    # Use brute-force search to set up retrieval using the trained representations.
    index = tfrs.layers.factorized_top_k.BruteForce(model.user_model)
    index.index_from_dataset(
        movies.batch(100).map(lambda title: (title, model.movie_model(title))))

    # Get some recommendations.
    _, titles = index(np.array([str(user_id)]))
    # print('Recommendation content based filtering\n')
    return titles[0, :3].numpy()
    

The movieLensModel:

import os
import pprint
import tempfile

from typing import Dict, Text

import numpy as np
import tensorflow as tf
import tensorflow_datasets as tfds
import tensorflow_recommenders as tfrs

class MovieLensModel(tfrs.Model):
    
  def __init__(self, user_model, movie_model, task):
    super().__init__()
    self.movie_model: tf.keras.Model = movie_model
    self.user_model: tf.keras.Model = user_model
    self.task: tf.keras.layers.Layer = task

  def compute_loss(self, features: Dict[Text, tf.Tensor], training=False) -> tf.Tensor:
    # We pick out the user features and pass them into the user model.
    user_embeddings = self.user_model(features["user_id"])
    # And pick out the movie features and pass them into the movie model,
    # getting embeddings back.
    positive_movie_embeddings = self.movie_model(features["movie_title"])

    # The task computes the loss and the metrics.
    return self.task(user_embeddings, positive_movie_embeddings)

An image error:

enter image description here

Solution

Look at the error, it says:

Saving the model to HDF5 format requires the model to be a Functional
model or a Sequential model. It does not work for subclassed models,
because such models are defined via the body of a Python method, which
isn’t safely serializable. Consider saving to the Tensorflow
SavedModel format (by setting save_format="tf") or using save_weights

You are experiencing this issue because of this line:

model.save('content_model.h5')

You should do as suggested, that is, save the model differently. You can follow mainly two methods.


Method 1

Try replacing that line with:

model.save("content_model", save_format='tf')

And to load it back:

loaded_model = tf.keras.models.load_model('./content_model')

Method 2

You could first save the weights like this:

model.save_weights('content_model_weights', save_format='tf')

And to load them back you need to instantiate your model object and load the weights in it:

loaded_model = MovieLensModel(user_model, movie_model, task)
loaded_model.load_weights('content_model_weights')

Answered By – ClaudiaR

Answer Checked By – Terry (Easybugfix Volunteer)

Leave a Reply

(*) Required, Your email will not be published