本文正在参加「金石计划 . 分割6万现金大奖」
前语
本文运用 cpu 版本的 tensorflow-2.1 来阐明过拟合与欠拟合现象,并介绍多种办法来解决此类问题。
本文纲要
- 获取数据
- 处理数据并进行归一化
- 建立模型练习进程函数
- small_model 的模型练习作用
- large_model 的模型练习作用
- 在 large_model 基础上参加 L2 正则的模型练习作用
- 在 large_model 基础上参加 Dropout 的模型练习作用
- 在 large_model 基础上参加 L2 和 Dropout 的模型练习作用
- 办法总结
首要思路和实现进程
1. 获取数据
(1)本文运用的是一份 HIGGS 数据,咱们无需重视细节,只需要知道每一行数据的第一列是标签,其余列都是特征即可。
(2)能够经过这个内置的函数进行下载。
gz = tf.keras.utils.get_file('HIGGS.csv.gz', 'http://mlphysics.ics.uci.edu/data/higgs/HIGGS.csv.gz')
(3)也能够直接复制下面地址在迅雷下载到文件夹。
http://mlphysics.ics.uci.edu/data/higgs/HIGGS.csv.gz
(4)我这儿直接下载到本地,经过 pandas 进行读取前 10000 行来完成本次的使命,本次使命首要阐明过拟合和欠拟合及其解决办法,不需要关怀练习的精确程度是否能到达实际运用作用。
import tensorflow as tf
import pandas as pd
from tensorflow.keras import layers
from tensorflow.keras import regularizers
from matplotlib import pyplot as plt
N_VALIDATION = int(1e3)
N_TRAIN = int(1e4)
BUFFER_SIZE = int(1e4)
BATCH_SIZE = 500
STEPS_PER_EPOCH = N_TRAIN//BATCH_SIZE
FEATURES = 28
size_histories = {}
regularizer_histories = {}
dataset = pd.read_csv('C:/Users/QJFY-VR/.keras/datasets/HIGGS.csv.gz', names=[str(i) for i in range(29)], compression="gzip", nrows=10000)
2. 处理数据并进行归一化
(1)依照必定的比例,取 90% 的数据为练习数据,取 10% 的数据为测验数据。
train_datas = dataset.sample(frac=0.9, random_state=0)
test_datas = dataset.drop(train_datas.index)
(2)这儿首要是运用一些内置的函数来查看练习集对每一列数据的各种常见的计算目标,首要有 count、mean、std、min、25%、50%、75%、max ,这样省去了咱们的计算,在后面进行归一化操作时候直接运用即可。
train_stats = d.describe()
train_stats.pop("0")
train_stats = train_stats.transpose()
(3)数据中的第 0 列就是咱们需要猜测的回归方针,咱们将这一列从练习集和测验会集弹出,独自做成标签。
train_labels = train_datas.pop('0')
test_labels = test_datas.pop('0')
(4)这儿首要是对练习数据和测验数据进行归一化,将每个特征应独立缩放到相同范围,因为当输入数据特征值存在不同范围时,不利于模型练习的快速收敛,这个在咱们之前的文章中屡次着重并展现过了。
def norm(stats, x):
return (x - stats['mean']) / stats['std']
train_datas = norm(train_stats, train_datas)
test_datas = norm(train_stats, test_datas)
3. 建立模型练习进程函数
(1)这儿首要是将模型的配置、编译、练习都放到同一个函数中,能够适配不同的模型结构。
(2)咱们挑选了最常用的优化器 Adam ,并且将其学习率设置跟着练习迭代次数的不断添加而进行衰减,这有利于模型的练习。
(3)因为这是一个二分类分体,所以损失值咱们挑选了最常见的二分交叉熵 BinaryCrossentropy 。
(4)评价目标咱们也挑选了二分交叉熵来对练习中的模型进行作用评价。
(5)为了避免或许出现无效的过拟合,咱们还合作运用了 EarlyStopping ,在经过 50 次 epochs 后没有改善,则自动中止练习。
(6)最终函数返回了练习时的各种目标成果。
def compile_and_fit(model, optimizer=None, max_epochs=10000):
if optimizer is None:
lr_schedule = tf.keras.optimizers.schedules.InverseTimeDecay( 0.001, decay_steps=STEPS_PER_EPOCH*1000, decay_rate=1, staircase=False)
optimizer = tf.keras.optimizers.Adam(lr_schedule)
model.compile( optimizer=optimizer,
loss=tf.keras.losses.BinaryCrossentropy(from_logits=True),
metrics=[ tf.keras.losses.BinaryCrossentropy(from_logits=True, name='binary_crossentropy'), 'accuracy'])
history = model.fit(train_datas,
train_labels,
batch_size=BATCH_SIZE,
epochs=max_epochs,
validation_split = 0.2,
callbacks=[ tf.keras.callbacks.EarlyStopping(monitor='val_binary_crossentropy', patience=50) ],
verbose=2)
return history
4. small_model 的模型练习作用
(1)这儿首要是定义一个绘图函数,为后面出现的各模型制作练习进程和验证进程的 binary_crossentropy 变化情况。
def plot_history(history):
hist = pd.DataFrame(history.history)
hist['epoch'] = history.epoch
plt.figure()
plt.xlabel("Epochs")
plt.ylabel('binary_crossentropy')
plt.plot(hist['epoch'], hist['binary_crossentropy'], label='Train binary_crossentropy')
plt.plot(hist['epoch'], hist['val_binary_crossentropy'], label = 'Val binary_crossentropy')
plt.legend()
plt.show()
(2)先运用一个最简略的模型来进行模型的练习,这个模型只有一层全衔接层和一层输出层,虽然有激活函数 elu ,但是输出维度较小,最终将练习目标和验证目标进行制作。
(3)能够看出跟着 epoch 的不断添加,这个简略模型在练习进程中验证目标无限收敛于某个值,无法再进一步,练习目标还在继续优化,阐明欠拟合,这是因为模型太过简略导致的,需要加大模型的杂乱度。
small_model = tf.keras.Sequential([
layers.Dense(16, activation='elu', input_shape=(FEATURES,)),
layers.Dense(1)
])
size_histories['Small'] = compile_and_fit(small_model)
plot_history(size_histories['Small'])
5. large_model 的模型练习作用
(1)对一个比较杂乱的多层模型进行练习,这个模型中有四层全衔接层和一层输出层,每层全衔接输出 64 维,并搭配运用 elu 激活函数,全体成果较为杂乱,最终将练习目标和验证目标进行制作。
(2)能够看出跟着 epoch 的不断添加,这个模型的验证目标呈现先降后升的趋势,而练习目标呈现一直下降的趋势,这是一种典型的过拟合现象,也就是在练习会集表现杰出但是在验证集或许测验集上表现较差,咱们在后续经过参加正则和 Dropout 来按捺这一现象。
large_model = tf.keras.Sequential([
layers.Dense(64, activation='elu', input_shape=(FEATURES,)),
layers.Dense(64, activation='elu'),
layers.Dense(64, activation='elu'),
layers.Dense(64, activation='elu'),
layers.Dense(1)
])
size_histories['Large'] = compile_and_fit(large_model)
plot_history(size_histories['Large'])
6. 在 large_model 基础上参加 L2 正则的模型练习作用
(1)在上面 large_model 的基础上,每一层全衔接层多参加了 L2 正则,全体结构较为杂乱,最终将练习目标和验证目标进行制作。
(2)能够看出跟着 epoch 的不断添加,这个模型的验证目标和练习目标虽然有抖动但现已趋于正常,标明在参加 L2 正则之后对上面发生的过拟合现象起到了必定的按捺作用,但是验证目标与练习目标有必定的距离,仍然有一点欠拟合。
l2_model = tf.keras.Sequential([
layers.Dense(64, activation='elu', kernel_regularizer=regularizers.l2(0.001), input_shape=(FEATURES,)),
layers.Dense(64, activation='elu', kernel_regularizer=regularizers.l2(0.001)),
layers.Dense(64, activation='elu', kernel_regularizer=regularizers.l2(0.001)),
layers.Dense(64, activation='elu', kernel_regularizer=regularizers.l2(0.001)),
layers.Dense(1)
])
regularizer_histories['l2'] = compile_and_fit(l2_model)
plot_history(regularizer_histories['l2'])
7. 在 large_model 基础上参加 Dropout 的模型练习作用
(1)在上面 large_model 的基础上,每一层全衔接层中心参加了一层 Dropout ,全体结构较为杂乱,最终将练习目标和验证目标进行制作。
(2)能够看出跟着 epoch 的不断添加,这个模型的验证目标和练习目标都有相同的趋势,标明在参加 Dropout 之后不只对上面发生的过拟合现象起到了必定的按捺作用,并且有利于模型在验证集的泛化作用。能够看出在仅仅用一种办法的情况下,运用 Dropout 比 L2 正则的作用要更好,并且单纯运用 Dropout 的作用现已很出色了。
dropout_model = tf.keras.Sequential([
layers.Dense(64, activation='elu', input_shape=(FEATURES,)),
layers.Dropout(0.5),
layers.Dense(64, activation='elu'),
layers.Dropout(0.5),
layers.Dense(64, activation='elu'),
layers.Dropout(0.5),
layers.Dense(64, activation='elu'),
layers.Dropout(0.5),
layers.Dense(1)
])
regularizer_histories['dropout'] = compile_and_fit(dropout_model)
plot_history(regularizer_histories['dropout'])
8. 在 large_model 基础上参加 L2 和 Dropout 的模型练习作用
(1)在上面 large_model 的基础上,每一层全衔接层中不只参加了 L2 正则,并且在每一层全衔接层中心参加了一层 Dropout ,全体结构相较于上面的模型是最杂乱,最终将练习目标和验证目标进行制作。
(2)能够看出跟着 epoch 的不断添加,这个模型的验证目标和练习目标都有相同的趋势,模型在验证集和练习会集的作用同步提高,标明在参加 L2 和 Dropout 之后不只对上面发生的过拟合现象起到了必定的按捺作用,并且有利于模型在验证集的泛化作用,并且模型在保证作用的同时收敛也较快。
combined_model = tf.keras.Sequential([
layers.Dense(64, kernel_regularizer=regularizers.l2(0.0003), activation='elu', input_shape=(FEATURES,)),
layers.Dropout(0.5),
layers.Dense(64, kernel_regularizer=regularizers.l2(0.0003), activation='elu'),
layers.Dropout(0.5),
layers.Dense(64, kernel_regularizer=regularizers.l2(0.0003), activation='elu'),
layers.Dropout(0.5),
layers.Dense(64, kernel_regularizer=regularizers.l2(0.0003), activation='elu'),
layers.Dropout(0.5),
layers.Dense(1)
])
regularizer_histories['combined'] = compile_and_fit(combined_model)
plot_history(regularizer_histories['combined'])
办法总结
其实因为深度学习模型的杂乱程度,咱们最常见到的就是过拟合现象,欠拟合现象较为少碰到,结合上文在这做一下总结。
应对欠拟合的办法总结:
- 加大模型杂乱程度
- 运用更多的数据集
- 数据增强
应对过拟合的办法总结:
- 减小模型杂乱程度
- 运用更多的数据集
- 数据增强
- 运用 L1 、L2 正则
- 运用 Dropout
- 结合运用正则和 Dropout
- 数据归一化