IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 人工智能 -> 深度学习 神经网络 -> 正文阅读

[人工智能]深度学习 神经网络

文章目录

基础知识

激活函数:引入非线性增加模型复杂度,不改变数据维度,a=激活函数(b) a、b维度一样

取值[0,1],如leru取值[0,正无穷)可归一化成[0,1],符合概率特点

为什么要引入?

线性函数只能进行线性划分,不能解决复杂的:如异或xor问题。
多层网络都能化成一层,为了增加复杂度;
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

sigmoid函数:取值 [0,1]

sigmoid函数:函数值处于[0,1],单调递增,且导数为饱和函数。只要满足三个条件,就是sigmoid函数,有很多种,如下图
在这里插入图片描述
其中最出名的是logistic函数【可见我的逻辑斯蒂回归博文,是因为正太分布而产生的函数】,直接把它叫做sigmoid函数:取值[0,1],导数取值[0,0.25]
在这里插入图片描述

在这里插入图片描述

relu:倒数函数不连续 取值[0,正无穷],导数取值0或1

在这里插入图片描述
在这里插入图片描述

softmax

y i ^ = p ( y = i ) = σ ( i ) = e z i ∑ j n ? 1 e z j n 个 类 , z = w x + b , y ^ = σ ( z ) , y i ^ 为 对 是 属 于 i 类 的 预 测 结 果 \hat{y_i}=p(y=i)=\sigma(i)=\frac{e^{{z_i}}}{\sum\limits_j^{n-1}{e^{{z_j}}}}\\ n个类,z=wx+b,\hat{y}=\sigma(z),\hat{y_i}为对是属于i类的预测结果\\ yi?^?=p(y=i)=σ(i)=jn?1?ezj?ezi??nz=wx+by^?=σ(z)yi?^?i
在这里插入图片描述
多分类时,需要对每个类别输出的概率满足: p i > 0 , 且 ∑ p i = 1 p_i>0,且\sum{p_i}=1 pi?>0pi?=1
y的标签编码方式为one-hot【只有一个是1,其余是0,因为最终结果只可能属于某一个类,标签的one-hot算法完成的,输入仍为原始标签】

为什么引入?

第一,节省计算量:采用sigmoid等函数,算激活函数时(指数运算),计算量大,反向传播求误差梯度时,求导涉及除法,计算量相对大,而采用Relu激活函数,整个过程的计算量节省很多。
第二,防止simoid反向传播时出现的梯度消失。对于深层网络,sigmoid函数反向传播时,很容易就会出现梯度消失的情况(在sigmoid接近饱和区时,变换太缓慢,导数趋于0,这种情况会造成信息丢失),从而无法完成深层网络的训练。
第三,Relu会使一部分神经元的输出为0,这样就造成了网络的稀疏性,并且减少了参数的相互依存关系,缓解了过拟合问题的发生

如何用?:多层神经网络的隐藏层

ReLU 主要用在神经网络中的隐藏层作为激活函数,很少用在输出层,输出层可用sigmoid或softmax等。

relu把负值全变成0,在隐藏层作为激活函数时,可造成网络的稀疏性,加快训练过程。在最后一层作为激活函数时,所有的负值都被丢掉,丢失了大量的信息,相当于把学到的结果丢了一半,此时再进行预测效果大打折扣。

sigmoid一般用于二分类最后一层,softmax用于多分类最后一层。

选定优先级

relu>tanh>sigmoid
后两个导函数为饱和函数(类似正太分布),有学习饱和问题:接近饱和区时,导数趋于0,这种情况会造成信息丢失
问题类型	最后一层激活	损失函数二分类问题	sigmoid	binary_crossentropy多分类、单标签问题	softmax	categorical_crossentropy多分类、多标签问题	sigmoid	binary_crossentropy回归到任意值	无	mse回归到0-1范围内的值	sigmoid	mse或binary_crossentropy

损失函数

用真实值与预测值之间的差距【距离差距,分布差距】来指导模型收敛的方向。

凸函数?

平方差/均值平方差:凸函数
交叉熵(逻辑回归):凸函数
神经网络:非凸函数

等高线

梯度的导数越大,越陡,走一步造成的高度差越大,等高线越密
在这里插入图片描述

损失函数是凸函数时

损失函数3D图

在这里插入图片描述

3D图等高线图,压缩到 θ 1 O θ 2 平 面 \theta_1O\theta_2平面 θ1?Oθ2?:可知,中心处损失最低

在这里插入图片描述

设损失函数 y = f ( x 1 , x 2 ) y=f(x_1,x_2) y=f(x1?,x2?)是个曲面,被平面c(为常数)所截曲线方程为:
y = f ( x 1 , x 2 ) y = c y=f(x_1,x_2)\\ y=c\\ y=f(x1?,x2?)y=c
该曲线在 x 1 O x 2 平 面 上 投 影 为 一 条 曲 线 : f ( x 1 , x 2 ) = c , 即 为 y = f ( x 1 , x 2 ) 在 x 1 O x 2 平 面 上 的 一 条 等 高 线 : 由 上 图 可 知 , 中 心 处 损 失 最 低 x_1Ox_2平面上投影为一条曲线:f(x_1,x_2)=c,即为y=f(x_1,x_2)在x_1Ox_2平面上的一条等高线:由上图可知,中心处损失最低 x1?Ox2?线f(x1?,x2?)=cy=f(x1?,x2?)x1?Ox2?线
在这里插入图片描述

