当前位置:   article > 正文

吴恩达机器学习:实践实验室-应用机器学习的建议(Advice for Applying )

吴恩达机器学习:实践实验室-应用机器学习的建议(Advice for Applying )

在这个实验室中,您将探索评估和改进机器学习模型的技术。
在这里插入图片描述

1 - Packages

首先,让我们运行下面的单元格来导入此分配过程中所需的所有包。

  • numpy是科学计算Python的基本包。
  • matplotlib是一个流行的Python绘图库。
  • scikitslearn是数据挖掘的基本库tensorflow是一个流行的机器学习平台。
import numpy as np
%matplotlib widget
import matplotlib.pyplot as plt
from sklearn.linear_model import LinearRegression, Ridge
from sklearn.preprocessing import StandardScaler, PolynomialFeatures
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error
import tensorflow as tf
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense
from tensorflow.keras.activations import relu,linear
from tensorflow.keras.losses import SparseCategoricalCrossentropy
from tensorflow.keras.optimizers import Adam

import logging
logging.getLogger("tensorflow").setLevel(logging.ERROR)

from public_tests_a1 import * 

tf.keras.backend.set_floatx('float64')
from assigment_utils import *

tf.autograph.set_verbosity(0)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

2-评估学习算法(多项式回归)

在这里插入图片描述
假设你已经创建了一个机器学习模型,你发现它非常适合你的训练数据。你完了吗?不完全是。创建模型的目标是能够预测新示例的值。
在部署新数据之前,如何在新数据上测试模型的性能?
答案有两部分:

  • 将原始数据集拆分为“训练”集和“测试”集。
    • 使用训练数据来拟合模型的参数
    • 使用测试数据在新数据上评估模型
  • 开发误差函数来评估模型。

2.1拆分数据集

讲座建议保留20-40%的数据集用于测试。让我们使用sklearn函数train_test_split来执行拆分。运行以下单元格后,请仔细检查形状。

# Generate some data
X,y,x_ideal,y_ideal = gen_data(18, 2, 0.7)
print("X.shape", X.shape, "y.shape", y.shape)

#split the data using sklearn routine 
X_train, X_test, y_train, y_test = train_test_split(X,y,test_size=0.33, random_state=1)
print("X_train.shape", X_train.shape, "y_train.shape", y_train.shape)
print("X_test.shape", X_test.shape, "y_test.shape", y_test.shape)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
import inspect
# 使用 inspect.getsource 获取函数源代码
source_code = inspect.getsource(gen_data)
# 打印函数源代码
print(source_code)
  • 1
  • 2
  • 3
  • 4
  • 5
def gen_data(m, seed=1, scale=0.7):
    """ generate a data set based on a x^2 with added noise """
    c = 0
    x_train = np.linspace(0,49,m)
    np.random.seed(seed)
    y_ideal = x_train**2 + c
    y_train = y_ideal + scale * y_ideal*(np.random.sample((m,))-0.5)
    x_ideal = x_train #for redraw when new data included in X
    return x_train, y_train, x_ideal, y_ideal
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

这段代码定义了一个名为 gen_data 的函数,其作用如下:

  1. 函数功能

    • 生成一个基于 x 2 x^2 x2 函数加入噪声的数据集。
  2. 参数说明

    • m:数据集中样本的数量。
    • seed:随机种子,用于控制随机数生成过程的随机性。
    • scale:控制噪声的幅度。
  3. 返回值

    • x_train:从0到49均匀分布的 m 个数据,用作训练集的特征。
    • y_train:根据理想值 x 2 x^2 x2 加上一定比例的随机噪声所生成的目标标签。
    • x_ideal:与 x_train 相同的理想输入特征,用于在包含新数据时重绘图形。
    • y_ideal:基于 x 2 x^2 x2 函数计算得到的理想目标标签,没有加入噪声。
  4. 具体操作

    • 首先,生成 x_train,从0到49均匀分布的 m 个数据点。
    • 然后,根据随机种子 seed,生成理想目标标签 y_ideal,其值为 x 2 x^2 x2
    • 接着,在 y_ideal 的基础上,添加一定比例的随机噪声,得到最终的训练集目标标签 y_train
    • 最后,返回生成的特征数据 x_train、目标标签数据 y_train、理想特征数据 x_ideal 和理想目标标签数据 y_ideal

这个函数主要用于生成一个带有噪声的数据集,可用于模拟实际情况下的数据。你可以调用这个函数来生成数据集,并用于机器学习模型的训练和测试。如果需要进一步解释或有其他问题,请随时告诉我!我会尽力帮助你。

2.1.1图列、测试集

您可以在下面看到,将作为训练一部分的数据点(红色)与未训练模型的数据点混合在一起(测试)。这个特定的数据集是一个添加了噪声的二次函数。所示的“理想”曲线仅供参考。

