From 5d6d417ff57e8824ef51573e00e5e21307b39697 Mon Sep 17 00:00:00 2001 From: Tomasz Cheda Date: Fri, 3 Sep 2021 06:20:12 -0700 Subject: [PATCH] [NCF/PyT] Adding BYOD capabilities --- PyTorch/Recommendation/NCF/.dockerignore | 2 + PyTorch/Recommendation/NCF/Dockerfile | 2 +- PyTorch/Recommendation/NCF/README.md | 776 +++++++++++++----- PyTorch/Recommendation/NCF/convert.py | 130 ++- PyTorch/Recommendation/NCF/convert_test.py | 158 ++++ .../NCF/data/csv_conversion/feature_spec.yaml | 43 + .../NCF/data/csv_conversion/test_data_1.csv | 30 + .../NCF/data/csv_conversion/train_data_1.csv | 60 ++ .../NCF/data/csv_conversion/train_data_2.csv | 40 + .../NCF/data/like_movielens/ratings.csv | 50 ++ .../data/ml-20m/feature_spec_template.yaml | 52 ++ PyTorch/Recommendation/NCF/dataloading.py | 280 +++++-- PyTorch/Recommendation/NCF/feature_spec.py | 50 ++ PyTorch/Recommendation/NCF/fp_optimizers.py | 45 - PyTorch/Recommendation/NCF/full_test_suite.md | 25 + PyTorch/Recommendation/NCF/img/box_plots.png | Bin 0 -> 38939 bytes PyTorch/Recommendation/NCF/img/df_diagram.png | Bin 0 -> 100651 bytes .../Recommendation/NCF/img/dgx1v16_curve.png | Bin 42646 -> 0 bytes .../Recommendation/NCF/img/dgx1v_32_curve.png | Bin 41910 -> 0 bytes .../Recommendation/NCF/img/hr_histogram.png | Bin 30062 -> 0 bytes .../Recommendation/NCF/img/layout_example.png | Bin 0 -> 46938 bytes PyTorch/Recommendation/NCF/img/val_curves.png | Bin 0 -> 79858 bytes PyTorch/Recommendation/NCF/inference.py | 15 +- PyTorch/Recommendation/NCF/load.py | 28 +- PyTorch/Recommendation/NCF/ncf.py | 171 ++-- PyTorch/Recommendation/NCF/neumf.py | 1 + PyTorch/Recommendation/NCF/neumf_constants.py | 18 + PyTorch/Recommendation/NCF/prepare_dataset.sh | 37 +- .../NCF/qa/generate_boxplots.py | 70 ++ .../Recommendation/NCF/qa/generate_tables.py | 113 +++ .../NCF/qa/generate_validation_curves.py | 66 ++ .../Recommendation/NCF/qa/inference_table.py | 44 + PyTorch/Recommendation/NCF/requirements.txt | 5 +- PyTorch/Recommendation/NCF/test_cases.sh | 42 + PyTorch/Recommendation/NCF/test_dataset.sh | 103 +++ .../NCF/test_featurespec_correctness.py | 90 ++ PyTorch/Recommendation/NCF/transcode.py | 127 +++ PyTorch/Recommendation/NCF/utils.py | 3 +- 38 files changed, 2216 insertions(+), 460 deletions(-) create mode 100644 PyTorch/Recommendation/NCF/.dockerignore create mode 100644 PyTorch/Recommendation/NCF/convert_test.py create mode 100644 PyTorch/Recommendation/NCF/data/csv_conversion/feature_spec.yaml create mode 100644 PyTorch/Recommendation/NCF/data/csv_conversion/test_data_1.csv create mode 100644 PyTorch/Recommendation/NCF/data/csv_conversion/train_data_1.csv create mode 100644 PyTorch/Recommendation/NCF/data/csv_conversion/train_data_2.csv create mode 100644 PyTorch/Recommendation/NCF/data/like_movielens/ratings.csv create mode 100644 PyTorch/Recommendation/NCF/data/ml-20m/feature_spec_template.yaml create mode 100644 PyTorch/Recommendation/NCF/feature_spec.py delete mode 100644 PyTorch/Recommendation/NCF/fp_optimizers.py create mode 100644 PyTorch/Recommendation/NCF/full_test_suite.md create mode 100644 PyTorch/Recommendation/NCF/img/box_plots.png create mode 100644 PyTorch/Recommendation/NCF/img/df_diagram.png delete mode 100644 PyTorch/Recommendation/NCF/img/dgx1v16_curve.png delete mode 100644 PyTorch/Recommendation/NCF/img/dgx1v_32_curve.png delete mode 100644 PyTorch/Recommendation/NCF/img/hr_histogram.png create mode 100644 PyTorch/Recommendation/NCF/img/layout_example.png create mode 100644 PyTorch/Recommendation/NCF/img/val_curves.png create mode 100644 PyTorch/Recommendation/NCF/neumf_constants.py create mode 100644 PyTorch/Recommendation/NCF/qa/generate_boxplots.py create mode 100644 PyTorch/Recommendation/NCF/qa/generate_tables.py create mode 100644 PyTorch/Recommendation/NCF/qa/generate_validation_curves.py create mode 100644 PyTorch/Recommendation/NCF/qa/inference_table.py create mode 100644 PyTorch/Recommendation/NCF/test_cases.sh create mode 100644 PyTorch/Recommendation/NCF/test_dataset.sh create mode 100644 PyTorch/Recommendation/NCF/test_featurespec_correctness.py create mode 100644 PyTorch/Recommendation/NCF/transcode.py diff --git a/PyTorch/Recommendation/NCF/.dockerignore b/PyTorch/Recommendation/NCF/.dockerignore new file mode 100644 index 00000000..fca132f4 --- /dev/null +++ b/PyTorch/Recommendation/NCF/.dockerignore @@ -0,0 +1,2 @@ +.git +data/ \ No newline at end of file diff --git a/PyTorch/Recommendation/NCF/Dockerfile b/PyTorch/Recommendation/NCF/Dockerfile index fd600120..fb5b3ee3 100644 --- a/PyTorch/Recommendation/NCF/Dockerfile +++ b/PyTorch/Recommendation/NCF/Dockerfile @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -ARG FROM_IMAGE_NAME=nvcr.io/nvidia/pytorch:20.06-py3 +ARG FROM_IMAGE_NAME=nvcr.io/nvidia/pytorch:21.04-py3 FROM ${FROM_IMAGE_NAME} RUN apt-get update && \ diff --git a/PyTorch/Recommendation/NCF/README.md b/PyTorch/Recommendation/NCF/README.md index 71b1fe71..7fad905e 100644 --- a/PyTorch/Recommendation/NCF/README.md +++ b/PyTorch/Recommendation/NCF/README.md @@ -1,56 +1,63 @@ # Neural Collaborative Filtering (NCF) for PyTorch This repository provides a script and recipe to train the Neural Collaborative Filtering (NCF) -model to achieve state of the art accuracy, and is tested and maintained by NVIDIA. +model to achieve state-of-the-art accuracy. The content of this repository is tested and maintained by NVIDIA. -Table of Contents -================= - * [Model overview](#model-overview) - * [Model architecture](#model-architecture) - * [Default configuration](#default-configuration) - * [Feature support matrix](#feature-support-matrix) +## Table Of Contents + +- [Model overview](#model-overview) + * [Model architecture](#model-architecture) + * [Default configuration](#default-configuration) + * [Feature support matrix](#feature-support-matrix) * [Features](#features) - * [Mixed precision training](#mixed-precision-training) + * [Mixed precision training](#mixed-precision-training) * [Enabling mixed precision](#enabling-mixed-precision) * [Enabling TF32](#enabling-tf32) - * [Setup](#setup) - * [Requirements](#requirements) - * [Quick Start Guide](#quick-start-guide) - * [Advanced](#advanced) - * [Scripts and sample code](#scripts-and-sample-code) - * [Command-line options](#command-line-options) - * [Getting the data](#getting-the-data) + * [BYO dataset functionality overview](#byo-dataset-functionality-overview) + * [Dataset feature specification](#dataset-feature-specification) + * [Data flow in NVIDIA Deep Learning Examples recommendation models](#data-flow-in-nvidia-deep-learning-examples-recommendation-models) + * [Example of dataset feature specification](#example-of-dataset-feature-specification) + * [BYO dataset functionality](#byo-dataset-functionality) + * [Glossary](#glossary) +- [Setup](#setup) + * [Requirements](#requirements) +- [Quick Start Guide](#quick-start-guide) +- [Advanced](#advanced) + * [Scripts and sample code](#scripts-and-sample-code) + * [Command-line options](#command-line-options) + * [Getting the data](#getting-the-data) * [Dataset guidelines](#dataset-guidelines) - * [Multi-dataset](#multi-dataset) + * [BYO dataset](#byo-dataset) * [ML-1m](#ml-1m) - * [Training process](#training-process) - * [Inference process](#inference-process) - * [Performance](#performance) - * [Benchmarking](#benchmarking) + * [Training process](#training-process) + * [Inference process](#inference-process) +- [Performance](#performance) + * [Benchmarking](#benchmarking) * [Training performance benchmark](#training-performance-benchmark) * [Inference performance benchmark](#inference-performance-benchmark) - * [Results](#results) + * [Results](#results) * [Training accuracy results](#training-accuracy-results) - * [Training accuracy: NVIDIA DGX A100(8x A100 40GB)](#training-accuracy-nvidia-dgx-a1008x-a100-40gb) - * [Training accuracy: NVIDIA DGX-1 (8x V100 16GB)](#training-accuracy-nvidia-dgx-1-8x-v100-16gb) - * [Training accuracy: NVIDIA DGX-1 (8x V100 32GB)](#training-accuracy-nvidia-dgx-1-8x-v100-32gb) - * [Training accuracy: NVIDIA DGX-2 (16x V100 32GB)](#training-accuracy-nvidia-dgx-2-16x-v100-32gb) - * [Training stability test](#training-stability-test) + * [Training accuracy: NVIDIA DGX A100(8x A100 40GB)](#training-accuracy-nvidia-dgx-a1008x-a100-40gb) + * [Training accuracy: NVIDIA DGX-1 (8x V100 16GB)](#training-accuracy-nvidia-dgx-1-8x-v100-16gb) + * [Training accuracy: NVIDIA DGX-1 (8x V100 32GB)](#training-accuracy-nvidia-dgx-1-8x-v100-32gb) + * [Training accuracy: NVIDIA DGX-2 (16x V100 32GB)](#training-accuracy-nvidia-dgx-2-16x-v100-32gb) + * [Training stability test](#training-stability-test) * [Training performance results](#training-performance-results) - * [Training performance: NVIDIA DGX A100 (8x A100 40GB)](#training-performance-nvidia-dgx-a100-8x-a100-40gb) - * [Training performance: NVIDIA DGX-1 (8x V100 16GB)](#training-performance-nvidia-dgx-1-8x-v100-16gb) - * [Training performance: NVIDIA DGX-1 (8x V100 32GB)](#training-performance-nvidia-dgx-1-8x-v100-32gb) - * [Training performance: NVIDIA DGX-2 (16x V100 32GB)](#training-performance-nvidia-dgx-2-16x-v100-32gb) + * [Training performance: NVIDIA DGX A100 (8x A100 40GB)](#training-performance-nvidia-dgx-a100-8x-a100-40gb) + * [Training performance: NVIDIA DGX-1 (8x V100 16GB)](#training-performance-nvidia-dgx-1-8x-v100-16gb) + * [Training performance: NVIDIA DGX-1 (8x V100 32GB)](#training-performance-nvidia-dgx-1-8x-v100-32gb) + * [Training performance: NVIDIA DGX-2 (16x V100 32GB)](#training-performance-nvidia-dgx-2-16x-v100-32gb) * [Inference performance results](#inference-performance-results) - * [Inference performance: NVIDIA DGX A100 (1x A100 40GB)](#inference-performance-nvidia-dgx-a100-1x-a100-40gb) - * [Inference performance: NVIDIA DGX-1 (8x V100 16GB)](#inference-performance-nvidia-dgx-1-8x-v100-16gb) - * [Release notes](#release-notes) - * [Changelog](#changelog) - * [Known issues](#known-issues) + * [Inference performance: NVIDIA DGX A100 (1x A100 40GB)](#inference-performance-nvidia-dgx-a100-1x-a100-40gb) + * [Inference performance: NVIDIA DGX-1 (1x V100 16GB)](#inference-performance-nvidia-dgx-1-1x-v100-16gb) +- [Release notes](#release-notes) + * [Changelog](#changelog) + * [Known issues](#known-issues) * [Scaling beyond 8 GPUs](#scaling-beyond-8-gpus) * [Memory usage](#memory-usage) + ## Model overview The NCF model focuses on providing recommendations, also known as collaborative filtering with implicit feedback. The training data for this model should contain binary information about whether a user interacted with a specific item. @@ -58,19 +65,20 @@ NCF was first described by Xiangnan He, Lizi Liao, Hanwang Zhang, Liqiang Nie, X The implementation in this repository focuses on the NeuMF instantiation of the NCF architecture. We modified it to use dropout in the FullyConnected layers. This reduces overfitting and increases the final accuracy. -Training the other two instantiations of NCF (GMF and MLP) is not supported. - +Training the other two instantiations of NCF (GMF and MLP) is not supported. + Contrary to the original paper, we benchmark the model on the larger [ML-20m dataset](https://grouplens.org/datasets/movielens/20m/) -instead of using the smaller [ML-1m](https://grouplens.org/datasets/movielens/1m/) dataset as we think this is more realistic of production type environments. +instead of using the smaller [ML-1m](https://grouplens.org/datasets/movielens/1m/) dataset because we think this is more realistic for production type environments. However, using the ML-1m dataset is also supported. -This model is trained with mixed precision using Tensor Cores on Volta, Turing, and the NVIDIA Ampere GPU architectures. Therefore, researchers can get results 2x faster than training without Tensor Cores, while experiencing the benefits of mixed precision training. +This model is trained with mixed precision using Tensor Cores on Volta, Turing, and the NVIDIA Ampere GPU architectures. +Therefore, researchers can get results 2x faster than training without Tensor Cores while experiencing the benefits of mixed precision training. ### Model architecture This model is based mainly on Embedding and FullyConnected layers. The control flow is divided into two branches: -* Multi Layer Perceptron (MLP) branch, which transforms the input through FullyConnected layers with ReLU activations and dropout. +* Multi Layer Perceptron (MLP) branch, which transforms the input through FullyConnected layers with ReLU activations, and dropout. * Matrix Factorization (MF) branch, which performs collaborative filtering factorization. Each user and each item has two embedding vectors associated with it -- one for the MLP branch and the other for the MF branch. @@ -88,7 +96,7 @@ Figure 1. The architecture of a Neural Collaborative Filtering model. Taken from The following features were implemented in this model: * Automatic Mixed Precision (AMP) - * Data-parallel multi-GPU training and evaluation + * Data-parallel multi-GPU training and evaluation * Dropout * Gradient accumulation @@ -99,9 +107,10 @@ The following performance optimizations were implemented in this model: ### Feature support matrix -The following features are supported by this model: +This model supports the following features: -| **Feature** | **NCF PyTorch** | + +| **Feature** | **NCF PyTorch** | |:---:|:--------:| | Automatic Mixed Precision (AMP) | Yes | | Multi-GPU training with Distributed Data Parallel (DDP) | Yes | @@ -110,24 +119,31 @@ The following features are supported by this model: #### Features * Automatic Mixed Precision - This implementation of NCF uses AMP to implement mixed precision training. -It allows us to use FP16 training with FP32 master weights by modifying just 3 lines of code. +It allows us to use FP16 training with FP32 master weights by modifying just three lines of code. * Multi-GPU training with Distributed Data Parallel - uses Apex's DDP to implement efficient multi-GPU training with NCCL. * Fused Adam - We use a special implementation of the Adam implementation provided by the Apex package. It fuses some operations for faster weight updates. Since NCF is a relatively lightweight model with a large number of parameters, we’ve observed significant performance improvements from using FusedAdam. ### Mixed precision training -Mixed precision is the combined use of different numerical precisions in a computational method. [Mixed precision](https://arxiv.org/abs/1710.03740) training offers significant computational speedup by performing operations in half-precision format, while storing minimal information in single-precision to retain as much information as possible in critical parts of the network. Since the introduction of [tensor cores](https://developer.nvidia.com/tensor-cores) in Volta, and following with both the Turing and Ampere architectures, significant training speedups are experienced by switching to mixed precision -- up to 3x overall speedup on the most arithmetically intense model architectures. Using mixed precision training requires two steps: +Mixed precision is the combined use of different numerical precisions in a computational method. +[Mixed precision](https://arxiv.org/abs/1710.03740) training offers significant computational speedup by performing +operations in half-precision format while storing minimal information in single-precision to retain as much information +as possible in critical parts of the network. Since the introduction of +[tensor cores](https://developer.nvidia.com/tensor-cores) in Volta, +and following with both the Turing and Ampere architectures, significant training speedups are experienced by switching +to mixed precision -- up to 3x overall speedup on the most arithmetically intense model architectures. +Using [mixed precision training](https://docs.nvidia.com/deeplearning/performance/mixed-precision-training/index.html) +previously required two steps: 1. Porting the model to use the FP16 data type where appropriate. 2. Adding loss scaling to preserve small gradient values. The ability to train deep learning networks with lower precision was introduced in the Pascal architecture and first supported in [CUDA 8](https://devblogs.nvidia.com/parallelforall/tag/fp16/) in the NVIDIA Deep Learning SDK. For information about: -- How to train using mixed precision, see the [Mixed Precision Training](https://arxiv.org/abs/1710.03740) paper and [Training With Mixed Precision](https://docs.nvidia.com/deeplearning/sdk/mixed-precision-training/index.html) documentation. -- Techniques used for mixed precision training, see the [Mixed-Precision Training of Deep Neural Networks](https://devblogs.nvidia.com/mixed-precision-training-deep-neural-networks/) blog. -- How to access and enable AMP for TensorFlow, see [Using TF-AMP](https://docs.nvidia.com/deeplearning/dgx/tensorflow-user-guide/index.html#tfamp) from the TensorFlow User Guide. -- APEX tools for mixed precision training, see the [NVIDIA Apex: Tools for Easy Mixed-Precision Training in PyTorch](https://devblogs.nvidia.com/apex-pytorch-easy-mixed-precision-training/). +- How to train using mixed precision, refer to the [Mixed Precision Training](https://arxiv.org/abs/1710.03740) paper and [Training With Mixed Precision](https://docs.nvidia.com/deeplearning/sdk/mixed-precision-training/index.html) documentation. +- Techniques used for mixed precision training, refer to the [Mixed-Precision Training of Deep Neural Networks](https://devblogs.nvidia.com/mixed-precision-training-deep-neural-networks/) blog. +- APEX tools for mixed precision training, refer to the [NVIDIA Apex: Tools for Easy Mixed-Precision Training in PyTorch](https://devblogs.nvidia.com/apex-pytorch-easy-mixed-precision-training/). #### Enabling mixed precision @@ -147,76 +163,240 @@ with amp.scale_loss(loss, optimizer) as scaled_loss: #### Enabling TF32 -TensorFloat-32 (TF32) is the new math mode in [NVIDIA A100](#https://www.nvidia.com/en-us/data-center/a100/) GPUs for handling the matrix math also called tensor operations. TF32 running on Tensor Cores in A100 GPUs can provide up to 10x speedups compared to single-precision floating-point math (FP32) on Volta GPUs. +TensorFloat-32 (TF32) is the new math mode in [NVIDIA A100](https://www.nvidia.com/en-us/data-center/a100/) GPUs for +handling the matrix math, also called tensor operations. TF32 running on Tensor Cores in A100 GPUs can provide up to 10x +speedups compared to single-precision floating-point math (FP32) on Volta GPUs. -TF32 Tensor Cores can speed up networks using FP32, typically with no loss of accuracy. It is more robust than FP16 for models which require high dynamic range for weights or activations. +TF32 Tensor Cores can speed up networks using FP32, typically with no loss of accuracy. It is more robust than FP16 for +models which require a high dynamic range for weights or activations. -For more information, refer to the [TensorFloat-32 in the A100 GPU Accelerates AI Training, HPC up to 20x](#https://blogs.nvidia.com/blog/2020/05/14/tensorfloat-32-precision-format/) blog post. +For more information, refer to the [TensorFloat-32 in the A100 GPU Accelerates AI Training, HPC up to 20x](https://blogs.nvidia.com/blog/2020/05/14/tensorfloat-32-precision-format/) blog post. TF32 is supported in the NVIDIA Ampere GPU architecture and is enabled by default. +### BYO dataset functionality overview + +This section describes how you can train the DeepLearningExamples RecSys models on your own datasets without changing the model or data loader and with similar performance to the one published in each repository. +This can be achieved thanks to Dataset Feature Specification, which describes how the dataset, data loader and model interact with each other during training, inference and evaluation. +Dataset Feature Specification has a consistent format across all recommendation models in NVIDIA’s DeepLearningExamples repository, regardless of dataset file type and the data loader, giving you the flexibility to train RecSys models on your own datasets. + +- [Dataset Feature Specification](#dataset-feature-specification) +- [Data Flow in Recommendation Models in DeepLearning examples](#data-flow-in-recommendation-models-in-deeplearning-examples) +- [Example of Dataset Feature Specification](#example-of-dataset-feature-specification) +- [BYO dataset functionality](#byo-dataset-functionality) +- [Glossary](#glossary) + +#### Dataset feature specification + +Data flow can be described abstractly: +Input data consists of a list of rows. Each row has the same number of columns; each column represents a feature. +The columns are retrieved from the input files, loaded, aggregated into channels and supplied to the model/training script. + +FeatureSpec contains metadata to configure this process and can be divided into three parts: + +* Specification of how data is organized on disk (source_spec). It describes which feature (from feature_spec) is stored in which file and how files are organized on disk. + +* Specification of features (feature_spec). Describes a dictionary of features, where key is feature name and values are features’ characteristics such as dtype and other metadata (for example, cardinalities for categorical features) + +* Specification of model’s inputs and outputs (channel_spec). Describes a dictionary of model’s inputs where keys specify model channel’s names and values specify lists of features to be loaded into that channel. Model’s channels are groups of data streams to which common model logic is applied, for example categorical/continuous data, user/item ids. Required/available channels depend on the model + + +The FeatureSpec is a common form of description regardless of underlying dataset format, dataset data loader form and model. + + +#### Data flow in NVIDIA Deep Learning Examples recommendation models + +The typical data flow is as follows: +* S.0. Original dataset is downloaded to a specific folder. +* S.1. Original dataset is preprocessed into Intermediary Format. For each model, the preprocessing is done differently, using different tools. The Intermediary Format also varies (for example, for NCF implementation in the PyTorch model, the Intermediary Format is Pytorch tensors in *.pt files.) +* S.2. The Preprocessing Step outputs Intermediary Format with dataset split into training and validation/testing parts along with the Dataset Feature Specification yaml file. Metadata in the preprocessing step is automatically calculated. +* S.3. Intermediary Format data together with Dataset Feature Specification are fed into training/evaluation scripts. Data loader reads Intermediary Format and feeds the data into the model according to the description in the Dataset Feature Specification. +* S.4. The model is trained and evaluated + + + +