在 等 高 线 f ( x 1 , x 2 ) 上 任 一 点 的 切 线 斜 率 为 : d x 2 d x 1 且 由 上 面 隐 函 数 求 导 可 知 : d x 2 d x 1 = ? f x 1 f x 2 则 在 该 处 的 法 线 斜 率 为 : ? 1 d x 2 d x 1 = ? 1 ? f x 1 f x 2 = f x 2 f x 1 由 上 面 梯 度 为 : ( ? f ? x 1 , ? f ? x 2 ) = ? f ? x 1 i ? + ? f ? x 2 j ? 在 x 1 O x 2 平 面 的 梯 度 方 向 为 : ? f ? x 2 / ? f ? x 1 , 并 指 向 远 离 圆 圈 中 心 的 方 向 【 梯 度 方 向 是 函 数 值 增 大 的 方 向 , 对 应 的 导 数 为 正 】 在等高线f(x_1,x_2)上任一点的切线斜率为:\frac{dx_2}{dx_1}\\ 且由上面隐函数求导可知:\frac{dx_2}{dx_1}=-\frac{f_{x_1}}{f_{x_2}}\\ 则在该处的法线斜率为:\frac{-1}{\frac{dx_2}{dx_1}}=\frac{-1}{-\frac{f_{x_1}}{f_{x_2}}}=\frac{f_{x_2}}{f_{x_1}}\\ 由上面梯度为:(\frac{\partial f}{\partial x_1}, \frac{\partial f}{\partial x_2})=\frac{\partial f}{\partial x_1}\vec{i} +\frac{\partial f}{\partial x_2}\vec{j}\\ 在x_1Ox_2平面的梯度方向为:\frac{\partial f}{\partial x_2}/\frac{\partial f}{\partial x_1},并指向远离圆圈中心的方向【梯度方向是函数值增大的方向,对应的导数为正】 线f(x1?,x2?)线dx1?dx2??dx1?dx2??=?fx2??fx1???线dx1?dx2???1?=?fx2??fx1????1?=fx1??fx2???(?x1??f?,?x2??f?)=?x1??f?i +?x2??f?j ?x1?Ox2??x2??f?/?x1??f?

均值平方差(MSE):真实值和预测值之间的距离的差距

一般:回归任务使用

对目标函数是sigmoid函数时,损失函数采用MSE的情况,其偏导值在输出概率值接近0或者接近1的时候非常小,这可能会造成模型刚开始训练时,偏导值几乎消失
J M S E = 1 N ∑ i = 1 N ( y ^ i ? y i ) 2 J_{M S E}=\frac{1}{N} \sum_{i=1}^{N}\left(\hat{y}_{i}-y_{i}\right)^{2} JMSE?=N1?i=1N?(y^?i??yi?)2
在这里插入图片描述

交叉熵:计算两个分布之间的差距

一般:分类任务使用
在这里插入图片描述

熵反应了不确定度,熵越小,网络输出不确定性越小,估计越准确,网络学到了东西。
在这里插入图片描述

交叉熵

1、交叉熵是正的(不要被负号影响, 因为yi <1)

2、当所有输入x的输出都接近期望的输出y的话,交叉熵也会很小,接近于0
H = ? ∑ i y i log ? ( y i ′ ) H=-\sum_{i} y_{i} \log \left(y_{i}^{\prime}\right) H=?i?yi?log(yi?)
y 是 真 实 分 布 , y ^ 是 预 测 分 布 y是真实分布,\hat{y}是预测分布 yy^?

二项分布

在这里插入图片描述

参数更新优化方法:梯度下降

1.前馈:计算损失函数的梯度(导数,曲线上某点的斜率)【对参数的偏导】
2 反馈,更新:根据学习率,将参数按照梯度的反方向走,更新参数,缩小损失:参数=参数-学习率*偏导
3.下一轮

在这里插入图片描述

在这里插入图片描述

import matplotlib.pyplot as plt

x_data=[1.0,2.0,3.0]
y_data=[2.0,4.0,6.0]

w=1

'''
获取y_pred
'''
def forward(x):
	return x*w

'''
定义损失函数loss
'''
def loss(xs, ys):
	loss=0
	for x,y in zip(xs, ys):
		y_pred=forward(x)
		loss+=(y_pred-y)**2
	return loss/len(xs)
'''
定义损失函数对w的导数
'''
def gradient(xs, ys):
	grad=0
	for x,y in zip(xs, ys):
		grad+=2*x*(x*w-y)
	return grad/len(xs)

epoch_list=[]
loss_list=[]

for epoch in range(100):
	l=loss(x_data,y_data)
	grad=gradient(x_data,y_data)
	w-=0.01*grad
	epoch_list.append(epoch)
	loss_list.append(l)

plt.plot(epoch_list, loss_list)
plt.ylabel("losss")
plt.xlabel("epoch")
plt.show()

梯度消失和梯度爆炸:为网络层数太深而引发的梯度反向传播中的连乘效应

原因

前面层上的梯度是来自于后面层上梯度的乘乘积。当存在过多的层次时,就出现了内在本质上的不稳定场景,如梯度消失和梯度爆炸。

详细公式见下面的反向传播

在这里插入图片描述
y L = w L ? x L ? 1 + b L x L = g ( y L ) : 激 活 函 数 倒 数 第 二 层 的 梯 度 : ? L o s s ? w L ? 1 = ? L o s s ? x L ? g ′ ( y L ) ? w L ? g ′ ( y L ? 1 ) ? x L ? 2 ? L o s s ? b L ? 1 = ? L o s s ? x L ? g ′ ( y L ) ? w L ? g ′ ( y L ? 1 ) y^L=w^L \cdot x^{L-1}+b^L\\ x^L=g(y^L):激活函数\\ 倒数第二层的梯度:\\ \frac{\partial Loss}{\partial w^{L-1}}=\frac{\partial Loss}{\partial x^L} \cdot g^{\prime}(y^L)\cdot w^L\cdot g^{\prime}(y^{L-1}) \cdot x^{L-2} \\ \frac{\partial Loss}{\partial b^{L-1}}= \frac{\partial Loss}{\partial x^L} \cdot g^{\prime}(y^L)\cdot w^L\cdot g^{\prime}(y^{L-1})\\ yL=wL?xL?1+bLxL=g(yL)?wL?1?Loss?=?xL?Loss??g(yL)?wL?g(yL?1)?xL?2?bL?1?Loss?=?xL?Loss??g(yL)?wL?g(yL?1)

