在真实的应用中,我们往往想要的不仅仅是模型能够在训练集上表现良好,而是希望训练得到的模型也能在未知的新输入数据上(这些新输入数据就是测试集)表现良好。这种能在未知的新输入数据上表现良好的能力被称为泛化。模型在未知的新输入数据上得到的误差称为泛化误差,或测量误差,我们也希望泛化误差很低。在降低训练误差和测试误差的过程中,我们就面临着机器学习中的两大挑战:过拟合和欠拟合。欠拟合是指模型不能够在训练集上获得足够低的误差,而过拟合是指训练误差和测试误差之间差距太大。
通常可以通过调整机器学习算法模型的容量来控制模型是否偏向于过拟合或欠拟合。通俗来讲,模型的容量是指其拟合各种函数的能力,如果容量适合于任务的复杂度和所提供的数据的规模,算法就会表现出不错的效果。容量不足的模型因为难以拟合训练集而出现欠拟合的现象,容量高的模型能够解决复杂的任务,但是当其容量高于任务所需时,可能会因为很好的记忆了每一个训练数据中随机噪音的分布导致忽略了对训练数据中通用趋势的学习,从而出现过拟合现象。
那么如何检测过拟合呢?
先来看普通的验证方法,即将整个数据集划分为三部分:训练集、验证集、测试集,划分代码如下:
x_train,x_val = tf.split(x,num_or_size_splits=[50000,10000])
y_train,y_val = tf.split(y,num_or_size_splits=[50000,10000])
但是这种方式使得数据并不能被充分利用,即验证集的数据不参与反向传播,那么如何做才能既检验过拟合又能使验证集参与到训练过程中呢?
这里有一个方法叫交叉验证,通俗点说就是先将训练集和验证集合并,然后将总的集合划分为N份,每次取N-1份做训练,1份做验证即可,这样交叉进行,可以保证网络不会形成记忆。
代码如下:
for epoch in range(500): idx = tf.range(60000) idx = tf.random.shuffle(idx) x_train,y_train = tf.gather(x,idx[:50000]),tf.gather(y,idx[:50000]) x_val,y_val = tf.gather(x,idx[-10000:]),tf.gather(y,idx[-10000:]) db_train = tf.data.Dataset.from_tensor_slices((x_train,y_train)) db_train = db_train.map(preprocess).shuffle(50000).batch(batchsize) db_val = tf.data.Dataset.from_tensor_slices((x_val,y_val)) db_val = db_val.map(preprocess).batch(batchsize)
# training
# evaluate
tf.keras提供了一个更简单的方法,代码如下:
network.fit(db_total,epochs=6,validation_split=0.1,validation_freq=1)
validation_split参数指定了从总数据集中分离出验证集的比例,如0.1代表每个epoch有十分之一的数据被用作验证集