+ +
+ +Fig.1. Data flow in Recommender models in NVIDIA Deep Learning Examples repository. Channels of the model are drawn in green. +

+ + +#### Example of dataset feature specification + +As an example, let’s consider a Dataset Feature Specification for a small CSV dataset. + +```yaml +feature_spec: + user_gender: + dtype: torch.int8 + cardinality: 3 #M,F,Other + user_age: #treated as numeric value + dtype: torch.int8 + user_id: + dtype: torch.int32 + cardinality: 2655 + item_id: + dtype: torch.int32 + cardinality: 856 + label: + dtype: torch.float32 + +source_spec: + train: + - type: csv + features: + - user_gender + - user_age + files: + - train_data_0_0.csv + - train_data_0_1.csv + - type: csv + features: + - user_id + - item_id + - label + files: + - train_data_1.csv + test: + - type: csv + features: + - user_id + - item_id + - label + - user_gender + - user_age + + files: + - test_data.csv + +channel_spec: + numeric_inputs: + - user_age + categorical_user_inputs: + - user_gender + - user_id + categorical_item_inputs: + - item_id + label_ch: + - label +``` + + +The data contains five features: (user_gender, user_age, user_id, item_id, label). Their data types and necessary metadata are described in the feature specification section. + +In the source mapping section, two mappings are provided: one describes the layout of the training data, the other of the testing data. The layout for training data has been chosen arbitrarily to showcase the flexibility. +The train mapping consists of two chunks. The first one contains user_gender and user_age, saved as a CSV, and is further broken down into two files. For specifics of the layout, refer to the following example and consult the glossary. The second chunk contains the remaining columns and is saved in a single file. Notice that the order of columns is different in the second chunk - this is alright, as long as the order matches the order in that file (that is, columns in the .csv are also switched) + + +Let’s break down the train source mapping. The table contains example data color-paired to the files containing it. + +

+ +