fig, ax = plt.subplots(1,1,figsize=(4,4))
ax.plot(x_ideal, y_ideal, "--", color = "orangered", label="y_ideal", lw=1)
ax.set_title("Training, Test",fontsize = 14)
ax.set_xlabel("x")
ax.set_ylabel("y")
ax.scatter(X_train, y_train, color = "red",           label="train")
ax.scatter(X_test, y_test,   color = dlc["dlblue"],   label="test")
ax.legend(loc='upper left')
plt.show()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

在这里插入图片描述

2.2模型评估的误差计算,线性回归

在评估线性回归模型时,将预测值和目标值的误差平方差取平均值。
在这里插入图片描述
练习1
下面创建一个函数来评估线性回归模型的数据集上的误差。

# UNQ_C1
# GRADED CELL: eval_mse
def eval_mse(y, yhat):
    """ 
    Calculate the mean squared error on a data set.
    Args:
      y    : (ndarray  Shape (m,) or (m,1))  target value of each example
      yhat : (ndarray  Shape (m,) or (m,1))  predicted value of each example
    Returns:
      err: (scalar)             
    """
    m = len(y)
    err = 0.0
    for i in range(m):
        err_i  = ( (yhat[i] - y[i])**2 ) 
        err   += err_i                                                                
    err = err / (2*m)                    
    return(err)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
y_hat = np.array([2.4, 4.2])
y_tmp = np.array([2.3, 4.1])
eval_mse(y_hat, y_tmp)
# BEGIN UNIT TEST
test_eval_mse(eval_mse)   #测试目标函数的准确度
# END UNIT TEST
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

在这里插入图片描述

打印函数源代码:

# 使用 inspect.getsource 获取函数源代码
source_code = inspect.getsource(test_eval_mse)

# 打印函数源代码
print(source_code)
  • 1
  • 2
  • 3
  • 4
  • 5
def test_eval_mse(target):
    y_hat = np.array([2.4, 4.2])
    y_tmp = np.array([2.3, 4.1])
    result = target(y_hat, y_tmp)
    
    #assert np.allclose(result, 0.005, atol=1e-6), f"Wrong value. Expected 0.005, got {result}"
    np.allclose(result, 0.005, atol=1e-6),f"Wrong value. Expected 0.005, got {result}"

    y_hat = np.array([3.] * 10)
    y_tmp = np.array([3.] * 10)
    result = target(y_hat, y_tmp)
    assert np.allclose(result, 0.), f"Wrong value. Expected 0.0 when y_hat == t_tmp, but got {result}"
    
    y_hat = np.array([3.])
    y_tmp = np.array([0.])
    result = target(y_hat, y_tmp)
    assert np.allclose(result, 4.5), f"Wrong value. Expected 4.5, but got {result}. Remember the square termn"
    
    y_hat = np.array([3.] * 5)
    y_tmp = np.array([2.] * 5)
    result = target(y_hat, y_tmp)
    assert np.allclose(result, 0.5), f"Wrong value. Expected 0.5, but got {result}. Remember to divide by (2*m)"
    
    print("\033[92m All tests passed.")
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

2.3比较训练和测试数据的表现

让我们建立一个高阶多项式模型来最小化训练误差。这将使用sklearn中的linear_regression函数。如果您想查看详细信息,代码位于导入的实用程序文件中。以下步骤是:

  • 创建并拟合模型。(“it”是训练或跑步梯度下降的另一个名称)。
  • 计算训练数据的误差。
  • 计算测试数据的误差。
# create a model in sklearn, train on training data
degree = 10
lmodel = lin_model(degree)
lmodel.fit(X_train, y_train)

# predict on training data, find training error
yhat = lmodel.predict(X_train)
err_train = lmodel.mse(y_train, yhat)

# predict on test data, find error
yhat = lmodel.predict(X_test)
err_test = lmodel.mse(y_test, yhat)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

训练集上的计算误差显著小于测试集的计算误差。

print(f"training err {err_train:0.2f}, test err {err_test:0.2f}")
  • 1
training err 58.01, test err 171215.01
  • 1

下图显示了为什么会这样。该模型非常适合训练数据。为此,它创建了一个复杂的函数。测试数据不是训练的一部分,模型在预测这些数据方面做得很差。
该模型将被描述为1)过拟合,2)具有高方差,3)“泛化”较差。

# plot predictions over data range 
x = np.linspace(0,int(X.max()),100)  # predict values for plot
y_pred = lmodel.predict(x).reshape(-1,1)

plt_train_test(X_train, y_train, X_test, y_test, x, y_pred, x_ideal, y_ideal, degree)
  • 1
  • 2
  • 3
  • 4
  • 5

在这里插入图片描述
测试集错误表明此模型在新数据上无法正常工作。如果你使用测试错误来指导模型的改进,那么模型将在测试数据上表现良好。。。但是测试数据是用来表示新数据的。您还需要另一组数据来测试新的数据性能。
讲座中提出的建议是将数据分为三组。下表所示的训练、交叉验证和测试集的分布是一种典型的分布,但可能会因可用数据量的不同而有所不同。
在这里插入图片描述
让我们生成以下三个数据集。我们将再次使用sklearn中的train_test_split,但将调用两次以获得三次拆分:

