24. 深度学习进阶 - 矩阵运算的维度和激活函数

news2024/11/28 5:39:06

在这里插入图片描述

Hi,你好。我是茶桁。

咱们经过前一轮的学习,已经完成了一个小型的神经网络框架。但是这也只是个开始而已,在之后的课程中,针对深度学习我们需要进阶学习。

我们要学到超参数,优化器,卷积神经网络等等。看起来,任务还是蛮重的。

行吧,让我们开始。

矩阵运算的维度

首先,我们之前写了一份拓朴排序的代码。那我们是否了解在神经网络中拓朴排序的作用。我们前面讲过的内容大家可以回忆一下,拓朴排序在咱们的神经网络中的作用不是为了计算方便,是为了能计算。

换句话说,没有拓朴排序的话,根本就没法计算了。Tensorflow和PyTourh最大的区别就是,Tensorflow在运行之前必须得把拓朴排序建好,PyTorch是在运行的过程中自己根据我们的连接状况一边运行一边建立。但是它们都有拓朴排序。

拓朴排序后要进行计算,那就要提到维度问题,在进行机器学习的时候一定要确保我们矩阵运算的维度正确。我们来看一下示例就明白我要说的了。

x = torch.from_numpy(np.random.random(size=(4, 10)))
print(x.shape)

---
torch.Size([4, 10])

假如说,现在我们生成了一个4,10的矩阵,也就是4行10列。

from torch import nn
linear = nn.Linear(in_features=10, out_features=5).double()
print(linear(x).shape)

---
torch.Size([4, 5])

然后我们来给他定义一个线性变化,in_features=10,这个就是必须的, 然后,out_features=5,假如把它分成5类。

这个时候,你看他就变成一个四行五列的一个东西了。

刚才我们说了,in_features=10是必须的,如果这个值我们设置成其他的,比如说8,那就不行了,运行不了。会收到警告:mat1 and mat2 shapes cannot be multiplied (4x10 and 8x5)

我们再给它来一个Softmax

nonlinear = nn.Softmax()
print(nonlinear(linear(x)))

这样,我们就得到了一个4*5的概率分布。

我们把这个非线性函数换一下,换成Sigmoid, 之前的Softmax赋值给yhat, 咱们做一个多层的:

yhat = nn.Softmax()
nonlinear = nn.Sigmoid()
linear2 = nn.linear(in_features=n, out_features=8).double()

print(yhat(linear2(nonlinear(linear(x)))))

好,这个时候,我还并没有给in_features赋值,我们来想想,这个时候应该赋值是多少?也就是说,我们现在的linear2到底传入的特征是多少?

我们这里定义的linearlinear2其实就是w*x+b

那这里我们来推一下,第一次使用linear的时候,我们得到了4*5的矩阵对吧?nonlinear并没有改变矩阵的维度。现在linear2中,那我们in_features赋值就得是5对吧?

yhat = nn.Softmax()
nonlinear = nn.Sigmoid()
linear2 = nn.linear(in_features=5, out_features=8).double()

print(yhat(linear2(nonlinear(linear(x)))).shape)

---
torch.Size([4, 8])

然后我们就得到了一个4*8的维度的矩阵。

那其实在PyTorch里提供了一种比较简单的方法,就叫做Sequential

model = nn.Sequential(
    nn.Linear(in_features=10, out_features=5).double(),
    nn.Sigmoid(),
    nn.Linear(in_features=5, out_features=8).double(),
    nn.Softmax(),
)

print(model(x).shape)

---
torch.Size([4, 8])

这样,我们就把刚才几个函数方法按顺序都一个一个的写在Sequential里,那其实刚才的过程,也就是解释了这个方法的原理。

接着,我们来写一个ytrue:

ytrue = torch.randint(8, (4, ))
loss_fn = nn.CrossEntropyLoss()

print(model(x).shape)
print(ytrue.shape)

---
torch.Size([4, 8])
torch.Size([4])

现在ytrue就是CrossEntropyLoss输入的一个label值。

然后我们就可以进行反向传播了:

loss.backward()

for p in model.parameters():
  print(p, p.grad)
  
---
Parameter containing:
tensor([...])
...

