RecList 2.0:开源系统化测试机器学习模型

RecList 2.0 Open-source systematic testing of machine learning models

一个新的RecList,为评估提供更灵活性和更好的支持

Lucas Pezeta拍摄的照片

介绍

评估是一个复杂的问题。管理涉及编写评估流程的不同组件通常很困难,你的模型在某个地方,你需要加载它,然后获取测试,然后运行测试,等等。

然后呢?好吧,你需要把结果保存在某个地方,也许在线记录输出,这样你就可以跟踪它们。

由于这总是一个困难的过程,我们最近试图提供一种更有结构化的测试方式。在这篇博文中,我们介绍并展示如何使用RecList beta,我们的开源评估包;RecList是一种通用的即插即用方法,用于扩展测试,并具有易于扩展的自定义用例接口。RecList是一个在GitHub上免费提供的开源项目。

RecList允许您将代码的评估部分分离出来,并将其封装在一个处理其他几个事情(例如存储和日志记录)的类中,并为您自动处理。

Reclist为您在训练了自己的模型之后提供了一种简单的系统化测试方式,并保存您需要的所有信息。

我们几年前开始研究RecList,RecList的alpha版本在一年多前发布。从那时起,RecList已经收集了400多个GitHub星标。

我们使用RecList进行了测试,并对其进行了压力测试,以在2022年的CIKM上进行了一个RecSys挑战,并正在为2023年的KDD准备即将到来的一个挑战。RecList使我们能够为所有参与者系统化评估。我们的经验总结出现在我们的Nature Machine Intelligence评论文章中。

RecList最初是在一篇学术论文中提出的,但我们也有一个总览,在Towards Data Science上发表了这篇文章:

NDCG不是唯一需要考虑的因素

使用RecList进行推荐系统行为测试

towardsdatascience.com

Chia, P. J., Tagliabue, J., Bianchi, F., He, C., & Ko, B. (2022, April). Beyond nDCG: Behavioral Testing of Recommender Systems with Reclist. In Companion Proceedings of the Web Conference 2022 (pp. 99–104).

虽然我们最初设计RecList用于推荐系统测试,但没有什么阻止使用RecList测试其他机器学习模型。那么,为什么会有一篇新的博文?嗯,开发第一个版本后,我们意识到它需要一些更新。

我们学到了什么:重新思考API

通常只有在构建完成后才会意识到如何改进它。

对于那些使用过RecList 1.0的人,我们对RecList API进行了重大更新。最初,我们对代码结构和输入/输出对有更严格的约束。

的确,当我们实施RecList时,我们打算为推荐系统的评估提供一个更通用的API,提供几个开箱即用的功能。然而,为了做到这一点,我们必须创建几个抽象接口,用户必须实现。

例如,原始的RecList 1.0要求用户将自己的模型和数据集封装到预定义的抽象类(即RecModel和RecDataset)中。这使我们能够实现一组由这些抽象连接的公共行为。然而,我们很快意识到,这可能经常使流程复杂化,并需要大量额外的工作,有些人可能不喜欢。

RecList 2.0 中,我们决定将这些约束条件变为可选项:我们使测试更加灵活。用户可以定义自己的评估用例,将其包装在一个方便的装饰器中,这样就可以实现元数据存储和日志记录。用户可以与其他人共享测试接口,他们可以运行完全相同的实验。

总结:我们意识到,在构建其他人必须使用的软件时,灵活性是多么重要。

RecList 2.0 的实际应用

现在,让我们来探索一个使用 RecList 编写和运行评估流程的简单用例。我们将使用非常简单的模型,该模型随机输出数字,以减少在机器学习项目中所涉及的复杂性。

一个简单的用例

让我们创建一个非常简单的用例,使用一个非常简单的数据集。假设我们有一个目标整数序列,每个整数都有一个关联的类别。我们只需生成一些随机数据。

n = 10000target = [randint(0, 1) for _ in range(n)]metadata = {"categories": [choice(["red", "blue", "yellow"])                           for _ in range(n)]}

我们非常简单的数据集应该看起来像这样:

>>> target[0, 1, 0, 1, 1, 0]>>> metadata{"categories" : ["red", "blue", "yellow", "blue", "yellow", "yellow"]}

一个简单的模型

现在,假设我们有一个 DummyModel,它以随机方式输出整数。当然,正如我们所说的,这不是一个“好”的模型,但它是一个我们可以用来看到整个评估流程的良好抽象。

class DummyModel:  def __init__(self, n):          self.n = n      def predict(self):          from random import randint          return [randint(0, 1) for _ in range(self.n)]simple_model = DummyModel(n)# 让我们运行一些预测predictions = simple_model.predict()

现在,我们如何进行评估?

一个简单的 RecList

RecList 是一个继承我们的 RecList 抽象类功能的 Python 类。RecList 实现了 RecTests,简单的抽象,允许您系统化评估。例如,这可能是一个可能的准确性测试。

@rec_test(test_type="Accuracy", display_type=CHART_TYPE.SCALAR)def accuracy(self):    """    计算准确性    """    from sklearn.metrics import accuracy_score    return accuracy_score(self.target, self.predictions)

