如何优化LightFM的超参数?

Tim*_*ser 3 optimization hyperparameters recommender-systems

我在数据集中使用了LightFM推荐程序库,该库在下面的图像中提供了结果。

经过一段时间后效果不佳

NUM_THREADS = 4
NUM_COMPONENTS = 30
NUM_EPOCHS = 5
ITEM_ALPHA = 1e-6
LEARNING_RATE = 0.005
LEARNING_SCHEDULE = 'adagrad'
RANDOM_SEED = 29031994    

warp_model = LightFM(loss='warp',
                    learning_rate=LEARNING_RATE,
                    learning_schedule=LEARNING_SCHEDULE,
                    item_alpha=ITEM_ALPHA,
                    no_components=NUM_COMPONENTS,
                    random_state=RANDOM_SEED)

bpr_model = LightFM(loss='bpr',
                    learning_rate=LEARNING_RATE,
                    learning_schedule=LEARNING_SCHEDULE,
                    item_alpha=ITEM_ALPHA,
                    no_components=NUM_COMPONENTS,
                    random_state=RANDOM_SEED)
Run Code Online (Sandbox Code Playgroud)

我的特征的形状如下:

项目和用户特征形状

我如何优化我的超参数以提高曲线下面积(AUC)分数?

Mac*_*ula 7

您可以在sklearn文档中找到有关超参数优化的良好通用指南。

可用于优化LightFM模型的一种简单但有效的技术是随机搜索。大致上,它包括以下步骤:

  1. 将您的数据分为训练集,验证集和测试集。
  2. Define a distribution for each hyperparameter you would like to optimize. For example, if you are optimizing your learning rate, you could use an exponential distribution with a mean of 0.05; if you are optimizing the loss function, you could sample uniformly from ['warp', 'bpr', 'warp-kos'].
  3. In each iteration of the optimization, sample all your hyperparameters and use them to fit the model on the training data. Evaluate the model's performance on the validation set.
  4. After performing a number of optimization steps, select the one with the best validation performance.

To gauge the performance of the final model you should use the test set: simply evaluate the best validation model on the test set.

The following script illustrates this:

import itertools

import numpy as np

from lightfm import LightFM
from lightfm.evaluation import auc_score


def sample_hyperparameters():
    """
    Yield possible hyperparameter choices.
    """

    while True:
        yield {
            "no_components": np.random.randint(16, 64),
            "learning_schedule": np.random.choice(["adagrad", "adadelta"]),
            "loss": np.random.choice(["bpr", "warp", "warp-kos"]),
            "learning_rate": np.random.exponential(0.05),
            "item_alpha": np.random.exponential(1e-8),
            "user_alpha": np.random.exponential(1e-8),
            "max_sampled": np.random.randint(5, 15),
            "num_epochs": np.random.randint(5, 50),
        }


def random_search(train, test, num_samples=10, num_threads=1):
    """
    Sample random hyperparameters, fit a LightFM model, and evaluate it
    on the test set.

    Parameters
    ----------

    train: np.float32 coo_matrix of shape [n_users, n_items]
        Training data.
    test: np.float32 coo_matrix of shape [n_users, n_items]
        Test data.
    num_samples: int, optional
        Number of hyperparameter choices to evaluate.


    Returns
    -------

    generator of (auc_score, hyperparameter dict, fitted model)

    """

    for hyperparams in itertools.islice(sample_hyperparameters(), num_samples):
        num_epochs = hyperparams.pop("num_epochs")

        model = LightFM(**hyperparams)
        model.fit(train, epochs=num_epochs, num_threads=num_threads)

        score = auc_score(model, test, train_interactions=train, num_threads=num_threads).mean()

        hyperparams["num_epochs"] = num_epochs

        yield (score, hyperparams, model)


if __name__ == "__main__":
    from lightfm.datasets import fetch_movielens

    data = fetch_movielens()
    train = data["train"]
    test = data["test"]

    (score, hyperparams, model) = max(random_search(train, test, num_threads=2), key=lambda x: x[0])

    print("Best score {} at {}".format(score, hyperparams))
Run Code Online (Sandbox Code Playgroud)

  • 我注意到,当不通过指标(auc / precision_at_k / recall_at_k)中的 train_interactions=train 时,相应的值会变得相当低。计算这些总是通过火车交互的正确方法是吗? (2认同)