梯度消失:深度网络中,采取了不合适的激活函数,导致学习不到东西。

反向传播时,得到非常小的对参数的导数 ? L o s s ? w L 和 ? L o s s ? b L \frac{\partial Loss}{\partial w^{L}}和\frac{\partial Loss}{\partial b^{L}} ?wL?Loss??bL?Loss?,原因较小的值连乘 ∏ i = 0 g ′ ( y L + i ) \prod_{i=0}g'({y^{L+i}}) i=0?g(yL+i)
经网络有很多层,每个隐藏层都使用Sigmoid函数作为激励函数时,很容易引起梯度消失的问题。
因为sigmoid导数是个饱和函数,形状类似正太分布,接近饱和区时,导数趋于0,由于bp的链式传导:
g ′ ( y L + i ) 趋 于 0 g ′ ( y L + i ? 1 ) , 由 于 训 练 是 逐 渐 逼 近 的 , 所 以 y L + 1 在 y L + 2 附 近 , 也 趋 于 0 g'(y^{L+i})趋于0\\ g'(y^{L+{i-1}}),由于训练是逐渐逼近的,所以y^{L+1}在y^{L+2}附近,也趋于0\\ g(yL+i)0g(yL+i?1)yL+1yL+20

梯度爆炸:深度网络中,参数初始值相对预期过大,导致学习到的网络不稳定。

反向传播时,得到非常大的对 ? L o s s ? w L 和 ? L o s s ? b L \frac{\partial Loss}{\partial w^{L}}和\frac{\partial Loss}{\partial b^{L}} ?wL?Loss??bL?Loss?的导数,原因较大的值连乘 ∏ i = 1 w L + i \prod_{i=1}w^{L+i} i=1?wL+i【有较大的w初始值】

解决方法

  • 解决梯度消失
    在隐藏层用ReLU来替代sigmod,relu的导数为0或1
  • 解决梯度爆炸
    梯度裁剪:梯度阈值,更新梯度时,如果梯度超过阈值,就将其强制限制在这个范围之内

Mini-batch 和batch

batch 批梯度下降

计算量开销大,计算速度慢,不支持在线学习
遍历全部数据集算一次损失函数,然后算函数对各个参数的梯度,更新梯度

stochastic 随机梯度下降 sgd

速度比较快,但是收敛性能不好,两次参数的更新可能互相抵消,造成目标函数震荡剧烈。
每一个数据就算一下损失函数,然后求梯度更新参数

Mini-batch 小批的梯度下降

折中手段,克服上面两种缺点
把数据分为若干个批,按批来更新参数,计算量不大,收敛性也不错。

参数更新优化方法:动量优化 Momentum

加快收敛速度,增加稳定性,摆脱局部最优的能力
把前几次的梯度也会参与当前的计算,借助之前的冲劲,步子迈得大一些。
如果当前梯度方向与历史梯度方向一致(表明不是异常点),增强该梯度。
如果当前梯度方向与历史梯度方向不一致(可能是异常点),减弱该梯度。
w = w ? △ w 梯 度 下 降 : △ w = η g 【 η 学 习 率 】 添 加 了 M o m e n t u m 的 梯 度 下 降 : △ w t = η g t + ρ △ w t ? 1 【 t 是 迭 代 次 数 , ρ 冲 量 系 数 】 w=w-△ w\\ 梯度下降:△ w=\eta g【\eta 学习率】\\ 添加了Momentum的梯度下降:△ w_t=\eta g_t+\rho △w_{t-1}【t是迭代次数,\rho 冲量系数】 \\ w=w?ww=ηgηMomentumwt?=ηgt?+ρwt?1?tρ

反向传播

计算图:代码就是在构建计算图
更新非倒数第一层的参数时,重点是要计算倒数第一层总损失对输入的偏导: ? L o s s ? x L ? 1 \frac{\partial Loss}{\partial x^{L-1}} ?xL?1?Loss?,详细见下
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

公式+图

在这里插入图片描述

方程

y L = w L ? x L ? 1 + b L x L = g ( y L ) : 激 活 函 数 y^L=w^L \cdot x^{L-1}+b^L\\ x^L=g(y^L):激活函数\\ yL=wL?xL?1+bLxL=g(yL)

反向传播时最后一层的导数:

? L o s s ? x L ? 1 \frac{\partial Loss}{\partial x^{L-1}} ?xL?1?Loss?:用于倒数第二层求 ? L o s s ? y L ? 1 \frac{\partial Loss}{\partial y^{L-1}} ?yL?1?Loss?,便于更新倒数第二层的参数

