吴恩达《机器学习》——欠拟合与过拟合

news2024/11/15 23:29:13

欠拟合与过拟合

  • 1. 方差与偏差
    • 模型的容量、过拟合和欠拟合
  • 2. Python代码实践
    • 2.1 拟合直线
    • 2.2 拟合多项式

数据集、源文件可以在Github项目中获得
链接: https://github.com/Raymond-Yang-2001/AndrewNg-Machine-Learing-Homework

1. 方差与偏差

在数学上,估计的偏差被定义为
b i a s ( θ ^ m ) = E ( θ ^ m ) − θ \rm{bias}(\hat{\theta}_{m})=\mathbb{E}(\hat{\theta}_{m})-\theta bias(θ^m)=E(θ^m)θ
其中,期望作用在所有数据(看做从随机变量上采样得到的)上, θ \theta θ是作用于定义分布的 θ \theta θ的真实值。如果 b i a s ( θ ^ m ) = 0 \rm{bias}(\hat{\theta}_{m})=0 bias(θ^m)=0,则说明这个估计是无偏估计;如果 lim ⁡ m → ∞ b i a s ( θ ^ m ) = 0 \lim_{m\to\infty}{\rm{bias}(\hat{\theta}_{m})=0} limmbias(θ^m)=0,则称这个估计为渐进无偏估计

除去偏差之外,我们有时还会考虑估计量的另一个性质是它作为数据样本的函数,期望的变化程度是多少。正如我们就可以计算估计量的期望来决定它的偏差,我们也可以计算出估计量的方差
V a r ( θ ^ ) \rm{Var}(\hat{\theta}) Var(θ^)
当独立地从潜在的数据生成过程中进行重采样数据集时,我们希望估计的偏差和方差都比较小。在下面,我们会从方差和偏差的概念出发,讨论其在机器学习中与模型容量、过拟合、欠拟合的关系。

模型的容量、过拟合和欠拟合

机器学习的主要挑战之一就是算法必须在先前未知的输入上表现良好,这叫做模型的泛化能力

在通常情况下,训练机器学习模型时,我们使用某个训练集,在训练集上的误差度量称作训练误差,优化算法的目标是降低训练误差,例如SGD算法。机器学习和优化的不同之处在与,机器学习还需要降低泛化误差,也成为测试误差。通常,我们会使用一个和训练集独立同分布的测试集来评估泛化误差。

我们可以总结影响机器学习算法好坏的因素如下:

  1. 降低训练误差
  2. 缩小训练误差和测试误差的差距

这其实对应了机器学习中两个关键的概念:欠拟合过拟合。欠拟合指模型不能获得足够小的训练误差;过拟合置训练误差和测试误差之间的差距太大。

通过调整模型的容量,可以控制模型是否偏向过拟合还是欠拟合。模型的容量指的是模型拟合各种函数的能力,容量低的模型可能会出现欠拟合,容量过高的模型可能出现过拟合,因为模型拟合了一些不适合泛化的特征。

偏差和方差就度量了训练误差和泛化误差

  • 偏差度量了偏离真实函数或参数的误差的期望
  • 方差度量了数据上任意特定采样导致的估计期望的偏差

也就是说,偏差越大的模型,对应了训练误差偏大,模型欠拟合;方差越大的模型,对应了训练误差小,但是泛化误差远大于训练误差,模型过拟合。具体泛化误差曲线如下图所示:
在这里插入图片描述

2. Python代码实践

接下来,我们将使用线性回归的例子来进行代码实践。使用的数据集如下图所示:
在这里插入图片描述
直观的感觉是,我们需要拟合一个二次及以上的曲线才能很好的进行回归。接下来,将分别实现一次直线和多项式的拟合。
这里给出线性回归类和需要用到的函数

import numpy as np


def loss(pred, target):
    """
    MSE Loss
    :param pred: ndarray, (n_sample, n_feature), prediction
    :param target: ndarray, (n_sample, n_feature), target
    :return:
    """
    return np.sum(np.power((pred - target), 2)) / (2 * pred.shape[0])


def reg_loss(pred, target, theta, scale):
    """
    Regularized Loss (L2 regularize)
    :param pred:
    :param target:
    :param theta: parameters
    :param scale: lambda for regularize
    :return:
    """
    reg_term = theta.copy()  # (1, 2)
    reg_term[:, 0] = 0
    return loss(pred, target) + scale / (2 * pred.shape[0]) * reg_term.sum()


def gradient(x, pred, target):
    """
    Get gradient for model
    :param x:
    :param pred:
    :param target:
    :return:
    """
    # x(n,2)
    t = np.ones(shape=(x.shape[0], 1))
    x = np.concatenate((t, x), axis=1)
    # pred-target (n,1)
    # gradient (1,2)
    g = np.matmul((pred-target).T, x)
    return g / pred.shape[0]