# Generate  data
X,y, x_ideal,y_ideal = gen_data(40, 5, 0.7)
print("X.shape", X.shape, "y.shape", y.shape)

#split the data using sklearn routine 
X_train, X_, y_train, y_ = train_test_split(X,y,test_size=0.40, random_state=1)
X_cv, X_test, y_cv, y_test = train_test_split(X_,y_,test_size=0.50, random_state=1)
print("X_train.shape", X_train.shape, "y_train.shape", y_train.shape)
print("X_cv.shape", X_cv.shape, "y_cv.shape", y_cv.shape)
print("X_test.shape", X_test.shape, "y_test.shape", y_test.shape)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
X.shape (40,) y.shape (40,)
X_train.shape (24,) y_train.shape (24,)
X_cv.shape (8,) y_cv.shape (8,)
X_test.shape (8,) y_test.shape (8,)
  • 1
  • 2
  • 3
  • 4

3-偏差和方差

在这里插入图片描述
上面,很明显多项式模型的阶数太高了。如何选择好的价值?事实证明,如图所示,训练和交叉验证性能可以提供指导。通过尝试一系列的度值,可以评估训练和交叉验证的性能。随着阶数变得太大,交叉验证性能将开始相对于训练性能下降。让我们在我们的例子中试试这个。

3.1绘图列、交叉验证、测试

您可以在下面看到,将作为训练一部分的数据点(红色)与模型未训练的数据点混合在一起(测试和cv)。

fig, ax = plt.subplots(1,1,figsize=(4,4))
ax.plot(x_ideal, y_ideal, "--", color = "orangered", label="y_ideal", lw=1)
ax.set_title("Training, CV, Test",fontsize = 14)
ax.set_xlabel("x")
ax.set_ylabel("y")

ax.scatter(X_train, y_train, color = "red",           label="train")
ax.scatter(X_cv, y_cv,       color = dlc["dlorange"], label="cv")
ax.scatter(X_test, y_test,   color = dlc["dlblue"],   label="test")
ax.legend(loc='upper left')
plt.show()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

在这里插入图片描述

3.2寻找最佳阶数

在之前的实验室中,您发现可以通过使用多项式来创建能够拟合复杂曲线的模型(请参阅课程1,第2周“特征工程和多项式回归实验室”)。此外,您证明了通过增加多项式的次数,可以创建过拟合。(参见课程1,第3周,过度拟合实验室)。让我们用这些知识来测试我们区分过度拟合和欠拟合的能力。
让我们反复训练模型,每次迭代都增加多项式的次数。在这里,我们将使用scikit-learn线性回归模型来提高速度和简单性。

max_degree = 9
err_train = np.zeros(max_degree)    
err_cv = np.zeros(max_degree)      
x = np.linspace(0,int(X.max()),100)  
y_pred = np.zeros((100,max_degree))  #columns are lines to plot

for degree in range(max_degree):
    lmodel = lin_model(degree+1)
    lmodel.fit(X_train, y_train)
    yhat = lmodel.predict(X_train)
    err_train[degree] = lmodel.mse(y_train, yhat)
    yhat = lmodel.predict(X_cv)
    err_cv[degree] = lmodel.mse(y_cv, yhat)
    y_pred[:,degree] = lmodel.predict(x)
    
optimal_degree = np.argmin(err_cv)+1  #这行代码的作用是找到交叉验证误差(cross-validation error)数组 err_cv 中的最小值,并返回最小值所对应的索引加一(因为索引是从0开始的,所以要加一),即找到最优的多项式回归模型的阶数。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

让我们画出结果:

plt.close("all") # 用于关闭所有当前打开的 Matplotlib 图形窗口,以便开始绘制新的图表或清理当前的图形环境。
plt_optimal_degree(X_train, y_train, X_cv, y_cv, x, y_pred, x_ideal, y_ideal, 
                   err_train, err_cv, optimal_degree, max_degree)
  • 1
  • 2
  • 3

在这里插入图片描述
上图表明,将数据分为两组,即模型训练的数据和模型未训练的数据,可用于确定模型是否拟合不足或拟合过度。在我们的例子中,我们通过增加所使用的多项式的次数,创建了从欠拟合到过拟合的各种模型。

  • 在左图中,实线表示这些模型的预测。次数为1的多项式模型生成一条与极少数数据点相交的直线,而最大次数则与每个数据点非常接近。
  • 右侧:
    • 训练数据上的误差(蓝色)随着模型复杂度的增加而减小,正如预期的那样。
    • 交叉验证数据的误差最初随着模型开始与数据一致而减小,但随后随着模型开始在训练数据上过度拟合而增大(未能泛化)。

值得注意的是,这些例子中的曲线并不像你在课堂上画的那样平滑。很明显,分配给每组的特定数据点会显著改变您的结果。总的趋势才是最重要的。

3.3调整正则化。

在以前的实验室中,您已经使用正则化来减少过拟合。类似于阶数,可以使用相同的方法来调整正则化参数lambda(

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Cpp五条/article/detail/343721
推荐阅读
相关标签