+ + + +The channel spec describes how the data will be consumed. Four streams will be produced and available to the script/model. The feature specification does not specify what happens further: names of these streams are only lookup constants defined by the model/script. +Based on this example, we can speculate that the model has three input channels: numeric_inputs, categorical_user_inputs, categorical_item_inputs, and one output channel: label. +Feature names are internal to the FeatureSpec and can be freely modified. + + +#### BYO dataset functionality + +In order to train any Recommendation model in NVIDIA Deep Learning Examples one can follow one of three possible ways: +* One delivers already preprocessed dataset in the Intermediary Format supported by data loader used by the training script (different models use different data loaders) together with FeatureSpec yaml file describing at least specification of dataset, features and model channels + +* One uses a transcoding script + +* One delivers dataset in non-preprocessed form and uses preprocessing scripts that are a part of the model repository. In order to use already existing preprocessing scripts, the format of the dataset needs to match the one of the original datasets. This way, the FeatureSpec file will be generated automatically, but the user will have the same preprocessing as in the original model repository. + +#### Glossary + +The Dataset Feature Specification consists of three mandatory and one optional section: + +feature_spec provides a base of features that may be referenced in other sections, along with their metadata. + Format: dictionary (feature name) => (metadata name => metadata value)
+ +source_spec provides information necessary to extract features from the files that store them. + Format: dictionary (mapping name) => (list of chunks)
+ +* Mappings are used to represent different versions of the dataset (think: train/validation/test, k-fold splits). A mapping is a list of chunks.
+* Chunks are subsets of features that are grouped together for saving. For example, some formats may constrain data saved in one file to a single data type. In that case, each data type would correspond to at least one chunk. Another example where this might be used is to reduce file size and enable more parallel loading. Chunk description is a dictionary of three keys:
+ * type provides information about the format in which the data is stored. Not all formats are supported by all models.
+ * features is a list of features that are saved in a given chunk. Order of this list may matter: for some formats, it is crucial for assigning read data to the proper feature.
+ * files is a list of paths to files where the data is saved. For Feature Specification in yaml format, these paths are assumed to be relative to the yaml file’s directory (basename). Order of this list matters: It is assumed that rows 1 to i appear in the first file, rows i+1 to j in the next one, etc.
+ +channel_spec determines how features are used. It is a mapping (channel name) => (list of feature names). + +Channels are model specific magic constants. In general, data within a channel is processed using the same logic. Example channels: model output (labels), categorical ids, numerical inputs, user data, and item data. + +metadata is a catch-all, wildcard section: If there is some information about the saved dataset that does not fit into the other sections, you can store it here. ## Setup The following section lists the requirements in order to start training the Neural Collaborative Filtering model. ### Requirements -This repository contains Dockerfile which extends the PyTorch NGC container and encapsulates some dependencies. Aside from these dependencies, ensure you have the following components: +This repository contains a Dockerfile that extends the PyTorch NGC container and encapsulates some dependencies. +Aside from these dependencies, ensure you have the following components: - [NVIDIA Docker](https://github.com/NVIDIA/nvidia-docker) -- PyTorch 20.06-py3+ NGC container +- PyTorch 21.04-py3+ NGC container - Supported GPUs: - [NVIDIA Volta architecture](https://www.nvidia.com/en-us/data-center/volta-gpu-architecture/) - - [NVIDIA Turing architecture](https://www.nvidia.com/en-us/geforce/turing/) + - [NVIDIA Turing architecture](https://www.nvidia.com/en-us/design-visualization/technologies/turing-architecture/) - [NVIDIA Ampere architecture](https://www.nvidia.com/en-us/data-center/nvidia-ampere-gpu-architecture/) -For more information about how to get started with NGC containers, see the following sections from the NVIDIA GPU Cloud Documentation and the Deep Learning Documentation: +For more information about how to get started with NGC containers, refer to the following sections from the NVIDIA GPU Cloud Documentation and the Deep Learning Documentation: - [Getting Started Using NVIDIA GPU Cloud](https://docs.nvidia.com/ngc/ngc-getting-started-guide/index.html) - [Accessing And Pulling From The NGC Container Registry](https://docs.nvidia.com/deeplearning/frameworks/user-guide/index.html#accessing_registry) Running PyTorch -For those unable to use the [framework name] NGC container, to set up the required environment or create your own container, see the versioned [NVIDIA Container Support Matrix](https://docs.nvidia.com/deeplearning/frameworks/support-matrix/index.html). - +For those unable to use the PyTorch NGC container, to set up the required environment or create your own container, refer to the versioned [NVIDIA Container Support Matrix](https://docs.nvidia.com/deeplearning/frameworks/support-matrix/index.html). + ## Quick Start Guide -To train your model using mixed or TF32 precision with Tensor Cores or using FP32, perform the following steps using the default parameters of the NCF model on the ML-20m dataset. For the specifics concerning training and inference, see the [Advanced](#advanced) section. +To train your model using mixed or TF32 precision with Tensor Cores or using FP32, perform the following steps using the default parameters of the NCF model on the ML-20m dataset. For the specifics concerning training and inference, refer to the [Advanced](#advanced) section. 1. Clone the repository. ```bash git clone https://github.com/NVIDIA/DeepLearningExamples -cd DeepLearningExamples/PyTorch/Recommendation/NCF/ +cd DeepLearningExamples/PyTorch/Recommendation/NCF ``` 2. Build an NCF PyTorch Docker container. -After Docker is setup, you can build the NCF image with: +After Docker is set up, you can build the NCF image with: ```bash docker build . -t nvidia_ncf -``` +``` 3. Start an interactive session in the NGC container to run preprocessing/training and inference. The NCF PyTorch container can be launched with: ```bash -mkdir data docker run --runtime=nvidia -it --rm --ipc=host -v ${PWD}/data:/data nvidia_ncf bash ``` This will launch the container and mount the `./data` directory as a volume to the `/data` directory inside the container. Any datasets and experiment results (logs, checkpoints etc.) saved to `/data` will be accessible -in the `./data` directory on the host. +in the `./data` directory on the host. 4. Download and preprocess the data. -Preprocessing consists of downloading the data, filtering out users that have less than 20 ratings (by default), sorting the data and dropping the duplicates. +Download the data from https://grouplens.org/datasets/movielens/20m/ and put it in `/data/ml-20m/ml-20m.zip`. + +Preprocessing consists of sorting the data, dropping the duplicates, renumbering users and items, +selecting last interaction of each user to include in the test set, +then randomly generating negative test set members (scoring candidates). The preprocessed train and test data is then saved in PyTorch binary format to be loaded just before training. ->Note: Preprocessing requires PyTorch and should therefore be run inside the Docker container. +Note: Preprocessing requires PyTorch and should therefore be run inside the Docker container. -No data augmentation techniques are used. - -To download and preprocess the ML-20m dataset you can run: +To preprocess the ML-20m dataset, you can run: ```bash ./prepare_dataset.sh @@ -224,15 +404,15 @@ To download and preprocess the ML-20m dataset you can run: Note: This command will return immediately without downloading anything if the data is already present in the `/data` directory. -This will store the preprocessed training and evaluation data in the `./data` directory so that it can be later +This will store the preprocessed training and evaluation data in the `/data` directory so that it can be later used to train the model (by passing the appropriate `--data` argument to the `ncf.py` script). 5. Start training. -After the Docker container is launched, the training with the default hyperparameters can be started with: +After the Docker container is launched, the training with the default hyperparameters (suitable for a DGX-1V or DGX A100 with 8 GPUs) can be started with: ```bash -python -m torch.distributed.launch --nproc_per_node=8 --use_env ncf.py --data /data/cache/ml-20m --checkpoint_dir /data/checkpoints/ +python -m torch.distributed.launch --nproc_per_node=8 --use_env ncf.py --data /data/cache/ml-20m --checkpoint_dir /data/checkpoints/ ``` This will result in a checkpoint file being written to `/data/checkpoints/model.pth`. @@ -256,36 +436,33 @@ The following sections provide greater details of the dataset, running training The `ncf.py` script contains most of the training and validation logic. Data loading and preprocessing code is located in `dataloading.py`. The model architecture is defined in `neumf.py`. Some initial data preprocessing is located in `convert.py`. The logger directory contains simple bookkeeping utilities for storing training results. +The `transcode.py` script enables transcoding data from a CSV containing preprocessed data to a format accessible by the model. ### Command-line options -To see the full list of available options and their descriptions, use the `-h` or `--help` command line option, for example: +To view the full list of available options and their descriptions, use the `-h` or `--help` command-line option, for example: `python ncf.py --help` The following example output is printed when running the sample: ``` -usage: ncf.py [-h] [--data DATA] [-e EPOCHS] [-b BATCH_SIZE] - [--valid_batch_size VALID_BATCH_SIZE] [-f FACTORS] - [--layers LAYERS [LAYERS ...]] [-n NEGATIVE_SAMPLES] - [-l LEARNING_RATE] [-k TOPK] [--seed SEED] - [--threshold THRESHOLD] - [--beta1 BETA1] [--beta2 BETA2] [--eps EPS] [--dropout DROPOUT] - [--checkpoint_dir CHECKPOINT_DIR] [--mode {train,test}] - [--grads_accumulated GRADS_ACCUMULATED] [--amp] - [--local_rank LOCAL_RANK] - -Train a Neural Collaborative Filtering model: +usage: ncf.py [-h] [--data DATA] [--feature_spec_file FEATURE_SPEC_FILE] [-e EPOCHS] [-b BATCH_SIZE] [--valid_batch_size VALID_BATCH_SIZE] [-f FACTORS] + [--layers LAYERS [LAYERS ...]] [-n NEGATIVE_SAMPLES] [-l LEARNING_RATE] [-k TOPK] [--seed SEED] [--threshold THRESHOLD] [--beta1 BETA1] [--beta2 BETA2] + [--eps EPS] [--dropout DROPOUT] [--checkpoint_dir CHECKPOINT_DIR] [--load_checkpoint_path LOAD_CHECKPOINT_PATH] [--mode {train,test}] + [--grads_accumulated GRADS_ACCUMULATED] [--amp] [--log_path LOG_PATH] +Train a Neural Collaborative Filtering model optional arguments: -h, --help show this help message and exit - --data DATA Path to test and training data files + --data DATA Path to the directory containing the feature specification yaml + --feature_spec_file FEATURE_SPEC_FILE + Name of the feature specification file or path relative to the data directory. -e EPOCHS, --epochs EPOCHS Number of epochs for training -b BATCH_SIZE, --batch_size BATCH_SIZE - Number of examples for each iteration + Number of examples for each iteration. This will be divided by the number of devices --valid_batch_size VALID_BATCH_SIZE - Number of examples in each validation chunk + Number of examples in each validation chunk. This will be the maximum size of a batch on each device. -f FACTORS, --factors FACTORS Number of predictive factors --layers LAYERS [LAYERS ...] @@ -303,54 +480,189 @@ optional arguments: --beta2 BETA2, -b2 BETA2 Beta1 for Adam --eps EPS Epsilon for Adam - --dropout DROPOUT Dropout probability, if equal to 0 will not use - dropout at all + --dropout DROPOUT Dropout probability, if equal to 0 will not use dropout at all --checkpoint_dir CHECKPOINT_DIR - Path to the directory storing the checkpoint file - --mode {train,test} Passing "test" will only run a single evaluation, - otherwise full training will be performed + Path to the directory storing the checkpoint file, passing an empty path disables checkpoint saving + --load_checkpoint_path LOAD_CHECKPOINT_PATH + Path to the checkpoint file to be loaded before training/evaluation + --mode {train,test} Passing "test" will only run a single evaluation; otherwise, full training will be performed --grads_accumulated GRADS_ACCUMULATED - Number of gradients to accumulate before performing an - optimization step - --amp Enable mixed precision training - --local_rank LOCAL_RANK - Necessary for multi-GPU training + Number of gradients to accumulate before performing an optimization step + --amp Enable mixed precision training + --log_path LOG_PATH Path for the JSON training log ``` + + ### Getting the data The NCF model was trained on the ML-20m dataset. -For each user, the interaction with the latest timestamp was included in the test set and the rest of the examples are used as the training data. +For each user, the interaction with the latest timestamp was included in the test set, and the rest of the examples are used as the training data. -This repository contains the `./prepare_dataset.sh` script which will automatically download and preprocess the training and validation datasets. -By default, data will be downloaded to the `/data` directory. The preprocessed data will be placed in `/data/cache`. +This repository contains the `./prepare_dataset.sh` script that automatically preprocess the training and validation datasets. +By default, the preprocessed data will be placed in `/data/cache`. #### Dataset guidelines -The required format of the data is a CSV file with three columns: `user_id`, `item_id` and `timestamp`. This CSV should contain only the positive examples, in other words, -the ones for which an interaction between a user and an item occurred. The negatives will be sampled during the training and validation. - -#### Multi-dataset - -This implementation is tuned for the ML-20m and ML-1m datasets. -Using other datasets might require tuning some hyperparameters (for example, learning rate, beta1 and beta2). - -If you'd like to use your custom dataset you can do it by adding support for it in the `prepare_dataset.sh` and `download_dataset.sh` scripts. - -The performance of the model depends on the dataset size. -Generally, the model should scale better for datasets containing more data points. -For a smaller dataset you might experience slower performance. - +NCF supports all datasets that include a Feature Specification file and are properly formatted. +For details, refer to the [BYO dataset](#byo-dataset) section. #### ML-1m -To download, preprocess and train on the ML-1m dataset run: +To preprocess and train on the ML-1m dataset run: ```bash ./prepare_dataset.sh ml-1m python -m torch.distributed.launch --nproc_per_node=8 --use_env ncf.py --data /data/cache/ml-1m ``` +### BYO dataset + +This implementation supports using other datasets thanks to BYO dataset functionality. +The BYO dataset functionality allows users to plug in their dataset in a common fashion for all Recommender models +that support this functionality. Using BYO dataset functionality, the user does not have to modify the source code of +the model thanks to the Feature Specification file. For general information on how BYO dataset works, refer to the +[BYO dataset overview section](#byo-dataset-functionality-overview). + +There are three ways to plug in user's dataset: +
+1. Provide an unprocessed dataset in a format matching the one used by ml-20m, then use ml-20m's preprocessing. Feature Specification file is then generated automatically. +The required format of the user's dataset is: + +* CSV file with three columns: `user_id`, `item_id` and `timestamp` +* This CSV should contain only the positive examples. The negatives will be sampled during the training and validation. + + +The correct torch.tensor dataset files together with the Feature Specification yaml file will be generated automatically by preprocessing script. + +The following example shows how to use this way of plugging a user's dataset: + +Build the NCF image with: +```bash +docker build . -t nvidia_ncf +``` +Launch the container with: +```bash +docker run --runtime=nvidia -it --rm --ipc=host -v ${PWD}/data:/data nvidia_ncf bash +``` + +Inside the container run: +```bash +./prepare_dataset.sh like_movielens +``` +This will preprocess the `data/like_movielens/ratings.csv` file and save the output in `data/cache/like_movielens` + +To run the training on 1 GPU: +```bash +python -m torch.distributed.launch --nproc_per_node=1 --use_env ncf.py --data /data/cache/like_movielens +``` + +To run the training on 8 GPUs +```bash +python -m torch.distributed.launch --nproc_per_node=8 --use_env ncf.py --data /data/cache/like_movielens +``` + +One can also add direct support for your dataset in the `prepare_dataset.sh` and `load.py` scripts. +
+ +
+2. Provide a CSV containing preprocessed data and a simplified Feature Specification yaml file, then transcode the data with `transcode.py` script +This option should be used if the user has their own CSV file with a preprocessed dataset they want to train on. + +The required format of the user's dataset is: +* CSV files containing the data, already split into train and test sets. +* Feature Specification yaml file describing the layout of the CSV data + +For an example of a feature specification file and properly formatted CSVs, refer to the `data/csv_conversion` folder. + +The CSV containing the data: +* should be already split into train and test +* should contain no header +* should contain one column per feature, in the order specified by the feature specification file +* `user_id` and `item_id` should be all non-negative integers of range (0,num_users), (0,num_items) respectively +* negative examples for the testing set should already be present +* negative examples for the training set may be already present. By default, the training script samples additional random negative examples (controlled by the '--negative_samples' flag supplied to the `ncf.py` script). + +The Feature Specification yaml file: +* needs to describe the layout of data in CSV files +* should contain information about user, item cardinalities. However, if set to `auto`, they will be inferred from the data by the transcoding script. + +Refer to `data/csv_conversion/feature_spec.yaml` for an example of the yaml Feature Specification. + +The following example shows how to use this way of plugging user's dataset: + + +Build the NCF image with: +```bash +docker build . -t nvidia_ncf +``` +Launch the container with: +```bash +docker run --runtime=nvidia -it --rm --ipc=host -v ${PWD}/data:/data nvidia_ncf bash +``` + +Inside the container run: +```bash +mkdir /data/conversion_output +python transcode.py --path /data/csv_conversion --output /data/conversion_output +``` + +This will convert the data from `data/csv_conversion` and save the output in `data/conversion_output`. +Refer to `data/csv_conversion/feature_spec.yaml` for an example of the yaml Feature Specification. + +To run the training on 1 GPU: +```bash +python -m torch.distributed.launch --nproc_per_node=1 --use_env ncf.py --data /data/conversion_output -k 3 +``` + +To run the training on 8 GPUs +```bash +python -m torch.distributed.launch --nproc_per_node=8 --use_env ncf.py --data /data/conversion_output -k 3 +``` + +The parameter `k` changes the computed metric from HR@10 to HR@3. This is done because the examples are extremely small, +and hit rate depth may not be longer than lists of candidates. +
+
+3. Provide a fully preprocessed dataset, saved in torch.tensor files, and a Feature Specification yaml file +This is the option to choose if you want full control over preprocessing and/or want to preprocess data directly to the target format. + +Your final output will need to contain a Feature Specification yaml describing data and file layout. For an example feature specification file, refer to `data/ml-20m/feature_spec_template.yaml` + +For details, refer to the [BYO dataset overview section](#byo-dataset-functionality-overview). +
+ + + +#### Channel definitions and requirements for NCF-PyT feature specifications. + +This model defines three channels, each accepting a single feature: + +- user_ch +- item_ch +- label_ch + +The training script expects two mappings: + +- train +- test + +As this NeuMF implementation computes list ranking metrics, the testing set actually consists of lists of candidates. +Usually, all entries in a list share the same user id, although this is not mandatory. +All entries from a given list must appear consecutively in the testing set. +List boundaries are not marked in the testing set. +All lists must have the same length. This length must be set by the metadata:test_samples_per_series parameter in the Feature Specification yaml file. + + +#### BYO dataset constraints for the model + +There are the following constraints of BYO dataset functionality for this model: +1. The performance of the model depends on the dataset size. Generally, the model should scale better for datasets containing more data points. For a smaller dataset, you might experience slower performance than the one reported for ml-20m +2. As this implementation keeps the training and testing data in GPU VRAM, supported dataset size is limited by the GPU VRAM size. +3. Using other datasets might require tuning some hyperparameters (for example, learning rate, beta1 and beta2) to reach desired accuracy. +4. The transcoding script uses pandas, and the user's dataset needs to fit into the system memory + + ### Training process The name of the training script is `ncf.py`. Because of the multi-GPU support, it should always be run with the torch distributed launcher like this: ```bash @@ -360,9 +672,9 @@ python -m torch.distributed.launch --nproc_per_node= --use_env n The main result of the training are checkpoints stored by default in `/data/checkpoints/`. This location can be controlled by the `--checkpoint_dir` command-line argument. -The validation metric is Hit Rate at 10 (HR@10) with 100 test negative samples. This means that for each positive sample in -the test set 100 negatives are sampled. All resulting 101 samples are then scored by the model. If the true positive sample is -among the 10 samples with highest scores we have a "hit" and the metric is equal to 1, otherwise it's equal to 0. +The validation metric is Hit Rate at 10 (HR@10) with 100 test negative samples. This means that for each positive sample in +the test set, 100 negatives are sampled. All resulting 101 samples are then scored by the model. If the true positive sample is +among the 10 samples with the highest scores we have a "hit," and the metric is equal to 1; otherwise, it's equal to 0. The HR@10 metric is the number of hits in the entire test set divided by the number of samples in the test set. ### Inference process @@ -385,7 +697,7 @@ The performance measurements in this document were conducted at the time of publ #### Training performance benchmark -NCF training on NVIDIA DGX systems is very fast, therefore, in order to measure train and validation throughput, you can simply run the full training job with: +NCF training on NVIDIA DGX systems is very fast; therefore, in order to measure train and validation throughput, you can simply run the full training job with: ```bash ./prepare_dataset.sh python -m torch.distributed.launch --nproc_per_node=8 --use_env ncf.py --data /data/cache/ml-20m --epochs 5 @@ -402,34 +714,38 @@ Validation throughput can be measured by running the full training job with: python -m torch.distributed.launch --nproc_per_node=8 --use_env ncf.py --data /data/cache/ml-20m --epochs 5 ``` -The best validation throughput is reported to the standard output. +The best validation throughput is reported to the standard output. ### Results -The following sections provide details on how we achieved our performance and accuracy in training and inference. +The following sections provide details on how we achieved our performance and accuracy in training and inference. #### Training accuracy results ##### Training accuracy: NVIDIA DGX A100(8x A100 40GB) -Our results were obtained by following the steps in the Quick Start Guide in the PyTorch 20.06-py3 NGC container on NVIDIA DGX A100 (8x A100 40GB) GPUs. +Our results were obtained by following the steps in the Quick Start Guide in the PyTorch 21.04-py3 NGC container on NVIDIA DGX A100 (8x A100 40GB) GPUs. -| GPUs | Batch size / GPU | Accuracy - TF32 | Accuracy - mixed precision | Time to train - TF32 | Time to train - mixed precision | Time to train speedup (TF32 to mixed precision) -|---|-----|------|---|---|---|---| -| 1 | 1048576 | 0.958805 | 0.958744 | 141.2 | 96.0 | 1.47 | -| 8 | 131072 | 0.958916 | 0.959045 | 31.99 | 25.21 | 1.27 | +The following table lists the best hit rate at 10 for DGX A100 with 8 A100 40GB GPUs. It also shows the time to reach this HR@10. +Results are averages across 20 random seeds. + +| GPUs | Batch size / GPU | Accuracy - TF32 | Accuracy - mixed precision | Time to train - TF32 | Time to train - mixed precision | Time to train speedup (TF32 to mixed precision) | +|-------:|-------------------:|------------------:|-----------------------------:|-----------------------:|----------------------------------:|--------------------------------------------------:| +| 1 | 1048576 | 0.958925 | 0.958892 | 140.771 | 94.2386 | 1.49 | +| 8 | 131072 | 0.958938 | 0.959089 | 30.0928 | 23.7362 | 1.27 | ##### Training accuracy: NVIDIA DGX-1 (8x V100 16GB) -Our results were obtained by following the steps in the Quick Start Guide in the PyTorch 20.06-py3 NGC container on NVIDIA DGX-1 with 8x V100 16GB GPUs. +Our results were obtained by following the steps in the Quick Start Guide in the PyTorch 21.04-py3 NGC container on NVIDIA DGX-1 with 8x V100 16GB GPUs. -The following table lists the best hit rate at 10 for DGX-1 with 8 V100 16GB GPUs. It also shows the average time to reach this HR@10 across 5 random seeds. +The following table lists the best hit rate at 10 for DGX-1 with 8 V100 16GB GPUs. It also shows the time to reach this HR@10. +Results are averages across 20 random seeds. The training time was measured excluding data downloading, preprocessing, validation data generation and library initialization times. -| **GPUs** | **Batch size / GPU** | **Accuracy - FP32** | **Accuracy - mixed precision** | **Time to train - FP32 (s)** | **Time to train - mixed precision (s)** | **Time to train speedup (FP32 to mixed precision)** -|------:|----:|----:|----:|---:|----:|------------------:| -| 1 | 1,048,576 | 0.958944 | 0.959093 | 304.922339 | 145.285286 | 2.10 | -| 8 | 131,072 | 0.959029 | 0.959107 | 55.120696 | 35.165247 | 1.58 | +| GPUs | Batch size / GPU | Accuracy - FP32 | Accuracy - mixed precision | Time to train - FP32 | Time to train - mixed precision | Time to train speedup (FP32 to mixed precision) | +|-------:|-------------------:|------------------:|-----------------------------:|-----------------------:|----------------------------------:|--------------------------------------------------:| +| 1 | 1048576 | 0.958857 | 0.958815 | 302.443 | 145.423 | 2.08 | +| 8 | 131072 | 0.958768 | 0.959052 | 53.7044 | 34.2503 | 1.57 | To reproduce this result, start the NCF Docker container interactively and run: ```bash @@ -439,20 +755,18 @@ python -m torch.distributed.launch --nproc_per_node=8 --use_env ncf.py --data /d ##### Training accuracy: NVIDIA DGX-1 (8x V100 32GB) -Our results were obtained by following the steps in the Quick Start Guide in the PyTorch 20.06-py3 NGC container on NVIDIA DGX-1 with 8x V100 32GB GPUs. +Our results were obtained by following the steps in the Quick Start Guide in the PyTorch 21.04-py3 NGC container on NVIDIA DGX-1 with 8x V100 32GB GPUs. -The following table lists the best hit rate at 10 for DGX-1 with 8 V100 16GB GPUs. It also shows the average time to reach this HR@10 across 5 random seeds. +The following table lists the best hit rate at 10 for DGX-1 with 8 V100 32GB GPUs. It also shows the time to reach this HR@10. +Results are averages across 20 random seeds. The training time was measured excluding data downloading, preprocessing, validation data generation and library initialization times. -| **GPUs** | **Batch size / GPU** | **Accuracy - FP32** | **Accuracy - mixed precision** | **Time to train - FP32 (s)** | **Time to train - mixed precision (s)** | **Time to train speedup (FP32 to mixed precision)** | -|------:|-------:|-----:|------:|-----:|----:|-----:| -| 1 | 1,048,576 | 0.959172 | 0.958409 | 309.942810 | 153.940982 | 2.01 | -| 8 | 131,072 | 0.958905 | 0.959228 | 56.922492 | 38.121914 | 1.49 | +| GPUs | Batch size / GPU | Accuracy - FP32 | Accuracy - mixed precision | Time to train - FP32 | Time to train - mixed precision | Time to train speedup (FP32 to mixed precision) | +|-------:|-------------------:|------------------:|-----------------------------:|-----------------------:|----------------------------------:|--------------------------------------------------:| +| 1 | 1048576 | 0.958992 | 0.959002 | 310.467 | 153.616 | 2.02 | +| 8 | 131072 | 0.95871 | 0.958925 | 55.716 | 36.3384 | 1.53 | -Here's an example validation accuracy curve for mixed precision vs single precision on DGX-1 with 8 V100 32GB GPUs: - -![ValidationAccuracy](./img/dgx1v_32_curve.png) To reproduce this result, start the NCF Docker container interactively and run: ```bash @@ -462,16 +776,18 @@ python -m torch.distributed.launch --nproc_per_node=8 --use_env ncf.py --data /d ##### Training accuracy: NVIDIA DGX-2 (16x V100 32GB) -Our results were obtained by following the steps in the Quick Start Guide in the PyTorch 20.06-py3 NGC container on NVIDIA DGX-1 with 8x V100 16GB GPUs. +Our results were obtained by following the steps in the Quick Start Guide in the PyTorch 21.04-py3 NGC container on NVIDIA DGX-2 with 16x V100 32GB GPUs. -The following table lists the best hit rate at 10 for DGX-1 with 8 V100 16GB GPUs. It also shows the average time to reach this HR@10 across 5 random seeds. +The following table lists the best hit rate at 10 for DGX-2 with 16 V100 32GB GPUs. It also shows the time to reach this HR@10. +Results are averages across 20 random seeds. The training time was measured excluding data downloading, preprocessing, validation data generation and library initialization times. -| **GPUs** | **Batch size / GPU** | **Accuracy - FP32** | **Accuracy - mixed precision** | **Time to train - FP32 (s)** | **Time to train - mixed precision (s)** | **Time to train speedup (FP32 to mixed precision)** | -|--------------------------:|-----------------------------:|--------------------------:|--------------------------:|-------------------------------:|-------------------------------:|------------------:| -| 1 | 1,048,576 | 0.958794 | 0.958873 | 290.648888 | 143.328581 | 2.03 | -| 8 | 131,072 | 0.959152 | 0.959150 | 53.792118 | 34.838838 | 1.54 | -| 16 | 65,536 | 0.959248 | 0.958812 | 40.925270 | 30.214568 | 1.35 | +| GPUs | Batch size / GPU | Accuracy - FP32 | Accuracy - mixed precision | Time to train - FP32 | Time to train - mixed precision | Time to train speedup (FP32 to mixed precision) | +|-------:|-------------------:|------------------:|-----------------------------:|-----------------------:|----------------------------------:|--------------------------------------------------:| +| 1 | 1048576 | 0.958756 | 0.958833 | 289.004 | 143.61 | 2.01 | +| 8 | 131072 | 0.958864 | 0.958806 | 52.1788 | 33.7456 | 1.55 | +| 16 | 65536 | 0.958905 | 0.958893 | 37.7075 | 27.174 | 1.39 | + To reproduce this result, start the NCF Docker container interactively and run: @@ -481,123 +797,135 @@ python -m torch.distributed.launch --nproc_per_node=16 --use_env ncf.py --data / ``` -##### Training stability test +##### Influence of AMP on accuracy -The histogram below shows the best HR@10 achieved -for 400 experiments using mixed precision and 400 experiments using single precision. -Mean HR@10 for mixed precision was equal to 0.95868 and for single precision it was equal to -0.95867. -![hr_histogram](./img/hr_histogram.png) +The box plots below show the best accuracy achieved in each run. +Twenty experiments were performed for each configuration. + +![hr_boxplot](./img/box_plots.png) + + +##### Training validation curves + +The plots below show the validation accuracy over the course of training. +One sample curve is shown for each configuration. + +![validation_accuracy](./img/val_curves.png) #### Training performance results +Results are averages over 20 runs for each configuration. ##### Training performance: NVIDIA DGX A100 (8x A100 40GB) -Our results were obtained by following the steps in the Quick Start Guide in the PyTorch 20.06-py3 NGC container on NVIDIA DGX A100 (8x A100 40GB) GPUs. Performance numbers (in items per second) were averaged over an entire training epoch. +Our results were obtained by following the steps in the Quick Start Guide in the PyTorch 21.04-py3 NGC container on NVIDIA DGX A100 (8x A100 40GB) GPUs. Performance numbers (in items per second) were averaged over an entire training epoch. -| GPUs | Batch size / GPU | Throughput - TF32 | Throughput - mixed precision | Throughput speedup (TF32 - mixed precision) | Strong scaling - TF32 | Strong scaling - mixed precision | -|----|----|----|----|----|---|----| -| 1 | 1,048,576 | 22.64M | 33.59M | 1.484 | 1 | 1 | -| 8 | 131,072 | 105.8M | 137.8M | 1.302 | 4.67 | 4.10 | +| GPUs | Batch size / GPU | Throughput - TF32 (samples/s) | Throughput - mixed precision (samples/s) | Throughput speedup (TF32 to mixed precision) | Strong scaling - TF32 | Strong scaling - mixed precision | +|-------:|-------------------:|:--------------------------------|:-------------------------------------------|-----------------------------------------------:|------------------------:|-----------------------------------:| +| 1 | 1048576 | 22.59M | 34.08M | 0.66 | 1 | 1 | +| 8 | 131072 | 110.16M | 142.90M | 0.77 | 4.88 | 4.19 | ##### Training performance: NVIDIA DGX-1 (8x V100 16GB) -Our results were obtained by following the steps in the Quick Start Guide in the PyTorch 20.06-py3 NGC container on NVIDIA DGX-1 with 8x V100 16GB GPUs. +Our results were obtained by following the steps in the Quick Start Guide in the PyTorch 21.04-py3 NGC container on NVIDIA DGX-1 with 8x V100 16GB GPUs. The following table shows the best training throughput: -| **GPUs** | **Batch Size / GPU** | **Throughput - FP32 (samples / s)** | **Throughput - Mixed precision (samples /s)** | **Throughput Speedup (FP32 to Mixed precision)** | **Strong Scaling - FP32** | **Strong scaling - Mixed precision** | -|--------------------------:|-----------------------------:|----------------------------------:|----------------------------------:|------------------:|---------------------:|---------------------:| -| 1 | 1,048,576| 10.32M | 21.90M | 2.12 | 1 | 1 | -| 8 | 131,072 | 58.55M | 93.73M | 1.60 | 5.67 | 4.28 | +| GPUs | Batch size / GPU | Throughput - FP32 (samples/s) | Throughput - mixed precision (samples/s) | Throughput speedup (FP32 to mixed precision) | Strong scaling - FP32 | Strong scaling - mixed precision | +|-------:|-------------------:|:--------------------------------|:-------------------------------------------|-----------------------------------------------:|------------------------:|-----------------------------------:| +| 1 | 1048576 | 10.42M | 21.84M | 0.48 | 1 | 1 | +| 8 | 131072 | 60.03M | 95.95M | 0.63 | 5.76 | 4.39 | ##### Training performance: NVIDIA DGX-1 (8x V100 32GB) -Our results were obtained by following the steps in the Quick Start Guide in the PyTorch 20.06-py3 NGC container on NVIDIA DGX-1 with 8x V100 32GB GPUs. +Our results were obtained by following the steps in the Quick Start Guide in the PyTorch 21.04-py3 NGC container on NVIDIA DGX-1 with 8x V100 32GB GPUs. The following table shows the best training throughput: -| **GPUs** | **Batch Size / GPU** | **Throughput - FP32 (samples / s)** | **Throughput - Mixed precision (samples /s)** | **Throughput Speedup (FP32 to Mixed precision)** | **Strong Scaling - FP32** | **Strong scaling - Mixed precision** | -|--------------------------:|-----------------------------:|----------------------------------:|----------------------------------:|------------------:|---------------------:|---------------------:| -| 1 | 1,048,576 | 10.15M |20.66M | 2.04 | 1 | 1 | -| 8 | 131,072 | 56.77M | 88.76M | 1.56 | 5.60| 4.29| +| GPUs | Batch size / GPU | Throughput - FP32 (samples/s) | Throughput - mixed precision (samples/s) | Throughput speedup (FP32 to mixed precision) | Strong scaling - FP32 | Strong scaling - mixed precision | +|-------:|-------------------:|:--------------------------------|:-------------------------------------------|-----------------------------------------------:|------------------------:|-----------------------------------:| +| 1 | 1048576 | 10.14M | 20.65M | 0.49 | 1 | 1 | +| 8 | 131072 | 58.50M | 91.77M | 0.64 | 5.77 | 4.44 | ##### Training performance: NVIDIA DGX-2 (16x V100 32GB) -Our results were obtained by following the steps in the Quick Start Guide in the PyTorch 20.06-py3 NGC container on NVIDIA DGX-2 with 16x V100 32GB GPUs. +Our results were obtained by following the steps in the Quick Start Guide in the PyTorch 21.04-py3 NGC container on NVIDIA DGX-2 with 16x V100 32GB GPUs. The following table shows the best training throughput: -| **GPUs** | **Batch Size / GPU** | **Throughput - FP32 (samples / s)** | **Throughput - Mixed precision (samples /s)** | **Throughput Speedup (FP32 to Mixed precision)** | **Strong Scaling - FP32** | **Strong scaling - Mixed precision** | -|--------------------------:|:-----------------------------|:----------------------------------|:----------------------------------|------------------:|---------------------:|---------------------:| -| 1 | 1,048,576 | 10.83M | 22.18M | 2.05 | 1 | 1 | -| 8 | 131,072 | 60.33M | 95.58M | 1.58 | 5.57 | 4.31 | -| 16 | 65,536 | 83.00M | 120.1M | 1.45 | 7.67 | 5.41 | +| GPUs | Batch size / GPU | Throughput - FP32 (samples/s) | Throughput - mixed precision (samples/s) | Throughput speedup (FP32 to mixed precision) | Strong scaling - FP32 | Strong scaling - mixed precision | +|-------:|-------------------:|:--------------------------------|:-------------------------------------------|-----------------------------------------------:|------------------------:|-----------------------------------:| +| 1 | 1048576 | 10.90M | 22.16M | 0.49 | 1 | 1 | +| 8 | 131072 | 62.16M | 98.56M | 0.63 | 5.7 | 4.45 | +| 16 | 65536 | 92.20M | 134.91M | 0.68 | 8.46 | 6.09 | #### Inference performance results ##### Inference performance: NVIDIA DGX A100 (1x A100 40GB) -Our results were obtained by running the `inference.py` script in the PyTorch 20.06 NGC container on NVIDIA DGX A100 with 1x A100 GPU. +Our results were obtained by running the `inference.py` script in the PyTorch 21.04 NGC container on NVIDIA DGX A100 with 1x A100 GPU. TF32 -| Batch size | Throughput Avg | Latency Avg | Latency 90% | Latency 95% | Latency 99% | -|-------------:|-----------------:|--------------:|--------------:|--------------:|---------------:| -| 1024 | 2.18e+06 | 0.00047 | 0.00045 | 0.00045 | 0.00045 | -| 4096 | 8.64e+06 | 0.00047 | 0.00046 | 0.00046 | 0.00046 | -| 16384 | 3.417e+07 | 0.00048 | 0.00046 | 0.00046 | 0.00046 | -| 65536 | 5.148e+07 | 0.00127 | 0.00125 | 0.00125 | 0.00125 | -| 262144 | 5.863e+07 | 0.00447 | 0.00444 | 0.00444 | 0.00444 | -| 1048576 | 6.032e+07 | 0.01738 | 0.01736 | 0.01736 | 0.01736 | +| Batch size | Throughput Avg | Latency Avg | Latency 90% | Latency 95% | Latency 99% | +|-------------:|-----------------:|--------------:|--------------:|--------------:|--------------:| +| 1024 | 2.96198e+06 | 0.000346 | 0.00037 | 0.000374 | 0.000383 | +| 4096 | 1.16823e+07 | 0.000351 | 0.000375 | 0.000382 | 0.000389 | +| 16384 | 4.01876e+07 | 0.000408 | 0.000442 | 0.000443 | 0.000445 | +| 65536 | 5.06161e+07 | 0.001295 | 0.001319 | 0.001321 | 0.001324 | +| 262144 | 5.62193e+07 | 0.004663 | 0.004655 | 0.00466 | 0.005091 | +| 1048576 | 5.74678e+07 | 0.018246 | 0.018258 | 0.018261 | 0.018276 | FP16 -| Batch size | Throughput Avg | Latency Avg | Latency 90% | Latency 95% | Latency 99% | -|-------------:|-----------------:|--------------:|--------------:|--------------:|---------------:| -| 1024 | 2.26e+06 | 0.00045 | 0.00044 | 0.00044 | 0.00044 | -| 4096 | 8.91e+06 | 0.00046 | 0.00044 | 0.00044 | 0.00044 | -| 16384 | 3.54e+07 | 0.00046 | 0.00045 | 0.00045 | 0.00045 | -| 65536 | 7.467e+07 | 0.00088 | 0.00086 | 0.00086 | 0.00086 | -| 262144 | 8.679e+07 | 0.00302 | 0.003 | 0.003 | 0.003 | -| 1048576 | 9.067e+07 | 0.01157 | 0.01154 | 0.01154 | 0.01154 | +| Batch size | Throughput Avg | Latency Avg | Latency 90% | Latency 95% | Latency 99% | +|-------------:|-----------------:|--------------:|--------------:|--------------:|--------------:| +| 1024 | 2.9068e+06 | 0.000352 | 0.000379 | 0.000383 | 0.000401 | +| 4096 | 1.1149e+07 | 0.000367 | 0.000394 | 0.000396 | 0.000402 | +| 16384 | 4.46873e+07 | 0.000367 | 0.000391 | 0.000397 | 0.000406 | +| 65536 | 7.15357e+07 | 0.000916 | 0.001064 | 0.001068 | 0.001071 | +| 262144 | 8.02216e+07 | 0.003268 | 0.00327 | 0.003272 | 0.00338 | +| 1048576 | 8.27085e+07 | 0.012678 | 0.012685 | 0.012688 | 0.012809 | -##### Inference performance: NVIDIA DGX-1 (8x V100 16GB) +##### Inference performance: NVIDIA DGX-1 (1x V100 16GB) -Our results were obtained by running the `inference.py` script in the PyTorch 20.06 NGC container on NVIDIA DGX-1 with 1x V100 16GB GPU. +Our results were obtained by running the `inference.py` script in the PyTorch 21.04 NGC container on NVIDIA DGX-1 with 1x V100 16GB GPU. FP32 -| Batch size | Throughput Avg | Latency Avg | Latency 90% | Latency 95% | Latency 99% | -|-------------:|-----------------:|--------------:|--------------:|--------------:|---------------:| -| 1024 | 1.53e+06 | 0.00067 | 0.00065 | 0.00065 | 0.00065 | -| 4096 | 6.02e+06 | 0.00068 | 0.00067 | 0.00067 | 0.00067 | -| 16384 | 2.062e+07 | 0.00079 | 0.00076 | 0.00076 | 0.00076 | -| 65536 | 2.802e+07 | 0.00234 | 0.0023 | 0.0023 | 0.0023 | -| 262144 | 3.023e+07 | 0.00867 | 0.00865 | 0.00865 | 0.00865 | -| 1048576 | 3.015e+07 | 0.03478 | 0.03452 | 0.03452 | 0.03452 | +| Batch size | Throughput Avg | Latency Avg | Latency 90% | Latency 95% | Latency 99% | +|-------------:|-----------------:|--------------:|--------------:|--------------:|--------------:| +| 1024 | 1.91315e+06 | 0.000535 | 0.000557 | 0.000565 | 0.000589 | +| 4096 | 7.4782e+06 | 0.000548 | 0.000566 | 0.000577 | 0.000718 | +| 16384 | 2.15241e+07 | 0.000761 | 0.000783 | 0.000791 | 0.000842 | +| 65536 | 2.77005e+07 | 0.002366 | 0.00242 | 0.002431 | 0.002435 | +| 262144 | 2.95251e+07 | 0.008879 | 0.008888 | 0.008895 | 0.008932 | +| 1048576 | 2.92491e+07 | 0.03585 | 0.03603 | 0.036078 | 0.036144 | FP16 -| Batch size | Throughput Avg | Latency Avg | Latency 90% | Latency 95% | Latency 99% | -|-------------:|-----------------:|--------------:|--------------:|--------------:|---------------:| -| 1024 | 1.61e+06 | 0.00064 | 0.00062 | 0.00062 | 0.00062 | -| 4096 | 6.37e+06 | 0.00064 | 0.00063 | 0.00063 | 0.00063 | -| 16384 | 2.543e+07 | 0.00064 | 0.00063 | 0.00063 | 0.00063 | -| 65536 | 5.23e+07 | 0.00125 | 0.00121 | 0.00121 | 0.00121 | -| 262144 | 5.967e+07 | 0.00439 | 0.00437 | 0.00437 | 0.00437 | -| 1048576 | 5.998e+07 | 0.01748 | 0.01739 | 0.01739 | 0.01739 | +| Batch size | Throughput Avg | Latency Avg | Latency 90% | Latency 95% | Latency 99% | +|-------------:|-----------------:|--------------:|--------------:|--------------:|--------------:| +| 1024 | 2.00172e+06 | 0.000512 | 0.000538 | 0.000546 | 0.000577 | +| 4096 | 8.08797e+06 | 0.000506 | 0.000519 | 0.000535 | 0.000569 | +| 16384 | 3.22482e+07 | 0.000508 | 0.000516 | 0.000519 | 0.000557 | +| 65536 | 5.20587e+07 | 0.001259 | 0.001265 | 0.001267 | 0.001278 | +| 262144 | 5.66404e+07 | 0.004628 | 0.004636 | 0.004638 | 0.004642 | +| 1048576 | 5.66507e+07 | 0.018509 | 0.018547 | 0.018556 | 0.018583 | ## Release notes -### Changelog +The performance measurements in this document were conducted at the time of publication and may not reflect +the performance achieved from NVIDIA’s latest software release. For the most up-to-date performance measurements, +go to [NVIDIA Data Center Deep Learning Product Performance](https://developer.nvidia.com/deep-learning-performance-training-inference). + +### Changelog 1. January 22, 2018 * Initial release 2. May, 2019 @@ -615,27 +943,35 @@ FP16 * Adjusting for API changes in PyTorch and APEX * Checkpoints loading fix 5. January, 2020 - * DLLogger support added -4. June, 2020 - * Updated performance tables to include A100 results + * DLLogger support added +6. June, 2020 + * Updated performance tables to include A100 results5. +7. June, 2021 + * Enhanced BYO dataset functionality - added Feature Specification and transcoding + * Default container changed to PyTorch 21.04-py3 + * Updated performance and accuracy tables and plots + * Code cleanup ### Known issues - + #### Scaling beyond 8 GPUs Neural Collaborative Filtering is a relatively lightweight model that trains quickly with this relatively smaller dataset, ML-20m. -Because of that, the high ratio of communication to computation makes it difficult to +Because of that, the high ratio of communication to computation makes it difficult to efficiently use more than 8 GPUs. Typically, this is not an issue because when using 8 GPUs with FP16 precision, the training is sufficiently fast. However, if you’d like to - scale the training to 16 GPUs and beyond, you might try modifying the model so that + scale the training to 16 GPUs and beyond, you might try modifying the model so that the communication-computation ratio facilitates better scaling. This could be done, for example, - by finding hyperparameters that enable using a larger batch size or by reducing the + by finding hyperparameters that enable using a larger batch size or by reducing the number of trainable parameters. #### Memory usage In the default settings, the additional memory beyond 16GB may not be fully utilized. -This is because we set the default batch size for ML-20m dataset to 1M, -which is too small to completely fill-up multiple 32GB GPUs. +This is because we set the default batch size for the ML-20m dataset to 1M, +which is too small to fill up multiple 32GB GPUs completely. 1M is the batch size for which we experienced the best convergence on the ML-20m dataset. However, on other datasets, even faster performance can be possible by finding hyperparameters that work well for larger batches and leverage additional GPU memory. + + + diff --git a/PyTorch/Recommendation/NCF/convert.py b/PyTorch/Recommendation/NCF/convert.py index 7bcf9519..af6e45c0 100644 --- a/PyTorch/Recommendation/NCF/convert.py +++ b/PyTorch/Recommendation/NCF/convert.py @@ -14,7 +14,7 @@ # # ----------------------------------------------------------------------- # -# Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved. +# Copyright (c) 2021, 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. @@ -31,13 +31,21 @@ from argparse import ArgumentParser import pandas as pd from load import implicit_load +from feature_spec import FeatureSpec +from neumf_constants import USER_CHANNEL_NAME, ITEM_CHANNEL_NAME, LABEL_CHANNEL_NAME, TEST_SAMPLES_PER_SERIES import torch +import os import tqdm -MIN_RATINGS = 20 +TEST_1 = 'test_data_1.pt' +TEST_0 = 'test_data_0.pt' +TRAIN_1 = 'train_data_1.pt' +TRAIN_0 = 'train_data_0.pt' + USER_COLUMN = 'user_id' ITEM_COLUMN = 'item_id' + def parse_args(): parser = ArgumentParser() parser.add_argument('--path', type=str, default='/data/ml-20m/ratings.csv', @@ -61,7 +69,7 @@ class _TestNegSampler: ids = (train_ratings[:, 0] * self.nb_items) + train_ratings[:, 1] self.set = set(ids) - def generate(self, batch_size=128*1024): + def generate(self, batch_size=128 * 1024): users = torch.arange(0, self.nb_users).reshape([1, -1]).repeat([self.nb_neg, 1]).transpose(0, 1).reshape(-1) items = [-1] * len(users) @@ -82,6 +90,71 @@ class _TestNegSampler: return items +def save_feature_spec(user_cardinality, item_cardinality, dtypes, test_negative_samples, output_path, + user_feature_name='user', + item_feature_name='item', + label_feature_name='label'): + feature_spec = { + user_feature_name: { + 'dtype': dtypes[user_feature_name], + 'cardinality': int(user_cardinality) + }, + item_feature_name: { + 'dtype': dtypes[item_feature_name], + 'cardinality': int(item_cardinality) + }, + label_feature_name: { + 'dtype': dtypes[label_feature_name], + } + } + metadata = { + TEST_SAMPLES_PER_SERIES: test_negative_samples + 1 + } + train_mapping = [ + { + 'type': 'torch_tensor', + 'features': [ + user_feature_name, + item_feature_name + ], + 'files': [TRAIN_0] + }, + { + 'type': 'torch_tensor', + 'features': [ + label_feature_name + ], + 'files': [TRAIN_1] + } + ] + test_mapping = [ + { + 'type': 'torch_tensor', + 'features': [ + user_feature_name, + item_feature_name + ], + 'files': [TEST_0], + }, + { + 'type': 'torch_tensor', + 'features': [ + label_feature_name + ], + 'files': [TEST_1], + } + ] + channel_spec = { + USER_CHANNEL_NAME: [user_feature_name], + ITEM_CHANNEL_NAME: [item_feature_name], + LABEL_CHANNEL_NAME: [label_feature_name] + } + source_spec = {'train': train_mapping, 'test': test_mapping} + feature_spec = FeatureSpec(feature_spec=feature_spec, metadata=metadata, source_spec=source_spec, + channel_spec=channel_spec, base_directory="") + feature_spec.to_yaml(output_path=output_path) + + def main(): args = parse_args() @@ -91,39 +164,54 @@ def main(): print("Loading raw data from {}".format(args.path)) df = implicit_load(args.path, sort=False) - print("Filtering out users with less than {} ratings".format(MIN_RATINGS)) - grouped = df.groupby(USER_COLUMN) - df = grouped.filter(lambda x: len(x) >= MIN_RATINGS) - print("Mapping original user and item IDs to new sequential IDs") df[USER_COLUMN] = pd.factorize(df[USER_COLUMN])[0] df[ITEM_COLUMN] = pd.factorize(df[ITEM_COLUMN])[0] + user_cardinality = df[USER_COLUMN].max() + 1 + item_cardinality = df[ITEM_COLUMN].max() + 1 + # Need to sort before popping to get last item df.sort_values(by='timestamp', inplace=True) # clean up data del df['rating'], df['timestamp'] - df = df.drop_duplicates() # assuming it keeps order + df = df.drop_duplicates() # assuming it keeps order - # now we have filtered and sorted by time data, we can split test data out + # Test set is the last interaction for a given user grouped_sorted = df.groupby(USER_COLUMN, group_keys=False) - test_data = grouped_sorted.tail(1).sort_values(by='user_id') - # need to pop for each group + test_data = grouped_sorted.tail(1).sort_values(by=USER_COLUMN) + # Train set is all interactions but the last one train_data = grouped_sorted.apply(lambda x: x.iloc[:-1]) - # Note: no way to keep reference training data ordering because use of python set and multi-process - # It should not matter since it will be later randomized again - # save train and val data that is fixed. - train_ratings = torch.from_numpy(train_data.values) - torch.save(train_ratings, args.output+'/train_ratings.pt') - test_ratings = torch.from_numpy(test_data.values) - torch.save(test_ratings, args.output+'/test_ratings.pt') - - sampler = _TestNegSampler(train_ratings.cpu().numpy(), args.valid_negative) + sampler = _TestNegSampler(train_data.values, args.valid_negative) test_negs = sampler.generate().cuda() test_negs = test_negs.reshape(-1, args.valid_negative) - torch.save(test_negs, args.output+'/test_negatives.pt') + + # Reshape train set into user,item,label tabular and save + train_ratings = torch.from_numpy(train_data.values).cuda() + train_labels = torch.ones_like(train_ratings[:, 0:1], dtype=torch.float32) + torch.save(train_ratings, os.path.join(args.output, TRAIN_0)) + torch.save(train_labels, os.path.join(args.output, TRAIN_1)) + + # Reshape test set into user,item,label tabular and save + # All users have the same number of items, items for a given user appear consecutively + test_ratings = torch.from_numpy(test_data.values).cuda() + test_users_pos = test_ratings[:, 0:1] # slicing instead of indexing to keep dimensions + test_items_pos = test_ratings[:, 1:2] + test_users = test_users_pos.repeat_interleave(args.valid_negative + 1, dim=0) + test_items = torch.cat((test_items_pos.reshape(-1, 1), test_negs), dim=1).reshape(-1, 1) + positive_labels = torch.ones_like(test_users_pos, dtype=torch.float32) + negative_labels = torch.zeros_like(test_users_pos, dtype=torch.float32).repeat(1, args.valid_negative) + test_labels = torch.cat((positive_labels, negative_labels), dim=1).reshape(-1, 1) + dtypes = {'user': str(test_users.dtype), 'item': str(test_items.dtype), 'label': str(test_labels.dtype)} + test_tensor = torch.cat((test_users, test_items), dim=1) + torch.save(test_tensor, os.path.join(args.output, TEST_0)) + torch.save(test_labels, os.path.join(args.output, TEST_1)) + + save_feature_spec(user_cardinality=user_cardinality, item_cardinality=item_cardinality, dtypes=dtypes, + test_negative_samples=args.valid_negative, output_path=args.output + '/feature_spec.yaml') + if __name__ == '__main__': main() diff --git a/PyTorch/Recommendation/NCF/convert_test.py b/PyTorch/Recommendation/NCF/convert_test.py new file mode 100644 index 00000000..9f189e2a --- /dev/null +++ b/PyTorch/Recommendation/NCF/convert_test.py @@ -0,0 +1,158 @@ +# Copyright (c) 2018, deepakn94, codyaustun, robieta. 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. +# +# ----------------------------------------------------------------------- +# +# Copyright (c) 2021, 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. + +from argparse import ArgumentParser +import pandas as pd +import numpy as np +from load import implicit_load +from convert import save_feature_spec, _TestNegSampler, TEST_0, TEST_1, TRAIN_0, TRAIN_1 +import torch +import os + +USER_COLUMN = 'user_id' +ITEM_COLUMN = 'item_id' + + +def parse_args(): + parser = ArgumentParser() + parser.add_argument('--path', type=str, default='/data/ml-20m/ratings.csv', + help='Path to reviews CSV file from MovieLens') + parser.add_argument('--output', type=str, default='/data', + help='Output directory for train and test files') + parser.add_argument('--valid_negative', type=int, default=100, + help='Number of negative samples for each positive test example') + parser.add_argument('--seed', '-s', type=int, default=1, + help='Manually set random seed for torch') + parser.add_argument('--test', type=str, help='select modification to be applied to the set') + return parser.parse_args() + + +def main(): + args = parse_args() + + if args.seed is not None: + torch.manual_seed(args.seed) + + print("Loading raw data from {}".format(args.path)) + df = implicit_load(args.path, sort=False) + + if args.test == 'less_user': + to_drop = set(list(df[USER_COLUMN].unique())[-100:]) + df = df[~df[USER_COLUMN].isin(to_drop)] + if args.test == 'less_item': + to_drop = set(list(df[ITEM_COLUMN].unique())[-100:]) + df = df[~df[ITEM_COLUMN].isin(to_drop)] + if args.test == 'more_user': + sample = df.sample(frac=0.2).copy() + sample[USER_COLUMN] = sample[USER_COLUMN] + 10000000 + df = df.append(sample) + users = df[USER_COLUMN] + df = df[users.isin(users[users.duplicated(keep=False)])] # make sure something remains in the train set + if args.test == 'more_item': + sample = df.sample(frac=0.2).copy() + sample[ITEM_COLUMN] = sample[ITEM_COLUMN] + 10000000 + df = df.append(sample) + + print("Mapping original user and item IDs to new sequential IDs") + df[USER_COLUMN] = pd.factorize(df[USER_COLUMN])[0] + df[ITEM_COLUMN] = pd.factorize(df[ITEM_COLUMN])[0] + + user_cardinality = df[USER_COLUMN].max() + 1 + item_cardinality = df[ITEM_COLUMN].max() + 1 + + # Need to sort before popping to get last item + df.sort_values(by='timestamp', inplace=True) + + # clean up data + del df['rating'], df['timestamp'] + df = df.drop_duplicates() # assuming it keeps order + + # Test set is the last interaction for a given user + grouped_sorted = df.groupby(USER_COLUMN, group_keys=False) + test_data = grouped_sorted.tail(1).sort_values(by=USER_COLUMN) + # Train set is all interactions but the last one + train_data = grouped_sorted.apply(lambda x: x.iloc[:-1]) + + sampler = _TestNegSampler(train_data.values, args.valid_negative) + test_negs = sampler.generate().cuda() + if args.valid_negative > 0: + test_negs = test_negs.reshape(-1, args.valid_negative) + else: + test_negs = test_negs.reshape(test_data.shape[0], 0) + + if args.test == 'more_pos': + mask = np.random.rand(len(test_data)) < 0.5 + sample = test_data[mask].copy() + sample[ITEM_COLUMN] = sample[ITEM_COLUMN] + 5 + test_data = test_data.append(sample) + test_negs_copy = test_negs[mask] + test_negs = torch.cat((test_negs, test_negs_copy), dim=0) + if args.test == 'less_pos': + mask = np.random.rand(len(test_data)) < 0.5 + test_data = test_data[mask] + test_negs = test_negs[mask] + + # Reshape train set into user,item,label tabular and save + train_ratings = torch.from_numpy(train_data.values).cuda() + train_labels = torch.ones_like(train_ratings[:, 0:1], dtype=torch.float32) + torch.save(train_ratings, os.path.join(args.output, TRAIN_0)) + torch.save(train_labels, os.path.join(args.output, TRAIN_1)) + + # Reshape test set into user,item,label tabular and save + # All users have the same number of items, items for a given user appear consecutively + test_ratings = torch.from_numpy(test_data.values).cuda() + test_users_pos = test_ratings[:, 0:1] # slicing instead of indexing to keep dimensions + test_items_pos = test_ratings[:, 1:2] + test_users = test_users_pos.repeat_interleave(args.valid_negative + 1, dim=0) + test_items = torch.cat((test_items_pos.reshape(-1, 1), test_negs), dim=1).reshape(-1, 1) + positive_labels = torch.ones_like(test_users_pos, dtype=torch.float32) + negative_labels = torch.zeros_like(test_users_pos, dtype=torch.float32).repeat(1, args.valid_negative) + test_labels = torch.cat((positive_labels, negative_labels), dim=1).reshape(-1, 1) + dtypes = {'user': str(test_users.dtype), 'item': str(test_items.dtype), 'label': str(test_labels.dtype)} + test_tensor = torch.cat((test_users, test_items), dim=1) + torch.save(test_tensor, os.path.join(args.output, TEST_0)) + torch.save(test_labels, os.path.join(args.output, TEST_1)) + + if args.test == 'other_names': + dtypes = {'user_2': str(test_users.dtype), + 'item_2': str(test_items.dtype), + 'label_2': str(test_labels.dtype)} + save_feature_spec(user_cardinality=user_cardinality, item_cardinality=item_cardinality, dtypes=dtypes, + test_negative_samples=args.valid_negative, output_path=args.output + '/feature_spec.yaml', + user_feature_name='user_2', + item_feature_name='item_2', + label_feature_name='label_2') + else: + save_feature_spec(user_cardinality=user_cardinality, item_cardinality=item_cardinality, dtypes=dtypes, + test_negative_samples=args.valid_negative, output_path=args.output + '/feature_spec.yaml') + + +if __name__ == '__main__': + main() diff --git a/PyTorch/Recommendation/NCF/data/csv_conversion/feature_spec.yaml b/PyTorch/Recommendation/NCF/data/csv_conversion/feature_spec.yaml new file mode 100644 index 00000000..ad801844 --- /dev/null +++ b/PyTorch/Recommendation/NCF/data/csv_conversion/feature_spec.yaml @@ -0,0 +1,43 @@ +feature_spec: + user: + cardinality: auto + item: + cardinality: auto + label: + +metadata: + test_samples_per_series: 3 + +source_spec: + train: + - type: csv + features: #Each line corresponds to a column in the csv files + - user + - item + - label + files: + - train_data_1.csv # we assume no header + - train_data_2.csv + test: + - type: csv + features: + - user + - item + - label + files: + - test_data_1.csv + +channel_spec: + user_ch: # Channel names are model-specific magics (in this model, neumf_constants.py) + - user + item_ch: + - item + label_ch: + - label + +# Requirements: + +# We assume the ids supplied have already been factorized into 0...N + +# In the mapping to be used for validation and testing, candidates for each series (each user) appear consecutively. +# Each series has the same number of items: metadata['test_samples_per_series'] \ No newline at end of file diff --git a/PyTorch/Recommendation/NCF/data/csv_conversion/test_data_1.csv b/PyTorch/Recommendation/NCF/data/csv_conversion/test_data_1.csv new file mode 100644 index 00000000..ae6219e7 --- /dev/null +++ b/PyTorch/Recommendation/NCF/data/csv_conversion/test_data_1.csv @@ -0,0 +1,30 @@ +0, 8, 0 +0, 18, 0 +0, 17, 1 +1, 7, 0 +1, 6, 0 +1, 16, 1 +2, 12, 0 +2, 13, 0 +2, 16, 1 +3, 3, 0 +3, 1, 0 +3, 5, 1 +4, 16, 0 +4, 3, 0 +4, 8, 1 +5, 14, 0 +5, 12, 0 +5, 12, 1 +6, 3, 0 +6, 3, 0 +6, 1, 1 +7, 3, 0 +7, 18, 0 +7, 8, 1 +8, 8, 0 +8, 8, 0 +8, 2, 1 +9, 19, 0 +9, 9, 0 +9, 18, 1 \ No newline at end of file diff --git a/PyTorch/Recommendation/NCF/data/csv_conversion/train_data_1.csv b/PyTorch/Recommendation/NCF/data/csv_conversion/train_data_1.csv new file mode 100644 index 00000000..2f65cc6f --- /dev/null +++ b/PyTorch/Recommendation/NCF/data/csv_conversion/train_data_1.csv @@ -0,0 +1,60 @@ +0, 14, 0 +0, 3, 0 +0, 18, 1 +0, 15, 1 +0, 2, 0 +0, 1, 1 +0, 5, 1 +0, 7, 0 +0, 12, 1 +0, 19, 0 +1, 9, 1 +1, 0, 0 +1, 16, 1 +1, 2, 0 +1, 8, 1 +1, 17, 0 +1, 17, 1 +1, 9, 0 +1, 5, 0 +1, 12, 1 +2, 8, 1 +2, 0, 1 +2, 1, 1 +2, 0, 0 +2, 4, 0 +2, 17, 1 +2, 18, 0 +2, 3, 0 +2, 10, 0 +2, 18, 1 +3, 14, 1 +3, 4, 0 +3, 0, 0 +3, 16, 1 +3, 6, 0 +3, 17, 1 +3, 0, 1 +3, 0, 0 +3, 3, 1 +3, 0, 1 +4, 13, 1 +4, 8, 1 +4, 1, 1 +4, 14, 0 +4, 18, 0 +4, 7, 1 +4, 19, 1 +4, 3, 1 +4, 17, 1 +4, 17, 0 +5, 8, 1 +5, 10, 0 +5, 4, 0 +5, 19, 0 +5, 12, 0 +5, 3, 1 +5, 5, 0 +5, 8, 1 +5, 19, 1 +5, 12, 0 \ No newline at end of file diff --git a/PyTorch/Recommendation/NCF/data/csv_conversion/train_data_2.csv b/PyTorch/Recommendation/NCF/data/csv_conversion/train_data_2.csv new file mode 100644 index 00000000..65655c68 --- /dev/null +++ b/PyTorch/Recommendation/NCF/data/csv_conversion/train_data_2.csv @@ -0,0 +1,40 @@ +6, 18, 0 +6, 19, 0 +6, 4, 0 +6, 16, 1 +6, 19, 0 +6, 2, 0 +6, 4, 0 +6, 2, 1 +6, 0, 0 +6, 12, 1 +7, 3, 0 +7, 7, 0 +7, 16, 0 +7, 4, 0 +7, 19, 0 +7, 11, 1 +7, 10, 1 +7, 13, 1 +7, 18, 0 +7, 4, 0 +8, 4, 0 +8, 5, 0 +8, 12, 0 +8, 2, 0 +8, 14, 0 +8, 19, 1 +8, 0, 0 +8, 17, 1 +8, 19, 1 +8, 15, 1 +9, 9, 1 +9, 17, 0 +9, 9, 1 +9, 14, 0 +9, 11, 0 +9, 17, 1 +9, 4, 0 +9, 1, 0 +9, 8, 0 +9, 10, 1 \ No newline at end of file diff --git a/PyTorch/Recommendation/NCF/data/like_movielens/ratings.csv b/PyTorch/Recommendation/NCF/data/like_movielens/ratings.csv new file mode 100644 index 00000000..e8d51e12 --- /dev/null +++ b/PyTorch/Recommendation/NCF/data/like_movielens/ratings.csv @@ -0,0 +1,50 @@ +0, 17, 38308 +0, 1, 38302 +0, 10, 53558 +0, 17, 53042 +0, 12, 43899 +1, 4, 85239 +1, 3, 44884 +1, 3, 37412 +1, 8, 58416 +1, 9, 39814 +2, 6, 53985 +2, 17, 63080 +2, 9, 85791 +2, 19, 37194 +2, 3, 76871 +3, 4, 32445 +3, 1, 97224 +3, 8, 76409 +3, 6, 81547 +3, 0, 52471 +4, 15, 96242 +4, 3, 72309 +4, 9, 54815 +4, 6, 94187 +4, 16, 97208 +5, 5, 56902 +5, 0, 23414 +5, 8, 55770 +5, 5, 27745 +5, 6, 61599 +6, 12, 21675 +6, 4, 53968 +6, 7, 66164 +6, 13, 94933 +6, 1, 92957 +7, 9, 30137 +7, 11, 85128 +7, 18, 30088 +7, 14, 32186 +7, 10, 84664 +8, 1, 39714 +8, 4, 27987 +8, 15, 70023 +8, 17, 93690 +8, 8, 93827 +9, 4, 80146 +9, 8, 20896 +9, 1, 55230 +9, 13, 29631 +9, 2, 46368 diff --git a/PyTorch/Recommendation/NCF/data/ml-20m/feature_spec_template.yaml b/PyTorch/Recommendation/NCF/data/ml-20m/feature_spec_template.yaml new file mode 100644 index 00000000..4cc0e820 --- /dev/null +++ b/PyTorch/Recommendation/NCF/data/ml-20m/feature_spec_template.yaml @@ -0,0 +1,52 @@ +feature_spec: + user: + dtype: torch.int64 + cardinality: 138493 + item: + dtype: torch.int64 + cardinality: 26744 + label: + dtype: torch.float32 + +metadata: + test_samples_per_series: 101 + +source_spec: + train: + - type: torch_tensor + features: + # For torch_tensor, each line corresponds to a column. They are ordered + - user + - item + files: + # Loader currently only supports one file per chunk + - train_data_0.pt # Paths are relative to data-spec's directory + - type: torch_tensor + features: + - label + files: + - train_data_1.pt + test: + - type: torch_tensor + features: + - user + - item + files: + - test_data_0.pt + - type: torch_tensor + features: + - label + files: + - test_data_1.pt + +channel_spec: + user_ch: # Channel names are model-specific magics (in this model, neumf_constants.py) + - user + item_ch: + - item + label_ch: + - label + +# Requirements: + +# During validation, for each user we have the same number of samples, supplied consecutively \ No newline at end of file diff --git a/PyTorch/Recommendation/NCF/dataloading.py b/PyTorch/Recommendation/NCF/dataloading.py index 85905a01..c3ca5716 100644 --- a/PyTorch/Recommendation/NCF/dataloading.py +++ b/PyTorch/Recommendation/NCF/dataloading.py @@ -14,7 +14,7 @@ # # ----------------------------------------------------------------------- # -# Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved. +# Copyright (c) 2021, 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. @@ -28,95 +28,227 @@ # See the License for the specific language governing permissions and # limitations under the License. -import time import torch +import os +from feature_spec import FeatureSpec +from neumf_constants import USER_CHANNEL_NAME, ITEM_CHANNEL_NAME, LABEL_CHANNEL_NAME, TEST_SAMPLES_PER_SERIES -def create_test_data(test_ratings, test_negs, args): - test_users = test_ratings[:,0] - test_pos = test_ratings[:,1].reshape(-1,1) +class TorchTensorDataset: + """ Warning! This dataset/loader uses torch.load. Torch.load implicitly uses pickle. Pickle is insecure. + It is trivial to achieve arbitrary code execution using a prepared pickle payload. Only unpickle data you trust.""" - # create items with real sample at last position - num_valid_negative = test_negs.shape[1] - test_users = test_users.reshape(-1,1).repeat(1, 1 + num_valid_negative) - test_items = torch.cat((test_negs, test_pos), dim=1) - del test_ratings, test_negs + def __init__(self, feature_spec: FeatureSpec, mapping_name: str, args): + self.local_rank = args.local_rank + self.mapping_name = mapping_name + self.features = dict() + self.feature_spec = feature_spec + self._load_features() - # generate dup mask and real indices for exact same behavior on duplication compare to reference - # here we need a sort that is stable(keep order of duplicates) - sorted_items, indices = torch.sort(test_items) # [1,1,1,2], [3,1,0,2] - sum_item_indices = sorted_items.float()+indices.float()/len(indices[0]) #[1.75,1.25,1.0,2.5] - indices_order = torch.sort(sum_item_indices)[1] #[2,1,0,3] - stable_indices = torch.gather(indices, 1, indices_order) #[0,1,3,2] - # produce -1 mask - dup_mask = (sorted_items[:,0:-1] == sorted_items[:,1:]) - dup_mask = dup_mask.type(torch.uint8) - dup_mask = torch.cat((torch.zeros_like(test_pos, dtype=torch.uint8), dup_mask), dim=1) - dup_mask = torch.gather(dup_mask, 1, stable_indices.sort()[1]) - # produce real sample indices to later check in topk - sorted_items, indices = (test_items != test_pos).type(torch.uint8).sort() - sum_item_indices = sorted_items.float()+indices.float()/len(indices[0]) - indices_order = torch.sort(sum_item_indices)[1] - stable_indices = torch.gather(indices, 1, indices_order) - real_indices = stable_indices[:,0] - - if args.distributed: - test_users = torch.chunk(test_users, args.world_size)[args.local_rank] - test_items = torch.chunk(test_items, args.world_size)[args.local_rank] - dup_mask = torch.chunk(dup_mask, args.world_size)[args.local_rank] - real_indices = torch.chunk(real_indices, args.world_size)[args.local_rank] - - test_users = test_users.view(-1).split(args.valid_batch_size) - test_items = test_items.view(-1).split(args.valid_batch_size) - - return test_users, test_items, dup_mask, real_indices + def _load_features(self): + chunks = self.feature_spec.source_spec[self.mapping_name] + for chunk in chunks: + assert chunk['type'] == 'torch_tensor', "Only torch_tensor files supported in this loader" + files_list = chunk['files'] + assert len(files_list) == 1, "Only one file per chunk supported in this loader" + file_relative_path = files_list[0] + path_to_load = os.path.join(self.feature_spec.base_directory, file_relative_path) + chunk_data = torch.load(path_to_load, map_location=torch.device('cuda:{}'.format(self.local_rank))) + running_pos = 0 + for feature_name in chunk['features']: + next_running_pos = running_pos + 1 + feature_data = chunk_data[:, running_pos:next_running_pos] + # This is needed because slicing instead of indexing keeps the data 2-dimensional + feature_data = feature_data.reshape(-1, 1) + running_pos = next_running_pos + self.features[feature_name] = feature_data -def prepare_epoch_train_data(train_ratings, nb_items, args): - # create label - train_label = torch.ones_like(train_ratings[:,0], dtype=torch.float32) - neg_label = torch.zeros_like(train_label, dtype=torch.float32) - neg_label = neg_label.repeat(args.negative_samples) - train_label = torch.cat((train_label,neg_label)) - del neg_label +class TestDataLoader: + def __init__(self, dataset: TorchTensorDataset, args): + self.dataset = dataset + self.feature_spec = dataset.feature_spec + self.channel_spec = self.feature_spec.channel_spec + self.samples_in_series = self.feature_spec.metadata[TEST_SAMPLES_PER_SERIES] + self.raw_dataset_length = None # First feature loaded sets this. Total length before splitting across cards + self.data = dict() + self.world_size = args.world_size + self.local_rank = args.local_rank + self.batch_size = args.valid_batch_size - train_users = train_ratings[:,0] - train_items = train_ratings[:,1] + self._build_channel_dict() + self._deduplication_augmentation() + self._split_between_devices() + self._split_into_batches() - train_users_per_worker = len(train_label) / args.world_size - train_users_begin = int(train_users_per_worker * args.local_rank) - train_users_end = int(train_users_per_worker * (args.local_rank + 1)) + def _build_channel_dict(self): + for channel_name, channel_features in self.channel_spec.items(): + channel_tensors = dict() + for feature_name in channel_features: + channel_tensors[feature_name] = self.dataset.features[feature_name] - # prepare data for epoch - neg_users = train_users.repeat(args.negative_samples) - neg_items = torch.empty_like(neg_users, dtype=torch.int64).random_(0, nb_items) + if not self.raw_dataset_length: + self.raw_dataset_length = channel_tensors[feature_name].shape[0] + else: + assert self.raw_dataset_length == channel_tensors[feature_name].shape[0] - epoch_users = torch.cat((train_users, neg_users)) - epoch_items = torch.cat((train_items, neg_items)) + self.data[channel_name] = channel_tensors - del neg_users, neg_items + def _deduplication_augmentation(self): + # Augmentation + # This adds a duplication mask tensor. + # This is here to exactly replicate the MLPerf training regime. Moving this deduplication to the candidate item + # generation stage increases the real diversity of the candidates, which makes the ranking task harder + # and results in a drop in HR@10 of approx 0.01. This has been deemed unacceptable (May 2021). - # shuffle prepared data and split into batches - epoch_indices = torch.randperm(train_users_end - train_users_begin, device='cuda:{}'.format(args.local_rank)) - epoch_indices += train_users_begin + # We need the duplication mask to determine if a given item should be skipped during ranking + # If an item with label 1 is duplicated in the sampled ones, we need to be careful to not mark the one with + # label 1 as a duplicate. If an item appears repeatedly only with label 1, no duplicates are marked. - epoch_users = epoch_users[epoch_indices] - epoch_items = epoch_items[epoch_indices] - epoch_label = train_label[epoch_indices] + # To easily compute candidates, we sort the items. This will impact the distribution of examples between + # devices, but should not influence the numerics or performance meaningfully. + # We need to assure that the positive item, which we don't want to mark as a duplicate, appears first. + # We do this by adding labels as a secondary factor - if args.distributed: - local_batch = args.batch_size // args.world_size - else: - local_batch = args.batch_size + # Reshape the tensors to have items for a given user in a single row + user_feature_name = self.channel_spec[USER_CHANNEL_NAME][0] + item_feature_name = self.channel_spec[ITEM_CHANNEL_NAME][0] + label_feature_name = self.channel_spec[LABEL_CHANNEL_NAME][0] + self.ignore_mask_channel_name = 'mask_ch' + self.ignore_mask_feature_name = 'mask' - epoch_users = epoch_users.split(local_batch) - epoch_items = epoch_items.split(local_batch) - epoch_label = epoch_label.split(local_batch) + items = self.data[ITEM_CHANNEL_NAME][item_feature_name].view(-1, self.samples_in_series) + users = self.data[USER_CHANNEL_NAME][user_feature_name].view(-1, self.samples_in_series) + labels = self.data[LABEL_CHANNEL_NAME][label_feature_name].view(-1, self.samples_in_series) - # the last batch will almost certainly be smaller, drop it - epoch_users = epoch_users[:-1] - epoch_items = epoch_items[:-1] - epoch_label = epoch_label[:-1] + sorting_weights = items.float() - labels.float() * 0.5 + _, indices = torch.sort(sorting_weights) + # The gather reorders according to the indices decided by the sort above + sorted_items = torch.gather(items, 1, indices) + sorted_labels = torch.gather(labels, 1, indices) + sorted_users = torch.gather(users, 1, indices) - return epoch_users, epoch_items, epoch_label + dup_mask = sorted_items[:, 0:-1] == sorted_items[:, 1:] # This says if a given item is equal to the next one + dup_mask = dup_mask.type(torch.bool) + # The first item for a given user can never be a duplicate: + dup_mask = torch.cat((torch.zeros_like(dup_mask[:, 0:1]), dup_mask), dim=1) + # Reshape them back + self.data[ITEM_CHANNEL_NAME][item_feature_name] = sorted_items.view(-1, 1) + self.data[USER_CHANNEL_NAME][user_feature_name] = sorted_users.view(-1, 1) + self.data[LABEL_CHANNEL_NAME][label_feature_name] = sorted_labels.view(-1, 1) + self.data[self.ignore_mask_channel_name] = dict() + self.data[self.ignore_mask_channel_name][self.ignore_mask_feature_name] = dup_mask.view(-1, 1) + + def _split_between_devices(self): + if self.world_size > 1: + # DO NOT REPLACE WITH torch.chunk (number of returned chunks can silently be lower than requested). + # It would break compatibility with small datasets. + num_test_cases = self.raw_dataset_length / self.samples_in_series + smaller_batch = (int(num_test_cases // self.world_size)) * self.samples_in_series + bigger_batch = smaller_batch + self.samples_in_series + remainder = int(num_test_cases % self.world_size) + samples_per_card = [bigger_batch] * remainder + [smaller_batch] * (self.world_size - remainder) + for channel_name, channel_dict in self.data.items(): + for feature_name, feature_tensor in channel_dict.items(): + channel_dict[feature_name] = \ + channel_dict[feature_name].split(samples_per_card)[self.local_rank] + + def _split_into_batches(self): + self.batches = None + # This is the structure of each batch, waiting to be copied and filled in with data + for channel_name, channel_dict in self.data.items(): + for feature_name, feature_tensor in channel_dict.items(): + feature_batches = feature_tensor.view(-1).split(self.batch_size) + if not self.batches: + self.batches = list( + {channel_name: dict() for channel_name in self.data.keys()} for _ in feature_batches) + for pos, feature_batch_data in enumerate(feature_batches): + self.batches[pos][channel_name][feature_name] = feature_batch_data + + def get_epoch_data(self): + return self.batches + + def get_ignore_mask(self): + return self.data[self.ignore_mask_channel_name][self.ignore_mask_feature_name] + + +class TrainDataloader: + def __init__(self, dataset: TorchTensorDataset, args): + self.dataset = dataset + self.local_rank = args.local_rank + if args.distributed: + self.local_batch = args.batch_size // args.world_size + else: + self.local_batch = args.batch_size + + self.feature_spec = dataset.feature_spec + self.channel_spec = self.feature_spec.channel_spec + self.negative_samples = args.negative_samples + + self.data = dict() + self.raw_dataset_length = None # first feature loaded sets this + self._build_channel_dict() + self.length_after_augmentation = self.raw_dataset_length * (self.negative_samples + 1) + samples_per_worker = self.length_after_augmentation / args.world_size + self.samples_begin = int(samples_per_worker * args.local_rank) + self.samples_end = int(samples_per_worker * (args.local_rank + 1)) + + def _build_channel_dict(self): + for channel_name, channel_features in self.channel_spec.items(): + channel_tensors = dict() + for feature_name in channel_features: + channel_tensors[feature_name] = self.dataset.features[feature_name] + if not self.raw_dataset_length: + self.raw_dataset_length = channel_tensors[feature_name].shape[0] + else: + assert self.raw_dataset_length == channel_tensors[feature_name].shape[0] + self.data[channel_name] = channel_tensors + + def get_epoch_data(self): + + # Augment, appending args.negative_samples times the original set, now with random items end negative labels + augmented_data = {channel_name: dict() for channel_name in self.data.keys()} + user_feature_name = self.channel_spec[USER_CHANNEL_NAME][0] + item_feature_name = self.channel_spec[ITEM_CHANNEL_NAME][0] + label_feature_name = self.channel_spec[LABEL_CHANNEL_NAME][0] + + # USER + user_tensor = self.data[USER_CHANNEL_NAME][user_feature_name] + neg_users = user_tensor.repeat(self.negative_samples, 1) + augmented_users = torch.cat((user_tensor, neg_users)) + augmented_data[USER_CHANNEL_NAME][user_feature_name] = augmented_users + del neg_users + + # ITEM + item_tensor = self.data[ITEM_CHANNEL_NAME][item_feature_name] + neg_items = torch.empty_like(item_tensor).repeat(self.negative_samples, 1) \ + .random_(0, self.feature_spec.feature_spec[item_feature_name]['cardinality']) + augmented_items = torch.cat((item_tensor, neg_items)) + augmented_data[ITEM_CHANNEL_NAME][item_feature_name] = augmented_items + del neg_items + + # LABEL + label_tensor = self.data[LABEL_CHANNEL_NAME][label_feature_name] + neg_label = torch.zeros_like(label_tensor, dtype=torch.float32).repeat(self.negative_samples, 1) + augmented_labels = torch.cat((label_tensor, neg_label)) + del neg_label + augmented_data[LABEL_CHANNEL_NAME][label_feature_name] = augmented_labels + + # Labels are not shuffled between cards. + # This replicates previous behaviour. + epoch_indices = torch.randperm(self.samples_end - self.samples_begin, device='cuda:{}'.format(self.local_rank)) + epoch_indices += self.samples_begin + + batches = None + for channel_name, channel_dict in augmented_data.items(): + for feature_name, feature_tensor in channel_dict.items(): + # the last batch will almost certainly be smaller, drop it + # Warning: may not work if there's only one + feature_batches = feature_tensor.view(-1)[epoch_indices].split(self.local_batch)[:-1] + if not batches: + batches = list({channel_name: dict() for channel_name in self.data.keys()} for _ in feature_batches) + for pos, feature_batch_data in enumerate(feature_batches): + batches[pos][channel_name][feature_name] = feature_batch_data + + return batches diff --git a/PyTorch/Recommendation/NCF/feature_spec.py b/PyTorch/Recommendation/NCF/feature_spec.py new file mode 100644 index 00000000..40d56a0e --- /dev/null +++ b/PyTorch/Recommendation/NCF/feature_spec.py @@ -0,0 +1,50 @@ +# Copyright (c) 2021, 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. + +import yaml +import os +from typing import List, Dict + + +class FeatureSpec: + def __init__(self, feature_spec, source_spec, channel_spec, metadata, base_directory): + self.feature_spec: Dict = feature_spec + self.source_spec: Dict = source_spec + self.channel_spec: Dict = channel_spec + self.metadata: Dict = metadata + self.base_directory: str = base_directory + + @classmethod + def from_yaml(cls, path): + with open(path, 'r') as feature_spec_file: + base_directory = os.path.dirname(path) + feature_spec = yaml.safe_load(feature_spec_file) + return cls.from_dict(feature_spec, base_directory=base_directory) + + @classmethod + def from_dict(cls, source_dict, base_directory): + return cls(base_directory=base_directory, **source_dict) + + def to_dict(self) -> Dict: + attributes_to_dump = ['feature_spec', 'source_spec', 'channel_spec', 'metadata'] + return {attr: self.__dict__[attr] for attr in attributes_to_dump} + + def to_string(self): + return yaml.dump(self.to_dict()) + + def to_yaml(self, output_path=None): + if not output_path: + output_path = self.base_directory + '/feature_spec.yaml' + with open(output_path, 'w') as output_file: + print(yaml.dump(self.to_dict()), file=output_file) diff --git a/PyTorch/Recommendation/NCF/fp_optimizers.py b/PyTorch/Recommendation/NCF/fp_optimizers.py deleted file mode 100644 index d53d3874..00000000 --- a/PyTorch/Recommendation/NCF/fp_optimizers.py +++ /dev/null @@ -1,45 +0,0 @@ -# Copyright (c) 2018, 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. - -import torch - -class Fp16Optimizer: - - def __init__(self, fp16_model, loss_scale=8192.0): - print('Initializing fp16 optimizer') - self.initialize_model(fp16_model) - self.loss_scale = loss_scale - - def initialize_model(self, model): - print('Reset fp16 grad') - self.fp16_model = model - for param in self.fp16_model.parameters(): - param.grad = None - - print('Initializing fp32 clone weights') - self.fp32_params = [param.clone().type(torch.cuda.FloatTensor).detach() - for param in model.parameters()] - for param in self.fp32_params: - param.requires_grad = True - - def backward(self, loss): - loss *= self.loss_scale - loss.backward() - - def step(self, optimizer): - optimizer.step(grads=[p.grad for p in self.fp16_model.parameters()], - output_params=self.fp16_model.parameters(), scale=self.loss_scale) - - for p in self.fp16_model.parameters(): - p.grad = None diff --git a/PyTorch/Recommendation/NCF/full_test_suite.md b/PyTorch/Recommendation/NCF/full_test_suite.md new file mode 100644 index 00000000..82b10efb --- /dev/null +++ b/PyTorch/Recommendation/NCF/full_test_suite.md @@ -0,0 +1,25 @@ +rm -r /data/cache/ml-20m + +## Prepare the standard dataset: + +./prepare_dataset.sh + +## Prepare the modified dataset: + +./test_dataset.sh + +## Run on the modified dataset: + +./test_cases.sh + +## Check featurespec: + +python test_featurespec_correctness.py /data/cache/ml-20m/feature_spec.yaml /data/ml-20m/feature_spec_template.yaml + +## Other dataset: + +rm -r /data/cache/ml-1m + +./prepare_dataset.sh ml-1m + +python -m torch.distributed.launch --nproc_per_node=1 --use_env ncf.py --data /data/cache/ml-1m --epochs 1 \ No newline at end of file diff --git a/PyTorch/Recommendation/NCF/img/box_plots.png b/PyTorch/Recommendation/NCF/img/box_plots.png new file mode 100644 index 0000000000000000000000000000000000000000..15f01b1c3a163ae6ab642982817570af6b42180a GIT binary patch literal 38939 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 literal 0 HcmV?d00001 diff --git a/PyTorch/Recommendation/NCF/img/df_diagram.png b/PyTorch/Recommendation/NCF/img/df_diagram.png new file mode 100644 index 0000000000000000000000000000000000000000..c6bc16fca900f9887b51626c7016c24d63201e60 GIT binary patch literal 100651 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‹X~GyP4{`QLREYnusjE86eyZQFW&fW& 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 A>Hq)$ literal 0 HcmV?d00001 diff --git a/PyTorch/Recommendation/NCF/img/dgx1v16_curve.png b/PyTorch/Recommendation/NCF/img/dgx1v16_curve.png deleted file mode 100644 index 340caea075d31ccb3af4d1f616aba27456093d25..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 42646 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 VaYMSv(%F3xKDfPD{*J@vegR`^=eYm? diff --git a/PyTorch/Recommendation/NCF/img/hr_histogram.png b/PyTorch/Recommendation/NCF/img/hr_histogram.png deleted file mode 100644 index 34405878709128ca1b1cb0ac1241f934206c6054..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 30062 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 diff --git a/PyTorch/Recommendation/NCF/img/layout_example.png b/PyTorch/Recommendation/NCF/img/layout_example.png new file mode 100644 index 0000000000000000000000000000000000000000..17104c63de6b62020b2292fe39cff45b8e826911 GIT binary patch literal 46938 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. + # It is theoretically possible for the hit rate to be zero in the first epoch, which would result in referring + # to an uninitialized variable. max_hr = 0 best_epoch = 0 + best_model_timestamp = time.time() train_throughputs, eval_throughputs = [], [] for epoch in range(args.epochs): begin = time.time() - - epoch_users, epoch_items, epoch_label = dataloading.prepare_epoch_train_data(train_ratings, nb_items, args) - num_batches = len(epoch_users) + batch_dict_list = train_loader.get_epoch_data() + num_batches = len(batch_dict_list) for i in range(num_batches // args.grads_accumulated): for j in range(args.grads_accumulated): batch_idx = (args.grads_accumulated * i) + j - user = epoch_users[batch_idx] - item = epoch_items[batch_idx] - label = epoch_label[batch_idx].view(-1,1) + batch_dict = batch_dict_list[batch_idx] - outputs = model(user, item) - loss = traced_criterion(outputs, label).float() + user_features = batch_dict[USER_CHANNEL_NAME] + item_features = batch_dict[ITEM_CHANNEL_NAME] + + user_batch = user_features[user_feature_name] + item_batch = item_features[item_feature_name] + + label_features = batch_dict[LABEL_CHANNEL_NAME] + label_batch = label_features[label_feature_name] + + outputs = model(user_batch, item_batch) + loss = traced_criterion(outputs, label_batch.view(-1, 1)).float() loss = torch.mean(loss.view(-1), 0) if args.amp: @@ -270,31 +299,27 @@ def main(): for p in model.parameters(): p.grad = None - del epoch_users, epoch_items, epoch_label + del batch_dict_list train_time = time.time() - begin begin = time.time() - epoch_samples = len(train_ratings) * (args.negative_samples + 1) + epoch_samples = train_loader.length_after_augmentation train_throughput = epoch_samples / train_time train_throughputs.append(train_throughput) - hr, ndcg = val_epoch(model, test_users, test_items, dup_mask, real_indices, args.topk, - samples_per_user=valid_negative + 1, - num_user=all_test_users, epoch=epoch, distributed=args.distributed) + hr, ndcg = val_epoch(model, test_loader, args.topk, distributed=args.distributed) val_time = time.time() - begin - - - eval_size = all_test_users * (valid_negative + 1) + eval_size = test_loader.raw_dataset_length eval_throughput = eval_size / val_time eval_throughputs.append(eval_throughput) dllogger.log(step=(epoch,), - data = {'train_throughput': train_throughput, - 'hr@10': hr, - 'train_epoch_time': train_time, - 'validation_epoch_time': val_time, - 'eval_throughput': eval_throughput}) + data={'train_throughput': train_throughput, + 'hr@10': hr, + 'train_epoch_time': train_time, + 'validation_epoch_time': val_time, + 'eval_throughput': eval_throughput}) if hr > max_hr and args.local_rank == 0: max_hr = hr diff --git a/PyTorch/Recommendation/NCF/neumf.py b/PyTorch/Recommendation/NCF/neumf.py index 674b77ff..f935feae 100644 --- a/PyTorch/Recommendation/NCF/neumf.py +++ b/PyTorch/Recommendation/NCF/neumf.py @@ -35,6 +35,7 @@ import torch.nn as nn import sys from os.path import abspath, join, dirname + class NeuMF(nn.Module): def __init__(self, nb_users, nb_items, mf_dim, mlp_layer_sizes, dropout=0): diff --git a/PyTorch/Recommendation/NCF/neumf_constants.py b/PyTorch/Recommendation/NCF/neumf_constants.py new file mode 100644 index 00000000..6c6e4c82 --- /dev/null +++ b/PyTorch/Recommendation/NCF/neumf_constants.py @@ -0,0 +1,18 @@ +# Copyright (c) 2021, 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. + +USER_CHANNEL_NAME = 'user_ch' +ITEM_CHANNEL_NAME = 'item_ch' +LABEL_CHANNEL_NAME = 'label_ch' +TEST_SAMPLES_PER_SERIES = 'test_samples_per_series' diff --git a/PyTorch/Recommendation/NCF/prepare_dataset.sh b/PyTorch/Recommendation/NCF/prepare_dataset.sh index 7ce57e25..bf04415d 100755 --- a/PyTorch/Recommendation/NCF/prepare_dataset.sh +++ b/PyTorch/Recommendation/NCF/prepare_dataset.sh @@ -14,7 +14,7 @@ # # ----------------------------------------------------------------------- # -# Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved. +# Copyright (c) 2021, 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. @@ -34,22 +34,26 @@ set -e set -x DATASET_NAME=${1:-'ml-20m'} -RAW_DATADIR=${2:-'/data'} -CACHED_DATADIR=${3:-"${RAW_DATADIR}/cache/${DATASET_NAME}"} +RAW_DATADIR=${2:-"/data/${DATASET_NAME}"} +CACHED_DATADIR=${3:-"/data/cache/${DATASET_NAME}"} # you can add another option to this case in order to support other datasets case ${DATASET_NAME} in 'ml-20m') ZIP_PATH=${RAW_DATADIR}/'ml-20m.zip' + SHOULD_UNZIP=1 RATINGS_PATH=${RAW_DATADIR}'/ml-20m/ratings.csv' ;; 'ml-1m') ZIP_PATH=${RAW_DATADIR}/'ml-1m.zip' + SHOULD_UNZIP=1 RATINGS_PATH=${RAW_DATADIR}'/ml-1m/ratings.dat' ;; - *) - echo "Unsupported dataset name: $DATASET_NAME" - exit 1 + *) + echo "Using unknown dataset: $DATASET_NAME." + RATINGS_PATH=${RAW_DATADIR}'/ratings.csv' + echo "Expecting file at ${RATINGS_PATH}" + SHOULD_UNZIP=0 esac if [ ! -d ${RAW_DATADIR} ]; then @@ -64,16 +68,21 @@ if [ -f log ]; then rm -f log fi -if [ ! -f ${ZIP_PATH} ]; then - echo "Dataset not found. Please download it from: https://grouplens.org/datasets/movielens/20m/ and put it in ${ZIP_PATH}" - exit 1 -fi - if [ ! -f ${RATINGS_PATH} ]; then - unzip -u ${ZIP_PATH} -d ${RAW_DATADIR} + if [ $SHOULD_UNZIP == 1 ]; then + if [ ! -f ${ZIP_PATH} ]; then + echo "Dataset not found. Please download it from: https://grouplens.org/datasets/movielens/20m/ and put it in ${ZIP_PATH}" + exit 1 + fi + unzip -u ${ZIP_PATH} -d ${RAW_DATADIR} + else + echo "File not found at ${RATINGS_PATH}. Aborting." + exit 1 + fi fi -if [ ! -f ${CACHED_DATADIR}/train_ratings.pt ]; then + +if [ ! -f ${CACHED_DATADIR}/feature_spec.yaml ]; then echo "preprocessing ${RATINGS_PATH} and save to disk" t0=$(date +%s) python convert.py --path ${RATINGS_PATH} --output ${CACHED_DATADIR} @@ -84,7 +93,7 @@ else echo 'Using cached preprocessed data' fi -echo "Dataset $DATASET_NAME successfully prepared at: $CACHED_DATADIR\n" +echo "Dataset $DATASET_NAME successfully prepared at: $CACHED_DATADIR" echo "You can now run the training with: python -m torch.distributed.launch --nproc_per_node= --use_env ncf.py --data ${CACHED_DATADIR}" diff --git a/PyTorch/Recommendation/NCF/qa/generate_boxplots.py b/PyTorch/Recommendation/NCF/qa/generate_boxplots.py new file mode 100644 index 00000000..51e60e9d --- /dev/null +++ b/PyTorch/Recommendation/NCF/qa/generate_boxplots.py @@ -0,0 +1,70 @@ +# Copyright (c) 2021, 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. + +import json +import matplotlib.pyplot as plt + + +def get_training_data(filename): + with open(filename, 'r') as opened: + line = opened.readlines()[-1] + json_content = line[len("DLLL "):] + data = json.loads(json_content)["data"] + with open(filename, 'r') as opened: + for line in opened.readlines(): + d = json.loads(line[len("DLLL "):]) + if d.get("step", "") == "PARAMETER": + data['batch_size'] = d["data"]["batch_size"] + return data + + +a100 = "runs/pytorch_ncf_A100-SXM4-40GBx{numgpus}gpus_{precision}_{num_run}.json" +v16 = "runs/pytorch_ncf_Tesla V100-SXM2-16GBx{numgpus}gpus_{precision}_{num_run}.json" +v32 = "runs/pytorch_ncf_Tesla V100-SXM2-32GBx{numgpus}gpus_{precision}_{num_run}.json" +dgx2 = "runs/pytorch_ncf_Tesla V100-SXM3-32GBx{numgpus}gpus_{precision}_{num_run}.json" + +fp32 = "FP32" +amp = "Mixed (AMP)" +tf32 = "TF32" + + +def get_accs(arch, numgpu, prec): + data = [get_training_data(arch.format(numgpus=numgpu, num_run=num_run, precision=prec)) for num_run in range(1, 21)] + accs = [d["best_accuracy"] for d in data] + return accs + + +def get_plots(): + archs = [dgx2, a100] + gpuranges = [(1, 8, 16), (1, 8)] + titles = ["DGX2 32GB", "DGX A100 40GB"] + fullprecs = [fp32, tf32] + fig, axs = plt.subplots(2, 3, sharey=True, figsize=(8, 8)) + plt.subplots_adjust(hspace=0.5) + for x, arch in enumerate(archs): + gpurange = gpuranges[x] + for y, gpu in enumerate(gpurange): + f_data = get_accs(arch, gpu, fullprecs[x]) + h_data = get_accs(arch, gpu, amp) + axs[x, y].boxplot([f_data, h_data]) + axs[x, y].set_xticklabels([fullprecs[x], amp]) + axs[x, y].set_title(f"{gpu} GPUs" if gpu > 1 else "1 GPU") + axs[x, 0].set_ylabel(titles[x]) + fig.delaxes(axs[1, 2]) + # plt.show() + plt.savefig("box_plots.png") + + +if __name__ == "__main__": + get_plots() diff --git a/PyTorch/Recommendation/NCF/qa/generate_tables.py b/PyTorch/Recommendation/NCF/qa/generate_tables.py new file mode 100644 index 00000000..30ac66b2 --- /dev/null +++ b/PyTorch/Recommendation/NCF/qa/generate_tables.py @@ -0,0 +1,113 @@ +# Copyright (c) 2021, 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. + +import json +import tabulate +import numpy as np + + +def get_training_data(filename): + with open(filename, 'r') as opened: + line = opened.readlines()[-1] + json_content = line[len("DLLL "):] + data = json.loads(json_content)["data"] + with open(filename, 'r') as opened: + for line in opened.readlines(): + d = json.loads(line[len("DLLL "):]) + if d.get("step", "") == "PARAMETER": + data['batch_size'] = d["data"]["batch_size"] + return data + + +a100 = "runs/pytorch_ncf_A100-SXM4-40GBx{numgpus}gpus_{precision}_{num_run}.json" +v16 = "runs/pytorch_ncf_Tesla V100-SXM2-16GBx{numgpus}gpus_{precision}_{num_run}.json" +v32 = "runs/pytorch_ncf_Tesla V100-SXM2-32GBx{numgpus}gpus_{precision}_{num_run}.json" +dgx2 = "runs/pytorch_ncf_Tesla V100-SXM3-32GBx{numgpus}gpus_{precision}_{num_run}.json" + +fp32 = "FP32" +amp = "Mixed (AMP)" +tf32 = "TF32" + +first = a100.format(numgpus=1, precision=fp32, num_run=1) + +timevar = 'time_to_target' #"time_to_best_model" + + +def get_acc_table(arch, numgpus, fullprec): + headers = ["GPUs", "Batch size / GPU", f"Accuracy - {fullprec}", "Accuracy - mixed precision", f"Time to train - {fullprec}", "Time to train - mixed precision", f"Time to train speedup ({fullprec} to mixed precision)"] + table = [] + for numgpus in numgpus: + data_full = [get_training_data(arch.format(numgpus=numgpus, num_run=num_run, precision=fullprec)) for num_run in range(1, 21)] + data_mixed = [get_training_data(arch.format(numgpus=numgpus, num_run=num_run, precision=amp)) for num_run in range(1, 21)] + bsize = data_full[0]['batch_size']/numgpus + accs_full = np.mean([d["best_accuracy"] for d in data_full]) + accs_mixed = np.mean([d["best_accuracy"] for d in data_mixed]) + time_full = np.mean([d[timevar] for d in data_full]) + time_mixed = np.mean([d[timevar] for d in data_mixed]) + speedup = time_full / time_mixed + row = [numgpus, int(bsize), + "{:.6f}".format(accs_full), + "{:.6f}".format(accs_mixed), + "{:.6f}".format(time_full), + "{:.6f}".format(time_mixed), + "{:.2f}".format(speedup)] + table.append(row) + print(tabulate.tabulate(table, headers, tablefmt='pipe')) + + +def get_perf_table(arch, numgpus, fullprec): + headers = ["GPUs", + "Batch size / GPU", + f"Throughput - {fullprec} (samples/s)", + "Throughput - mixed precision (samples/s)", + f"Throughput speedup ({fullprec} to mixed precision)", + f"Strong scaling - {fullprec}", + "Strong scaling - mixed precision", + ] + table = [] + base_full = None + base_mixed = None + for numgpus in numgpus: + data_full = [get_training_data(arch.format(numgpus=numgpus, num_run=num_run, precision=fullprec)) for num_run in range(1, 21)] + data_mixed = [get_training_data(arch.format(numgpus=numgpus, num_run=num_run, precision=amp)) for num_run in range(1, 21)] + bsize = data_full[0]['batch_size']/numgpus + _full = np.mean([d["best_train_throughput"] for d in data_full]) + _mixed = np.mean([d["best_train_throughput"] for d in data_mixed]) + if numgpus == 1: + base_full = _full + base_mixed = _mixed + scaling_full = _full/ base_full + scaling_mixed = _mixed / base_mixed + time_mixed = np.mean([d[timevar] for d in data_mixed]) + speedup = _full / _mixed + row = [numgpus, int(bsize), + "{:.2f}M".format(_full / 10**6), + "{:.2f}M".format(_mixed / 10**6), + "{:.2f}".format(speedup), + "{:.2f}".format(scaling_full), + "{:.2f}".format(scaling_mixed)] + + table.append(row) + print(tabulate.tabulate(table, headers, tablefmt='pipe')) + + +#get_acc_table(a100, (1, 8), tf32) +#get_acc_table(v16, (1, 8), fp32) +#get_acc_table(v32, (1, 8), fp32) +#get_acc_table(dgx2, (1, 8, 16), fp32) + +#get_perf_table(a100, (1, 8), tf32) +#get_perf_table(v16, (1, 8), fp32) +#get_perf_table(v32, (1, 8), fp32) +#get_perf_table(dgx2, (1, 8, 16), fp32) \ No newline at end of file diff --git a/PyTorch/Recommendation/NCF/qa/generate_validation_curves.py b/PyTorch/Recommendation/NCF/qa/generate_validation_curves.py new file mode 100644 index 00000000..1547b4df --- /dev/null +++ b/PyTorch/Recommendation/NCF/qa/generate_validation_curves.py @@ -0,0 +1,66 @@ +# Copyright (c) 2021, 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. + +import json +import matplotlib.pyplot as plt + + +def get_curve(filename): + hrs = [] + with open(filename, 'r') as opened: + for line in opened.readlines(): + d = json.loads(line[len("DLLL "):]) + try: + hrs.append(d["data"]["hr@10"]) + except KeyError: + pass + return hrs + + +a100 = "runs/pytorch_ncf_A100-SXM4-40GBx{numgpus}gpus_{precision}_{num_run}.json" +v16 = "runs/pytorch_ncf_Tesla V100-SXM2-16GBx{numgpus}gpus_{precision}_{num_run}.json" +v32 = "runs/pytorch_ncf_Tesla V100-SXM2-32GBx{numgpus}gpus_{precision}_{num_run}.json" +dgx2 = "runs/pytorch_ncf_Tesla V100-SXM3-32GBx{numgpus}gpus_{precision}_{num_run}.json" + +fp32 = "FP32" +amp = "Mixed (AMP)" +tf32 = "TF32" + + +def get_accs(arch, numgpu, prec): + data = [get_curve(arch.format(numgpus=numgpu, num_run=num_run, precision=prec)) for num_run in range(1, 21)] + return data[0] + + +def get_plots(): + archs = [dgx2, a100] + titles = ["DGX2 32GB", "DGX A100 40GB"] + fullprecs = [fp32, tf32] + halfprecs = [amp, amp] + gpuranges = [(1, 8, 16), (1, 8)] + fig, axs = plt.subplots(1, 2, sharey=True, figsize=(10, 5)) + plt.subplots_adjust(hspace=0.5) + for x, prec in enumerate([fullprecs, halfprecs]): + for i, arch in enumerate(archs): + for numgpu in gpuranges[i]: + d = get_accs(arch, numgpu, prec[i]) + axs[x].plot(range(len(d)), d, label=f"{titles[i]} x {numgpu} {prec[i]}") + axs[x].legend() + + #plt.show() + plt.savefig("val_curves.png") + + +if __name__ == "__main__": + get_plots() diff --git a/PyTorch/Recommendation/NCF/qa/inference_table.py b/PyTorch/Recommendation/NCF/qa/inference_table.py new file mode 100644 index 00000000..b8828690 --- /dev/null +++ b/PyTorch/Recommendation/NCF/qa/inference_table.py @@ -0,0 +1,44 @@ +# Copyright (c) 2021, 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. + +import json +import tabulate + +archs = ["a100", "v100"] +precs = ["full", "half"] + +for arch in archs: + for prec in precs: + filename = f"inference/{arch}_{prec}.log" + with open(filename) as opened: + line = opened.readlines()[-1] + log = json.loads(line[len("DLLL "):])['data'] + print(log) + batch_sizes = [1024, 4096, 16384, 65536, 262144, 1048576] + t_avg = "batch_{}_mean_throughput" + l_mean = "batch_{}_mean_latency" + l_90 = "batch_{}_p90_latency" + l_95 = "batch_{}_p95_latency" + l_99 = "batch_{}_p99_latency" + headers = ["Batch size", "Throughput Avg", "Latency Avg", "Latency 90%", "Latency 95%", "Latency 99%"] + table = [] + for bsize in batch_sizes: + table.append([bsize, + "{:3.3f}".format(log[t_avg.format(bsize)]), + "{:.6f}".format(log[l_mean.format(bsize)]), + "{:.6f}".format(log[l_90.format(bsize)]), + "{:.6f}".format(log[l_95.format(bsize)]), + "{:.6f}".format(log[l_99.format(bsize)])]) + print(filename) + print(tabulate.tabulate(table, headers, tablefmt='pipe')) diff --git a/PyTorch/Recommendation/NCF/requirements.txt b/PyTorch/Recommendation/NCF/requirements.txt index e0a699fc..4ec39401 100644 --- a/PyTorch/Recommendation/NCF/requirements.txt +++ b/PyTorch/Recommendation/NCF/requirements.txt @@ -1,3 +1,4 @@ -pandas +pandas>=0.24.2 tqdm -git+https://github.com/NVIDIA/dllogger#egg=dllogger +pyyaml +git+https://github.com/NVIDIA/dllogger#egg=dllogger diff --git a/PyTorch/Recommendation/NCF/test_cases.sh b/PyTorch/Recommendation/NCF/test_cases.sh new file mode 100644 index 00000000..e8e8e39b --- /dev/null +++ b/PyTorch/Recommendation/NCF/test_cases.sh @@ -0,0 +1,42 @@ +#!/bin/bash +# Copyright (c) 2021, 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. +set -e +set -x + +for test_name in more_pos less_pos less_user less_item more_user more_item other_names; +do + CACHED_DATADIR='/data/cache/ml-20m' + NEW_DIR=${CACHED_DATADIR}/${test_name} + echo "Trying to run on modified dataset: $test_name" + python -m torch.distributed.launch --nproc_per_node=1 --use_env ncf.py --data ${NEW_DIR} --epochs 1 + echo "Model runs on modified dataset: $test_name" +done + +for test_sample in '0' '10' '200'; +do + CACHED_DATADIR='/data/cache/ml-20m' + NEW_DIR=${CACHED_DATADIR}/sample_${test_name} + echo "Trying to run on dataset with test sampling: $test_sample" + python -m torch.distributed.launch --nproc_per_node=1 --use_env ncf.py --data ${NEW_DIR} --epochs 1 + echo "Model runs on dataset with test sampling: $test_sample" +done + +for online_sample in '0' '1' '10'; +do + CACHED_DATADIR='/data/cache/ml-20m' + echo "Trying to run with train sampling: $online_sample" + python -m torch.distributed.launch --nproc_per_node=1 --use_env ncf.py --data ${CACHED_DATADIR} --epochs 1 -n ${online_sample} + echo "Model runs with train sampling: $online_sample" +done \ No newline at end of file diff --git a/PyTorch/Recommendation/NCF/test_dataset.sh b/PyTorch/Recommendation/NCF/test_dataset.sh new file mode 100644 index 00000000..5424ea73 --- /dev/null +++ b/PyTorch/Recommendation/NCF/test_dataset.sh @@ -0,0 +1,103 @@ + # Copyright (c) 2018, deepakn94, robieta. 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. +# +# ----------------------------------------------------------------------- +# +# Copyright (c) 2021, 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. + + +#!/bin/bash +set -e +set -x + +DATASET_NAME=${1:-'ml-20m'} +RAW_DATADIR=${2:-"/data/${DATASET_NAME}"} +CACHED_DATADIR=${3:-"$/data/cache/${DATASET_NAME}"} + +# you can add another option to this case in order to support other datasets +case ${DATASET_NAME} in + 'ml-20m') + ZIP_PATH=${RAW_DATADIR}/'ml-20m.zip' + RATINGS_PATH=${RAW_DATADIR}'/ml-20m/ratings.csv' + ;; + 'ml-1m') + ZIP_PATH=${RAW_DATADIR}/'ml-1m.zip' + RATINGS_PATH=${RAW_DATADIR}'/ml-1m/ratings.dat' + ;; + *) + echo "Unsupported dataset name: $DATASET_NAME" + exit 1 +esac + +if [ ! -d ${RAW_DATADIR} ]; then + mkdir -p ${RAW_DATADIR} +fi + +if [ ! -d ${CACHED_DATADIR} ]; then + mkdir -p ${CACHED_DATADIR} +fi + +if [ -f log ]; then + rm -f log +fi + +if [ ! -f ${ZIP_PATH} ]; then + echo "Dataset not found. Please download it from: https://grouplens.org/datasets/movielens/20m/ and put it in ${ZIP_PATH}" + exit 1 +fi + +if [ ! -f ${RATINGS_PATH} ]; then + unzip -u ${ZIP_PATH} -d ${RAW_DATADIR} +fi + +for test_name in more_pos less_pos less_user less_item more_user more_item other_names; +do + NEW_DIR=${CACHED_DATADIR}/${test_name} + + if [ ! -d ${NEW_DIR} ]; then + mkdir -p ${NEW_DIR} + fi + + python convert_test.py --path ${RATINGS_PATH} --output $NEW_DIR --test ${test_name} + echo "Generated testing for $test_name" +done + +for test_sample in '0' '10' '200'; +do + NEW_DIR=${CACHED_DATADIR}/sample_${test_name} + + if [ ! -d ${NEW_DIR} ]; then + mkdir -p ${NEW_DIR} + fi + + python convert_test.py --path ${RATINGS_PATH} --output $NEW_DIR --valid_negative $test_sample + echo "Generated testing for $test_name" +done + +echo "Dataset $DATASET_NAME successfully prepared at: $CACHED_DATADIR" +echo "You can now run the training with: python -m torch.distributed.launch --nproc_per_node= --use_env ncf.py --data ${CACHED_DATADIR}" + + diff --git a/PyTorch/Recommendation/NCF/test_featurespec_correctness.py b/PyTorch/Recommendation/NCF/test_featurespec_correctness.py new file mode 100644 index 00000000..1169f093 --- /dev/null +++ b/PyTorch/Recommendation/NCF/test_featurespec_correctness.py @@ -0,0 +1,90 @@ +# Copyright (c) 2021, 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. + +from feature_spec import FeatureSpec +from neumf_constants import TEST_SAMPLES_PER_SERIES +from dataloading import TorchTensorDataset +import torch +import os +import sys + + +def test_matches_template(path, template_path): + loaded_featurespec_string = FeatureSpec.from_yaml(path).to_string() + loaded_template_string = FeatureSpec.from_yaml(template_path).to_string() + assert loaded_template_string == loaded_featurespec_string + + +def mock_args(): + class Obj: + pass + + args = Obj() + args.__dict__['local_rank'] = 0 + return args + + +def test_dtypes(path): + loaded_featurespec = FeatureSpec.from_yaml(path) + features = loaded_featurespec.feature_spec + declared_dtypes = {name: data['dtype'] for name, data in features.items()} + source_spec = loaded_featurespec.source_spec + for mapping in source_spec.values(): + for chunk in mapping: + chunk_dtype = None + for present_feature in chunk['features']: + assert present_feature in declared_dtypes, "unknown feature in mapping" + # Check declared type + feature_dtype = declared_dtypes[present_feature] + if chunk_dtype is None: + chunk_dtype = feature_dtype + else: + assert chunk_dtype == feature_dtype + + path_to_load = os.path.join(loaded_featurespec.base_directory, chunk['files'][0]) + loaded_data = torch.load(path_to_load) + assert str(loaded_data.dtype) == chunk_dtype + + +def test_cardinalities(path): + loaded_featurespec = FeatureSpec.from_yaml(path) + features = loaded_featurespec.feature_spec + declared_cardinalities = {name: data['cardinality'] for name, data in features.items() if 'cardinality' in data} + source_spec = loaded_featurespec.source_spec + + for mapping_name, mapping in source_spec.items(): + dataset = TorchTensorDataset(loaded_featurespec, mapping_name, mock_args()) + for feature_name, cardinality in declared_cardinalities.items(): + feature_data = dataset.features[feature_name] + biggest_num = feature_data.max().item() + assert biggest_num < cardinality + + +def test_samples_in_test_series(path): + loaded_featurespec = FeatureSpec.from_yaml(path) + + series_length = loaded_featurespec.metadata[TEST_SAMPLES_PER_SERIES] + dataset = TorchTensorDataset(loaded_featurespec, 'test', mock_args()) + for feature in dataset.features.values(): + assert len(feature) % series_length == 0 + + +if __name__ == '__main__': + tested_spec = sys.argv[1] + template = sys.argv[2] + + test_cardinalities(tested_spec) + test_dtypes(tested_spec) + test_samples_in_test_series(tested_spec) + test_matches_template(tested_spec, template) diff --git a/PyTorch/Recommendation/NCF/transcode.py b/PyTorch/Recommendation/NCF/transcode.py new file mode 100644 index 00000000..862c323e --- /dev/null +++ b/PyTorch/Recommendation/NCF/transcode.py @@ -0,0 +1,127 @@ +# Copyright (c) 2021, 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. + +from argparse import ArgumentParser +import os +import torch +import pandas as pd + +from feature_spec import FeatureSpec +from neumf_constants import USER_CHANNEL_NAME, ITEM_CHANNEL_NAME, LABEL_CHANNEL_NAME + + +def parse_args(): + parser = ArgumentParser() + parser.add_argument('--path', type=str, default='', + help='Path to input data directory') + parser.add_argument('--feature_spec_in', type=str, default='feature_spec.yaml', + help='Name of the input feature specification file, or path relative to data directory.') + parser.add_argument('--output', type=str, default='/data', + help='Path to output data directory') + parser.add_argument('--feature_spec_out', type=str, default='feature_spec.yaml', + help='Name of the output feature specification file, or path relative to data directory.') + return parser.parse_args() + + +def main(): + args = parse_args() + args_output = args.output + args_path = args.path + args_feature_spec_in = args.feature_spec_in + args_feature_spec_out = args.feature_spec_out + + feature_spec_path = os.path.join(args_path, args_feature_spec_in) + feature_spec = FeatureSpec.from_yaml(feature_spec_path) + + # Only three features are transcoded - this is NCF specific + user_feature_name = feature_spec.channel_spec[USER_CHANNEL_NAME][0] + item_feature_name = feature_spec.channel_spec[ITEM_CHANNEL_NAME][0] + label_feature_name = feature_spec.channel_spec[LABEL_CHANNEL_NAME][0] + + categorical_features = [user_feature_name, item_feature_name] + + found_cardinalities = {f: 0 for f in categorical_features} + + new_source_spec = {} + for mapping_name, mapping in feature_spec.source_spec.items(): + # Load all chunks and link into one df + chunk_dfs = [] + for chunk in mapping: + assert chunk['type'] == 'csv', "Only csv files supported in this transcoder" + file_dfs = [] + for file in chunk['files']: + path_to_load = os.path.join(feature_spec.base_directory, file) + file_dfs.append(pd.read_csv(path_to_load, header=None)) + chunk_df = pd.concat(file_dfs, ignore_index=True) + chunk_df.columns = chunk['features'] + chunk_df.reset_index(drop=True, inplace=True) + chunk_dfs.append(chunk_df) + mapping_df = pd.concat(chunk_dfs, axis=1) # This takes care of making sure feature names are unique + + for feature in categorical_features: + mapping_cardinality = mapping_df[feature].max() + 1 + previous_cardinality = found_cardinalities[feature] + found_cardinalities[feature] = max(previous_cardinality, mapping_cardinality) + + # We group together users and items, while separating labels. This is because of the target dtypes: ids are int, + # while labels are float to compute loss. + ints_tensor = torch.from_numpy(mapping_df[[user_feature_name, item_feature_name]].values).long() + ints_file = f"{mapping_name}_data_0.pt" + ints_chunk = {"type": "torch_tensor", + "features": [user_feature_name, item_feature_name], + "files": [ints_file]} + torch.save(ints_tensor, os.path.join(args_output, ints_file)) + + floats_tensor = torch.from_numpy(mapping_df[[label_feature_name]].values).float() + floats_file = f"{mapping_name}_data_1.pt" + floats_chunk = {"type": "torch_tensor", + "features": [label_feature_name], + "files": [floats_file]} + torch.save(floats_tensor, os.path.join(args_output, floats_file)) + + new_source_spec[mapping_name] = [ints_chunk, floats_chunk] + + for feature in categorical_features: + found_cardinality = found_cardinalities[feature] + declared_cardinality = feature_spec.feature_spec[feature].get('cardinality', 'auto') + if declared_cardinality != "auto": + declared = int(declared_cardinality) + assert declared >= found_cardinality, "Specified cardinality conflicts data" + found_cardinalities[feature] = declared + + new_inner_feature_spec = { + user_feature_name: { + "dtype": "torch.int64", + "cardinality": int(found_cardinalities[user_feature_name]) + }, + item_feature_name: { + "dtype": "torch.int64", + "cardinality": int(found_cardinalities[item_feature_name]) + }, + label_feature_name: { + "dtype": "torch.float32" + } + } + + new_feature_spec = FeatureSpec(feature_spec=new_inner_feature_spec, + source_spec=new_source_spec, + channel_spec=feature_spec.channel_spec, + metadata=feature_spec.metadata, + base_directory="") + feature_spec_save_path = os.path.join(args_output, args_feature_spec_out) + new_feature_spec.to_yaml(output_path=feature_spec_save_path) + + +if __name__ == '__main__': + main() diff --git a/PyTorch/Recommendation/NCF/utils.py b/PyTorch/Recommendation/NCF/utils.py index e7863c8d..86e42c65 100644 --- a/PyTorch/Recommendation/NCF/utils.py +++ b/PyTorch/Recommendation/NCF/utils.py @@ -13,9 +13,8 @@ # limitations under the License. import os -import json from functools import reduce -import time + def count_parameters(model): c = map(lambda p: reduce(lambda x, y: x * y, p.size()), model.parameters())