求解反向传播之后就可以得到它的梯度了。然后再经过一轮一轮的训练,就可以把梯度稳定在某个值,这就是神经网络进行学习的一个过程。那主要是在这个过程中,一定要注意矩阵前后的大小。

激活函数

然后我们来看看激活函数的重要性。

在我们之前的课程中,我们提到过一个概念「激活函数」,不知道大家还有没有印象。那么激活函数的作用是什么呢? 是实现非线性拟合对吧?

打比方来说,如果我们现在要拟合一个函数f(x) = w*x+b, 你把它再给送到一个g(x), 再比如g(x)=w2*x+b,我们来做一个拟合,那么g(f(x)), 那是不是还是一样,g(f(x)) = w2*(w*x+b)+b, 然后就变成w2*w*x + w2*b + b, 那其实这个就还是一个线性函数。

我们每一段都给它进行一个线性变化,再进行一个非线性变化,再进行一个线性变化,一段一段这样折起来,理论上它可以拟合任何函数。

这个怎么理解?其实我们如何用已知的函数去拟合函数在高等数学里边是一个一直在学习,一直在研究的东西。学高数的同学应该知道,高数里面有一个著名的东西叫做傅立叶变化,这是一种线性积分变换,用于函数在时域和频域之间的变换。

我们给定任意一个复杂的函数,都可以通过sin和cos来把它拟合出来,其关键思想是任何连续、周期或非周期的函数都可以表示为正弦和余弦函数的组合。通过计算不同频率的正弦和余弦成分的系数an和bn, 我们可以了解一个函数的频谱特性,即它包含那些频率成分。

f ( x ) = a 0 + ∑ n = 1 0 ( a n c o s ( 2 π n f x ) + b n s i n ( 2 π n f x ) ) \begin{align*} f(x) = a_0 + \sum_{n=1}^0(a_n cos(2\pi nfx) + b_n sin(2\pi n fx)) \end{align*} f(x)=a0+n=10(ancos(2πnfx)+bnsin(2πnfx))

除此之外,我们还有一个泰勒展开。我在数学篇的时候有仔细讲解过这个部分,大家可以回头去读一下我那篇文章,应该是数学篇第13节课,在那里我曾说过,所有的复杂函数都是用泰勒展开转换成多项式函数计算的。

之前有同学给我私信,也有同学在我文章下留言,说到某个位置看不懂了,还是数学拖了后腿。但是其实只是应用的话无所谓,但是如果想在这个方面有所建树,想要做些不一样的东西出来,还是要把数学的东西好好补一下的。

OK,那其实呢,我们的深度学习本质上其实就是在做这么一件事情,就是来自动拟合,到底是由什么构成的。

大家再来想一下,一个比较重要的,就是反向传播和前向传播。这个我们前面的课程里有详细的讲过,就是,我们的前向传播和反向传播的作用是什么。

那现在我们学完前几节了,回过头来我们想想,前向传播的作用是什么?反向传播的这个作用呢?

现在,假如说我已经训练出来了一个模型,我要用这个模型去预测。那么第一个问题是,预测的时候需不需要求loss?第二个是我需不需要做反向传播?

然后我们再来思考一个问题,如果我们需要求loss对于某个参数wi的偏导 ∂ l o s s ∂ w i \frac{\partial loss}{\partial w_i} wiloss,那么我们首先需要进行反向传播对吧?那我们在进行反向传播之前,能不能不进行前向传播?

也就是说,我们把这个模型放在这里,一个x,然后输入进去得到一个loss。那么咱们训练了一轮之后,我们能不能在求解的时候不进行前向传播,直接进行反向传播?

我们只要知道,求loss值需要预测值就明白了。

那我们继续来思考,loss值和precision、recall等等的关系是什么?这些是什么?我们之前学习过,这些是评测指标对吧?也就是再问,loss和评测指标的关系是什么?

也就是说,我们能不能用precision,能不能用precision来做我们的loss函数?不能对吧,无法求导。

所以在整个机器学习的过程中,如果要有反向传播、梯度下降,必须得是可导的。像我们所说的MSE是可导的,cross-entropy也是可以求导的。

那如果上过我之前课程的同学应该记得,可求导的的函数需要满足什么条件?光滑性和连续性对吧?连续性呢,是可求导的一个必要条件,但不是充分条件,还必须在某个点附近足够光滑,以使得导数存在。

