Configuration file

Input Data Configuration

The first key component of the config file is the data_config section.

experiment:
  data_config:
    strategy: dataset|fixed|hierarchy
    dataset_path: this/is/the/path.tsv
    root_folder: this/is/the/path
    train_path: this/is/the/path.tsv
    validation_path: this/is/the/path.tsv
    test_path: this/is/the/path.tsv
    side_information:
        - dataloader: ChainedKG|ItemAttributes|VisualAttribute
          map: this/is/the/path.tsv
          features: this/is/the/path.tsv
          properties: this/is/the/path.conf

In this section, we can define which input files and how they should be loaded.

In the following, we will consider as datasets, tab-separated-value files that contain one interaction per row, in the format:

UserID ItemID Rating [ TimeStamp ]

where TimeStamp is optional.

Strategies

According to the kind of data we have, we can choose among three different loading strategies: dataset, fixed, hierarchy.

dataset assumes that the input data is NOT previously split in training, validation, and test set. For this reason, ONLY if we adopt a dataset strategy we can later perform prefiltering and splitting operations.

dataset takes just ONE default parameter: dataset_path, which points to the stored dataset.

experiment:
  data_config:
    strategy: dataset
    dataset_path: this/is/the/path.tsv

fixed strategy assumes that our data has been previously split into training/validation/test sets or training/test sets. Since data is supposed as previously split, no further prefiltering and splitting operation is contemplated.

fixed takes two mandatory parameters: train_path and test_path, and one optional parameter, validation_path.

experiment:
  data_config:
    strategy: fixed
    train_path: this/is/the/path.tsv
    validation_path: this/is/the/path.tsv
    test_path: this/is/the/path.tsv

The last strategy is hierarchy. hierarchy is designed to load a dataset that has been previously split and filtered with Elliot. Here, the data is assumed as split and no further prefiltering and splitting operations are needed.

hierarchy takes one mandatory parameter, root_folder, that points to the folder where we previously stored the split files.

experiment:
  data_config:
    strategy: hierarchy
    root_folder: this/is/the/path

Data Loaders

Within the data_config section, we can also enable data-specific Data Loaders. Each Data Loader is designed to handle a specific kind of additional data.

It is possible to enable a Data Loader by inserting the field dataloader and passing the corresponding name. For instance, the Visual Data Loader lets the user consider precomputed visual feature vectors or (inclusive) images.

To pass the required parameters to the Data Loader, we use a specific subsection, named side_information. There we can enable the required (by the specific Data Loader) fields and insert the corresponding values.

An example can be:

experiment:
  data_config:
    strategy: fixed
    dataloader: VisualLoader
    train_path: this/is/the/path.tsv
    test_path: this/is/the/path.tsv
    side_information:
        feature_data: this/is/the/path/to/features.npy

For further details regarding the Data Loaders, please refer to the section.

Data Prefiltering

Elliot provides several prefiltering strategies. To enable Prefiltering operations, we can insert the corresponding block into our config file. Moreover it is possible to specify multiple prefiltering steps by set multiple strategy into prefiltering section:

experiment:
  prefiltering:
    - strategy: global_threshold|user_average|user_k_core|item_k_core|iterative_k_core|n_rounds_k_core|cold_users
      threshold: 3|average
      core: 5
      rounds: 2
    - strategy: global_threshold|user_average|user_k_core|item_k_core|iterative_k_core|n_rounds_k_core|cold_users
      threshold: 3|average
      core: 5
      rounds: 2

In detail, Elliot provides eight main prefiltering approaches: global_threshold, user_average, user_k_core, item_k_core, iterative_k_core, n_rounds_k_core, cold_users.

global_threshold assumes a single system-wise threshold to filter out irrelevant transactions. global_threshold takes one mandatory parameter, threshold. threshold takes, as values, a float (ratings >= threshold will be kept), or the string average. With average, the system computes the global mean of the rating values and filters out all the ratings below.

experiment:
  prefiltering:
    strategy: global_threshold
    threshold: 3