? L o s s ? y L = ? L o s s ? x L ? ? x L ? y L = ? L o s s ? x L ? g ′ ( y L ) ? L o s s ? w L = ? L o s s ? y L ? ? y L ? w L = ? L o s s ? y L ? ? ( w L ? x L ? 1 + b L ) ? w L = ? L o s s ? y L ? x L ? 1 = ? L o s s ? x L ? g ′ ( y L ) ? x L ? 1 ? L o s s ? b L = ? L o s s ? y L ? ? y L ? b L = ? L o s s ? y L ? ? ( w L ? x L ? 1 + b L ) ? b L = ? L o s s ? y L ? 1 = ? L o s s ? x L ? g ′ ( y L ) ? L o s s ? x L ? 1 = ? L o s s ? y L ? ? y L ? x L ? 1 = ? L o s s ? y L ? ? ( w L ? x L ? 1 + b L ) ? x L ? 1 = ? L o s s ? y L ? w L = ? L o s s ? x L ? g ′ ( y L ) ? w L \frac{\partial Loss}{\partial y^L}=\frac{\partial Loss}{\partial x^L} \cdot \frac{\partial x^L}{\partial y^L}=\frac{\partial Loss}{\partial x^L} \cdot g^{\prime}(y^L)\\ \frac{\partial Loss}{\partial w^L}=\frac{\partial Loss}{\partial y^L} \cdot \frac{\partial y^L}{\partial w^L}=\frac{\partial Loss}{\partial y^L} \cdot \frac{\partial (w^L \cdot x^{L-1}+b^L)}{\partial w^L}=\frac{\partial Loss}{\partial y^L} \cdot x^{L-1}=\frac{\partial Loss}{\partial x^L} \cdot g^{\prime}(y^L) \cdot x^{L-1}\\ \frac{\partial Loss}{\partial b^L}=\frac{\partial Loss}{\partial y^L} \cdot \frac{\partial y^L}{\partial b^L}=\frac{\partial Loss}{\partial y^L} \cdot \frac{\partial (w^L \cdot x^{L-1}+b^L)}{\partial b^L}=\frac{\partial Loss}{\partial y^L} \cdot 1=\frac{\partial Loss}{\partial x^L} \cdot g^{\prime}(y^L)\\ \frac{\partial Loss}{\partial x^{L-1}}=\frac{\partial Loss}{\partial y^L} \cdot \frac{\partial y^L}{\partial x^{L-1}}=\frac{\partial Loss}{\partial y^L} \cdot \frac{\partial (w^L \cdot x^{L-1}+b^L)}{\partial x^{L-1}}=\frac{\partial Loss}{\partial y^L} \cdot w^L=\frac{\partial Loss}{\partial x^L} \cdot g^{\prime}(y^L)\cdot w^L\\ ?yL?Loss?=?xL?Loss???yL?xL?=?xL?Loss??g(yL)?wL?Loss?=?yL?Loss???wL?yL?=?yL?Loss???wL?(wL?xL?1+bL)?=?yL?Loss??xL?1=?xL?Loss??g(yL)?xL?1?bL?Loss?=?yL?Loss???bL?yL?=?yL?Loss???bL?(wL?xL?1+bL)?=?yL?Loss??1=?xL?Loss??g(yL)?xL?1?Loss?=?yL?Loss???xL?1?yL?=?yL?Loss???xL?1?(wL?xL?1+bL)?=?yL?Loss??wL=?xL?Loss??g(yL)?wL

更新最后一层的参数

w L = w L ? η ? ? L o s s ? w L b L = b L ? η ? ? L o s s ? b L w^L=w^L-\eta \cdot \frac{\partial Loss}{\partial w^L}\\ b^L=b^L-\eta \cdot\frac{\partial Loss}{\partial b^L}\\ wL=wL?η??wL?Loss?bL=bL?η??bL?Loss?

反向传播时倒数第二层的导数:

? L o s s ? x L ? 2 \frac{\partial Loss}{\partial x^{L-2}} ?xL?2?Loss?:用于倒数第二层求 ? L o s s ? y L ? 2 \frac{\partial Loss}{\partial y^{L-2}} ?yL?2?Loss?,便于更新倒数第二层的参数