对于loss函数的设定,第一点,一定是要能求偏导的。第二呢,就是它一定得是一个凸函数:Convex functions。

那什么叫做凸函数呢?如果一个函数上的任意两点连线上的函数值都不低于这两点的函数值的线段,就称为凸函数。常见的比如线性函数,指数函数,幂函数,绝对值函数等都是凸函数。

想象一下,有一辆车,从a点开到b点,如果这个车在a点到b点的时候方向盘始终是打在一个方向的,那我们就说它是凸函数。

不过在一些情况下有些函数它不是凸函数,就在数学上专门有一个研究领域,Convex optimization,凸优化其实就是解决对于这种函数怎么样快速的求出他的基值,另外一个就是对于这种非凸函数怎么把它变成凸函数。

不同的激活函数它有什么区别呢?在最早的时候,大家用的是Sigmoid

σ ( z ) = 1 1 + e − z \begin{align*} \sigma(z)=\frac{1}{1+e^{-z}} \end{align*} σ(z)=1+ez1

Sigmoid

为什么最早用Sigmoid,这是因为Sigmoid有个天然的优势,就是它输出是0-1,而且它处处可导。

但是后来Sigmoid的结果有个e^x,指数运算就比较费时,这是第一个问题。第二个问题是Sigmoid的输出虽然是在0~1之间,但是平均值是0.5,对于程序来说,我们希望获得均值等于0,STD等于1。我们往往希望把它变成这样的一种函数,这样的话做梯度下降的时候比较好做。

于是就又提出来了一个更简单的方法,就是反正切函数:Tanh

σ ( z ) = e z − e − z e z + e − z \sigma(z) = \frac{e^z - e^{-z}}{e^z + e^{-z}} σ(z)=ez+ezezez

Tanh

它的形式和Sigmoid很像,不同的是平均值,它的平均值是0。现在这个用的也挺多。

但是Tanh和sigmoid一样都有一个小问题,就是它的绝大多数地方loss都等于0, 那么wi大部分时候就没有办法学习,也就不会更新。

为了解决这个问题,就是有人提出来了一种非常简单的方法,就是ReLU