experiment:
  prefiltering:
    strategy: global_threshold
    threshold: average

user_average has no parameters, and the system filters out the ratings below each user rating values mean.

experiment:
  prefiltering:
    strategy: user_average

user_k_core filters out all the users with a number of transactions lower than the given k core. It takes a parameter, core, where the user passes an int corresponding to the desired value.

experiment:
  prefiltering:
    strategy: user_k_core
    core: 5

item_k_core filters out all the items with a number of transactions lower than the given k core. It takes a parameter, core, where the user passes an int corresponding to the desired value.

experiment:
  prefiltering:
    strategy: item_k_core
    core: 5

iterative_k_core runs iteratively user_k_core, and item_k_core until the dataset is no further modified. It takes a parameter, core, where the user passes an int corresponding to the desired value.

experiment:
  prefiltering:
    strategy: iterative_k_core
    core: 5

n_rounds_k_core runs iteratively user_k_core, and item_k_core for a specified number of rounds. It takes the first parameter, core, where the user passes an int corresponding to the desired value. It takes the second parameter, rounds, where the user passes an int corresponding to the desired value.

experiment:
  prefiltering:
    strategy: n_rounds_k_core
    core: 5
    rounds: 2

cold_users filters out all the users with a number of interactions higher than a given threshold. It takes a parameter, threshold, where the user passes an int corresponding to the desired value.

experiment:
  prefiltering:
    strategy: cold_users
    threshold: 3

Data Splitting

Elliot provides several splitting strategies. To enable the splitting operations, we can insert the corresponding section:

experiment:
  splitting:
    save_on_disk: True
    save_folder: this/is/the/path/
    test_splitting:
        strategy: fixed_timestamp|temporal_hold_out|random_subsampling|random_cross_validation
        timestamp: best|1609786061
        test_ratio: 0.2
        leave_n_out: 1
        folds: 5
    validation_splitting:
        strategy: fixed_timestamp|temporal_hold_out|random_subsampling|random_cross_validation
        timestamp: best|1609786061
        test_ratio: 0.2
        leave_n_out: 1
        folds: 5

Before deepening the splitting configurations, we can configure Elliot to save on disk the split files, once the splitting operation is completed.

To this extent, we can insert two fields into the section: save_on_disk, and save_folder.

save_on_disk enables the writing process, and save_folder specifies the system location where to save the split files:

experiment:
  splitting:
    save_on_disk: True
    save_folder: this/is/the/path/

Now, we can insert one (or two) specific subsections to detail the train/test, and the train/validation splitting via the corresponding fields: test_splitting, and validation_splitting. test_splitting is clearly mandatory, while validation_splitting is optional. Since the two subsections follow the same guidelines, here we detail test_splitting without loss of generality.

Elliot enables four splitting families: fixed_timestamp, temporal_hold_out, random_subsampling, random_cross_validation.

fixed_timestamp assumes that there will be a specific timestamp to split prior interactions (train) and future interactions. It takes the parameter timestamp, that can assume one of two possible kind of values: a long corresponding to a specific timestamp, or the string best computed following Anelli et al.

experiment:
  splitting:
    test_splitting:
        strategy: fixed_timestamp
        timestamp: 1609786061
experiment:
  splitting:
    test_splitting:
        strategy: fixed_timestamp
        timestamp: best

temporal_hold_out relies on a temporal split of user transactions. The split can be realized following two different approaches: a ratio-based and a leave-n-out-based approach. If we enable the test_ratio field with a float value, Elliot splits data retaining the last (100 * test_ratio) % of the user transactions for the test set. If we enable the leave_n_out field with an int value, Elliot retains the last leave_n_out transactions for the test set.

experiment:
  splitting:
    test_splitting:
        strategy: temporal_hold_out
        test_ratio: 0.2
experiment:
  splitting:
    test_splitting:
        strategy: temporal_hold_out
        leave_n_out: 1

