机器学习实战——基于Scikit-Learn和TensorFlow 阅读笔记 之 第四章:训练模型

版权声明:访问者可将本博客提供的内容或服务用于个人学习、研究或欣赏,以及其他非商业性或非盈利性用途,但同时应遵守著作权法及其他相关法律的规定,不得侵犯本网站及相关权利人的合法权利。除此以外,将本网站任何内容或服务用于其他用途时,须及时征得本网站及相关权利人的明确许可。 https://blog.csdn.net/qq_38262728/article/details/88022533
《机器学习实战——基于Scikit-Learn和TensorFlow》
这是一本非常好的机器学习和深度学习入门书,既有基本理论讲解,也有实战代码示例。
我将认真阅读此书,并为每一章内容做一个知识笔记。
我会摘录一些原书中的关键语句和代码,若有错误请为我指出。

在这里插入图片描述

第四章 训练模型

虽然不理解模型对于代码实现基本不产生影响,但是理解系统如何工作对于帮助快速定位到合适的模型、正确的训练算法、一套合适的产参数,和执行错误调试、错误分析非常有帮助。

1 线性回归

线性模型就是对输入特征加权求和,再加上一个 偏置项(截距项) 的常数,以此进行预测。
y ^ = θ 0 + θ 1 x 1 + . . . + θ n x n \hat{y}=\theta_0+\theta_1x_1+...+\theta_nx_n
y ^ = h θ ( X ) = θ T X \hat{y}=h_\theta(X)=\theta^T\cdot X

成本函数:
M S E ( X , h θ ) = 1 m i = 1 m ( θ T X ( i ) y ( i ) ) 2 MSE(X,h_\theta)=\frac{1}{m}\sum_{i=1}^m(\theta^T\cdot X^{(i)}-y^{(i)})^2

1.1 标准方程

闭式解 方法:
θ ^ = ( X T X ) 1 X T y \hat{\theta}=(X^T\cdot X)^{-1}\cdot X^T\cdot y

测试:

import numpy as np

X = 2 * np.random.rand(100, 1)
y = 4 + 3 * X + np.random.randn(100, 1)

X_b = np.c_[np.ones((100, 1)), X]  # add x0 = 1 to each instance
theta_best = np.linalg.inv(X_b.T.dot(X_b)).dot(X_b.T).dot(y)

X_new = np.array([[0], [2]])
X_new_b = np.c_[np.ones((2, 1)), X_new]  # add x0 = 1 to each instance
y_predict = X_new_b.dot(theta_best)
y_predict

plt.plot(X_new, y_predict, "r-")
plt.plot(X, y, "b.")
plt.axis([0, 2, 0, 15])
plt.show()

或

from sklearn.linear_model import LinearRegression
lin_reg = LinearRegression()
lin_reg.fit(X, y)
lin_reg.intercept_, lin_reg.coef_
lin_reg.predict(X_new)

1.2 计算复杂度

标准方程求逆是计算复杂度通常为O(n2.4)到O(n3)之间。
特征数量较大时,标准方程的计算将极其缓慢。

2 梯度下降

梯度下降是非常通用的优化算法,能够为大范围的问题找到最优解。
梯度下降的中心思想就是迭代地调整参数从而使成本函数最小化。
通过测量参数向量相关的误差函数的局部梯度,并不断沿着梯度的方向调整,直到梯度降为0,到达最小值。

梯度下降中一个重要的参数是每一步的步长,取决于超参数学习率。
学习率太低,经过大量迭代才能收敛,耗时长。
学习率太高,算法发散,可能导致值越来越大,无法找到很好的解决方案。

扫描二维码关注公众号,回复: 5551698 查看本文章

主要挑战:
随机初始化导致收敛到局部最小值。
过早停止无法到达最小值,过晚停止可能无穷无尽。

成本函数是凸函数,能保证梯度下降一定可以趋近全局最小值。

应用梯度下降时,需要保证所有特征值的大小比例都差不多(可使用scikit-learn的standscaler类),否则收敛时间会长很多。

模型的参数越多,意味着维度越高,搜索越困难。

2.1 批量梯度下降

计算成本函数关于参数的偏导数。

每一步都使用整批训练数据。
面对庞大的数据集会极慢,但是随特征数量扩展的表现比较好。

梯度下降步长:
θ ( n e x t s t e p ) = θ η θ M S E ( θ ) \theta^{(next step)}=\theta-\eta\nabla_\theta MSE(\theta)

eta = 0.1
n_iterations = 1000
m = 100
theta = np.random.randn(2,1)

for iteration in range(n_iterations):
    gradients = 2/m * X_b.T.dot(X_b.dot(theta) - y)
    theta = theta - eta * gradients

成本函数为凸函数且斜率没有陡峭的变化时,BGD一个固定的学习率有一个收敛率,为O(1/迭代次数)。

2.2 随机梯度下降

随机梯度下降SGD,每一步在训练集中随机选择一个实例,并且仅基于该单个实例来计算梯度。