R e L U ( z ) = { z , z > 0 0 , o t h e r w i s e \begin{align*} ReLU(z) = \begin{cases} z, z>0 \\ 0, otherwise \end{cases} \end{align*} ReLU(z)={z,z>00,otherwise

Alt text

这种方法看似非常简单,但其实非常好用。它就是当一个x值经过ReLU的时候,如果它大于0就还保持原来的值,如果不大于0就直接把它变成0。

这样大家可能会觉得x<0时有这么多值没有办法求导,但其实比起sigmoid来说可求导的范围其实已经变多了。而且你会发现要对他x大于0的地方求偏导非常的简单,就直接等于1。

可以保证它肯定是可以做更新的,而且ReLU这种函数它是大量的被应用在卷积神经网络里边。

在咱们后面的课程中,会讲到卷积,它是有一个卷积核,[F1,F2,F3,F4]然后把它经过ReLU之后,可能会变成[F1,0,F3,0]。那我们只要更新F1,F3就可以了,下一次再经过某种方式,在重新把F2和F4我们重新计算一下。

也就是说现在的wx+b不像以前一样,只有一个w,如果x值等于0,那整个都等于0. 而是我们会有一个矩阵,它部分等于0也没关系。而且它的求导会变得非常的快,比求指数的导数快多了。

那其实这里还有一个小问题,面试的时候可能会问到,就是ReLU其实在0点的时候不可导,怎么办?

这个很简单,可以在函数里边直接设置一下,直接给他一个0的值就可以了,就是在代码里面加一句话。

再后来,又有人提出了一种方法:LeakyRelU

L e a k y R e L U ( z ) = { z , z > 0 a z , o t h e r w i s e LeakyReLU(z) = \begin{cases} z, z>0 \\ az, otherwise \end{cases} LeakyReLU(z)={z,z>0az,otherwise

Alt text

它把小于0的这些地方,也加了一个很小的梯度,这样的话大于0的时候partial就恒等于1,小于的时候partial也恒等于一个值,比如定一个a=0.2, 都可以。那这样就可以实现处处有导数。

但是其实用的也不太多,因为我们事实上发现在这种卷积神经网络里边,我们每一次把部分的权重设置成0不更新,反而可以提升它的训练效率,我们反而可以每次把训练focus on在几个参数上。

好,下节课,咱们来看看初始化的内容。

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

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

相关文章

用xlwings新建一个excel并同时生成多个sheet

新建一个excel并同时生成多个sheet&#xff0c;要实现如下效果&#xff1a; 一般要使用数据透视表来快速实现。 今天记录用xlwings新建一个excel并同时生成多个sheet。 import xlwings as xw # 打开excel,参数visible表示处理过程是否可视,add_book表示是否打开新的Excel程序…

电子学会C/C++编程等级考试2022年12月(二级)真题解析

C/C++等级考试(1~8级)全部真题・点这里 第1题:数组逆序重放 将一个数组中的值按逆序重新存放。例如,原来的顺序为8,6,5,4,1。要求改为1,4,5,6,8。输入 输入为两行:第一行数组中元素的个数n(1输出 输出为一行:输出逆序后数组的整数,每两个整数之间用空格分隔。样例输入 …

摆脱无用代码的负担:TreeShaking 的魔力

&#x1f90d; 前端开发工程师&#xff08;主业&#xff09;、技术博主&#xff08;副业&#xff09;、已过CET6 &#x1f368; 阿珊和她的猫_CSDN个人主页 &#x1f560; 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 &#x1f35a; 蓝桥云课签约作者、已在蓝桥云…

QGIS安装及简单使用

QGIS&#xff08;Quantum GIS&#xff09;是一个自由、开源的跨平台桌面地理信息系统&#xff08;GIS&#xff09;应用程序&#xff0c;它允许用户创建、编辑、查看、分析和发布地理空间数据和地图。 操作系统&#xff1a;Windows 10 QGIS版本&#xff1a;QGIS Desktop 3.28.…

2023年03月 Scratch(三级)真题解析#中国电子学会#全国青少年软件编程等级考试

Scratch等级考试(1~4级)全部真题・点这里 一、单选题(共25题,每题2分,共50分) 第1题 计算“2+4+8+……+128”,用变量n表示每项,根据变化规律,变量n的赋值用下列哪个最合适?( ) A: B: C: D: 答案:D

[Linux]进程创建➕进程终止

文章目录 1.再谈fork()函数1.1fork()创建子进程 OS都做了哪些工作?1.2对上述问题的理解1.3写时拷贝进行父子进程分离的优势1.4了解eip寄存器和pc1.5了解进程的上下文数据1.6对计算机组成的理解1.7fork常规用法1.8fork调用失败的原因 2.进程终止2.1进程终止时操作系统要做的工作…

offer 选择难?说说我的 2 个思考

大家好&#xff0c;我是鱼皮。秋招仍在进行中&#xff0c;随着越来越多的公司开奖&#xff0c;最近 编程导航星球 的小伙伴们也陆续发来了 offer 报喜&#xff1a; 图片 图片 但也有一部分小伙伴陷入了 “甜蜜的烦恼”&#xff0c;拿了几个 offer 却不知道怎么选择。 offer 选择…

【深入剖析K8s】容器技术基础(一):从进程开始说起

容器其实是一种特殊的进程而已。 可执行镜像 为了能够让这些代码正常运行’我们往往还要给它提供数据’比如我们这个加法程序所需要的输人文件这些数据加上代码本身的二进制文件放在磁盘上’就是我们平常所说的一个程序,也叫代码的可执行镜像&#xff08;executablejmage&…

路径规划之A*算法

系列文章目录 路径规划之Dijkstra算法 路径规划之Best-First Search算法 路径规划之A*算法 路径规划之A*算法 系列文章目录前言一、前期准备1.1 算法对比1.2 数学式方法1.3 启发式方法 二、A*算法2.1 起源2.2 思想2.3 启发式函数2.4 过程2.5 案例查看 前言 之前提过Dijkstra算…

2018年2月16日 Go生态洞察:Go 1.10版本发布分析

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页——&#x1f405;&#x1f43e;猫头虎的博客&#x1f390; &#x1f433; 《面试题大全专栏》 &#x1f995; 文章图文…

2017年11月16日 Go生态洞察:Go用户调查深度解析

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页——&#x1f405;&#x1f43e;猫头虎的博客&#x1f390; &#x1f433; 《面试题大全专栏》 &#x1f995; 文章图文…

BeanUtil的正确使用方式

shigen日更文章的博客写手&#xff0c;擅长Java、python、vue、shell等编程语言和各种应用程序、脚本的开发。记录成长&#xff0c;分享认知&#xff0c;留住感动。 在实际的开发中&#xff0c;我们常常会用到工具类去拷贝对象的属性&#xff0c;将一个对象的属性转换成另外一个…

机器人开发的选择

喷涂机器人 码垛机器人 纸箱码垛机器人 焊接机器人 跳舞机器人 管道清理机器人 工地巡检机器人 点餐机器人 化工巡检机器人 装箱机器人 安防巡检机器人 迎宾机器人好像有点像软银那个 污水管道检测机器人 大酒店用扫地机器人 家用扫地机器人 工厂用&#xff08;…

100元预算,轻松涨粉1000!腾讯运营面试秘籍大揭秘!

大家好啊&#xff01;小米在这里&#xff5e; 很高兴又有机会和大家见面啦&#xff01;最近小米参加了一场腾讯的运营面试&#xff0c;遇到了一个超有趣的问题&#xff1a;如果让你运营一个公众号&#xff0c;近期需要增加1000个关注&#xff0c;预算100元&#xff0c;怎么完成…

如何判断一个题目用“贪心/动态规划“还是用“BFS/DFS”方法解决

1 总结 1.1 贪心、动态规划和BFS/DFS题解的关系 一般能使用贪心、动态规划解决一个问题时&#xff0c;使用BFS&#xff0c;DFS也能解决这个题&#xff0c;但是反之不能成立。 1.2 2 贪心 -> BFS/DFS 2.1 跳跃游戏1和3的异同 这两道题&#xff0c;“跳跃游戏”&#xf…

【DevOps】基于 KubeSphere 的 Kubernetes 生产实践之旅(万字长文)

基于 KubeSphere 的 Kubernetes 生产实践 1.KubeSphere 简介1.1 全栈的 Kubernetes 容器云 PaaS 解决方案1.2 选型理由&#xff08;从运维的角度考虑&#xff09; 2.部署架构图3.节点规划3.1 软件版本3.2 规划说明3.2.1 K8s 集群规划3.2.2 存储集群3.2.3 中间件集群3.2.4 网络规…

详解Java中的异常体系结构(throw,throws,try-catch,finally,自定义异常)

目录 一.异常的概念 二.异常的体系结构 三.异常的处理 异常处理思路 LBYL&#xff1a;Look Before You Leap EAFP: Its Easier to Ask Forgiveness than Permission 异常抛出throw 异常的捕获 提醒声明throws try-catch捕获处理 finally的作用 四.自定义异常类 一.异…

人力资源管理后台 === 登陆+主页灵鉴权

目录 1. 分析登录流程 2. Vuex中用户模块的实现 3.Vue-cli代理解决跨域 4.axios封装 5.环境区分 6. 登录联调 7.主页权限验证-鉴权 1. 分析登录流程 传统思路都是登录校验通过之后&#xff0c;直接调用接口&#xff0c;获取token之后&#xff0c;跳转到主页。 vue-elemen…

一、深入简出串口(USRT)通信——基本概念。

一、前言 串口到底是什么&#xff1f;简单来说一句话就可以解释&#xff0c;串口就是一种通信协议。 看到这里可能大家会觉得你这不是放屁么&#xff0c;说了跟没说一样。所以这里做前言来描述&#xff0c;大家要先对通信协议有一个下意识地认识才能在学习串口的时候不至于迷茫…

使用Pytorch从零开始构建Normalizing Flow

归一化流 (Normalizing Flow) &#xff08;Rezende & Mohamed&#xff0c;2015&#xff09;学习可逆映射 f : X → Z f: X \rightarrow Z f:X→Z, 在这里X是我们的数据分布&#xff0c;Z是选定的潜在分布。 归一化流是生成模型家族的一部分&#xff0c;其中包括变分自动编…