random_subsampling generalizes random hold-out strategy. It takes a test_ratio parameter with a float value to define the train/test ratio for user-based hold-out splitting. Alternatively, it can take leave_n_out with an int value to define the number of transaction retained for the test set. Moreover, the splitting operation can be repeated enabling the folds field and passing an int. In that case, the overall splitting strategy corresponds to a user-based random subsampling strategy.

experiment:
  splitting:
    test_splitting:
        strategy: random_subsampling
        test_ratio: 0.2
experiment:
  splitting:
    test_splitting:
        strategy: random_subsampling
        test_ratio: 0.2
        folds: 5
experiment:
  splitting:
    test_splitting:
        strategy: random_subsampling
        leave_n_out: 1
        folds: 5

random_cross_validation adopts a k-folds cross-validation splitting strategy. It takes the parameter folds with an int value, that defines the overall number of folds to consider.

experiment:
  splitting:
    test_splitting:
        strategy: random_cross_validation
        folds: 5

Negative Sampling

Elliot let us to set up a set of negative items for each user, these items are useful to provide a negative sampling evaluation. It is possible to provide a file with these items or give to Elliot the possibility to generate a specific number of negative items for each user.

experiment:
    negative_sampling:
        strategy: fixed|random
        files: [ path/to/file ]
        num_items: 5

For further details regarding the file format and other feature about Negative Sampling, please refer to the section.

Dataset Name Configuration

Elliot needs a MANDATORY field, dataset, that identifies the name of the dataset used for the experiment. This information is used in the majority of the experimental steps, to identify the experiment and save the files correctly:

experiment:
  dataset: dataset_name

Output Configuration

Elliot lets the user specify where to store specific output files: the recommendation lists, the model weights, the evaluation results, and the logs:

experiment:
  path_output_rec_result: this/is/the/path/
  path_output_rec_weight: this/is/the/path/
  path_output_rec_performance: this/is/the/path/
  path_log_folder: this/is/the/path/

path_output_rec_result lets the user define the path to the folder to store the recommendation lists.

path_output_rec_weight lets the user define the path to the folder to store the model weights.

path_output_rec_performance lets the user define the path to the folder to store the evaluation results.

path_log_folder lets the user define the path to the folder to store the logs.

If not provided, Elliot creates a results folder in the parent folder of the config file location.

Inside it, Elliot creates an experiment-specific folder with the name of the dataset, and there it creates the recs/, weights/, and performance/ folders, respectively.

Moreover, Elliot creates a log/ folder in the parent folder of the config file location.

Evaluation Configuration

Elliot provides several facilities to evaluate recommendation systems. The majority of the evaluation techniques require the computation of user-specific recommendation lists (some techniques use recommendation systems to perform knowledge completion or other tasks).

To define the length of the user recommendation list, Elliot provides a specific mandatory field, top_k, that takes an int representing the list length.

Beyond the former general definition, to specify the evaluation configuration, we can insert a specific section:

experiment:
  top_k: 50
  evaluation:
    cutoffs: [10, 5]
    simple_metrics: [ nDCG, Precision, Recall]
    relevance_threshold: 1
    paired_ttest: True
    wilcoxon_test: True
    complex_metrics:
    - metric: DSC
      beta: 2
    - metric: SRecall
      feature_data: this/is/the/path.tsv

In that section, we can detail the main characteristics of our experimental benchmark.

In particular, we can provide Elliot with the information regarding the metrics we want to compute. According to the metrics definition, some of them might require additional parameters or files. To make it easier for the user to pass metrics and optional arguments, Elliot partitions the metrics into simple_metrics and complex_metrics.

simple_metrics can be inserted as a field into the evaluation section, and it takes as a value the list of the metrics we want to compute. In the simple metrics set, we find all the metrics that DO NOT require any other additional parameter or file:

experiment:
  top_k: 50
  evaluation:
    cutoffs: [10, 5]
    simple_metrics: [ nDCG, Precision, Recall]
    relevance_threshold: 1

The majority of the evaluation metrics relies on the notions of cut-off and relevance threshold.

