我们是如何测试人工智能的(一)基础效果篇(内含大模型的测试内容)

我们是如何测试人工智能的(一)基础效果篇(内含大模型的测试内容)

作者:山治

前言

这个系列算是科普文吧,尤其这第一篇可能会比较长,因为我这 8 年里一直在 AI 领域里做测试,涉及到的场景有些多, 我希望能尽量把我经历过的东西都介绍一下,算是给大家科普一下我们这些在 AI 领域内做测试的人,每天都在做什么事情。 当然 AI 领域很庞杂,我涉及到的可能也仅仅是一小部分,这篇帖子算是抛砖引玉,欢迎大家一起来讨论。

我打算先简单讲解一下人工智能的原理,毕竟后面要围绕这些去做测试, 并且包括了在测试大模型以及其他一些场景的时候,需要自己构建模型来辅助测试, 所以我觉得至少先讲明白迁移学习的原理,这样我们后面做模型微调定制自己的模型的时候才有据可依。

PS:由于是科普性质的,所以不会讲的特别深, 很多地方我都简化过并且翻译成大白话方便大家理解。 要是每一个点都很详细的深入的去讲,那估计都能写成本书了。

专家系统与机器学习

我们举一个信用卡反欺诈的例子, 以前的时候在银行里有一群业务专家, 他们的工作就是根据自己的知识和经验向系统中输入一些规则。例如某一张卡在一个城市有了一笔交易,之后 1 小时内在另一个城市又有了一笔交易。这些专家根据以前的经验判断这种情况是有盗刷的风险的。他们在系统中输入了 1 千多条这样的规则,组成了一个专家系统。 这个专家系统是建立在人类对过往的数据所总结出的经验下建立的。 我们可以把它就看成一个大脑,我们业务是受这个大脑控制的。但这个大脑是有极限的,我们要知道这种规则从 0 条建立到 1 条是很容易的,但是从几千条扩展到几千零一条是很难的。 因为你要保证新的规则有效,要保证它不会跟之前所有的规则冲突,所这很难,因为人的分析能力毕竟是有限的。 我听说过的最大的专家系统是百度凤巢的,好像是在 10 年的时候吧,广告系统里有 1W 条专家规则。但这是极限了,它们已经没办法往里再添加了。 所以说这是人脑的一个极限。 后来呢大家引入机器学习, 给机器学习算法中灌入大量的历史数据进行训练, 它跟人类行为很像的一点就是它可以从历史数据中找到规律,而且它的分析能力更强。 以前人类做分析的时候,可能说在反欺诈的例子里,一个小时之内的跨城市交易记录是一个规则,但如果机器学习来做的话,它可能划分的更细,例如 10 分钟之内有个权重,10 分钟到 20 分钟有个权重,1 小时 10 分钟也有个权重。 也就是说它把这些时间段拆的更细。 也可以跟其他的规则组合,例如虽然我是 1 小时内的交易记录跨越城市了,但是我再哪个城市发生了这类情况也有个权重,发生的时间也有个权重,交易数额也有权重。也就是说机器学习能帮助我们找个更多更细隐藏的更深的规则。 以前银行的专家系统有 1000 多条规则,引入了机器学习后我们生成了 8000W 条规则。 百度在引入机器学习后从 1w 条规则扩展到了几十亿还是几百亿条 (我记不清楚了)。 所以当时百度广告推荐的利润很轻易的提升了 4 倍。 我们可以把专家系统看成是一个比较小的大脑,而机器学习是更大的大脑。 所以说我们叫它机器学习,是因为它像人类一样可以从历史中库刻画出规律,只不过它比人类的分析能力更强。 所以在网上有个段子么,说机器学习就是学出来海量的 if else, 其实想想也有道理,套路都是 if 命中了这条规则,就怎么么样的,else if 命中了那个规则,就怎么怎么样的。 人类的分析能力有限么,专家系统里人类写 1 千,1w 个 if else 就到头了。 但是机器学习给你整出来几百个亿的 if else 出来。 我们就可以把机器学习想的 low 一点么,不要把它想的那么神秘。

那深度学习是什么呢, 深度学习就是机器学习的一个分支,他把基础的机器学习算法(逻辑回归),扩展成了神经网络:

在这里插入图片描述