算法变快,下降变得不规则(成本函数不断震荡,但总趋势向下)。
和BGD相比,SGD更有利于跳出局部最小值,对找到全局最优势更有优势。
可以逐步降低学习率,开始的步长比较大(利于快速展开和逃离局部最小值),越来越小让算法尽量靠近全局最小值。这个过程为 模拟退火

n_epochs = 50
t0, t1 = 5, 50 # learning schedule hyperparameters

def learning_schedule(t):
return t0 / (t + t1)

theta = np.random.randn(2,1) # random initialization

for epoch in range(n_epochs):
for i in range(m):
if epoch == 0 and i < 20: # not shown in the book
y_predict = X_new_b.dot(theta) # not shown
style = “b-” if i > 0 else “r–” # not shown
plt.plot(X_new, y_predict, style) # not shown
random_index = np.random.randint(m)
xi = X_b[random_index:random_index+1]
yi = y[random_index:random_index+1]
gradients = 2 * xi.T.dot(xi.dot(theta) - yi)
eta = learning_schedule(epoch * m + i)
theta = theta - eta * gradients
theta_path_sgd.append(theta) # not shown

plt.plot(X, y, “b.”) # not shown
plt.xlabel(" x 1 x_1 ", fontsize=18) # not shown
plt.ylabel(" y y ", rotation=0, fontsize=18) # not shown
plt.axis([0, 2, 0, 15]) # not shown
save_fig(“sgd_plot”) # not shown
plt.show() # not shown

在scikit-learn里,用SGD执行线性回归可以使用SGDRegressor类,其默认优化的成本函数是平方误差。

2.3 小批量梯度下降

每一步的梯度计算基于一小部分随机的实例集也就是小批量。

优势在于可以从矩阵运算的硬件优化中获得显著的性能提升,特别是需要用到图形处理器时。
下降比SGD稳定一点,也更接近最小值一点,但是更难从局部最小值中跳出。

3 多项式回归

更复杂的数据的情形,可以将每个特征的幂次方添加为一个新特征,然后在这个拓展过的特征集上训练线性模型。即 多项式回归

可用scikit-learn的PolynomialFeatures类来转换训练数据。
当存在多个特征时,多项式回归能发现特征和特征之间的关系,因为它会添加两个特征的乘积项。

from sklearn.preprocessing import PolynomialFeatures
poly_features = PolynomialFeatures(degree=2, include_bias=False)
X_poly = poly_features.fit_transform(X)
X[0] 

lin_reg = LinearRegression()
lin_reg.fit(X_poly, y)
lin_reg.intercept_, lin_reg.coef_

X_new=np.linspace(-3, 3, 100).reshape(100, 1)
X_new_poly = poly_features.transform(X_new)
y_new = lin_reg.predict(X_new_poly)
plt.plot(X, y, "b.")
plt.plot(X_new, y_new, "r-", linewidth=2, label="Predictions")
plt.xlabel("$x_1$", fontsize=18)
plt.ylabel("$y$", rotation=0, fontsize=18)
plt.legend(loc="upper left", fontsize=14)
plt.axis([-3, 3, 0, 10])
save_fig("quadratic_predictions_plot")
plt.show()

4 学习曲线

如果模型在训练集上表现良好,但是交叉验证的泛化表现非常糟糕,那么模型就是过度拟合。
如果在二者上的表现都不佳,那就是拟合不足。

或使用 学习曲线 来判断,它绘制了模型在训练集和验证集上关于“训练集大小”的性能函数。

from sklearn.metrics import mean_squared_error
from sklearn.model_selection import train_test_split

def plot_learning_curves(model, X, y):
    X_train, X_val, y_train, y_val = train_test_split(X, y, test_size=0.2, random_state=10)
    train_errors, val_errors = [], []
    for m in range(1, len(X_train)):
        model.fit(X_train[:m], y_train[:m])
        y_train_predict = model.predict(X_train[:m])
        y_val_predict = model.predict(X_val)
        train_errors.append(mean_squared_error(y_train[:m], y_train_predict))
        val_errors.append(mean_squared_error(y_val, y_val_predict))

    plt.plot(np.sqrt(train_errors), "r-+", linewidth=2, label="train")
    plt.plot(np.sqrt(val_errors), "b-", linewidth=3, label="val")
    plt.legend(loc="upper right", fontsize=14)   # not shown in the book
    plt.xlabel("Training set size", fontsize=14) # not shown
    plt.ylabel("RMSE", fontsize=14)              # not shown

lin_reg = LinearRegression()
plot_learning_curves(lin_reg, X, y)
plt.axis([0, 80, 0, 3])                         # not shown in the book
save_fig("underfitting_learning_curves_plot")   # not shown
plt.show()                                      # not shown

如果你的模型对训练数据拟合不足,添加更多训练示例也于事无补。你需要使用更复杂的模型或者找到更好的特征。
改进过度拟合的方法之一是提供更多的训练数据,直到验证误差接近训练误差。

泛化误差可以表示为三个截然不同的误差之和:

  • 偏差
    错误的假设 => 增加模型复杂度
  • 方差
    模型对训练数据的微小变化过度敏感 =>降低模型复杂度
  • 无可避免的误差
    数据本身的噪声导致 => 清理数据

5 正则线性模型