? L o s s ? y L ? 1 = ? L o s s ? x L ? 1 ? ? x L ? 1 ? y L ? 1 = ? L o s s ? x L ? 1 ? g ′ ( y L ? 1 ) = ? L o s s ? y L ? w L ? g ′ ( y L ? 1 ) = ? L o s s ? x L ? g ′ ( y L ) ? w L ? g ′ ( y L ? 1 ) ? L o s s ? w L ? 1 = ? L o s s ? y L ? 1 ? ? y L ? 1 ? w L ? 1 = ? L o s s ? y L ? 1 ? ? ( w L ? 1 ? x L ? 2 + b L ? 1 ) ? w L ? 1 = ? L o s s ? y L ? 1 ? x L ? 2 = ? L o s s ? x L ? g ′ ( y L ) ? w L ? g ′ ( y L ? 1 ) ? x L ? 2 ? L o s s ? b L ? 1 = ? L o s s ? y L ? 1 ? ? y L ? 1 ? b L ? 1 = ? L o s s ? y L ? 1 ? ? ( w L ? 1 ? x L ? 2 + b L ? 1 ) ? b L ? 1 = ? L o s s ? y L ? 1 ? 1 = ? L o s s ? x L ? g ′ ( y L ) ? w L ? g ′ ( y L ? 1 ) ? L o s s ? x L ? 2 = ? L o s s ? y L ? 1 ? ? y L ? 1 ? x L ? 2 = ? L o s s ? y L ? 1 ? w L ? 1 = ? L o s s ? x L ? g ′ ( y L ) ? w L ? g ′ ( y L ? 1 ) ? w L ? 1 \frac{\partial Loss}{\partial y^{L-1}}=\frac{\partial Loss}{\partial x^{L-1}} \cdot \frac{\partial x^{L-1}}{\partial y^{L-1}}=\frac{\partial Loss}{\partial x^{L-1}} \cdot g^{\prime}(y^{L-1})=\frac{\partial Loss}{\partial y^L} \cdot w^L\cdot g^{\prime}(y^{L-1})=\frac{\partial Loss}{\partial x^L} \cdot g^{\prime}(y^L)\cdot w^L\cdot g^{\prime}(y^{L-1})\\ \frac{\partial Loss}{\partial w^{L-1}}=\frac{\partial Loss}{\partial y^{L-1}} \cdot \frac{\partial y^{L-1}}{\partial w^{L-1}}=\frac{\partial Loss}{\partial y^{L-1}} \cdot \frac{\partial (w^{L-1} \cdot x^{L-2}+b^{L-1})}{\partial w^{L-1}}=\frac{\partial Loss}{\partial y^{L-1}} \cdot x^{L-2}=\frac{\partial Loss}{\partial x^L} \cdot g^{\prime}(y^L)\cdot w^L\cdot g^{\prime}(y^{L-1}) \cdot x^{L-2}\\ \frac{\partial Loss}{\partial b^{L-1}}=\frac{\partial Loss}{\partial y^{L-1}} \cdot \frac{\partial y^{L-1}}{\partial b^{L-1}}=\frac{\partial Loss}{\partial y^{L-1}} \cdot \frac{\partial (w^{L-1} \cdot x^{L-2}+b^{L-1})}{\partial b^{L-1}}=\frac{\partial Loss}{\partial y^{L-1}} \cdot 1=\frac{\partial Loss}{\partial x^L} \cdot g^{\prime}(y^L)\cdot w^L\cdot g^{\prime}(y^{L-1})\\ \frac{\partial Loss}{\partial x^{L-2}}=\frac{\partial Loss}{\partial y^{L-1}} \cdot \frac{\partial y^{L-1}}{\partial x^{L-2}}=\frac{\partial Loss}{\partial y^{L-1}} \cdot w^{L-1}=\frac{\partial Loss}{\partial x^L} \cdot g^{\prime}(y^L)\cdot w^L\cdot g^{\prime}(y^{L-1})\cdot w^{L-1}\\ ?yL?1?Loss?=?xL?1?Loss???yL?1?xL?1?=?xL?1?Loss??g(yL?1)=?yL?Loss??wL?g(yL?1)=?xL?Loss??g(yL)?wL?g(yL?1)?wL?1?Loss?=?yL?1?Loss???wL?1?yL?1?=?yL?1?Loss???wL?1?(wL?1?xL?2+bL?1)?=?yL?1?Loss??xL?2=?xL?Loss??g(yL)?wL?g(yL?1)?xL?2?bL?1?Loss?=?yL?1?Loss???bL?1?yL?1?=?yL?1?Loss???bL?1?(wL?1?xL?2+bL?1)?=?yL?1?Loss??1=?xL?Loss??g(yL)?wL?g(yL?1)?xL?2?Loss?=?yL?1?Loss???xL?2?yL?1?=?yL?1?Loss??wL?1=?xL?Loss??g(yL)?wL?g(yL?1)?wL?1

更新倒数第二层的参数

w L ? 1 = w L ? 1 ? η ? ? L o s s ? w L ? 1 = w L ? 1 ? η ? ? L o s s ? x L ? g ′ ( y L ) ? w L ? g ′ ( y L ? 1 ) ? x L ? 2 b L ? 1 = b L ? 1 ? η ? ? L o s s ? b L ? 1 = b L ? 1 ? η ? ? L o s s ? x L ? g ′ ( y L ) ? w L ? g ′ ( y L ? 1 ) w^{L-1}=w^{L-1}-\eta \cdot \frac{\partial Loss}{\partial w^{L-1}}=w^{L-1}-\eta \cdot \frac{\partial Loss}{\partial x^L} \cdot g^{\prime}(y^L)\cdot w^L\cdot g^{\prime}(y^{L-1}) \cdot x^{L-2} \\ b^{L-1}=b^{L-1}-\eta \cdot\frac{\partial Loss}{\partial b^{L-1}}=b^{L-1}-\eta \cdot \frac{\partial Loss}{\partial x^L} \cdot g^{\prime}(y^L)\cdot w^L\cdot g^{\prime}(y^{L-1})\\ wL?1=wL?1?η??wL?1?Loss?=wL?1?η??xL?Loss??g(yL)?wL?g(yL?1)?xL?2bL?1=bL?1?η??bL?1?Loss?=bL?1?η??xL?Loss??g(yL)?wL?g(yL?1)

代码

import matplotlib.pyplot as plt
import torch

x_data=[1.0,2.0,3.0]
y_data=[2.0,4.0,6.0]

#学习率
rate=0.01
#w是个tensor 默认Tensor不会保存损失对参数的导数
w=torch.Tensor([1.0])
w.requires_grad=True


#定义模型:y_hat=x*w
def forward(x):
    #w是Tensor,x不一定是Tensor,也把x转换为Tensor
    return x*w

'''
定义loss
每调用一次loss函数,就把计算图动态的构建出来
'''
def loss(x,y):
    y_pred=forward(x)
    return (y_pred-y)**2

#Tensor.item() 当Tensor中数据为标量时,返回python的标量:只适用于保存了标量的Tensor
#把w的梯度数据取出来,否则w.grad会构建计算图,吃内存
print("predict (before training)",4,forward(4).item())

epoch_list=[]
loss_list=[]

for epoch in range(100):
    for x,y in zip(x_data,y_data):
        #前馈过程,构建计算图,计算y_pred,得到loss
        #l是Tensor
        l=loss(x,y)
        #自动把链路上所有的梯度都求出来,对w、对x、对b,并保存到w张量、x张量、b张量中
        #然后释放计算图,下一次前馈时,再重新动态构建计算图:因为每次的计算图可能不一样
        l.backward()
        
        print('\t grad:',x,y,w.grad.item())
        #更新参数 w.data返回和w的相同数据的tensor, 将参数从网络中隔离开,不会加入到w的计算历史里,不参与更新
        # 一般张量参与运算时,即构建计算图。但张量.data参与运算时,此时不参与构建计算图
        w.data=w.data-rate*w.grad.data
        #把w张量中梯度的数据清零,否则一下次得到的值=这次梯度+下次梯度
        w.grad.data.zero_()
        
    print('progress:', epoch, l.item())
    epoch_list.append(epoch)
    loss_list.append(l)
    

