神经⽹络(深度学习)(笔记)
最近在⾃学图灵教材《Python机器学习基础教程》,在csdn以博客的形式做些笔记。
⼀类被称为神经⽹络的算法最近以“深度学习”的名字再度流⾏。虽然深度学习在许多机 器学习应⽤中都有巨⼤的潜⼒,但深度学习算法往往经过精确调整,只适⽤于特定的使 ⽤场景。这⾥只讨论⼀些相对简单的⽅法,即⽤于分类和回归的多层感知机(multilayer perceptron,MLP),它可以作为研究更复杂的深度学习⽅法的起点。MLP 也被称为(普 通)前馈神经⽹络,有时也简称为神经⽹络。(摘于书中)
神经⽹路模型
MLP 可以被视为⼴义的线性模型,执⾏多层处理后得到结论。 还记得线性回归的预测公式为: ŷ = w[0] * x[0] + w[1] * x[1] + … +
w[p] * x[p] + b 简单来说,y是输⼊特征 x[0] 到 x[p] 的加权求和,权重为学到的系数 w[0] 到 w[p]。我们可 以将这个公式可视化
图中,左边的每个结点代表⼀个输⼊特征,连线代表学到的系数,右边的结点代表输出, 是输⼊的加权求和。 在 MLP 中,多次重复这个计算加权求和的过程,⾸先计算代表中间过程的隐单元(hidden unit),然后再计算这些隐单元的加权求和并得到最终结果
这个模型需要学习更多的系数(也叫作权重):在每个输⼊与每个隐单元(隐单元组成了 隐层)之间有⼀个系数,在每个隐单元与输出之间也有⼀个系数。 从数学的⾓度看,计算⼀系列加权求和与只计算⼀个加权求和是完全相同的,因此,为了 让这个模型真正⽐线性模型更为强⼤,我们还需要⼀个技巧。在计算完每个隐单元的加权 求和之后,对结果再应⽤⼀个⾮线性函数——通常是校正⾮线性(rectifying nonlinearity, 也叫校正线性单元或 relu)或正切双曲线(tangens hyperbolicus,tanh)。然后将这个函数 的结果⽤于加权求和,计算得到输出 y
对于上图所⽰的⼩型神经⽹络,计算回归问题的 y的完整公式如下(使⽤ tanh ⾮线性):
h[0] = tanh(w[0, 0] * x[0] + w[1, 0] * x[1] + w[2, 0] * x[2] + w[3, 0] * x[3] + b[0])
h[1] = tanh(w[0, 0] * x[0] + w[1, 0] * x[1] + w[2, 0] * x[2] + w[3, 0] * x[3] + b[1])
肺活量怎么提高h[2] = tanh(w[0, 0] * x[0] + w[1, 0] * x[1] + w[2, 0] * x[2] + w[3, 0] * x[3] + b[2])
ŷ = v[0] * h[0] + v[1] * h[1] + v[2] * h[2] + b
其中,w 是输⼊ x 与隐层 h 之间的权重,v 是隐层 h 与输出 y之间的权重。权重 w 和 v 要 从数据中学
习得到,x 是输⼊特征,y是计算得到的输出,h 是计算的中间结果。需要⽤户 设置的⼀个重要参数是隐层中的结点个数。对于⾮常⼩或⾮常简单的数据集,这个值可以 ⼩到 10;对于⾮常复杂的数据,这个值可以⼤到 10 000。也可以添加多个隐层。
神经⽹络调参
我们将 MLPClassifier 应⽤到two_moons 数据集上
ural_network import MLPClassifier
from sklearn.datats import make_moons
X, y = make_moons(n_samples=100, noi=0.25, random_state=3)
X_train, X_test, y_train, y_test = train_test_split(X, y, stratify=y,random_state=42)
厌氧环境
mlp = MLPClassifier(solver='lbfgs', random_state=0).fit(X_train, y_train)
mglearn.plots.plot_2d_parator(mlp, X_train, fill=True, alpha=.3)
mglearn.discrete_scatter(X_train[:, 0], X_train[:, 1], y_train)
plt.xlabel("Feature 0")
plt.ylabel("Feature 1")
恢复桌面图标
默认情况下,MLP 使⽤ 100 个隐结点,这对于这个⼩型数据集来说已经相当多了。我们可 以减少其数量(从⽽降低了模型复杂度),但仍然得到很好的结果。
mlp = MLPClassifier(solver='lbfgs', random_state=0, hidden_layer_sizes=[10])
mlp.fit(X_train, y_train)
国家法定工作时间
mglearn.plots.plot_2d_parator(mlp, X_train, fill=True, alpha=.3)
mglearn.discrete_scatter(X_train[:, 0], X_train[:, 1], y_train)
plt.xlabel("Feature 0")
plt.ylabel("Feature 1")
只有 10 个隐单元时,决策边界看起来更加参差不齐。默认的⾮线性是 relu。如果使⽤单隐层,那么决策函数将由 10 个直线段组成。如果想得到更加平滑的决策边界,可以添加更多的隐单元、添加第⼆个隐层或者使⽤ tanh ⾮线性.
我们还可以利⽤ L2 惩罚使权重趋向于 0,从⽽控制神经⽹络的复杂度,正如我们在中所做的那样。MLPClassifier 中调节 L2 惩罚的参数是 alpha(与线 性回归模型中的相同),它的默认值很⼩(弱正则化)。图 2-52 显⽰了不同 alpha 值对 two_ moons 数据集的影响,⽤的是 2 个隐层的神经⽹络,每层包含 10 个或 100 个单元。
fig, axes = plt.subplots(2, 4, figsize=(20, 8))
for axx, n_hidden_nodes in zip(axes, [10, 100]):
for ax, alpha in zip(axx, [0.0001, 0.01, 0.1, 1]):
mlp = MLPClassifier(solver='lbfgs', random_state=0,
hidden_layer_sizes=[n_hidden_nodes, n_hidden_nodes],
alpha=alpha)
跳跳豆
mlp.fit(X_train, y_train)
mglearn.plots.plot_2d_parator(mlp, X_train, fill=True, alpha=.3, ax=ax)
mglearn.discrete_scatter(X_train[:, 0], X_train[:, 1], y_train, ax=ax)
ax.t_title("n_hidden=[{}, {}]\nalpha={:.4f}".format(
n_hidden_nodes, n_hidden_nodes, alpha))
神经⽹络的⼀个重要性质是,在开始学习之前其权重是随机设置的,这种随机初始化会影响学到的模型。也就是说,即使使⽤完全相同的参数,如果随机种⼦不同的话,我们也可能得到⾮常不⼀样的模
型。如果⽹络很⼤,并且复杂度选择合理的话,那么这应该不会对精度有太⼤影响,但应该记住这⼀点(特别是对于较⼩的⽹络) 。
实战
接下来我们来看看将神经⽹络运⽤到乳腺癌数据集上是怎样的效果
from sklearn.datats import load_breast_cancer
cancer=load_breast_cancer()
X_train, X_test, y_train, y_test = train_test_split(cancer.data, cancer.target, random_state=0)
mlp = MLPClassifier(random_state=42)
mlp.fit(X_train, y_train)
print("Accuracy on training t: {:.2f}".format(mlp.score(X_train, y_train)))
print("Accuracy on test t: {:.2f}".format(mlp.score(X_test, y_test)))
MLP 的精度相当好,但没有其他模型好。与较早的 SVC 例⼦相同(具体见),原因可能在于数据的缩放。神经⽹络也要求所有输⼊特征的变化范围相似,最理想的情况是均值为 0、⽅差为 1。我们必须对数据进⾏缩放以满⾜这些要求。
# 计算训练集中每个特征的平均值
mean_on_train = an(axis=0)
# 计算训练集中每个特征的标准差
std_on_train = X_train.std(axis=0)
# 减去平均值,然后乘以标准差的倒数
# 如此运算之后,mean=0,std=1
X_train_scaled = (X_train - mean_on_train) / std_on_train
# 对测试集做相同的变换(使⽤训练集的平均值和标准差)
X_test_scaled = (X_test - mean_on_train) / std_on_train
mlp = MLPClassifier(random_state=0)
mlp.fit(X_train_scaled, y_train)
print("Accuracy on training t: {:.3f}".format(
mlp.score(X_train_scaled, y_train)))
老天保佑print("Accuracy on test t: {:.3f}".format(mlp.score(X_test_scaled, y_test)))
我们可以看到缩放之后的结果要好很多,但是系统却给了我们⼀个警告 ,告诉我们已经达到了最⼤的迭代次数这是⽤于学习模型的 adam 算法的⼀部分,告诉我们应该增加迭代次数:
mlp = MLPClassifier(max_iter=1000, random_state=0)
mlp.fit(X_train_scaled, y_train)
print("Accuracy on training t: {:.3f}".format(
听歌曲识别歌名
mlp.score(X_train_scaled, y_train)))
print("Accuracy on test t: {:.3f}".format(mlp.score(X_test_scaled, y_test)))
增加迭代次数仅提⾼了训练集性能,同时也提⾼了泛化性能(这是⼀项惊喜收获,因为⼀般⽽⾔增加迭代次数并不会提⾼泛化性能或者说提⾼不多)。模型的表现相当不错。由于训练性能和测试性能之间仍有⼀些差距,所以我们可以尝试降低模型复杂度来得到更好的泛化性能。这⾥我们选择增⼤ alpha 参数(变化范围相当⼤,从 0.0001 到 1),以此向 权重添加更强的正则化:
mlp = MLPClassifier(max_iter=1000, alpha=1, random_state=0)
mlp.fit(X_train_scaled, y_train)
print("Accuracy on training t: {:.3f}".format(mlp.score(X_train_scaled, y_train)))
print("Accuracy on test t: {:.3f}".format(mlp.score(X_test_scaled, y_test)))
遗憾的是对于这个数据集增⼤alpha参数并没有⽤,但是在⼤多数情况下,都是有⽤的。
接下来分析⼀下这个神经⽹络学到了什么
想要看模型学到了什么,⼀种普遍的⽅法就是查看模型的权重。下图显⽰了连接输⼊和第⼀个隐层之间的权重。图中的⾏对应 30 个输⼊特征,列对应 100 个隐单元。 浅⾊代表较⼤的正值,⽽深⾊代表负值。
游手好闲的意思plt.figure(figsize=(20, 5))
plt.fs_[0], interpolation='none', cmap='viridis')
plt.xlabel("Columns in weight matrix")
plt.ylabel("Input feature")
我们可以推断,如果某个特征对所有隐单元的权重都很⼩,那么这个特征对模型来说就 “不太重要”。可以看到,与其他特征相
⽐,“mean smoothness”“mean compactness”以及 “smoothness error”和“fractal dimension error”之间的特征的权重都相对较⼩。这可能说 明这些特征不太重要,也可能是我们没有⽤神经⽹络可以使⽤的⽅式来表⽰这些特征。
总结
使⽤神经⽹络,主要关注模型的定义:层数、每层的结点个数、正则化和⾮线性。这些内容定义了我们想要学习的模型。还有⼀个问题是,如何学习模型或⽤来学习参数的算法,这⼀点由 solver 参数设定。solver 有两个好⽤的选项。默认选项是 'adam',在⼤多 数情况下效果都很好,但对数据的缩放相
当敏感(因此,始终将数据缩放为均值为 0、⽅差为 1 是很重要的)。另⼀个选项是 'lbfgs',其鲁棒性相当好,但在⼤型模型或⼤型数据 集上的时间会⽐较长。还有更⾼级的 'sgd' 选项,许多深度学习研究⼈员都会⽤到。'sgd' 选项还有许多其他参数需要调节,以便获得最佳结果。当你开始使⽤ MLP 时,建议使⽤ 'adam' 和 'lbfgs'。