# Copyright 2022 NVIDIA Corporation. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
http://developer.download.nvidia.com/compute/machine-learning/frameworks/nvidia_logo.png

Getting Started with Merlin Models: Develop a Model for MovieLens

Overview

Merlin Models is a library for training recommender models. Merlin Models let Data Scientists and ML Engineers easily train standard RecSys models on their own dataset, getting GPU-accelerated models with best practices baked into the library. This will also let researchers to build custom models by incorporating standard components of deep learning recommender models, and then benchmark their new models on example offline datasets. Merlin Models is part of the Merlin open source framework.

Core features are:

  • Many different recommender system architectures (tabular, two-tower, sequential) or tasks (binary, multi-class classification, multi-task)

  • Flexible APIs targeted to both production and research

  • Deep integration with NVIDIA Merlin platform, including NVTabular for ETL and Merlin Systems model serving

Learning objectives

Downloading and preparing the dataset

import merlin.models.tf as mm

from merlin.datasets.entertainment import get_movielens
2022-04-05 14:47:25.928570: I tensorflow/core/platform/cpu_feature_guard.cc:151] This TensorFlow binary is optimized with oneAPI Deep Neural Network Library (oneDNN) to use the following CPU instructions in performance-critical operations:  AVX2 AVX512F FMA
To enable them in other operations, rebuild TensorFlow with the appropriate compiler flags.
2022-04-05 14:47:28.104380: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1525] Created device /job:localhost/replica:0/task:0/device:GPU:0 with 16249 MB memory:  -> device: 0, name: Quadro GV100, pci bus id: 0000:15:00.0, compute capability: 7.0
2022-04-05 14:47:28.105455: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1525] Created device /job:localhost/replica:0/task:0/device:GPU:1 with 29778 MB memory:  -> device: 1, name: Quadro GV100, pci bus id: 0000:2d:00.0, compute capability: 7.0
2022-04-05 14:47:28.110332: I tensorflow/stream_executor/cuda/cuda_driver.cc:739] failed to allocate 15.87G (17038311424 bytes) from device: CUDA_ERROR_OUT_OF_MEMORY: out of memory
2022-04-05 14:47:28.112154: I tensorflow/stream_executor/cuda/cuda_driver.cc:739] failed to allocate 14.28G (15334479872 bytes) from device: CUDA_ERROR_OUT_OF_MEMORY: out of memory
2022-04-05 14:47:28.114081: I tensorflow/stream_executor/cuda/cuda_driver.cc:739] failed to allocate 12.85G (13801031680 bytes) from device: CUDA_ERROR_OUT_OF_MEMORY: out of memory

We provide the get_movielens() function as a convenience to download the dataset, perform simple preprocessing, and split the data into training and validation datasets.

train, valid = get_movielens(variant="ml-1m")
WARNING:tensorflow:From /home/gmoreira/projects/nvidia/nvidia_merlin/models/merlin/models/utils/nvt_utils.py:14: is_gpu_available (from tensorflow.python.framework.test_util) is deprecated and will be removed in a future version.
Instructions for updating:
Use `tf.config.list_physical_devices('GPU')` instead.
WARNING:tensorflow:From /home/gmoreira/projects/nvidia/nvidia_merlin/models/merlin/models/utils/nvt_utils.py:14: is_gpu_available (from tensorflow.python.framework.test_util) is deprecated and will be removed in a future version.
Instructions for updating:
Use `tf.config.list_physical_devices('GPU')` instead.
2022-04-05 14:47:28.568643: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1525] Created device /device:GPU:0 with 16249 MB memory:  -> device: 0, name: Quadro GV100, pci bus id: 0000:15:00.0, compute capability: 7.0
2022-04-05 14:47:28.570027: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1525] Created device /device:GPU:1 with 29778 MB memory:  -> device: 1, name: Quadro GV100, pci bus id: 0000:2d:00.0, compute capability: 7.0
/home/gmoreira/miniconda3/envs/merlin_22.04_dev/lib/python3.8/site-packages/cudf/core/dataframe.py:1253: UserWarning: The deep parameter is ignored and is only included for pandas compatibility.
  warnings.warn(

Training the DLRM Model with Merlin Models

We define the DLRM model, whose prediction task is a binary classification. From the schema, the categorical features are identified (and embedded) and the target column is also automatically inferred, because of the schema tags. We talk more about the schema in the next example notebook (02),

model = mm.DLRMModel(
    train.schema,
    embedding_dim=64,
    bottom_block=mm.MLPBlock([128, 64]),
    top_block=mm.MLPBlock([128, 64, 32]),
    prediction_tasks=mm.BinaryClassificationTask(train.schema),
)

model.compile(optimizer="adam")

Next, we train the model.

model.fit(train, batch_size=1024)
2022-04-05 14:47:29.832785: W tensorflow/python/util/util.cc:368] Sets are not currently considered sequences, but this may change in the future, so consider avoiding using them.
782/782 [==============================] - 18s 18ms/step - rating_binary/binary_classification_task/precision: 0.7286 - rating_binary/binary_classification_task/recall: 0.8216 - rating_binary/binary_classification_task/binary_accuracy: 0.7212 - rating_binary/binary_classification_task/auc: 0.7841 - loss: 0.5474 - regularization_loss: 0.0000e+00 - total_loss: 0.5474
<keras.callbacks.History at 0x7fb7c04772e0>

We evaluate the model…

metrics = model.evaluate(valid, batch_size=1024, return_dict=True)
2022-04-05 14:47:49.426085: W tensorflow/core/grappler/optimizers/loop_optimizer.cc:907] Skipping loop optimization for Merge node with control input: cond/then/_0/cond/cond/branch_executed/_170
196/196 [==============================] - 4s 12ms/step - rating_binary/binary_classification_task/precision: 0.7350 - rating_binary/binary_classification_task/recall: 0.8234 - rating_binary/binary_classification_task/binary_accuracy: 0.7285 - rating_binary/binary_classification_task/auc: 0.7936 - loss: 0.5388 - regularization_loss: 0.0000e+00 - total_loss: 0.5388

… and check the evaluation metrics. We use by default typical binary classification metrics – Precision, Recall, Accuracy and AUC. But you can also provide your own metrics list by setting BinaryClassificationTask(..., metrics=[]).

metrics
{'rating_binary/binary_classification_task/precision': 0.7349662184715271,
 'rating_binary/binary_classification_task/recall': 0.8234366178512573,
 'rating_binary/binary_classification_task/binary_accuracy': 0.7284606695175171,
 'rating_binary/binary_classification_task/auc': 0.7936176657676697,
 'loss': 0.5581252574920654,
 'regularization_loss': 0.0,
 'total_loss': 0.5581252574920654}

Conclusion

Merlin Models enables users to define and train a deep learning recommeder model with only 3 commands.

model = mm.DLRMModel(
    train.schema,
    embedding_dim=64,
    bottom_block=mm.MLPBlock([128, 64]),
    top_block=mm.MLPBlock([128, 64, 32]),
    prediction_tasks=mm.BinaryClassificationTask(
        train.schema.select_by_tag(Tags.TARGET).column_names[0]
    ),
)
model.compile(optimizer="adam")
model.fit(train, batch_size=1024)

Next steps

In the next example notebooks, we will show how the integration with NVTabular and how to explore different recommender models.