def reg_gradient(x, pred, target, theta, scale):
    """
    Regularized gradient
    :param x:
    :param pred:
    :param target:
    :param theta:
    :param scale:
    :return:
    """
    g = gradient(x, pred, target)
    reg_term = theta.copy()
    reg_term[:, 0] = 0
    return g + (scale / pred.shape[0]) * reg_term


class LinearRegression:
    def __init__(self):
        self.theta = None

    def init_theta(self, shape):
        self.theta = np.zeros(shape)
        # self.theta = np.ones(shape)

    def optimize(self, g, lr):
        self.theta = self.theta - lr * g

    def load_parameters(self, parameters):
        self.theta = parameters

    def __call__(self, x, *args, **kwargs):
        #  x (n,2)
        t = np.ones(shape=(x.shape[0], 1))
        x = np.concatenate((t, x), axis=1)
        # (n,2)@(2,1)=(n,1)
        return x @ self.theta.T

2.1 拟合直线

from Bias import LinearRegression,loss,reg_loss,gradient,reg_gradient

epochs = 100
alpha = 0.05
regularize = False
scale = 0.1
x_norm = (train_x-train_x.mean(axis=0))/train_x.std(axis=0)
y_norm = (train_y-train_y.mean(axis=0))/train_y.std(axis=0)
train_loss = []
val_loss = []
test_loss = []
model = LinearRegression()
model.init_theta(shape=(1,2))
for epoch in range(epochs):
    pred = model(x_norm)
    g = reg_gradient(x_norm, pred, y_norm, model.theta, scale) if regularize else gradient(x_norm, pred, y_norm)
    model.optimize(g,alpha)

    theta = model.theta.copy()
    _theta = model.theta.copy()
    _theta[0, 1:] = _theta[0, 1:] / train_x.std(axis=0).T * train_y.std(axis=0)[0]
    _theta[0, 0] = _theta[0, 0] * train_y.std(axis=0)[0] + train_y.mean(axis=0)[0] - np.dot(_theta[0, 1:], train_x.mean(axis=0).T)
    # _theta[0, 0] = _theta[0, 0] - np.dot(_theta[0, 1:], train_x.mean(axis=0).T)
    model.load_parameters(_theta)
    pred = model(train_x)
    t_loss = reg_loss(pred,train_y,model.theta,scale) if regularize else loss(pred,train_y)
    train_loss.append(t_loss)
    pred_val = model(val_x)
    v_loss = reg_loss(pred_val,val_y,model.theta,scale) if regularize else loss(pred_val,val_y)
    val_loss.append(v_loss)

    test_pred = model(test_x)
    t_loss = reg_loss(test_pred, test_y, model.theta, scale)
    test_loss.append(t_loss)


    print("Epoch: {}/{}\tTrain Loss: {:.4f}\t\tVal Loss: {:.4f}\tTest Loss: {:.4f}".format(epoch, epochs,t_loss,v_loss, t_loss))
    model.load_parameters(theta)

# unscaling parameters
theta_f = np.zeros_like(model.theta)
theta_f[0, 1:] = model.theta[0, 1:] / train_x.std(axis=0).T * train_y.std(axis=0)[0]
theta_f[0, 0] = model.theta[0, 0] * train_y.std(axis=0)[0] + train_y.mean(axis=0)[0] - np.dot(theta_f[0, 1:], train_x.mean(axis=0).T)
theta_f

训练过程如下所示:
在这里插入图片描述
可以看到,在不使用正则化的时候,在训练的最后验证损失出现了轻微的上升,这其实是轻微的过拟合。但整体而言,训练损失、验证损失、泛化损失都在20-40的范围内,对于分布在0-60内的数据来说,这样的即使是训练损失也显得过大,这就证明模型的容量不足,存在严重的欠拟合现象,需要进一步提高模型容量来提升模型的拟合效果。

决策边界可视化如下图所示:
在这里插入图片描述

接下来,我们将使用多项式拟合。

2.2 拟合多项式

我们首先要对数据进行增强,这里将数据扩展为八个维度,对应1-8次方,并试图拟合一个八次多项式进行回归分析。

def feature_mapping(x, degree):
    # feature = np.zeros([x.shape[0],1])
    feature = [np.power(x[:,0],i) for i in range(1, degree+1)]
    return np.array(feature).T

train_x_map = feature_mapping(train_x,8)
val_x_map = feature_mapping(val_x,8)
test_x_map = feature_mapping(test_x, 8)
train_x_map

增强后的数据如下所示,以训练集为例:
在这里插入图片描述
进行训练

from Bias import LinearRegression,loss,reg_loss,gradient,reg_gradient

