- 为什么要分训练集、验证集和测试集
评估模型的重点是将数据划分为3个集合:训练集、验证集和测试集。在训练数据上训练模型,在验证数据上评估模型。一旦找到最佳参数,就在测试数据上测试。
之所以划分为3个集合而不是只有训练集和测试集,是因为在开发模型时是需要调节模型配置的,如层数或每层的大小(称为模型的超参数)。这个调节过程需要使用模型在验证数据上的性能作为反馈信息,这个调节过程本质上就是一种学习:在某个参数空间中寻找良好的模型配置。所以如果基于模型在验证集上的性能来调节模型配置。会很快导致模型在验证集上过拟合。造成这一现象的关键在于信息泄露。每次基于模型在验证集上的性能来调节模型超参数,都会有一些关于验证数据的信息泄露到模块中。如果对每个参数值调节一次,那么泄露的信息就很少,验证集仍然能够可靠地评估模型。但如果多次重复这一过程(即运行一次实验,在验证集上评估,然后据此修改模型),就会有更多的信息泄露到模型中。
最后得到的模型在验证集上的性能很好。但要关心的是在全新数据上的性能,所以引入测试集。
- 经典的评估方法
1.简单的留出验证
留出一定比例的数据作为测试集,在剩余的数据上训练模型,然后在测试集上评估模型。为防止信息泄露,不能基于测试集来调节模型,还应保留验证集。
#伪代码
num_validation_samples = 10000
#打乱数据
np.random.shuffle(data)
#定义验证集
validation_data = data[:num_validation_samples]
data = data[num_validation_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)
这种评估方法的缺点就是如果可用的数据很少,验证集和测试集包含的数据就很少,难以代表数据。而且在划分数据之前进行随机打乱,最终得到的模型性能差别很大。
2.K折验证
#伪代码
k = 4
num_validation_samples = 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] + [num_validation_samples*(fold+1):]
model = get_model()
model.train(training_data)
validation_score = model.evaluate(validation_data)
validation_scores.append(validation_score)
validation_score = np.average(validation_scores)
model = get_model()
model.train(data)
test_score = model.evaluate(test_data)
3.带有打乱数据的重复K折验证
如果可用的数据相对较少,而又需要尽可能精确地评估模型。那么可以选择带有打乱数据的重复K折验证。具体而言即多次使用K折验证。在每次将数据划分为K个分区之前都先将数据打乱。最终分数是每次K折验证分数的平均值。此方法共需要训练和评估PxK个模型。
- 评估模型的注意事项
1.数据代表性
若希望训练集和测试集都能够代表当前数据。如对图像进行分类,而样本是按类别进行排序的,若将前80%作为训练集,而将剩下的20%作为测试集。那么可能会导致训练集中只包含类别0-7,而测试集中只包含8-9。所以在将数据划分为训练集和测试集之前需要进行随机打乱。
2.时间箭头
若要根据未来预测未来(如股市走向),那么在划分前不应该随机打乱数据,因为如果打乱数据就会出现时间泄露。并且确保测试集所有数据的时间都晚于训练集数据。
3.数据冗余
如果数据中的某些数据点出现了两次,那么打乱数据并划分成训练集和测试集就会导致数据冗余,即在部分训练数据上评估模型。所以要确保训练集和测试集之间没有交集。