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

2023年08月17日 由 alex 发表 294 0

介绍


在本文中,我们介绍并展示了如何使用开源包RecList beta进行评估;RecList是一种通用的即插即用方法,用于扩大测试规模,并提供了一个易于扩展的接口,适用于定制的使用场景。RecList是一个开源项目,在GitHub上免费提供。


RecList可以让您将代码中的评估部分分离出来,并将其封装在一个类中,该类会自动处理其他一些事情(例如存储和记录)。


1


RecList的alpha版本大约一年多前发布。自那时以来,RecList已经获得了400多个GitHub星标。


我们已经使用RecList并对其进行了大规模压力测试,以在2022年的CIKM(信息与知识管理国际会议)上进行了一个推荐系统挑战赛,并目前正在准备2023年在KDD(知识发现与数据挖掘国际会议)上的下一个挑战赛。RecList使我们能够为所有参与者系统化地进行评估。这样,一旦每个人都使用相同的RecList,比较不同的评估结果就变得容易了。


重新思考API


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


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


实际上,当我们实现RecList时,我们的目标是为推荐系统的评估提供一个更通用的API,提供一些开箱即用的功能。然而,为了做到这一点,我们不得不创建几个抽象接口,供用户实现。


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


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


RecList 2.0实际应用


现在,让我们来探索如何使用RecList编写和运行评估流程的简单用例。我们将使用非常简单的模型,在输出随机数字的情况下降低了机器学习项目的复杂性。


一个简单的用例


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


n = 10000
target = [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)
# let's run some predictions
predictions = simple_model.predict()


那么,我们如何运行评估呢?


简单的RecList


RecList是一个Python类,继承了我们的RecList抽象类的功能。RecList实现了RecTests,这是一种简单的抽象,可以帮助您系统化地进行评估。例如,下面是一个可能的准确度测试。


@rec_test(test_type="Accuracy", display_type=CHART_TYPE.SCALAR)
def accuracy(self):
    """
    Compute the accuracy
    """
    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):
    """
    Compute the accuracy by slice
    """
    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):
        """
        Compute the accuracy by slice
        """
        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):
        """
        Compute the accuracy
        """
        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):
        """
        Compute the accuracy by country
        """
        # TODO: note that is a static test, 
        # used to showcase the bin display
        from random import randint
        return {"US": randint(0, 100), 
                "CA": randint(0, 100), 
                "FR": randint(0, 100)}


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


只要您的指标返回一些值,您可以以任何您喜欢的方式实现它们。例如,这个BasicRecList在特定的上下文中评估特定的模型。但是,您完全可以生成更具体的模型reclist(例如,GPT-RecList)或数据集特定的reclist(例如,IMDB-Reclist)。


运行并获取输出


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


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


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


1-2


指标也会自动进行绘图。例如,AccuracyByCountry应该显示类似于这样的内容:


1-3


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


{
  "metadata": {
    "model_name": "myRandomModel",
    "reclist": "BasicRecList",
    "tests": [
      "sliced_accuracy",
      "accuracy",
      "accuracy_by_country"
    ]
  },
  "data": [
    {
      "name": "SlicedAccuracy",
      "description": "Compute the accuracy by slice",
      "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 reclist
rlist(verbose=True)


以非常类似的方式,只需添加以下内容:


bucket=os.environ["S3_BUCKET"]


这将使我们能够使用S3存储桶来存储元数据(当然,您仍然需要设置一些环境变量)。


结论


创建RecList是为了使推荐系统的评估更加系统化和有组织。希望这次大规模的API重构能帮助人们构建更可靠的评估流程!


文章来源:https://towardsdatascience.com/reclist-2-0-open-source-systematic-testing-of-ml-models-9c62b654170c
欢迎关注ATYUN官方公众号
商务合作及内容投稿请联系邮箱:bd@atyun.com
评论 登录
热门职位
Maluuba
20000~40000/月
Cisco
25000~30000/月 深圳市
PilotAILabs
30000~60000/年 深圳市
写评论取消
回复取消