12.机器学习基础:评估机器学习模型

评估机器学习模型

机器学习的目的是得到可以**泛化(generalize)**的模型,即在前所未见的数据上表现很好的模型,而过拟合则是核心难点。你只能控制可以观察的事情,所以能够可靠地衡量模型的泛化能力非常重要。

训练集、验证集和测试集

评估模型的重点是将数据划分为三个集合:训练集、验证集和测试集。在训练数据上训练,在验证数据上评估模型。一道找到了最佳参数,就在测试数据上最后测试一次。

为何不将数据分为训练集和测试集呢?因为在于开发模型时总是需要调节模型配置,比如选择层数或每层大小(这叫做模型的超参数,以便与模型参数,即权重区分开)。这个调节过程需要使用模型在验证数据上的性能作为反馈信号。这个调节过程本质上就是一种学习:在某个参数空间中寻找良好的模型配置。因此,如果基于模型在验证集上的性能来调节模型配置,会很快导致模型在验证集上过拟合,即使你并没有在验证集上直接训练模型也会如此。

造成这种现象的关键在于信息泄露(information leak)。每次基于模型的验证集上的性能来调节模型超参数,都会有一些关于验证数据的信息泄漏到模型中。

最后,得到的模型在验证集上的性能非常好(人为造成的),因为这是优化的目的。你关心的是模型在全新数据上的性能,而不是在验证数据上的性能,因此你需要使用一个完全不同的数据集来评估模型,也就是测试集。

将数据划分为训练集、验证集和测试集很简单,但是在数据很少的时候,还有几种高级方法可以排上用场。如以下三种:简单的留出验证、K折验证,以及带有打乱数据的重复K折验证。

简单的留出验证

留出一定比例的数据作为验证集。在剩余的数据上训练模型,然后在测试集上评估模型。留出验证(hold-out validation)的示意图见下

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fbdzctE8-1659358739960)(D:\桌面杂物\Markdown笔记\CSDN博客\Python深度学习\img\简单的留出验证数据划分.png)]

代码如下

num_validation_samples = 10000

# 打乱数据
np.random.shuffle(data)

# 定义验证集
validation_data = data[:num_valdation_samples]

# 定义训练集
training_data = data[:]

# 在训练数据上训练模型并在验证数据上评估模型
model = get_model()
model.train(training_data)
validation_score = model.evaluate(validation_data)

# 此时进行模型的调节,重新训练、评估,然后再次调节。

#调节结束,通常就在所有非测试数据上从头开始训练最终模型
model = get_model()
model.train(np.concatenate([training_data,
                            validation_data]))
test_score = model.evaluate(test_data)

这是最简单的评估方法,但有一个缺点:如果可用的数据很少,那么可能验证集和测试集包含的样本就太少,从而无法在统计学上代表数据。这个问题很容易发现:如果在划分数据前进行不同的随机打乱,最终得到的模型性能差别很大,那么就存在这个问题。

K折验证

K折验证(K-fold validation)将会数据划分为大小相同的K个分区。对于每个分区 i ,在剩余的 K-1 个分区上训练模型,然后再分区 i 上进行评估模型。最终分数等于 K个分数的平均值·。对于不同的训练集-测试集划分,如果模型性能的变化很大,那么这种方法很有用。与留出验证一样,这种方法也需要独立的验证集进行模型矫正。

在这里插入图片描述

代码如下:

k = 4
num_validation_sampels = len(data) // k

np.random.shuffle(data)

validation_scores = []
for fold in range(k):
	# 选择验证数据分区
    validation_data = data[num_validation_samples * fold: num_validation_samples * (fold + 1)]
    # 训练数据分区,即测试数据中除了验证分区外的所有数据
    training_data = data[:num_validation_samples * fold] + data[num_validation * (flod + 1):]
    
    # 创建一个全新的模型实例(未训练的)
    mdoel = get_model()
    model.train(training_data)
    validation_score = model.evaluate(validation_data)
    validation_scores.append(validation_score)
# 最终验证分数:K折验证分数的平均值
validation_score = np.average(validation_scores)
# 在所有非测试数据上训练最终模型
model = get_model()
model.train(data)
test_score = model.evaluate(test_data)
带有打乱数据的重复K折验证

如果可用数据相对较少,而你又需要尽可能精确地评估模型,那么可以选择带有打乱数据的重复K折验证。该方法在Kaggle竞赛中特别有用。

具体做法是多次使用K折验证,然后将数据划分为K个分区之间都将数据打乱。最终分数是每次K折验证分数的平均值。但值得注意的是,这种方法一共需要评估 P×K 个模型(P是重复次数),计算代价很大。

评估模型的注意事项

  • **数据代表性(data representativeness)。**你希望训练集和测试集都能够代表当前数据。例如,你如果想要对数字图像进行分类,而图像样本是按类别排序的,如果你将前80%作为训练集,剩余20%作为测试集,那么只会导致训练集中只包含类别07,而测试集中只包含类别89。因此,数据划分为训练集和测试集之前,通常应该随机打乱数据
  • 时间箭头(the arrow of time)。如果想要根据过去预测未来(比如明天的天气、股票走势等),那么在划分数据前你不应该suiji打乱数据,因为这么做会造成时间泄露(temporal leak):你的模型将在未来数据上得到有效的训练。在这种情况下,你应该始终确保测试集中所有数据的时间都晚于训练集数据。
    i打乱数据,因为这么做会造成时间泄露(temporal leak):你的模型将在未来数据上得到有效的训练。在这种情况下,你应该始终确保测试集中所有数据的时间都晚于训练集数据。
  • 数据冗余(redundancy)。如果数据中的某些数据点出现了两次(这在现实中的数据里是十分常见的),那么打乱数据并划分成训练集和验证集会导致训练集和验证集之间的数据冗余。从效果上来看,你是在部分训练数据上评估模型,这是极其糟糕的,一定要确保训练集和验证集之间没有交集。
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值