The cut-off is the maximum length of the recommendation list we want to consider when computing the metric (it could be different from the top k). To pass cut-off values, we can enable the cutoffs field and pass a single value or a list of values. Elliot will compute the evaluation results for each considered cut-off. If cutoffs field is not provided, top_k value is assumed as a cut-off.

The relevance threshold is the minimum value of the rating to consider a test transaction relevant for the evaluation process. We can pass the relevance threshold value to the corresponding relevance_threshold field. If not given, relevance_threshold is set to 0.

The set of metrics that require additional arguments is referred to as complex_metrics. The inclusion of the metrics follows the syntax:

experiment:
  evaluation:
    complex_metrics:
    - metric: complex_metric_name_0
      parameter_0: 2
    - metric: complex_metric_name_1
      parameter_1: this/is/the/path.tsv

where parameter_0 and parameter_1 are metric-specific parameters of any kind.

For further details about the available metrics, please see the corresponding section.

Finally, Elliot enables the computation of paired statistical hypothesis tests, namely, Wilcoxon, and Student’s paired t-tests.

To enable them, we can insert the corresponding boolean fields into the evaluation section:

experiment:
  evaluation:
    paired_ttest: True
    wilcoxon_test: True

All the evaluation results are available in the performance folder at the end of the experiment.

Test the config file

Since an experiment may take a long time, a possible error in the configuration file in the last model configuration can lead to a severe waste of time. To avoid common mistakes in config file creation, Elliot provides a specific field that tests our configuration file before the actual run of the experiment. The feature can be activated as follows:

experiment:
  config_test: True

NOTE: The configuration test uses small data mock-ups. Consequently, some model parameter values (e.g. a high value of the neighborhood for Item-kNN) do no fit. In such cases, uses compatible values for testing, then remove config_test field and run the full experiment.

GPU Acceleration

Elliot lets the user enable GPU acceleration with Tensorflow. To select the gpu on which we can run our experiments, use the following syntax:

experiment:
  gpu: 1

If a negative value is passed, or the field is missing, the computation will take place on the CPU.

Please note that the configuration of tensorflow to work with GPUs is not covered by this guide. Please refer to the Tensorflow documentation for that.

Recommendation Model Configuration

To include the recommendation models, Elliot provides a straightforward syntax.

First, we can create a new section in the experiment, named models:

experiment:
  models:

Then, we can insert a list of recommendation models in which each model respects the following syntax:

experiment:
  models:
    model_0:
      meta:
        meta_parameter_0: something
      model_parameter_0: something
      model_parameter_1: something
      model_parameter_2: something
    model_1:
      meta:
        meta_parameter_0: something
      model_parameter_0: something
      model_parameter_1: something
      model_parameter_2: something

meta is a mandatory field that lets the user define some parameters that all recommendation models share, but they can decline differently.

The decision to save model weights and recommendations, the choice of the validation metric and cut-off, the chosen hyperparameter tuning strategy, the verbosity, and the frequency of the evaluation during the training belong to this category.

In detail, use:

verbose boolean field to enable verbose logs

save_recs boolean field to enable recommendation lists storage

save_weights boolean field to enable model weights storage

validation_metric mixed field (string @ int) to define the simple metric and the cut-off used for the model selection. If not provided it takes the first provided simple metric, and the first cut-off.

validation_rate int field: where applicable, define the iteration interval for the validation and test evaluation

hyper_opt_alg string field: it defines the hyperparameter tuning strategy

hyper_max_evals int field: where applicable, it defines the number of samples to consider for hyperparameter evaluation

To fully understand how to conduct hyperparameter optimization in Elliot, please refer to the corresponding section.

Finally, model_parameter_0, model_parameter_1, and model_parameter_2 represents the model-specific parameters.

For further details on model-specific parameters see the corresponding section.

Example:

experiment:
  models:
    KaHFMEmbeddings:
      meta:
        hyper_max_evals: 20
        hyper_opt_alg: tpe
        validation_rate: 1
        verbose: True
        save_weights: True
        save_recs: True
        validation_metric: nDCG@10
      epochs: 100
      batch_size: -1
      lr: 0.0001
      l_w: 0.005
      l_b: 0