如何做360网站优化,有人有免费的片资源吗,阿里云上如何用iis做网站,广告联盟全自动赚钱系统根据前面我的文章看来#xff0c;咱们只能控制可以观察到的东西。因为您的目标是开发出能够成功泛化到新数据的模型#xff0c;所以能够可靠地衡量模型泛化能力是至关重要的#xff0c;咱们这篇文章将正式介绍评估机器学习模型的各种方法。 政安晨的个人主页#xff1a;政安…根据前面我的文章看来咱们只能控制可以观察到的东西。因为您的目标是开发出能够成功泛化到新数据的模型所以能够可靠地衡量模型泛化能力是至关重要的咱们这篇文章将正式介绍评估机器学习模型的各种方法。 政安晨的个人主页政安晨 欢迎 点赞✍评论⭐收藏 收录专栏: 政安晨的机器学习笔记 希望政安晨的博客能够对您有所裨益如有不足之处欢迎在评论区提出指正 本系列的前一篇文章为
政安晨【机器学习基础】一—— 泛化机器学习的目标https://blog.csdn.net/snowdenkeke/article/details/136275013 训练集、验证集和测试集
评估模型的重点是将可用数据划分为三部分训练集、验证集和测试集。
在训练数据上训练模型在验证数据上评估模型。模型准备上线之前在测试数据上最后测试一次测试数据应与生产数据尽可能相似。做完这些工作之后就可以在生产环境中部署该模型。
你可能会问为什么不将数据划分为两部分即训练集和测试集在训练数据上进行训练在测试数据上进行评估。这样做简单多了。
原因在于开发模型时总是需要调节模型配置比如确定层数或每层大小这些叫作模型的超参数hyperparameter以便与参数权重区分开。这个调节过程需要使用模型在验证数据上的表现作为反馈信号。
该过程本质上是一种学习过程在某个参数空间中寻找良好的模型配置。因此基于模型在验证集上的表现来调节模型配置很快会导致模型在验证集上过拟合即使你并没有在验证集上直接训练模型。造成这一现象的核心原因是信息泄露information leak。
每次基于模型在验证集上的表现来调节模型超参数都会将验证数据的一些信息泄露到模型中。如果对每个参数只调节一次那么泄露的信息很少验证集仍然可以可靠地评估模型。但如果多次重复这一过程运行一次实验在验证集上评估然后据此修改模型那么会有越来越多的验证集信息泄露到模型中。
最后得到的模型在验证数据上的表现非常好——这是人为造成的因为这正是你优化模型的目的。你关心的是模型在全新数据上的表现而不是在验证数据上的表现因此你需要一个完全不同、前所未见的数据集来评估模型这就是测试集。
你的模型一定不能读取与测试集有关的任何信息间接读取也不行如果基于测试集表现对模型做了任何调节那么对泛化能力的衡量将是不准确的。
将数据划分为训练集、验证集和测试集看起来可能很简单但如果可用数据很少那么有几种高级方法可以派上用场。
我们将介绍三种经典的评估方法简单的留出验证、K折交叉验证以及带有打乱数据的重复K折交叉验证。我们还会介绍使用基于常识的基准以判断模型训练是否有效。
简单的留出验证
留出一定比例的数据作为测试集。在剩余的数据上训练模型然后在测试集上评估模型。如前所述为防止信息泄露你不能基于测试集来调节模型所以还应该保留一个验证集。
下图展示了留出验证的原理并且往下代码给出了其简单实现 留出验证下段代码省略了标签不可执行
num_validation_samples 10000# 通常需要打乱数据
np.random.shuffle(data)# 定义验证集
validation_data data[:num_validation_samples]# 定义训练集
training_data data[num_validation_samples:]# (本行及以下2行)在训练数据上训练模型然后在验证数据上评估模型
model get_model()
model.fit(training_data, ...)
validation_score model.evaluate(validation_data, ...)# 现在可以对模型进行调节、重新训练、评估然后再次调节
...# (本行及以下3行)调节好模型的超参数之后通常的做法是在所有非测试数据上从头开始训练最终模型
model get_model()model.fit(np.concatenate([training_data,validation_data]), ...)test_score model.evaluate(test_data, ...)
这是最简单的评估方法但它有一个缺点如果可用的数据很少那么可能验证集包含的样本就很少无法在统计学上代表数据。
这个问题很容易发现在划分数据前进行不同的随机打乱如果最终得到的模型性能差别很大那么就存在这个问题。接下来会介绍解决这一问题的两种方法K折交叉验证和重复K折交叉验证。
K折交叉验证
K折交叉验证是指将数据划分为K个大小相等的分区。
对于每个分区i在剩余的K-1个分区上训练模型然后在分区i上评估模型。最终分数等于K个分数的平均值。对于不同的训练集−测试集划分如果模型的性能变化很大那么这种方法很有用。与留出验证一样这种方法也需要独立的验证集来校准模型。
下图展示了K折交叉验证的原理下面代码给出了其简单实现 K折交叉验证省略了标签
k 3
num_validation_samples len(data) // k
np.random.shuffle(data)
validation_scores []
for fold in range(k):# (本行及以下1行)选择验证数据分区validation_data data[num_validation_samples * fold:num_validation_samples * (fold 1)]# (本行及以下2行)使用剩余数据作为训练数据。注意运算符表示列表拼接不是加法training_data np.concatenate(data[:num_validation_samples * fold],data[num_validation_samples * (fold 1):])# 创建一个全新的模型实例未训练model get_model()model.fit(training_data, ...)validation_score model.evaluate(validation_data, ...)validation_scores.append(validation_score)# 最终验证分数K折交叉验证分数的平均值
validation_score np.average(validation_scores)# (本行及以下2行)在所有非测试数据上训练最终模型
model get_model()
model.fit(data, ...)
test_score model.evaluate(test_data, ...)
带有打乱数据的重复K折交叉验证
如果可用的数据相对较少而你又需要尽可能精确地评估模型那么可以使用带有打乱数据的重复K折交叉验证。
您会发现这种方法在Kaggle竞赛中特别有用具体做法是多次使用K折交叉验证每次将数据划分为K个分区之前都将数据打乱。最终分数是每次K折交叉验证分数的平均值。注意这种方法一共要训练和评估P * K个模型P是重复次数计算代价很大。
超越基于常识的基准
除了不同的评估方法你还应该了解的是利用基于常识的基准。
训练深度学习模型就好比在平行世界里按下发射火箭的按钮你听不到也看不到。你无法观察流形学习过程它发生在数千维空间中即使投影到三维空间中你也无法解释它。唯一的反馈信号就是验证指标就像隐形火箭的高度计。
特别重要的是我们需要知道火箭是否离开了地面。发射地点的海拔高度是多少模型似乎有15%的精度——这算是很好吗在开始处理一个数据集之前你总是应该选择一个简单的基准并努力去超越它。如果跨过了这道门槛你就知道你的方向对了——模型正在使用输入数据中的信息做出具有泛化能力的预测你可以继续做下去。这个基准既可以是随机分类器的性能也可以是你能想到的最简单的非机器学习方法的性能。 比如对于MNIST数字分类示例一个简单的基准是验证精度大于0.1随机分类器对于IMDB示例基准可以是验证精度大于0.5。对于路透社示例由于类别不均衡因此基准约为0.180.19。对于一个二分类问题如果90%的样本属于类别A10%的样本属于类别B那么一个总是预测类别A的分类器就已经达到了0.9的验证精度你需要做得比这更好。 在面对一个全新的问题时你需要设定一个可以参考的基于常识的基准这很重要。如果无法超越简单的解决方案那么你的模型毫无价值——也许你用错了模型也许你的问题根本不能用机器学习方法来解决。这时应该重新思考解决问题的思路。
模型评估的注意事项
选择模型评估方法时需要注意以下几点
数据代表性data representativeness。训练集和测试集应该都能够代表当前数据。假设你要对数字图像进行分类而初始样本是按类别排序的如果你将前80%作为训练集剩余20%作为测试集那么会导致训练集中只包含类别07而测试集中只包含类别8和9。这个错误看起来很可笑但非常常见。因此将数据划分为训练集和测试集之前通常应该随机打乱数据。
时间箭头the arrow of time。如果想根据过去预测未来比如明日天气、股票走势等那么在划分数据前不应该随机打乱数据因为这么做会造成时间泄露temporal leak模型将在未来数据上得到有效训练。对于这种情况应该始终确保测试集中所有数据的时间都晚于训练数据。
数据冗余redundancy in your data。如果某些数据点出现了两次这对于现实世界的数据来说十分常见那么打乱数据并划分成训练集和验证集将导致训练集和验证集之间出现冗余。从效果上看你将在部分训练数据上评估模型这是极其糟糕的。一定要确保训练集和验证集之间没有交集。
有了评估模型性能的可靠方法你就可以监控机器学习的核心矛盾——优化与泛化之间的矛盾以及欠拟合与过拟合之间的矛盾。
改进模型拟合
为了实现完美的拟合你必须首先实现过拟合。由于事先并不知道界线在哪里因此你必须穿过界线才能找到它。在开始处理一个问题时你的初始目标是构建一个具有一定泛化能力并且能够过拟合的模型。得到这样一个模型之后你的重点将是通过降低过拟合来提高泛化能力。
在这一阶段你会遇到以下3种常见问题
训练不开始训练损失不随着时间的推移而减小。
训练开始得很好但模型没有真正泛化模型无法超越基于常识的基准。
训练损失和验证损失都随着时间的推移而减小模型可以超越基准但似乎无法过拟合这表示模型仍然处于欠拟合状态。
我们来看一下如何解决这些问题从而抵达机器学习项目的第一个重要里程碑
得到一个具有一定泛化能力可以超越简单的基准并且能够过拟合的模型。
调节关键的梯度下降参数
有时训练不开始或者过早停止。损失保持不变。这个问题总是可以解决的——请记住对随机数据也可以拟合一个模型。即使你的问题毫无意义也应该可以训练出一个模型不过模型可能只是记住了训练数据。
出现这种情况时问题总是出在梯度下降过程的配置优化器、模型权重初始值的分布、学习率或批量大小。所有这些参数都是相互依赖的因此保持其他参数不变调节学习率和批量大小通常就足够了。
咱们来看一个具体的例子
训练MNIST模型但选取一个过大的学习率取值为1代码如下所示
使用过大的学习率训练MNIST模型
(train_images, train_labels), _ mnist.load_data()
train_images train_images.reshape((60000, 28 * 28))
train_images train_images.astype(float32) / 255model keras.Sequential([layers.Dense(512, activationrelu),layers.Dense(10, activationsoftmax)
])
model.compile(optimizerkeras.optimizers.RMSprop(1.),losssparse_categorical_crossentropy,metrics[accuracy])
model.fit(train_images, train_labels,epochs10,batch_size128,validation_split0.2)
这个模型的训练精度和验证精度很快就达到了30%40%但无法超出这个范围。下面我们试着把学习率降低到一个更合理的值1e-2代码如下所示
使用更合理的学习率训练同一个模型
model keras.Sequential([layers.Dense(512, activationrelu),layers.Dense(10, activationsoftmax)
])
model.compile(optimizerkeras.optimizers.RMSprop(1e-2),losssparse_categorical_crossentropy,metrics[accuracy])
model.fit(train_images, train_labels,epochs10,batch_size128,validation_split0.2) 注要使用上述代码进行训练您还需先准备如下工作再执行上述代码 import tensorflow
from tensorflow import keras
from tensorflow.keras import layersfrom tensorflow.keras.datasets import mnist(train_images, train_labels), _ mnist.load_data()
train_images train_images.reshape((60000, 28 * 28))
train_images train_images.astype(float32) / 255 演绎如下 现在模型可以正常训练了。
如果你自己的模型出现类似的问题那么可以尝试以下做法 降低或提高学习率。学习率过大可能会导致权重更新大大超出正常拟合的范围就像前面的例子一样。学习率过小则可能导致训练过于缓慢以至于几乎停止。增加批量大小。如果批量包含更多样本那么梯度将包含更多信息且噪声更少方差更小。最终你会找到一个能够开始训练的配置。 利用更好的架构预设
你有了一个能够拟合的模型但由于某些原因验证指标根本没有提高。这些指标一直与随机分类器相同也就是说模型虽然能够训练但并没有泛化能力。这是怎么回事
这也许是你在机器学习中可能遇到的最糟糕的情况。这表示你的方法从根本上就是错误的而且可能很难判断问题出在哪里。下面给出一些提示
首先你使用的输入数据可能没有包含足够的信息来预测目标。也就是说这个问题是无法解决的。前面我们试图拟合一个标签被打乱的MNIST模型它就属于这种情况模型可以训练得很好但验证精度停留在10%因为这样的数据集显然是不可能泛化的。
其次你使用的模型类型可能不适合解决当前问题。对于一个时间序列预测问题的示例密集连接架构的性能无法超越简单的基准而更加合适的循环架构则能够很好地泛化。模型能够对问题做出正确的假设这是实现泛化的关键你应该利用正确的架构预设。
未来年还会学到针对各种数据模式的最佳架构这些数据模式包括图像、文本、时间序列等。总体来说你应该充分调研待解决任务的架构最佳实践因为你可能不是第一个尝试解决这个任务的人。
提高模型容量
如果你成功得到了一个能够拟合的模型验证指标正在下降而且模型似乎具有一定的泛化能力那么您就快要成功了。接下来你需要让模型过拟合。
考虑下面这个小模型如下代码所示它是在MNIST上训练的一个简单的logistic回归模型。
model keras.Sequential([layers.Dense(10, activationsoftmax)])
model.compile(optimizerrmsprop,losssparse_categorical_crossentropy,metrics[accuracy])
history_small_model model.fit(train_images, train_labels,epochs20,batch_size128,validation_split0.2)
演绎如下 模型得到的损失曲线如下所示
import matplotlib.pyplot as plt
val_loss history_small_model.history[val_loss]
epochs range(1, 21)
plt.plot(epochs, val_loss, b--,labelValidation loss)
plt.title(Effect of insufficient model capacity on validation loss)
plt.xlabel(Epochs)
plt.ylabel(Loss)
plt.legend()
演绎如下 上图为模型容量不足对损失曲线的影响。
验证指标似乎保持不变或者改进得非常缓慢而不是达到峰值后扭转方向。
验证损失达到了0.26然后就保持不变。
你可以拟合模型但无法实现过拟合即使在训练数据上多次迭代之后也无法实现。
在你的职业生涯中你可能会经常遇到类似的曲线。
请记住任何情况下应该都可以实现过拟合。与训练损失不下降的问题一样这个问题也总是可以解决的。如果无法实现过拟合可能是因为模型的表示能力representational power存在问题你需要一个容量capacity更大的模型也就是一个能够存储更多信息的模型。若要提高模型的表示能力你可以添加更多的层、使用更大的层拥有更多参数的层或者使用更适合当前问题的层类型也就是更好的架构预设。
我们尝试训练一个更大的模型它有两个中间层每层有96个单元
model keras.Sequential([layers.Dense(96, activationrelu),layers.Dense(96, activationrelu),layers.Dense(10, activationsoftmax),
])
model.compile(optimizerrmsprop,losssparse_categorical_crossentropy,metrics[accuracy])
history_large_model model.fit(train_images, train_labels,epochs20,batch_size128,validation_split0.2)
演绎如下 现在验证曲线看起来正是它应有的样子模型很快拟合并在8轮之后开始过拟合如下图所示
代码如下
import matplotlib.pyplot as plt
val_loss history_large_model.history[val_loss]
epochs range(1, 21)
plt.plot(epochs, val_loss, b--,labelValidation loss)
plt.title(Effect of insufficient model capacity on validation loss)
plt.xlabel(Epochs)
plt.ylabel(Loss)
plt.legend()
演绎和图如下 至此咱们这篇文章的讲解目标达到。