【机器学习笔记5】过拟合与正则化

目录

前置知识

什么是欠拟合与过拟合?

导致欠拟合与过拟合的原因

解决方法

正则化

正则化后的线性回归和逻辑回归

代价函数

梯度计算(求偏导)

使用正则化后过拟合模型的变化


前言:这篇文章皆以回归模型为例。

 在开始之前,你可能先要了解以下几个概念:

前置知识

偏差与方差

在机器学习中,偏差描述的是根据样本拟合出的模型输出结果与真实结果的差距,损失函数就是依据模型偏差的大小进行反向传播的。降低偏差,就需要复杂化模型,增加模型参数,但容易造成过拟合。方差描述的是样本上训练出的模型在测试集上的表现,降低方差,继续要简化模型,减少模型的参数,但容易造成欠拟合。根本原因是,我们总是希望用有限的训练样本去估计无限的真实数据。假定我们可以获得所有可能的数据集合,并在这个数据集上将损失函数最小化,则这样的模型称之为“真实模型”。但实际应用中,并不能获得且训练所有可能的数据,所以真实模型一定存在,但无法获得。欠拟合_百度百科 (baidu.com)

泛化能力

通俗来讲,就是训练出的模型对新鲜样本的适应能力。

什么是欠拟合与过拟合?

示例:正常拟合情况

欠拟合:表现为高偏差。欠拟合模型在训练集、验证集和测试集表现均不佳。就像一个不好好学习的学生,在模拟考试和新的考试都考不好。

过拟合:表现为高方差。过拟合模型在训练集上表现很好,但遇到陌生数据时就表现得很差,即模型的泛化能力很差。就像一个学生在做模拟卷时太过于努力了,但是他学会的太贴合模拟卷的题型,但是遇到新的考试就做的很差。

 下图是逻辑回归的过拟合示例:

 注:红线为正常拟合情况

导致欠拟合与过拟合的原因

欠拟合(underfitting):

  • 特征量太少

  • 模型复杂度过低

过拟合(overfitting): 这里只讨论回归模型的过拟合原因

  • 样本数量太少

  • 模型复杂度过高

  • 特征量太多

  • 样本的噪音数据干扰过大

解决方法

欠拟合

相对较好解决。

  1. 选择更复杂的模型

  2. 增加更多特征

  3. 调整学习率、训练次数等参数

过拟合:

  1. 增加训练数据量,数据量越多,过拟合可能越小

  2. 减小模型复杂度。

  3. 减少特征数目。去除某些特征,可以提高模型泛化能力。

  4. 正则化(推荐)

正则化

这里只对线性回归和逻辑回归的正则化进行说明,其他模型和范数暂不拓展。

现在有下(右图)的过拟合模型:

 一种解决过拟合的方式是,我们可以手动筛选特征,直接将x^3,x^4去除。于是我们可以得到左边的模型。但还有一种不那么暴力的方法,我们如果可以让w_3,w_4尽量小,比如0.0000001,那么就相当于消除了x^3,x^4

这是原来的代价函数:

J(\vec w,b) = \frac{1}{2m}\sum_{i=1}^{m}(f_{\vec w,b}(\vec x^{(i)})-y^{(i)})^2

现在,我们让J(\vec w,b)+1000w_3^2+1000w_4^2,如果要让现在的代价函数尽量小,w_3,w_4必须足够小。否则代价函数会非常非常大。于是我们就可以求得很小很小的w_3,w_4,有效的消除了x^3,x^4这两项特征的影响。

上面这个例子就是正则化的思想,我们正则化了x^3,x^4两个特征。

然而,实际中我们可能有许多种特征,比如100个特征,我们可能分不清哪些特征是重要的,哪些应该被正则化。所以正则化一般的实现方式是正则化所有特征。不过一般不会正则化常数b。

正则化后的线性回归代价函数:

J(\vec w,b) = \frac{1}{2m}\sum_{i=1}^{m}(f_{\vec w,b}(\vec x^{(i)})-y^{(i)})^2+\frac{\lambda}{2m}\sum_{j = 0}^{n-1}w_j^2

\lambda过小时,正则化效果较差。比如等于0时没有正则化。当\lambda过大时,可能会发生欠拟合。比如\lambda = 10^{10},拟合出来的可能是一条几乎平行于x轴的直线f(x) = b.

正则化后的线性回归和逻辑回归

代价函数

线性回归

公式:J(\vec w,b) = \frac{1}{2m}\sum_{i=1}^{m}(f_{\vec w,b}(\vec x^{(i)})-y^{(i)})^2+\frac{\lambda}{2m}\sum_{j = 0}^{n-1}w_j^2

其中,f_{\vec w,b}(x^{(i)}) = \vec w\cdot\vec x^{(i)}+b

# 线性回归正则化代价函数
def compute_cost_linear_reg(X, y, w, b, lambda_ = 1):
    '''

    :param X(narray(m,n)): m个样例,n个特征
    :param y(ndarray (m,)):目标值
    :param w(ndarray (n,)):模型参数
    :param b(scalar):模型参数
    :param lambda_(scalar):正则化控制量
    :return:
        total_cost (scalar):  损失值
    '''

    m,n = X.shape
    cost = 0.0
    for i in range(m):
        f_wb_i = np.dot(X[i],w) + b
        cost = cost + (f_wb_i - y[i])**2
    cost = cost / (2*m)

    reg_cost = 0
    for j in range(n):
        reg_cost += w[j]**2
    reg_cost = (lambda_/(2*m)) * reg_cost

    total_cost = cost + reg_cost
    return total_cost

 逻辑回归