print("predict (before training)",4,forward(4).item())

plt.plot(epoch_list, loss_list)
plt.ylabel("losss")
plt.xlabel("epoch")
plt.show()

卷积神经网络 Convolutional Neural Network CNN

基础术语

感知机/神经元

指单层的神经网络,作为二元线性分类器。
感知机的输出是输入向量x与权重向量w求得内积后,经激活函数f所得到的标量。
在这里插入图片描述

通道

输入通道数

图像在输入时,黑白图像是单通道的(input_ch
annel=1),rgb(
彩色)是3通道的(input_channel=3)是三维:第一维的三个分别是红色分量、绿色分量和蓝色分量
在这里插入图片描述

输出通道数

上一层的输出通道数,是下一层的输入通道数
输出通道数=卷积核数量
output_channel=filte_number
1个卷积核时,输入图片是RGB 3通道,卷积核是3通道,输出是1通道,这里的1通道是把3个通道的输出合并了,相当于通过求和操作把3个通道压成了1个通道
在这里插入图片描述
2个卷积核,得到输出通道数为2
在这里插入图片描述

卷积神经网络结构

1. 特征提取器
		卷积层
		池化层
2. 分类器
		全连接层

在这里插入图片描述

卷积层:保存图像的空间信息

通道数可能变,高宽可能变
在这里插入图片描述

卷积核=filter滤波器=权值w:不减少信息的情况下,降低计算量

每个卷积核的通道数=输入数据的通道数:2维卷积核是三维的=(通道数,高,宽),1维卷积核是3维的=(通道数,1,1)。
卷积核的个数=输出数据的通道数。
kernel_size指的是卷积核的高/宽:3=(3,3)或者(4,3) 一般宽=高,且为奇数

图像数据与卷积核(kennel)按照步长(stride length)相乘,得到图像特征(feature map)

(batch_size,in_channel,,)->(batch_size,out_channel,2,2) kernel=(kernel_num=out_channel,kernel_channel=in_channel,',宽')-高'+1=2-宽'+1=2

在这里插入图片描述

卷积核具体的数值

是随机的,之根据前馈时的误差反馈更新

卷积核的类型

1维卷积核 1*1

未损失信息的情况下,改变通道数量,降低计算量
1维卷积核是3维的=(通道数,1,1):每个卷积核的通道数=输入数据的通道数
0.5,0.3,0.2都是信息融合时的权重,不一定一样
在这里插入图片描述
在这里插入图片描述

2维卷积核 h*w

2维卷积核是3维的=(通道数,高,宽):每个卷积核的通道数=输入数据的通道数

在这里插入图片描述

输入数据与一个卷积核作用得到一个通道的输出数据

在这里插入图片描述
在这里插入图片描述

卷积的宽窄

窄卷积

在这里插入图片描述

宽卷积/padding

在输入层填充0
在这里插入图片描述

卷积的步长 stride length

stride=1

5-3+1=3
在这里插入图片描述

stride=2

(5-3)/2+1=2
在这里插入图片描述

stride=3

(6-3)/3+1=2
在这里插入图片描述

输出尺寸计算

( 高 , 宽 ) = ( ? i n h ? k e r n e l h + 2 p a d d i n g s t r i d e ? , ? i n w ? k e r n e l w + 2 p a d d i n g s t r i d e ? ) (高,宽)=(\lfloor{\frac{in_h-kernel_h+2padding}{stride}}\rfloor,\lfloor{\frac{in_w-kernel_w+2padding}{stride}}\rfloor) (,)=(?strideinh??kernelh?+2padding??,?strideinw??kernelw?+2padding??)

与全连接时区别

全连接层的输入输出数据是二维[n,features],此时丧失了图像的空间信息。
卷积层的输入输出都是四维[n,chanel_num,width,height]
卷积层是稀疏连接,输出单元只与有限个输入单元连接
全连接层的输出单元与所有输入单元连接

池化层/下采样层

图像的通道数不变,宽和高改变
(高,宽)->(高/2,宽/2) 池化=2

作用

减少特征,降低数据量,降低运算
防止过拟合

类型

max-pooling:最大值

在这里插入图片描述

average-pooling:均值

全连接层

其他网络结构的主干结构:高级cnn

Inception Module (初始模块)

多分支,每个分支最后得到的(batch_size,channel,h,w)中branc_size,h,w都一样
全连接神经网络是串行的,一层输出就是下一层输入net1->net2->…->net_n

Inception Module 结构

在这里插入图片描述

作用

超参数的选择:如二维卷积核的高宽,不知道哪个好,就都用一下,找到最优的,但是要保证数据的高宽一致
eg:一个55个卷积核,同两次33的卷积核

代码