上面是一个神经网络的结构图, 可以理解为这个神经网络里, 除了输入层外,每一个神经元(节点)都是一个逻辑回归, 这样我们的算法就更加的复杂,能够计算更加复杂的情况。 所以我们说传统的结构化数据比较少会用到深度学习, 因为结构化数据比较简单,不需要那么复杂的计算。 而为了能够计算图像和 NLP 领域内的复杂场景,才需要用到神经网络。 而深度学习就是一个拥有很多个隐藏层的神经网络,科学家们把这种情况命名为深度学习。

什么是模型

人类负责提供数据提取特征, 而算法负责学习这些特征对应的权重, 比如我们有下面这张表:

在这里插入图片描述

还是以信用卡反欺诈为例子,假设这张表中 label 列就是表明该用户是否是欺诈行为的列。 当我们告诉算法, 性别,年龄,职业和收入是有助于判断用户行为是否为欺诈行为的重要特征,那么算法就会去学习这些特征对预测最终结果的权重。 并把这些保存成一个模型。 我们可以理解为模型就是保存这些特征和权重的数据库。 比如可以简单理解为模型里保存的主要是:

在这里插入图片描述

当用户的一条数据过来后, 就要到模型里面去查询对应特征的权重了, 比如新来了一条数据,是男性,收入 2300,年龄 24,职业是程序员。那么算法的计算过程就是:y = 男性 0.1 + 程序员 0.22 + 23000.3 + 24 * 0.2 。 假设最终的结果是 0.8,代表着这条数据有 80% 的概率是信用卡欺诈行为。 然后我们自己设定一个阈值, 或者叫置信度, 比如这个值是 0.7,意思是如果模型预测这个数据是欺诈行为的概率是大于 0.7 的,那我们就让系统认为这个用户就是欺诈行为, 而如果模型预测的解雇欧式这个数据是欺诈行为的概率小于 0.7,那我们就让系统判定它是非欺诈行为,这就是一个典型的二分类模型的原理 – 算法输出的是概率,系统通过设定阈值来做最后判断。 所以算法本身的公式其实就是: y= w1x1+ w2x2 + w3x3 … wn*xn +b 。 其中 x 是特征, w 是特征对应的权重,b 是偏移量。其实模型的原理换成大白话来说还是比较简单的。

而我们说机器学习, 它学习的就是 w 和 b(因为我们特征值的已知的),算法要通过一种方式来学习什么的 w 和 b 的值能让最终的结果与真实的情况最接近, 而这个方法就叫梯度下降,但是我不打算在这里讲它的原理了, 因为毕竟我们这里是讲如何做测试的, 不懂这个梯度下降的原理也没关系。 感兴趣的同学可以查查我之前写的深度学习的帖子。

什么是迁移学习

还拿上面的例子来说明,我们已经训练好了一个模型,在这个模型中针对职业分别保存了程序员,测试人员和产品经理的特征和权重,它在当前场景下工作的很好。 我们想把这个模型放到另外一个公司里面使用,但是这个公司里除了这 3 种职业外,还有财务人员和行政人员,这样这个模型的效果就不能满足新公司的需要了。 这时候怎么办呢?再根据新公司的数据重新训练一个模型么?可以是可以, 但是这个成本可能太高了, 因为模型是要基于很大的数据进行训练的,这对数据质量和算力都有比较高的要求。 所以这时候我们可以换个思路,虽然旧的模型中没有财务人员和行政人员的记录,但是它里面的程序员,测试人员和产品经理在新公司里也有这些职位的,所以旧模型并不是完全没用,起码在这三个职位上我们还可以用旧模型工作起来。 那假如我们让算法去学习在财务和行政人员的权重后,再更新到旧的模型里,可不可以呢:

在这里插入图片描述

答案是可以的, 这就是迁移学习,也叫模型微调。 在已有的模型的基础上稍微进行调整来满足新的场景。打个比喻,就好像我们有一本练习题, 之前有位学霸已经写下了练习题的所有答案了, 后来这本练习题出了新的版本,但其实 90% 的题还是老的。 只有 10% 的题不一样,那么我们只需要把老的题的答案都照着抄下来, 我们自己去写剩下 10% 就可以了。

当然在模型微调的时候也可以修改旧模型中的特征, 比如我们觉得那位学霸在明朝历史方面的造诣不如我们自己, 那我们就可以选择在这方面更相信自己的判断,并不会全盘照抄(参数冻结,后面讲微调的时候我们会说)。

迁移学习对于人工智能的发展至关重要, 我们可以使用权威的模型(这些模型经过了时间和各个项目的考验)并进行微调以适应自己的场景。 这也为在某些场景下测试人员利用模型的能力来辅助测试场景带来了可能性(毕竟从头训练一个新模型的成本太高)