公式:

J(\vec w,b) = \frac{1}{m}\sum_{i=0}^{m-1}[-y^{(i)}log(f_{\vec w,b}(\vec x^{(i)})-(1-y^{(i)})log(1-f_{\vec w,b}(\vec x^{(i)})]+\frac{\lambda}{2m}\sum_{j = 0}^{n-1}w_j^2

其中,

f_{\vec w,b}(\vec x^{(i)}) = sigmoid(\vec w \cdot \vec x+b)

sigmoid(z) = \frac{1}{1+e^{-z}}

def sigmoid(z):
    '''

    :param z: 标量
    :return: 标量
    '''
    g = 1 / (1 + np.exp(-z))
    return g   


# 逻辑函数正则化代价函数
def compute_cost_logistic_reg(X, y, w, b, lambda_ = 1):
    '''

    :param X(narray(m,n)): m个样例,n个特征
    :param y(ndarray (m,)):目标值
    :param w(ndarray (n,)):模型参数
    :param b(scalar):模型参数
    :param lambda_(scalar):正则化控制量
    :return:
        total_cost (scalar):  损失值
    '''
    m, n = X.shape
    cost = 0.0
    for i in range(m):
        z_i = np.dot(X[i], w) + b
        f_wb_i = sigmoid(z_i)
        cost += -y[i] * np.log(f_wb_i) - (1 - y[i]) * np.log(1 - f_wb_i)

    cost = cost / m

    reg_cost = 0
    for j in range(n):
        reg_cost += (w[j] ** 2)
    reg_cost = (lambda_ / (2 * m)) * reg_cost

    total_cost = cost + reg_cost
    return total_cost

梯度计算(求偏导)

线性回归和逻辑回归的梯度计算出来格式都一样,注意里面的f_{\vec w,b}(\vec x)指代不同即可。

公式:

\frac{\partial J(\vec w,b)}{\partial b} = \frac{1}{m}\sum_{i=0}^{m-1}(f_{\vec w,b}(\vec x^{(i)})-y^{(i)})x_j^{(i)}+\frac {\lambda}{m}w_j

\frac{\partial J(\vec w,b)}{\partial b} = \frac{1}{m}\sum_{i=0}^{m-1}(f_{\vec w,b}(\vec x^{(i)})-y^{(i)})

线性回归中,f_{\vec w,b}(\vec x^{(i)}) = \vec w \cdot \vec x+b

逻辑回归中,f_{\vec w,b}(\vec x) = sigmoid(\vec w\cdot \vec x+b)

线性回归:

def compute_gradient_linear_reg(X, y, w, b, lambda_):
    '''

    :param X(narray(m,n)): m个样例,n个特征
    :param y(ndarray (m,)):目标值
    :param w(ndarray (n,)):模型参数
    :param b(scalar):模型参数
    :param lambda_(scalar):正则化控制量
    :return:
        dj_dw (ndarray (n,)): 代价函数对w的偏导
        dj_db (scalar): 代价函数对b的偏导
    '''
    m, n = X.shape 
    dj_dw = np.zeros((n,))
    dj_db = 0.

    for i in range(m):
        err = (np.dot(X[i], w) + b) - y[i]
        for j in range(n):
            dj_dw[j] = dj_dw[j] + err * X[i, j]
        dj_db = dj_db + err
    dj_dw = dj_dw / m
    dj_db = dj_db / m

    for j in range(n):
        dj_dw[j] = dj_dw[j] + (lambda_ / m) * w[j]

    return dj_db, dj_dw

 逻辑回归:

# 逻辑回归梯度计算
def compute_gradient_logistic_reg(X, y, w, b, lambda_):
    '''

    :param X(narray(m,n)): m个样例,n个特征
    :param y(ndarray (m,)):目标值
    :param w(ndarray (n,)):模型参数
    :param b(scalar):模型参数
    :param lambda_(scalar):正则化控制量
    :return:
        dj_dw (ndarray (n,)): 代价函数对w的偏导
        dj_db (scalar): 代价函数对b的偏导
    '''

    m, n = X.shape
    dj_dw = np.zeros((n,))
    dj_db = 0.0

    for i in range(m):
        f_wb_i = sigmoid(np.dot(X[i], w) + b)
        err_i = f_wb_i - y[i]
        for j in range(n):
            dj_dw[j] = dj_dw[j] + err_i * X[i, j]
        dj_db = dj_db + err_i
    dj_dw = dj_dw / m
    dj_db = dj_db / m

    for j in range(n):
        dj_dw[j] = dj_dw[j] + (lambda_ / m) * w[j]

    return dj_db, dj_dw

 梯度迭代就不写了,之前的文章有详细写过,没什么变化。

使用正则化后过拟合模型的变化

这是正则化之后的结果:

 嗯...对比开始的过拟合,结果好得多了,虽然比起红线模拟的模型还是有一些差距。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Twilight Sparkle.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值