欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

TensorFlow 2.0 入门实战笔记(八)过拟合及其处理

程序员文章站 2022-05-02 15:13:55
...


八、过拟合及其处理

8.1 过拟合与欠拟合

fitting:拟合,就是说这个曲线能不能很好的描述这个样本,有比较好的泛化能力

过拟合(OverFititing):太过贴近于训练数据的特征了,在训练集上表现非常优秀,近乎完美的预测/区分了所有的数据,但是在新的测试集上却表现平平。

欠拟合(UnderFitting):样本不够或者算法不精确,测试样本特性没有学到,不具泛化性,拿到新样本后没有办法去准确的判断

TensorFlow 2.0 入门实战笔记(八)过拟合及其处理

解决过拟合的方法:降低数据量,正则化(L1,L2),Dropout(把其中的一些神经元去掉只用部分神经元去构建神经网络)

解决欠拟合的方法:增加训练数据,优化算法

8.2 交叉验证

更详细参考交叉验证(Cross Validation)

数据集可划分为三类:

  • 训练集——用于训练的数据集
  • 评估验证集——用于训练过程中进行评估反馈的集合,有时候也参与训练集
  • 测试集——用于验收训练结果
    TensorFlow 2.0 入门实战笔记(八)过拟合及其处理
# 分为三个集合db_train、 db_val、 db_test
(x,y),(xtest,y_test)=datasets.mnist.load_data()
xtrain,xval=tf.split(x,numor_size_splits=[50000,10000])
y_train,y_val=tf.split(y,num_or_size_splits=[50000,10000])
db_train=tf.data.Dataset.from_tensor_slices((x_train,y_train))
db_train=db_train.map(preprocess).shuffle(50000).batch(batchsz)
db_val=tf.data.Dataset.from_tensor_slices((x_val,y_val))
db_val=db_val.map(preprocess).shuffle(10000).batch(batchsz)db_test=tf.data.Dataset.from_tensor_slices((x_test,y_test))
db_test=db_test.map(preprocess).batch(batchsz)
# 建立模型
network. compile(optimizer=optimizers. Adam(Lr=0.01), loss=tf. losses. CategoricalCrossentropy(from_logit s=True), metrics=[' accuracy']
# 执行模型
# validation_data=db_val 为评估集合;validation_freq=2为每两个epochs评估一次
network. fit(db_train, epochs=5, validation_data=db_val, validation_freq=2)
# 测试
print(' Test performance:1)
network. evaluate(db_test)
 

进一步可以使用交叉验证方法,即将数据集分为训练集和测试集,其中训练集均分为N份,每个epochs随机采用N-1份作为训练集,剩余一份作为评估验证集,实现交叉验证。
TensorFlow 2.0 入门实战笔记(八)过拟合及其处理
第一种编程表达方式(原始):

for epoch in range(500): idx=tf. range(60000)
idx=tf. random. shuffle(idx) # 随机打散
xtrain, ytrain=tf. gather(x, idx[:50000]), tf. gather(y, idx[:50000]) # 5/6作为训练集
xval,y_val=tf. gather(x, idx[-10000:]), tf. gather(y, idx[-10000:]) # 1/6作为测试集
db_train=tf. data. Dataset. from_tensor_slices((x_train,y_train))
db_train=db_train. map(preprocess). shuffle(50000). batch(batchsz)
db_val=tf. data. Dataset. from_tensor_slices((x_val,y_val))
db_val=db_val. map(preprocess). shuffle(10000). batch(batchsz)
# training…
# evalutation..

第二种编程表达方式(封装):

# 其中validation_split=0.1表示评估验证集占1/10,验证方式为交叉验证;validation_freq=2为每两个epochs评估一次
network.fit(db_train_val,epochs=6,validation_split=0.1,validation_freq=2)

8.3 正则化(Regularization)

简单来说,正则化是一种为了减小测试误差的行为(有时候会增加训练误差)。我们在构造机器学习模型时,最终目的是让模型在面对新数据的时候,可以有很好的表现。当你用比较复杂的模型比如神经网络,去拟合数据时,很容易出现过拟合现象(训练集表现很好,测试集表现较差),这会导致模型的泛化能力下降,这时候,我们就需要使用正则化,降低模型的复杂度。

作者:Zero黑羽枫 链接:https://www.jianshu.com/p/569efedf6985

正则化一般分为:

l2_model=keras. models. Sequential([
	keras. layers. Dense(16, kernel_regularizer=keras. regularizers.l2(0.001), 
		activation=tf. nn. relu, input_shape=(NUM_WORDS,)),
	keras. layers. Dense(16, kerne l_regularizer=keras. regularizers.L2(0.001), 
		activation=tf. nn. relu),
	keras. layers. Dense(1, activation=tf. nn. sigmoid)
])

以上代码只是对W进行了正则化
kernel_regularizer=keras. regularizers.l2(0.001)表示对kernel,即W进行正则化,l2表示L2范数正则化,0.001表示λ=0.001

更加灵活的正则化代码:

for step, (x,y) in enumerate(db):

    with tf.GradientTape() as tape:
  		 ......
        loss = tf.reduce_mean(tf.losses.categorical_crossentropy(y_onehot, out, from_logits=True))

        # --------------正则化惩罚项--------------
        loss_regularization = []
        for p in network.trainable_variables:
            loss_regularization.append(tf.nn.l2_loss(p)) # l2范数正则化
        loss_regularization = tf.reduce_sum(tf.stack(loss_regularization))
        # --------------正则化惩罚项--------------
        loss = loss + 0.0001 * loss_regularization
 

    grads = tape.gradient(loss, network.trainable_variables)
    optimizer.apply_gradients(zip(grads, network.trainable_variables))

8.4 动量与学习率

8.4.1 动量梯度下降

动量梯度下降法是对梯度下降法的改良版本,通常来说优化效果好于梯度下降法。
普通的梯度下降法每次更新仅与当前梯度值相关,并不涉及之前的梯度。而动量梯度下降法使用指数加权平均之后梯度代替原梯度进行参数更新,将之前的梯度影响考虑在内。

更详细参考:动量梯度下降法(gradient descent with momentum)

TensorFlow 2.0 入门实战笔记(八)过拟合及其处理
以下代码中的momentum就是表示之前的梯度影响有多大,0.9表示 之前的梯度影响:现在梯度为 9:1

optimizer=SGD(learning_rate=0.02, momentum=0.9) # 随机梯度下降
optimizer=RMSprop(learning_rate=0.02, momentum=0.9)# AdaGrad算法的一种改进
optimizer=Adma(learning_rate=0.02, beta_1=0.9, beta_2=0.999) # 自适应时刻估计方法,momentum也采用自适应,无需设置

各种神经网络优化算法参考:

8.4.2 学习率调整

直接在代码中实现调整,一般设置为随着训练的进行学习率逐渐减小
Adaptive learning rate:

optimizer=SGD(learning_rate=0.2)
for epoch in range(100):
# get loss
# change learning rate 
optimizer. learning_rate=0.2*(100-epoch)/100
# update weights

8.5 其他训练Tricks

8.5.1 Early Stopping

TensorFlow 2.0 入门实战笔记(八)过拟合及其处理
在测试结果最好的时候停下并保存训练参数,称为早停法

详细内容参考深度学习技巧之Early Stopping(早停法)

8.5.2 Dropout

dropout是指在深度学习网络的训练过程中,对于神经网络单元,按照一定的概率将其暂时从网络中丢弃。
TensorFlow 2.0 入门实战笔记(八)过拟合及其处理
主要作用是减小训练负担,避免过拟合现象

TensorFlow 2.0 入门实战笔记(八)过拟合及其处理
API:

  • layer.Dropout(rate)
  • tf.nn.dropout(x, rate)

CODE:

network=Sequential([ layers. Dense(256, activation=' relu'), 
layers. Dropout(0.5),#0.5 rate to drop 
layers. Dense(128, activation=' relu'), 
layers. Dropout(0.5),#0.5 rate to drop 
layers. Dense(64, activation=' relul), 
Layers. Dense(32, activation=' relul), 
layers. Dense(10)])

在训练过程中要注意training=True而测试或者评估验证时training=False

for step,(x,y) in enumerate(db): with tf. GradientTape() as tape:
#[b,28,28]=>[b,784]
x=tf. reshape(x,(-1,28*28))
#[b,784]=>[b,10]
out=network(x, training=True)
# test out=network(x, training=False)

更详细参考:深度学习网络大杀器之Dropout——深入解析Dropout

8.5.3 【易混淆解释】Stochastic not random!

类似于按照某分布随机抽样求均值,再进行梯度更新,而不是随机的方向;
随机梯度下降法减小了计算开销。
TensorFlow 2.0 入门实战笔记(八)过拟合及其处理

相关标签: Tensorflow