'''
(batch_size,in_channel,h,w)->(batch_size,88,h,w),只有通道数可能改变
中间有几条分支
'''
class Inception(torch.nn.Module):
    def __init__(self,in_channels):
        super(Inception,self).__init__()
        #(batch_size,in_channel,h,w)->(batch_size,16,h,w)
        self.branch1x1=torch.nn.Conv2d(in_channels,16, kernel_size=1)
        
        #(batch_size,in_channel,h,w)->(batch_size,16,h,w)
        self.branch5x5_1=torch.nn.Conv2d(in_channels,16, kernel_size=1)
        #(batch_size,16,h,w)->(batch_size,24,h,w) h+2*2-5+1=h
        self.branch5x5_2=torch.nn.Conv2d(16,24, kernel_size=5,padding=2)
        
        #(batch_size,in_channel,h,w)->(batch_size,16,h,w)
        self.branch3x3_1=torch.nn.Conv2d(in_channels,16, kernel_size=1)
        #(batch_size,16,h,w)->(batch_size,24,h,w) h+2*1-3+1=h
        self.branch3x3_2=torch.nn.Conv2d(16, 24,kernel_size=3,padding=1)
        #(batch_size,24,h,w)->(batch_size,24,h,w) h+2*1-3+1=h
        self.branch3x3_3=torch.nn.Conv2d(24,24,kernel_size=3,padding=1)
        
        self.branch_pool=torch.nn.Conv2d(in_channels, 24, kernel_size=1)
        
        
    def forward(self,x):
        #(batch_size,in_channel,h,w)->(batch_size,16,h,w)
        branch1x1=self.branch1x1(x)
        
        #(batch_size,in_channel,h,w)->(batch_size,24,h,w)
        branch5x5=self.branch5x5_1(x)
        branch5x5=self.branch5x5_2(branch5x5)
        
        #(batch_size,in_channel,h,w)->(batch_size,24,h,w)
        branch3x3=self.branch3x3_1(x)
        branch3x3=self.branch3x3_2(branch3x3)
        branch3x3=self.branch3x3_3(branch3x3)
        
        #(batch_size,in_channel,h,w)->(batch_size,24,h,w)
        branch_pool=F.avg_pool2d(x, kernel_size=3,stride=1,padding=1)
        branch_pool=self.branch_pool(branch_pool)
        
        outputs=[branch1x1,branch5x5,branch3x3,branch_pool]
        #(batch_size,channel,h,w) -1指的是在通道维度拼接 24+16+24+24=88
        return torch.cat(outputs,dim=1)
class Net(torch.nn.Module):
    def __init__(self):
        super(Net,self).__init__()
        
        '''
        w和b的维度,自然就定了:
        y_pred=wx+b
        y_(n*6)=x_(n*8)*w+b
        w=8*6
        b=1*6最后广播机制,复制成n*6
        '''
        #第一个线性模型:输入的样本特征为784个,输出的特征为512
        #self.linear1=torch.nn.Linear(784, 512)
        
        #torch.nn.Sigmoid是个Module,也是继承torch.nn.Module,但是由于没有参数,故只定义一个即可,作为一个层,区分层标志为非线性激活函数,卷积层也是线性的
        #self.sigmoid=torch.nn.Sigmoid()
        #self.relu=torch.nn.ReLU()
        
        '''
        Conv2d:卷积核是2维的,有高宽,通道数由输入通道数决定
        torch.nn.Conv2d(in_channel,out_channel,kernel_size,stride=1,padding=0,groups=1,bias=True)
        in_channel:输入通道数
        out_channel:输出通道数
        kernel_size:卷积核(通道数=in_channel,高,宽) 
            3 : 高=宽=3
            (3,3):高=宽=3
        stride:int或元组
        padding:是否为宽卷积
            1:输入数据外圈加一圈0
            
        (batch_size,in_channel,高,宽)->(batch_size,out_channel,高2,宽2) kernel=(kernel_num=out_channel,kernel_channel=in_channel,高',宽')
        高-高'+1=高2
        宽-宽'+1=宽2
        '''
        #(batch_size,1,高,宽)->(batch_size,10,高2,宽2) kernel=(10,1,5,5) 10个卷积核
        self.conv1=torch.nn.Conv2d(1, 10, kernel_size=5)
        #(batch_size,88,高,宽)->(batch_size,20,高2,宽2) kernel=(20,88,5,5) 20个卷积核
        self.conv2=torch.nn.Conv2d(88, 20, kernel_size=5)
        
        #(batch_size,10,h,w)->(batch_size,88,h,w)
        self.incept1=Inception(in_channels=10)
        #(batch_size,20,h,w)->(batch_size,88,h,w) 
        self.incept2=Inception(in_channels=20)
        
        #池化层:由于没有参数,定义一个即可(高,宽)->(高/2,宽/2)
        self.max_pooling=torch.nn.MaxPool2d(2)
        #全连接层 (batch_size,320)->(batch_size,10)
        self.full_conn=torch.nn.Linear(1408, 10)
       
        
        
        
    def forward(self,x_data):
        '''
        只用一个x_data变量,虽然是有很多层,但是为了防止写错和节省内存
        激活函数作为一个层,区分层标志为非线性激活函数,卷积层也是线性的
        '''
        
        
        batch_size=x_data.size(0)#样本数量
        '''
        self.conv1(x_data):
            (batch_size,1,28,28)->(batch_size,10,24,24) kernel=(10,1,5,5) 10个卷积核
                24=28-5+1
        self.max_pooling():
            (batch_size,10,24,24)->(batch_size,10,12,12)  
        '''
        x_data=F.relu(self.max_pooling(self.conv1(x_data)))
        #(batch_size,10,12,12)->(batch_size,88,12,12) 
        x_data=self.incept1(x_data)
        '''
        self.conv2(x_data):
            (batch_size,88,12,12)->(batch_size,20,8,8) kernel=(20,88,5,5) 20个卷积核
                8=12-5+1
        self.max_pooling():
            (batch_size,20,8,8)->(batch_size,20,4,4)  
        '''
        x_data=F.relu(self.max_pooling(self.conv2(x_data)))
        #(batch_size,20,4,4)->(batch_size,88,4,4) 
        x_data=self.incept2(x_data)
        #(batch_size,88,4,4)->(batch_size,1408) -1表示该位置自动计算大小
        x_data=x_data.view(batch_size,-1)
        '''
        y_pred,还没有使用激活函数
        该层1408个神经元,全连接要求输入样本是矩阵即2维  (batch_size,320)->(batch_size,10)
        '''
        return self.full_conn(x_data)
        
    
    