模型评估指标

接下来终于要说到如何测试模型了, 在这个领域里模型其实没有 bug 一说, 我们通过会说一个模型的效果好或者不好, 不会说这个模型有 bug – 因为世界上没有 100% 满足所有场景的模型。 那我们要如何评估模型呢。 下面以分类模型为主。分类模型就是需要模型帮我们判断这条数据属于哪些分类,比如是信用卡欺诈行为或者不是,这就是二分类。 也可以是判断目标是猫,还是狗,还是老鼠或者是人, 这种就是多分类。 一般要评估这种分类模型,我们需要统计一些标准的评估方法。 首先说一下为什么不能直接用模型预测的正确率。正确率越高说明模型效果越好, 这其实是一个普遍的误区。 举一个例子把,假设我们有一个预测癌症的场景,健康的人有 99 个 (y=0),得癌症的病人有 1 个 (y=1)。我们用一个特别糟糕的模型,永远都输出 y=0,就是让所有的病人都是健康的。这个时候我们的 “准确率” accuracy=99%,判断对了 99 个,判断错了 1 个,但是很明显地这个模型相当糟糕,在真实生活中我们大部分场景都是正/负向本相差十分悬殊的,一旦分布十分悬殊那么准确率这种简单粗暴的方法就难以表达模型真正的效果, 所以准确率往往是我们最不常用的评估方法。因此需要一种很好的评测方法,来把这些 “作弊的” 模型给揪出来。

混淆矩阵

混淆矩阵是一个用于描述分类模型性能的矩阵,它显示了模型对于每个类别的预测结果与实际结果的对比情况。

以分类模型中最简单的二分类为例,对于这种问题,我们的模型最终需要判断样本的结果是 0 还是 1,或者说是 positive 还是 negative。

我们通过样本的采集,能够直接知道真实情况下,哪些数据结果是 positive,哪些结果是 negative。同时,我们通过用样本数据跑出分类型模型的结果,也可以知道模型认为这些数据哪些是 positive,哪些是 negative。

因此,我们就能得到这样四个基础指标,我称他们是一级指标(最底层的):

真实值是positive,模型认为是positive的数量(True Positive=TP)
真实值是positive,模型认为是negative的数量(False Negative=FN)
真实值是negative,模型认为是positive的数量(False Positive=FP)
真实值是negative,模型认为是negative的数量(True Negative=TN)

将这四个指标一起呈现在表格中,就能得到如下这样一个矩阵,我们称它为混淆矩阵(Confusion Matrix):

在这里插入图片描述

多分类的混淆矩阵
当分类的结果多于两种的时候,混淆矩阵同时适用。

下面的混淆矩阵为例,我们的模型目的是为了预测样本是什么动物,这是我们的结果:

在这里插入图片描述

二级指标

但是,混淆矩阵里面统计的是个数,有时候面对大量的数据,光凭算个数,很难衡量模型的优劣。 所以我们需要在混淆矩阵的基础上引入其他几个指标

因此混淆矩阵在基本的统计结果上又延伸了如下几个个指标:

  • 召回率:recall,召回率就是说,所有得了癌症的病人中,有多少个被查出来得癌症。公式是:TP/TP+FN。 意思是真正类在所有正样本中的比率,也就是真正类率
  • 精准率:precision,还是拿刚才的癌症的例子说。精准率 (precision) 就是说,所有被查出来得了癌症的人中,有多少个是真的癌症病人。公式是 TP/TP+FP。

召回和精准理解起来可能比较绕,我多解释一下,我们说要统计召回率,因为我们要知道所有得了癌症中的人中,我们预测出来多少。因为预测癌症是我们这个模型的主要目的, 我们希望的是所有得了癌症的人都被查出来。不能说得了癌症的我预测说是健康的,这样耽误人家的病情是不行的。 但同时我们也要统计精准率, 为什么呢, 假如我们为了追求召回率,我又输入一个特别糟糕的模型,永远判断你是得了癌症的,这样真正得了癌症的患者肯定不会漏掉了。但明显这也是不行的对吧, 人家明明是健康的你硬说人家得了癌症,结果人家回去悲愤欲绝,生无可恋,自杀了。或者回去以后散尽家财,出家为僧。结果你后来跟人说我们误诊了, 那人家砍死你的心都有。 所以在统计召回的同时我们也要加入精准率, 计算所有被查出来得了癌症的人中,有多少是真的癌症病人。 说到这大家可能已经看出来召回和精准在某称程度下是互斥的, 因为他们追求的是几乎相反的目标。 有些时候召回高了,精准就会低。精准高了召回会变低。 所以这时候就要根据我们的业务重心来选择到底选择召回高的模型还是精准高的模型。 有些业务比较看重召回,有些业务比较看重精准。 当然也有两样都很看重的业务,就例如我们说的这个预测癌症的例子。或者说银行的反欺诈场景。 反欺诈追求高召回率,不能让真正的欺诈场景漏过去,在一定程度上也注重精准率,不能随便三天两头的判断错误把用户的卡给冻结了对吧,来这么几次用户就该换银行了。 所以我们还有一个指标叫 F1 score, 大家可以理解为是召回和精准的平均值,在同时关注这两种指标的场景下作为评估维度。F1 = 2PR/(P+R) 其中,P 代表 Precision,R 代表 Recall。

