基础知识
激活函数:引入非线性增加模型复杂度,不改变数据维度,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)=j∑n?1?ezj?ezi??n个类,z=wx+b,y^?=σ(z),yi?^?为对是属于i类的预测结果  多分类时,需要对每个类别输出的概率满足:
p
i
>
0
,
且
∑
p
i
=
1
p_i>0,且\sum{p_i}=1
pi?>0,且∑pi?=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,这种情况会造成信息丢失 
损失函数
用真实值与预测值之间的差距【距离差距,分布差距】来指导模型收敛的方向。
凸函数?
平方差/均值平方差:凸函数 交叉熵(逻辑回归):凸函数 神经网络:非凸函数
等高线
梯度的导数越大,越陡,走一步造成的高度差越大,等高线越密 
损失函数是凸函数时
损失函数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?)=c,即为y=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=1∑N?(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}是预测分布
y是真实分布,y^?是预测分布
二项分布

参数更新优化方法:梯度下降
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+1在yL+2附近,也趋于0
梯度爆炸:深度网络中,参数初始值相对预期过大,导致学习到的网络不稳定。
反向传播时,得到非常大的对
?
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?△w梯度下降:△w=ηg【η学习率】添加了Momentum的梯度下降:△wt?=η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=torch.Tensor([1.0])
w.requires_grad=True
def forward(x):
return x*w
'''
定义loss
每调用一次loss函数,就把计算图动态的构建出来
'''
def loss(x,y):
y_pred=forward(x)
return (y_pred-y)**2
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):
l=loss(x,y)
l.backward()
print('\t grad:',x,y,w.grad.item())
w.data=w.data-rate*w.grad.data
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?resnet结构:x?>f(x)?>f(x)+x?>σ(f(x)+x)?>yresnet结构的梯度:当?x?f?很小时,?x?Loss?趋于1,连乘导致趋于1?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
self.conv1=torch.nn.Conv2d(channels, channels, kernel_size=3,padding=1)
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)
return F.relu(x+y)
问题
0. 神经网络的层数
层数越多,学习能力越强,但是如果层数过多,会导致过拟合,连噪声也学习了。找到 泛化和拟合的平衡。
1. 为什么神经网络要用多层?
- x_8维-6维->2维->y_1维:层数越少,即维度降低的越快,丢失的数据越多(即学习能力不行)
|