epochs = 200
alpha = 0.2
regularize = True
scale = 0
x_norm = (train_x_map-train_x_map.mean(axis=0))/train_x_map.std(axis=0)
y_norm = (train_y-train_y.mean(axis=0))/train_y.std(axis=0)
train_loss = []
val_loss = []
test_loss = []
model = LinearRegression()
model.init_theta(shape=(1,9))
for epoch in range(epochs):
    pred = model(x_norm)
    g = reg_gradient(x_norm, pred, y_norm, model.theta, scale) if regularize else gradient(x_norm, pred, y_norm)
    model.optimize(g,alpha)

    theta = model.theta.copy()
    _theta = model.theta.copy()
    _theta[0, 1:] = _theta[0, 1:] / train_x_map.std(axis=0).T * train_y.std(axis=0)[0]
    _theta[0, 0] = _theta[0, 0] * train_y.std(axis=0)[0] + train_y.mean(axis=0)[0] - np.dot(_theta[0, 1:], train_x_map.mean(axis=0).T)
    # _theta[0, 0] = _theta[0, 0] - np.dot(_theta[0, 1:], train_x_map.mean(axis=0).T)
    model.load_parameters(_theta)
    pred = model(train_x_map)
    t_loss = reg_loss(pred,train_y,model.theta,scale) if regularize else loss(pred,train_y)
    train_loss.append(t_loss)
    pred_val = model(val_x_map)
    v_loss = reg_loss(pred_val,val_y,model.theta,scale) if regularize else loss(pred_val,val_y)
    val_loss.append(v_loss)
    test_pred = model(test_x_map)
    t_loss = reg_loss(test_pred, test_y, model.theta, scale)
    test_loss.append(t_loss)

    print("Epoch: {}/{}\tTrain Loss: {:.4f}\t\tVal Loss: {:.4f}\tTest Loss: {:.4f}".format(epoch, epochs,t_loss,v_loss,t_loss))
    model.load_parameters(theta)


theta_f = np.zeros_like(model.theta)
theta_f[0, 1:] = model.theta[0, 1:] / train_x_map.std(axis=0).T * train_y.std(axis=0)[0]
theta_f[0, 0] = model.theta[0, 0] * train_y.std(axis=0)[0] + train_y.mean(axis=0)[0] - np.dot(theta_f[0, 1:], train_x_map.mean(axis=0).T)
theta_f

不进行正则化(正则化参数为0)
在这里插入图片描述
能看到在后半部分验证误差和测试误差明显加大,存在过拟合。

下面进行正则化,正则化参数为20

在这里插入图片描述
可以看到,整体损失要显著大于上图,这说明出现严重的欠拟合,我们可以从决策边界看出来、
在这里插入图片描述
正则化参数为1
在这里插入图片描述
可以看到很明显地减轻了过拟合的现象。
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/141205.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Java基础漏洞(二)

继续填补自己的知识漏洞 1.&、&&、|、||之间的区别 &是逻辑与,而&&则是短路与。&和&&之间的区别是,在短路与&&的情况下,两个条件当第一个条件为假时,则不再执行第二个条件&#xf…

java学习之类方法

目录 一、基本介绍 二、类方法的调用 三、类方法的应用实例 代码 内存分析 运行结果 四、类方法的经典使用场景 五、类方法使用细节 第一条 第二条 第三条 第四条 第五条 第六条 六、练习 第一题 考察点 分析 结果 第二题 代码 考察点 结果 第三题 类方法 …

LeetCode498. 对角线遍历