多分类评估举例

在这里插入图片描述

将多分类混淆矩阵二分化,以猫为例,我们可以将上面的图合并为二分问题:

Accuracy

在总共 66 个动物中,我们一共预测对了 10 + 15 + 20=45 个样本,所以准确率(Accuracy)=45/66 = 68.2%。

Precision

所以,以猫为例,模型的结果告诉我们,66 只动物里有 13 只是猫,但是其实这 13 只猫只有 10 只预测对了。模型认为是猫的 13 只动物里,有 1 条狗,两只猪。所以,Precision(猫)= 10/13 = 76.9%

Recall

以猫为例,在总共 18 只真猫中,我们的模型认为里面只有 10 只是猫,剩下的 3 只是狗,5 只都是猪。这 5 只八成是橘猫,能理解。所以,Recall(猫)= 10/18 = 55.6%

F1-Score

通过公式,可以计算出,对猫而言,F1-Score=(2 * 0.769 * 0.556)/( 0.769 + 0.556)= 64.54%

ROA 与 AUC

ROC(Receiver Operating Characteristic Curve)和 AUC(Area Under Curve)是评价分类模型性能的指标,常用于二分类问题。
ROC 曲线是将真阳性率(True Positive Rate,TPR)和假阳性率(False Positive Rate,FPR)在不同阈值下的表现绘制成的曲线。TPR(也称为敏感性)表示正类样本中正确识别的正类样本所占的比例,而 FPR(1-特异性)表示负类样本中错误识别为正类样本的负类样本所占的比例。

AUC 则是 ROC 曲线下的面积,用来量化模型的分类能力。AUC 越大,表示模型的分类性能越好。

在二分类问题中,ROC 曲线一般是从左上角到右下角,曲线下的面积(AUC)为 0.5,表示模型对正负类的预测概率相等。如果 AUC 大于 0.5,表示模型对正类预测较好,如果 AUC 小于 0.5,表示模型对负类预测较好。

ROC 曲线和 AUC 可以作为评估分类模型性能的参考指标,并且可以帮助选择合适的分类阈值。

在这里插入图片描述

一般在一些机器学习的库中,会有相关的算法去统计 AUC 指标,比如在 spark 库中:

from pyspark.ml.evaluation import BinaryClassificationEvaluator
from pyspark.ml.feature import VectorAssembler
from pyspark.sql import SparkSession
from pyspark.sql.types import StructType, StructField, DoubleType, IntegerType


spark = SparkSession.builder \
    .appName("AUC Calculation") \
    .getOrCreate()

data = [(0, 1.0), (1, 0.9), (0, 0.8), (1, 0.7), (0, 0.6), (1, 0.5), (0, 0.4), (1, 0.3), (0, 0.2), (1, 0.1)]

# 定义数据模式
schema = StructType([
    StructField("label", IntegerType(), True),
    StructField("probability", DoubleType(), True)
])

# 将数据转换为 DataFrame
df = spark.createDataFrame(data, schema=schema)


# 计算 AUC
evaluator = BinaryClassificationEvaluator(rawPredictionCol="probability", labelCol="label")
auc = evaluator.evaluate(df)

print("AUC:", auc)

分组指标的统计