我们采用 sklearn 的准确性度量标准,并将其包装在另一个方法中。这与简单的准确性函数有何不同?嗯,装饰器允许我们带入一些额外的功能:例如,rectest 现在会自动存储信息在本地文件夹中。此外,定义图表类型允许我们为这些结果创建一些可视化。

如果我们想要更复杂的测试怎么办?例如,如果我们想要查看准确性在不同类别(例如,红色对象的准确性是否高于黄色对象的准确性)上的稳定性怎么办?

@rec_test(test_type="SlicedAccuracy", display_type=CHART_TYPE.SCALAR)def sliced_accuracy_deviation(self):    """    按切片计算准确性    """    from reclist.metrics.standard_metrics import accuracy_per_slice        return accuracy_per_slice(        self.target, self.predictions, self.metadata["categories"])

现在,让我们来看一个完整的 RecList 示例!

class BasicRecList(RecList):    def __init__(self, target, metadata, predictions, model_name, **kwargs):        super().__init__(model_name, **kwargs)        self.target = target        self.metadata = metadata        self.predictions = predictions    @rec_test(test_type="SlicedAccuracy", display_type=CHART_TYPE.SCALAR)    def sliced_accuracy_deviation(self):        """        按切片计算准确性        """        from reclist.metrics.standard_metrics import accuracy_per_slice        return accuracy_per_slice(            self.target, self.predictions, self.metadata["categories"]        )    @rec_test(test_type="Accuracy", display_type=CHART_TYPE.SCALAR)    def accuracy(self):        """        计算准确性        """        from sklearn.metrics import accuracy_score        return accuracy_score(self.target, self.predictions)    @rec_test(test_type="AccuracyByCountry", display_type=CHART_TYPE.BARS)    def accuracy_by_country(self):        """        按国家计算准确性        """        # TODO: 注意这是一个静态测试,         # 用于展示条形显示        from random import randint        return {"US": randint(0, 100),                 "CA": randint(0, 100),                 "FR": randint(0, 100)}

我们只需要几行代码就能将我们所需的一切放在一个地方。我们可以重用这段代码用于新模型,或者添加测试并重新运行过去的模型。

只要您的指标返回一些值,您可以按任何方式实现它们。例如,这个BasicRecList在特定的上下文中评估一个特定的模型。但是没有什么可以阻止您生成更多特定于模型的推荐列表(如GPT-RecList)或特定于数据集的推荐列表(如IMDB-Reclist)。如果您想看一个关于RecList的深度模型的示例,可以查看这个colab。

运行和获取输出

让我们运行RecList。我们需要目标数据、元数据和预测结果。我们还可以指定一个记录器和一个元数据存储。

rlist = BasicRecList(    target=target,    metadata=metadata,    predictions=predictions,    model_name="myRandomModel",)# run reclistrlist(verbose=True)

这个过程的输出是什么?我们在命令行中将看到以下一组结果:对于每个测试,我们都有一个实际分数。

这些指标也会自动绘制。例如,AccuracyByCountry应该显示如下:

Example of plot generated by a RecTest.

除此之外,RecList还保存了一个包含刚刚运行的所有实验信息的JSON文件:

{  "metadata": {    "model_name": "myRandomModel",    "reclist": "BasicRecList",    "tests": [      "sliced_accuracy",      "accuracy",      "accuracy_by_country"    ]  },  "data": [    {      "name": "SlicedAccuracy",      "description": "按切片计算准确率",      "result": 0.00107123176804103,      "display_type": "CHART_TYPE.SCALAR"    },...}

好处是,只需添加几行额外的代码,大部分记录工作都会为我们处理!

使用在线记录器和元数据存储

默认情况下,RecList运行程序将使用以下记录器和元数据设置。

logger=LOGGER.LOCAL,metadata_store= METADATA_STORE.LOCAL,

然而,我们可以使用在线和云解决方案。例如,我们封装了CometML和Neptune API,这样您就可以直接在评估流水线中使用它们。我们还支持S3数据存储。

例如,向BasicReclist添加一些参数将允许我们在Neptune上记录信息(我们也为Comet.ml提供类似的支持)!

rlist = BasicRecList(    target=target,    model_name="myRandomModel",    predictions=predictions,    metadata=metadata,    logger=LOGGER.NEPTUNE,    metadata_store= METADATA_STORE.LOCAL,    NEPTUNE_KEY=os.environ["NEPTUNE_KEY"],    NEPTUNE_PROJECT_NAME=os.environ["NEPTUNE_PROJECT_NAME"],)# run reclistrlist(verbose=True)

以非常相似的方式,添加以下内容:

bucket=os.environ["S3_BUCKET"]

将允许我们使用S3 Bucket存储元数据(当然,您需要为此设置一些环境变量键)。

结论

就是这样!我们创建了RecList,以使推荐系统的评估更加系统化和有组织。我们希望这个大规模的API重构能够帮助人们构建更可靠的评估流水线!

致谢

在2022年6月至12月期间,我们的beta版本的开发得到了Comet、Neptune、Gantry的支持,并在Unnati Patel的帮助下开发。