LeetCode刷题记录 文章目录📜题目描述💡解题思路⌨C代码📜题目描述 给你一个大小为 m x n 的矩阵 mat ,请以对角线遍历的顺序,用一个数组返回这个矩阵中的所有元素。 示例1 输入:mat [[1,2,3],[4,5,6],[…

VUE2使用浏览器缓存的方法

分两种:localStorage和sessionStorage,它两统称webStorage 注意点1:localStorage对象和sessionStorage对象都是window对象下的,且方法都是一样的,默认”window.”可以省略,添加可用setItem(K,V),查询可用ge…

数据库|scMethBank:单细胞全基因组 DNA 甲基化图谱数据库

甲基化是DNA的一种重要化学修饰,可调节基因的表达和关闭,与癌症、衰老、老年痴呆等许多疾病密切相关,是表观遗传学的重要研究内容之一。测序技术的发展,极大促进了单细胞DNA甲基化研究。然而大量数据的不断积累,对单细…

《HTTP权威指南》----HTTP报文

目录 报文流 报文的组成部分 报文语法 1.起始行 2.首部 通用首部,既可以出现在请求报文中也可以出现在响应报文中。 请求首部,提供更多有关请求的信息。 响应首部,提供更多有关响应的信息。 实体首部,描述主题的长度和内…

2022年,一个技术账号的年终独白,满篇都写着2个字:真难。

2022年,梦想橡皮擦这个账号经历了成长,突破,回归 2023年,适应改变 文章目录序2022年,梦想橡皮擦账号整体汇总原创博客KPI计划与完成总排名KPI计划与完成2022年,橡皮擦获得的荣誉2022年,做技术博…

日志收集系统架构

背景 应用服务器多,日志文件被分散在各个应用服务器上,需要依次登录每台设备才能查看日志,效率低下,且不利于服务器安全管控,加大生产服务器的风险;日志文件不统一,各项目日志没有统一的规范&a…

Python Django教程之实现天气应用程序

基本设置 将目录更改为天气 cd weather启动服务器 python manage.py runserver要检查服务器是否正在运行,请转到 Web 浏览器并输入为 URL。现在,您可以通过按以下命令停止服务器http://127.0.0.1:8000/ ctrl-c 实现 python manage.py startapp main…

Vehicle Speed Forecasting Based On GCN-LSTM Combined Model

GCN-LSTM模型预测道路交通车辆速度 Vehicle Speed Forecasting Based On GCN-LSTM Combined Model Summary This research offers a multistep traffic flow forecasting framework relying on interest spatial-temporal-graph neural network-long short-term memory neura…

【阅读】《MYSQL技术内幕:innodb》索引

概念 索引的类型 聚集索引:叶子节点包含行记录的全部数据辅助索引:叶子节点不包含行记录的全部数据,除了键值以外,还包含指向索引行的书签。 堆表和索引组织表 堆表 无论是主键索引还是普通索引都是辅助索引。数据是按照插入…

​力扣解法汇总2042. 检查句子中的数字是否递增

目录链接: 力扣编程题-解法汇总_分享记录-CSDN博客 GitHub同步刷题项目: https://github.com/September26/java-algorithms 原题链接:力扣 描述: 句子是由若干 token 组成的一个列表,token 间用 单个 空格分隔&…

微信小程序实战十五:Https服务搭建及Nginx配置

文章目录 1.最终效果预览2.后端jar包部署及启动3.前端管理系统部署4.Nginx的配置5.https证书申请6.小程序后台中配置子域名这篇文章重点介绍下微信小程序正式版上线前https服务的搭建及配置过程,之前整个流程都操作过,时隔一年再次从零开始操作有些地方的印象已经模糊了,好记…

Java Swing五子棋项目

一、项目简介 本项目为Java Swing五子棋项目,主要针对计算机相关专业的正在做毕设的学生与需要项目实战练习的Java学习者。 包含:项目源码、数据库脚本等,该项目附带全部源码可作为毕设使用。 项目都经过严格调试,eclipse 确保可…

ArcGIS基础实验操作100例--实验50以栅格分区裁剪面要素

本实验专栏参考自汤国安教授《地理信息系统基础实验操作100例》一书 实验平台:ArcGIS 10.6 实验数据:请访问实验1(传送门) 高级编辑篇--实验50 以栅格分区裁剪面要素 目录 一、实验背景 二、实验数据 三、实验步骤 &#xff0…

Vulkan PBR与IBL实践

对我来说,每天能过得心情舒畅,有酒喝有美味佳肴吃,必要时工作一会儿,晚上睡得舒舒服服,就行了。 ——迪希亚 序 说实话我已经记不清上一篇文章是什么时候的事情了,感觉得有好几个月了,但其实我…

【Linux】【信号】

文章目录一、信号是什么1.生活中的信号2.什么是Linux信号3.信号处理的常见方式4.Linux当中的信号二、信号的产生1.signal函数2.核心转储3.验证进程等待中的core dump标记位三、信号的系统调用接口1.kill2.raise3.abort四、由软件条件产生信号alarm五、硬件异常产生信号1.除零异…

从编译到可执行,eBPF 加速容器网络的原理分析 | 龙蜥技术

编者按:eBPF(extended Berkeley Packet Filter) 是一种可以在 Linux 内核中运行用户编写的程序,而不需要修改内核代码或加载内核模块的技术。简单说,eBPF 让 Linux 内核变得可编程化了。本文整理自龙蜥大讲堂第 57 期,浪潮信息 SE…

HTML防数据采集

什么是防采集 就是我们想利用爬虫工具采集某个网站的数据(前提当然是公开合法数据),但网站不想给你采集而设置的技术阻挡措施。 常见的防止采集方案 利用输入验证码框验证,在采集某些网站过程中,要求你输入验证码&a…

电源特性测试测试哪些方面?电源特性自动测试系统NSAT-8000介绍

假设电源适配器厂家对电源适配器进行了很合理的测试验证工作,那么电源适配器输出的电压应该是个稳定的电源输出。那么对于一些小型设备而言,电源测试就主要测试设备电源端的测试工作。下面纳米软件Namisoft小编将带大家一起看看,关于电源特性…