当前位置:网站首页>12.机器学习基础:评估机器学习模型
12.机器学习基础:评估机器学习模型
2022-08-03 04:05:00 【好名字能更容易让朋友记住】
评估机器学习模型
机器学习的目的是得到可以**泛化(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)。如果数据中的某些数据点出现了两次(这在现实中的数据里是十分常见的),那么打乱数据并划分成训练集和验证集会导致训练集和验证集之间的数据冗余。从效果上来看,你是在部分训练数据上评估模型,这是极其糟糕的,一定要确保训练集和验证集之间没有交集。
边栏推荐
- 浏览器监听标签页关闭
- 中非合作论坛非洲产品电商推广季启动 外交部:推动中非合作转型升级
- 数字3d虚拟交互展厅顺应时代发展需求和趋势
- 找不到符号@SuperBuilder,你以为真的是Lombok的问题?
- Senior ClickHouse -
- 利用索引机制进行绕过
- 移植RT-Thread编译报错thumb conditional instruction should be in IT block
- Compose the displacement of the view
- Jincang Database Pro*C Migration Guide (3. KingbaseES Pr*oc Compatibility with Oracle Pro*c)
- leetcode刷题学习之路
猜你喜欢
随机推荐
我将GuiLite移植到了STM32F4开发板上
【uni-APP搭建项目】
(2022牛客多校五)G-KFC Crazy Thursday(二分+哈希)
AF-DNAT
第三方支付--分账对接
(一)Nacos注册中心集群环境搭建
MySQL【约束】
道通转债,微芯转债,博22转债上市价格预测
vscode hide activity bar
移植RT-Thread编译报错thumb conditional instruction should be in IT block
测开:项目管理模块-项目curd开发
金仓数据库 OCCI 迁移指南(5. 程序开发示例)
Chapter 8 Character Input Output and Input Validation
ESP8266-Arduino编程实例-MCP3008-ADC转换器驱动
urlencode 和rawurlencode的区别
js Fetch返回数据res.json()报错问题
Smart fitness gesture recognition: PP - TinyPose build AI virtual trainer!
利用索引机制进行绕过
钢铁电商行业方案:钢铁工业产品全生命周期管理解决方案
log4j设置日志的时区