减少过度拟合的一个好办法就是对模型正则化(即约束它):它拥有的自由度越低,就越不容易过度拟合数据。

5.1 岭回归

岭回归(吉洪诺夫正则化) :在成本函数中添加一个等于 α i = 1 n θ i 2 \alpha\sum_{i=1}^{n}\theta_i^2 的正则项。

岭回归使得学习算法不仅需要拟合数据,同时还要让模型权重保持最小。

注意,正则项只能在训练的时候添加到成本函数中,一旦训练完成,你需要使用未经正则化的性能指标来评估模型性能。

在执行岭回归之前,必须对数据进行缩放,因为它对输入特征的大小非常敏感。大多数正则化模型都是如此。

5.2 套索回归

最小绝对收缩和选择算子回归(Least Absolute Shrinkage and Selection Operator Regression, Lasso回归,套索回归)
J ( θ ) = M S E ( θ ) + α i = 1 n θ i J(\theta)=MSE(\theta)+\alpha\sum_{i=1}^n{\left| \theta_i \right| }

Lasso回归倾向于完全消除掉最不重要特征的权重,而套索回归没有这么绝对

5.3 弹性网络

弹性网络是岭回归和Lasso回归之间的中间地带。
其正则项就是岭回归和Lasso回归的正则项的混合,混合比例通过r控制。当r=0时,弹性网络即等于岭回归,而当r=1时,即相当于Lasso回归。

岭回归是个不错的默认选择,但是如果实际使用到的特征只有少数几个,应该倾向于Lasso回归或弹性网络,因为它们会将无用特征的权重降为零。
一般而言,弹性网络优于Lasso回归,因为当特征数量超过训练实例数量,又或是几个特征强相关时,Lasso回归的表现可能非常不稳定。

5.4 早期停止法

在验证误差达到最小值时停止训练,叫做 早期停止法

Hinton称其为“美丽的免费午餐”。

from sklearn.base import clone
sgd_reg = SGDRegressor(max_iter=1, tol=-np.infty, warm_start=True, penalty=None,
                       learning_rate="constant", eta0=0.0005, random_state=42)

minimum_val_error = float("inf")
best_epoch = None
best_model = None
for epoch in range(1000):
    sgd_reg.fit(X_train_poly_scaled, y_train)  # continues where it left off
    y_val_predict = sgd_reg.predict(X_val_poly_scaled)
    val_error = mean_squared_error(y_val, y_val_predict)
    if val_error < minimum_val_error:
        minimum_val_error = val_error
        best_epoch = epoch
        best_model = clone(sgd_reg)

5.5 逻辑回归

一些回归算法可用于分类(反之亦然)。
逻辑回归(罗吉斯回归)可估计一个实例属于某个特定类别的概率,以50%为阈值就可以看做一个二元分类器。

5.6 概率估算

逻辑回归模型概率估算:
p ^ = h θ ( x ) = σ ( θ T x ) \hat{p}=h_\theta(x)=\sigma(\theta^T\cdot x)

其中,逻辑函数:
σ ( t ) = 1 1 + e t \sigma(t)=\frac{1}{1+e^{-t}}

预测:
y ^ = { 0 p ^ &lt; 0.5 1 p ^ 0.5 \hat{y}=\begin{cases}0&amp;\hat{p}&lt;0.5\\1&amp;\hat{p}\ge0.5\end{cases}

5.7 训练和成本函数

单个训练实例的成本函数:
c ( θ ) = { l o g ( p ^ ) y = 1 l o g ( 1 p ^ ) y = 0 c(\theta)=\begin{cases}-log(\hat{p})&amp;y=1\\-log(1-\hat{p})&amp;y=0\end{cases}

整个训练集的成本函数即为所有训练实例的平均成本。

5.8 决策边界

鸢尾花数据集。150朵鸢尾花,来自三个品种。

存在一个决策边界,在此上时,分类器对两个类别的分类概率相等。

5.9 Softmax回归

逻辑斯蒂推广到多个类别,就是softmax回归,或叫多元逻辑回归。

类别k的softmax分数:
s k ( x ) = θ k T x s_k(x)=\theta_k^T\cdot x

softmax函数:
p k ^ = σ ( s ( x ) ) k = e s k ( x ) j = 1 K e s j x \hat{p_k}=\sigma(s(x))_k=\frac{e^{s_k(x)}}{\sum_{j=1}^{K}e^{s_j{x}}}

softmax回归分类器一次只会预测一个类别(是多类别,但不是多输出),所以它只适用于互斥的类别之上,不能用来识别一张照片中的多个人。

使用交叉熵成本函数来实现训练。
因为模型会目标类别做出较低概率的估算时,会受到惩罚。
交叉熵经常用来于衡量一组估算出的类别概率跟目标类别的匹配程度。
J ( Θ ) = 1 m i = 1 m k = 1 K y k ( i ) l o g ( p ^ k ( i ) ) J(\mathcal{\Theta})=-\frac{1}{m}\sum_{i=1}^m\sum_{k=1}^Ky_k^{(i)}log(\hat{p}_k^{(i)})

猜你喜欢

转载自blog.csdn.net/qq_38262728/article/details/88022533