人工智能小白日记之15 ML学习篇之11训练神经网络 Training Neural Network
前言
这一篇单独列出来,说明对于神经网络的训练可是不太容易的,从上一篇的练习中就可以看出来。上一篇发现重复训练的时候初始化情况可能不太一样,然后节点数太多就会很慢,节点太少可能欠拟合。总之,很蛋疼,看看这篇怎么说的吧
课程内容
1 反向传播算法
这个算法演示还是要看看的,很清晰明了,算法描述了在训练神经网络过程中如何传递数据,以及如何通过反向传播调节节点权重的。这也为我们揭开了神经网络是如何训练出来的这个神秘面纱。
https://google-developers.gonglchuangl.net/machine-learning/crash-course/backprop-scroll/
反向传播依赖于梯度,各种函数中存在一两个小的间断点没关系, 但一般来说,我们需要可微函数, 从而能够使用神经网络进行学习。演示里使用了大量的微分,如果不可微是无法继续推导的。
2 神经网络训练注意事项
很多常见情况都会导致反向传播算法出错。
2-1 梯度消失
当设置的层数太多时,较低层(更接近输入)的梯度可能会变得非常小。在深度网络中,计算这些梯度时,可能涉及许多小项的乘积。当较低层的梯度逐渐消失到 0 时,这些层的训练速度会非常缓慢,甚至不再训练。
因此,需要控制在最小有效深度,同时默认的ReLU 激活函数有助于防止梯度消失。
2-2 梯度爆炸
如果网络中的权重过大,则较低层的梯度会涉及许多大项的乘积。在这种情况下,梯度就会爆炸:梯度过大导致难以收敛。
批标准化可以降低学习速率,因而有助于防止梯度爆炸。
批标准化类似归一但是有所不同,其目的是在激活函数之前对y= Wx + b进行规范化,使结果(输出信号的各个维度)的均值都为0,方差为1,让每一层的输入有一个稳定的分布会有利于网络的训练。相关资料:https://blog.csdn.net/fontthrone/article/details/76652772
2-3 ReLU 单元消失
ReLU函数表达式为max(0,x),一旦 ReLU 单元的加权和低于 0,ReLU 单元就可能会停滞。它会输出对网络输出没有任何贡献的 0 激活,而梯度在反向传播算法期间将无法再从中流过。由于梯度的来源被切断,ReLU 的输入可能无法作出足够的改变来使加权和恢复到 0 以上。
降低学习速率有助于防止 ReLU 单元消失。
3 丢弃正则化
这是称为丢弃的另一种形式的正则化,可用于神经网络。其工作原理是,在梯度下降法的每一步中随机丢弃一些网络单元。丢弃得越多,正则化效果就越强:
- 0.0 = 无丢弃正则化。
- 1.0 = 丢弃所有内容。模型学不到任何规律。
- 0.0 和 1.0 之间的值更有用。
4 编程练习
4-1 老生常谈
前戏跟上一篇一样,同样的加载数据->特征,标签->特征列->输入函数
->DNNRegressor神经网络模型->训练
_ = train_nn_regression_model(
my_optimizer=tf.train.GradientDescentOptimizer(learning_rate=0.0007),
steps=5000,
batch_size=70,
hidden_units=[10, 10],
training_examples=training_examples,
training_targets=training_targets,
validation_examples=validation_examples,
validation_targets=validation_targets)
运行一下:
作为老司机,我们知道还要在多跑几次
曲线还是不够平滑
4-2 任务 1:使用线性缩放将特征标准化
将输入标准化以使其位于 (-1, 1) 范围内可能是一种良好的标准做法。这样一来,SGD 在一个维度中采用很大步长(或者在另一维度中采用很小步长)时不会受阻。
花费 5 分钟左右的时间来训练和评估新标准化的数据。您能达到什么程度的效果?
一般来说,当输入特征大致位于相同范围时,神经网络的训练效果最好。
对您的标准化数据进行健全性检查。(如果您忘了将某个特征标准化,会发生什么情况?)
给出了线性缩放函数:
def linear_scale(series):
min_val = series.min()
max_val = series.max()
scale = (max_val - min_val) / 2.0
return series.apply(lambda x:((x - min_val) / scale) - 1.0)
对所有特征进行对应缩放即可:
def normalize_linear_scale(examples_dataframe):
"""Returns a version of the input `DataFrame` that has all its features normalized linearly."""
processed_features = pd.DataFrame()
processed_features["latitude"] = linear_scale(examples_dataframe["latitude"])
processed_features["longitude"] = linear_scale(examples_dataframe["longitude"])
processed_features["housing_median_age"] = linear_scale(examples_dataframe["housing_median_age"])
processed_features["total_rooms"] = linear_scale(examples_dataframe["total_rooms"])
processed_features["total_bedrooms"] = linear_scale(examples_dataframe["total_bedrooms"])
processed_features["population"] = linear_scale(examples_dataframe["population"])
processed_features["households"] = linear_scale(examples_dataframe["households"])
processed_features["median_income"] = linear_scale(examples_dataframe["median_income"])
processed_features["rooms_per_person"] = linear_scale(examples_dataframe["rooms_per_person"])
return processed_features
normalized_dataframe = normalize_linear_scale(preprocess_features(california_housing_dataframe))
normalized_training_examples = normalized_dataframe.head(12000)
normalized_validation_examples = normalized_dataframe.tail(5000)
_ = train_nn_regression_model(
my_optimizer=tf.train.GradientDescentOptimizer(learning_rate=0.005),
steps=2000,
batch_size=50,
hidden_units=[10, 10],
training_examples=normalized_training_examples,
training_targets=training_targets,
validation_examples=normalized_validation_examples,
validation_targets=validation_targets)
nice,再跑几次
稳定有木有
4-3 任务 2:尝试其他优化器
** 使用 AdaGrad 和 Adam 优化器并对比其效果。**
AdaGrad 优化器是一种备选方案。AdaGrad 的核心是灵活地修改模型中每个系数的学习率,从而单调降低有效的学习率。该优化器对于凸优化问题非常有效,但不一定适合非凸优化问题的神经网络训练。您可以通过指定 AdagradOptimizer(而不是 GradientDescentOptimizer)来使用 AdaGrad。请注意,对于 AdaGrad,您可能需要使用较大的学习率。
对于非凸优化问题,Adam 有时比 AdaGrad 更有效。要使用 Adam,请调用 tf.train.AdamOptimizer 方法。此方法将几个可选超参数作为参数,但我们的解决方案仅指定其中一个 (learning_rate)。在应用设置中,您应该谨慎指定和调整可选超参数。
ps:之前的代码中已经把评估器作为参数拿出来了,改成AdaGrad或Adam。题目中提示AdaGrad使用较大的学习率,所以针对这个选择大一点的学习速率;Adam还是用小的学习率
#AdaGrad
_, adagrad_training_losses, adagrad_validation_losses = train_nn_regression_model(
my_optimizer=tf.train.AdagradOptimizer(learning_rate=0.5),
steps=500,
batch_size=100,
hidden_units=[10, 10],
training_examples=normalized_training_examples,
training_targets=training_targets,
validation_examples=normalized_validation_examples,
validation_targets=validation_targets)
#adam
_, adam_training_losses, adam_validation_losses = train_nn_regression_model(
my_optimizer=tf.train.AdamOptimizer(learning_rate=0.009),
steps=500,
batch_size=100,
hidden_units=[10, 10],
training_examples=normalized_training_examples,
training_targets=training_targets,
validation_examples=normalized_validation_examples,
validation_targets=validation_targets)
AdaGrad结果:
Adam结果:
#输出误差对比
plt.ylabel("RMSE")
plt.xlabel("Periods")
plt.title("Root Mean Squared Error vs. Periods")
plt.plot(adagrad_training_losses, label='Adagrad training')
plt.plot(adagrad_validation_losses, label='Adagrad validation')
plt.plot(adam_training_losses, label='Adam training')
plt.plot(adam_validation_losses, label='Adam validation')
_ = plt.legend()
4-4 任务 3:尝试其他标准化方法
尝试对各种特征使用其他标准化方法,以进一步提高性能。
如果仔细查看转换后数据的汇总统计信息,您可能会注意到,对某些特征进行线性缩放会使其聚集到接近 -1 的位置。
例如,很多特征的中位数约为 -0.8,而不是 0.0。
_ = training_examples.hist(bins=20, figsize=(18, 12), xlabelsize=2)
绘制直方图,20个柱子,18X12的图表,x标签尺寸为2,标签尺寸太小了,用默认值
_ = training_examples.hist(bins=20, figsize=(18, 12))
通过选择其他方式来转换这些特征,我们可能会获得更好的效果。以下提供了转换的几种函数。
例如,对数缩放可能对某些特征有帮助。或者,截取极端值可能会使剩余部分的信息更加丰富。
def log_normalize(series):
return series.apply(lambda x:math.log(x+1.0))
def clip(series, clip_to_min, clip_to_max):
return series.apply(lambda x:(
min(max(x, clip_to_min), clip_to_max)))
def z_score_normalize(series):
mean = series.mean()
std_dv = series.std()
return series.apply(lambda x:(x - mean) / std_dv)
def binary_threshold(series, threshold):
return series.apply(lambda x:(1 if x > threshold else 0))
以上这些只是我们能想到的处理数据的几种方法。其他转换方式可能会更好!
households、median_income 和 total_bedrooms 在对数空间内均呈现为正态分布。
如果 latitude、longitude 和 housing_median_age 像之前一样进行线性缩放,效果可能会更好。
population、totalRooms 和 rooms_per_person 具有几个极端离群值。这些值似乎过于极端,以至于我们无法利用对数标准化处理这些离群值。因此,我们直接截取掉这些值。
def normalize(examples_dataframe):
"""Returns a version of the input `DataFrame` that has all its features normalized."""
processed_features = pd.DataFrame()
processed_features["households"] = log_normalize(examples_dataframe["households"])
processed_features["median_income"] = log_normalize(examples_dataframe["median_income"])
processed_features["total_bedrooms"] = log_normalize(examples_dataframe["total_bedrooms"])
processed_features["latitude"] = linear_scale(examples_dataframe["latitude"])
processed_features["longitude"] = linear_scale(examples_dataframe["longitude"])
processed_features["housing_median_age"] = linear_scale(examples_dataframe["housing_median_age"])
processed_features["population"] = linear_scale(clip(examples_dataframe["population"], 0, 5000))
processed_features["rooms_per_person"] = linear_scale(clip(examples_dataframe["rooms_per_person"], 0, 5))
processed_features["total_rooms"] = linear_scale(clip(examples_dataframe["total_rooms"], 0, 10000))
return processed_features
normalized_dataframe = normalize(preprocess_features(california_housing_dataframe))
normalized_training_examples = normalized_dataframe.head(12000)
normalized_validation_examples = normalized_dataframe.tail(5000)
#重新看下直方图
_ = normalized_training_examples.hist(bins=20, figsize=(18, 12))
ps:结果被处理的很漂亮,离群值没有,x特征被规范到[-1,1],或者[0,9]之间.
再次执行
_ = train_nn_regression_model(
my_optimizer=tf.train.AdagradOptimizer(learning_rate=0.15),
steps=1000,
batch_size=50,
hidden_units=[10, 10],
training_examples=normalized_training_examples,
training_targets=training_targets,
validation_examples=normalized_validation_examples,
validation_targets=validation_targets)
666
4-5 可选挑战:仅使用纬度和经度特征
训练仅使用纬度和经度作为特征的神经网络模型。
房地产商喜欢说,地段是房价的唯一重要特征。 我们来看看能否通过训练仅使用纬度和经度作为特征的模型来证实这一点。
只有我们的神经网络模型可以从纬度和经度中学会复杂的非线性规律,才能达到我们想要的效果。
注意:我们可能需要一个网络结构,其层数比我们之前在练习中使用的要多。
ps:去掉其他特征即可,根据提示还要加几层
def location_location_location(examples_dataframe):
"""Returns a version of the input `DataFrame` that keeps only the latitude and longitude."""
processed_features = pd.DataFrame()
processed_features["latitude"] = linear_scale(examples_dataframe["latitude"])
processed_features["longitude"] = linear_scale(examples_dataframe["longitude"])
return processed_features
lll_dataframe = location_location_location(preprocess_features(california_housing_dataframe))
lll_training_examples = lll_dataframe.head(12000)
lll_validation_examples = lll_dataframe.tail(5000)
_ = train_nn_regression_model(
my_optimizer=tf.train.AdagradOptimizer(learning_rate=0.05),
steps=500,
batch_size=50,
hidden_units=[10, 8, 6, 4,3],
training_examples=lll_training_examples,
training_targets=training_targets,
validation_examples=lll_validation_examples,
validation_targets=validation_targets)
貌似一般般