model=Net()

ResidualBlock resnet 残差网络:解决神经网络的梯度消失

梯度消失问题

当网络较深时,效果会更差,因为如果梯度较小,经过多次相乘后得到的梯度趋于0,即没有学习到东西

resnet 结构

f(x)和x是在(batch_size,channel,h,w)四个维度都是一样的
f(x)+x时,直接同位置元素相加

在这里插入图片描述

resnet怎么解决梯度消失问题

正 常 结 构 : x ? > f ( x ) ? > σ ( f ( x ) ) = y 正 常 结 构 的 梯 度 : 当 ? f ? x 很 小 时 , ? L o s s ? x 很 小 , 连 乘 导 致 趋 于 0 ? L o s s ? x = ? L o s s ? y ? ? y ? x = ? L o s s ? y ? ? y ? σ ? ? σ ? x = ? L o s s ? y ? ? y ? σ ? ? σ ? f ? ? f ? x r e s n e t 结 构 : x ? > f ( x ) ? > f ( x ) + x ? > σ ( f ( x ) + x ) ? > y r e s n e t 结 构 的 梯 度 : 当 ? f ? x 很 小 时 , ? L o s s ? x 趋 于 1 , 连 乘 导 致 趋 于 1 ? L o s s ? x = ? L o s s ? y ? ? y ? x = ? L o s s ? y ? ? y ? σ ? ? σ ? x = ? L o s s ? y ? ? y ? σ ? ? σ ? f ? ( ? f ? x + 1 ) 正常结构:x->f(x)->\sigma(f(x))=y\\ 正常结构的梯度:当\frac{\partial f}{\partial x}很小时,\frac{\partial Loss}{\partial x}很小,连乘导致趋于0\\ \frac{\partial Loss}{\partial x}=\frac{\partial Loss}{\partial y} \cdot \frac{\partial y}{\partial x}=\frac{\partial Loss}{\partial y} \cdot \frac{\partial y}{\partial \sigma} \cdot \frac{\partial \sigma}{\partial x}=\frac{\partial Loss}{\partial y} \cdot \frac{\partial y}{\partial \sigma} \cdot \frac{\partial \sigma}{\partial f} \cdot \frac{\partial f}{\partial x}\\ resnet结构:x->f(x)->f(x)+x->\sigma(f(x)+x)->y\\ resnet结构的梯度:当\frac{\partial f}{\partial x}很小时,\frac{\partial Loss}{\partial x}趋于1,连乘导致趋于1\\ \frac{\partial Loss}{\partial x}=\frac{\partial Loss}{\partial y} \cdot \frac{\partial y}{\partial x}=\frac{\partial Loss}{\partial y} \cdot \frac{\partial y}{\partial \sigma} \cdot \frac{\partial \sigma}{\partial x}=\frac{\partial Loss}{\partial y} \cdot \frac{\partial y}{\partial \sigma} \cdot \frac{\partial \sigma}{\partial f} \cdot (\frac{\partial f}{\partial x}+1)\\ x?>f(x)?>σ(f(x))=y?x?f??x?Loss?0?x?Loss?=?y?Loss???x?y?=?y?Loss???σ?y???x?σ?=?y?Loss???σ?y???f?σ???x?f?resnetx?>f(x)?>f(x)+x?>σ(f(x)+x)?>yresnet?x?f??x?Loss?11?x?Loss?=?y?Loss???x?y?=?y?Loss???σ?y???x?σ?=?y?Loss???σ?y???f?σ??(?x?f?+1)

resblock 代码

'''
残差网络:解决nn中的梯度消失问题
正常:y=relu(f(x))
resnet:y=relu(f(x)+x)
'''
class ResidualBlock(torch.nn.Module):
    def __init__(self,channels):
        super(ResidualBlock,self).__init__()
        self.channels=channels
        #(batch_size,channel,h,w)->(batch_size,channel,h,w) h+2*1-3+1=h
        self.conv1=torch.nn.Conv2d(channels, channels, kernel_size=3,padding=1)
        #(batch_size,channel,h,w)->(batch_size,channel,h,w) h+2*1-3+1=h
        self.conv2=torch.nn.Conv2d(channels, channels, kernel_size=3,padding=1)
        
    def forward(self,x):
        '''
        self.conv1(x):
            #(batch_size,channel,h,w)->(batch_size,channel,h,w) h+2*1-3+1=h
        
        '''
        y=F.relu(self.conv1(x))
        '''
        self.conv2(x):
            #(batch_size,channel,h,w)->(batch_size,channel,h,w) h+2*1-3+1=h
        
        '''
        y=self.conv2(y)
        #x和y在(batch_size,channel,h,w)上四个维度是一样的,然后同位置相加
        return F.relu(x+y)

问题

0. 神经网络的层数

层数越多,学习能力越强,但是如果层数过多,会导致过拟合,连噪声也学习了。找到 泛化和拟合的平衡。

1. 为什么神经网络要用多层?

  • x_8维-6维->2维->y_1维:层数越少,即维度降低的越快,丢失的数据越多(即学习能力不行)
  人工智能 最新文章
2022吴恩达机器学习课程——第二课(神经网
第十五章 规则学习
FixMatch: Simplifying Semi-Supervised Le
数据挖掘Java——Kmeans算法的实现
大脑皮层的分割方法
【翻译】GPT-3是如何工作的
论文笔记:TEACHTEXT: CrossModal Generaliz
python从零学(六)
详解Python 3.x 导入(import)
【答读者问27】backtrader不支持最新版本的
上一篇文章      下一篇文章      查看所有文章
加:2021-08-01 14:30:37  更:2021-08-01 14:33:08 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2025年3日历 -2025/3/26 13:37:15-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码