我们现在有了一些常用的评估指标。 但这些往往还是不够,因为我们每一个模型都是有业务场景的,业务场景有很复杂的逻辑和不同的侧重点。 以前在测试模型的时候经常的漏测场景就是忽略了业务含义而做的测试。 举个例子,我们拿某视频网站的视频推荐系统来说。 我们使用二分类模型来做推荐问题, 怎么做呢, 我们有一个用户, 同时有 2000 个视频候选集,我们分别用这些视频和用户分别用模型算出 2000 个概率,意思是每个视频用户会点击的概率。然后从高到低排序。把排行前面的视频推荐给用户。 所以我们就把一个推荐系统的问题转换为一个分类问题。只不过这里我们不设置阈值了而已。如果按照我们刚才讲的评估指标,我们计算了 AUC,召回,精准。 就可以了么,大家想一想这样做有没有什么问题? 问题是这些指标的统计都是建立在所有测试集下进行的统计的,粒度是非常粗的。 也就是说我们并没有对测试数据进行分类。 举个例子, 在视频网站中, 新用户和新视频的点击情况可能也是比较看重的指标。 尤其是视频网站上每日新增的视频是很多的,对于新增的热点视频的曝光率也就是被推荐的概率也是很重要的维度。 假如我们有一个模型,我们测试之后发现各项指标都很好,但其实可能它对新用户或者新视频的预测并不好,只是由于新增的用户和视频在整个数据集中的占比太小了,所以从整体的评估指标上来看是比较好的。 所以一般我们测试一个模型的时候,要根据业务引入分组指标的统计。并且要保证每一个分组都有足够的样本,如果某个分组的样本数量太少,那么不足以表达它的真实效果。所以在数据采集的时候就需要注意。

其实就是需要测试人员要理解你的业务, 熟悉你的数据。 你需要了解产品的用户画像, 需要知道用户要切分成多少个分类。 比如按职业分类, 按性别分类, 按爱好分类, 按时间段分类,按年龄分分类, 按行为分类等等等等。 只要足够了解了用户和数据,测试人员才知道都需要从哪些维度评估模型的效果。 我们说搞算法测试的人 8 成时间都是在跟数据打交道, 就是因为这样。 所以比起对 AI 算法的理解, 数据处理技术可能对测试人员来说才是更重要的。比如处理结构化数据需要学习 spark,hive 这样的分布式计算框架,处理图像数据需要学习 opencv 和 ffmpeg。 因为需要对数据进行采集,分析,统计。 毕竟符合场景要求的数据不会自己飞到你面前。下一篇文章会详细介绍数据处理相关的内容, 这一次只介绍效果测试的方法。

计算机视觉下的模型效果测试

上面我们聊的所有的场景都是在结构化数据下的,通常在金融领域或者在某些互联网系统中(比如推荐系统)。 但在计算机视觉场景里,模型的评估指标会稍微有些不一样。 但其大部分的基本方法论仍然是通用的,比如召回,精准, FIcore 依然是通用的。只是在一些特殊场景里会有不同。 比如在目标检测场景中:

在这里插入图片描述

这是我周末带老婆孩子去体育场玩时拍下来的照片。 我使用这张照片输入到 yolo 模型中(计算机视觉中非常著名的算法),希望模型可以识别出图片中的人类并画出人类所在位置的长方形的框(框上面的数字是这个目标属于人类的概率)。 而这就是目标检测,同时目标检测也是计算机视觉中的基础算法,很多其他场景都需要依赖目标检测。 比如 OCR 要识别文字, 就需要先定位到文字所在的位置,所以需要先经过目标检测。

那么在这样的场景中,我们同样需要使用召回率,精准率这些指标来统计目标识别的效果,用来评估有多少真正的目标被识别出来了,又有多少非目标物体被错误的识别出来了。 但也需要额外再去评估这个框的准确性, 就是虽然目标识别出来了, 但是你画框的位置有偏差,这样就不好了。 就像我们刚才说 OCR 的流程是先跑一个目标检测把目标的位置识别出来, 然后再把目标位置的图像信息输入到另一个模型(负责文字识别),所以如果位置识别的有偏差, 可能会造成最终结果的南辕北辙。而评估这个位置的指标,我们叫 IOU。直接上代码:

# IoU是目标检测中常用的一种重叠度量,用于衡量检测框和真实标注框之间的重叠程度。IoU值越大,表示检测结果越准确。它的达标标准取决于具体的应用场景和需求。
# 在目标检测任务中,常用的IoU阈值为0.5或0.7,即当检测框与真实标注框的IoU值大于等于0.5或0.7时,认为检测结果正确。在一些特定的应用场景中,IoU阈值可能会更高或更低,比如如果用于OCR, 那么准确度要求是非常高的。

def compute_iou(box1, box2):
    # 计算两个矩形框的面积
    area1 = (box1[2] - box1[0] + 1) * (box1[3] - box1[1] + 1)
    area2 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值