# DNN

## 0.简介

​ `多层功能`神经元相连构成`深度神经网络DNN`，输入层与输出层之间的所有层神经元，称为`隐藏层`，输入层和输出层只有一个，中间的隐藏层可以有很多层。最后一层通常表示某种概率预测。

![](/files/-LpsmagD0rOVj2OtnzM4)

## 1.激活函数

​ 神经元会`对化学物质的刺激`进行，当达到一定程度的时候，神经元才`会兴奋`，并向其他神经元发送信息。神经网络中的激活函数就是用来`判断我们所计算的信息是否达到`了往后面传输的条件。`需要非线性的`。

### 为什么激活函数都是非线性的

​ 计算过程中，`每层都相当于矩阵相乘`，无论神经网络有多少层输出`都是输入的线性组合`，就算我们有几千层的计算，无非还是个矩阵相乘，和一层矩阵相乘所`获得的信息差距不大`，所以`需要激活函数`来引入非线性因素，`使得神经网络可以任意逼近任何非线性函数`，这样神经网络就可以`应用到众多的非线性模型`中，增加了神经网络模型`泛化的特性`。

### sigmod 函数

$$a=\frac{1}{1+e^{-z}}$$ 导数 ：$$a^\prime =a(1 - a)$$

在sigmod函数中我们可以看到，其输出是在(0,1)这个开区间,它能够把输入的连续实值变换为0和1之间的输出，如果是非常大的负数，那么输出就是0；如果是非常大的正数输出就是1，起到了抑制的作用。

sigmod由于`需要进行指数运算`（这个对于计算机来说是比较慢，相比relu），再加上函数输出`不是以0为中心`的（这样会使`权重更新效率降低`），当输入稍微远离了坐标原点，函数的`梯度就变得很小了`（几乎为零）。在神经网络反向传播的过程中不利于权重的优化，这个问题叫做`梯度饱和`，也可以叫`梯度弥散`。这些不足，所以现在使用到sigmod基本很少了，`基本上只有在做二元分类`（0，1）时的输出层才会使用。

```python
import torch
import torch.nn.functional as F
import matplotlib.pyplot as plt
import numpy as np

x= torch.linspace(-10,10,60)
ax = plt.gca()
ax.spines['right'].set_color('none')
ax.spines['top'].set_color('none')
ax.xaxis.set_ticks_position('bottom')
ax.spines['bottom'].set_position(('data', 0))
ax.yaxis.set_ticks_position('left')
ax.spines['left'].set_position(('data', 0))

plt.ylim((0, 1))
#进行sigmod运算
sigmod=torch.sigmoid(x)
plt.plot(x.numpy(),sigmod.numpy())
```

![](/files/-LokoRN414B2nPLtbs67)

### tanh 函数

$$a=\frac{e^z-e^{-z}}{e^z+e^{-z}}$$ 导数：$$a^\prime =1 - a^2$$

tanh是双曲正切函数，`输出区间是在(-1,1)`之间，而且整个函数是`以0为中心`的。

当输入稍微远离了坐标原点，梯度还是会很小，但是好在tanh是以0为中心点，如果使用tanh作为激活函数，还能起到归一化（均值为0）的效果。

一般二分类问题中，隐藏层用tanh函数，输出层用sigmod函数，但是随着Relu的出现所有的隐藏层基本上都使用relu来作为激活函数了

```python
ax = plt.gca()
ax.spines['right'].set_color('none')
ax.spines['top'].set_color('none')
ax.xaxis.set_ticks_position('bottom')
ax.spines['bottom'].set_position(('data', 0))
ax.yaxis.set_ticks_position('left')
ax.spines['left'].set_position(('data', 0))
plt.ylim((-1, 1))

tanh=torch.tanh(x)
plt.plot(x.numpy(),tanh.numpy())
```

![](/files/-LokoRN6DynFQVlExlO0)

### ReLU 函数

Relu（Rectified Linear Units）修正线性单元，$$a=max(0,z)$$ 导数大于0时1，小于0时0。

也就是说：

z>0时，梯度始终为1，从而提高神经网络基于梯度算法的运算速度。

当z<0时，梯度一直为0。

ReLU函数只有线性关系（只需要判断输入是否大于0）不管是前向传播还是反向传播，都比sigmod和tanh要快很多。

当输入是负数的时候，ReLU是完全不被激活的，这就表明一旦输入到了负数，ReLU就会死掉。但是到了反向传播过程中，输入负数，梯度就会完全到0，这个和sigmod函数、tanh函数有一样的问题。 但是实际的运用中，该缺陷的影响不是很大。

```python
ax = plt.gca()
ax.spines['right'].set_color('none')
ax.spines['top'].set_color('none')
ax.xaxis.set_ticks_position('bottom')
ax.spines['bottom'].set_position(('data', 0))
ax.yaxis.set_ticks_position('left')
ax.spines['left'].set_position(('data', 0))
plt.ylim((-3, 10))

relu=F.relu(x)
plt.plot(x.numpy(),relu.numpy())
```

![](/files/-LokoRN8SkhGqnV4eHzZ)

### Leaky Relu 函数

为了解决relu函数z<0时的问题出现了 Leaky ReLU函数，该函数保证`在z<0的时候，梯度仍然不为0`。 ReLU的`前半段设为αz而非0`，通常α=0.01 $$a=max(\alpha z,z)$$

```python
ax = plt.gca()
ax.spines['right'].set_color('none')
ax.spines['top'].set_color('none')
ax.xaxis.set_ticks_position('bottom')
ax.spines['bottom'].set_position(('data', 0))
ax.yaxis.set_ticks_position('left')
ax.spines['left'].set_position(('data', 0))
plt.ylim((-3, 10))

l_relu=F.leaky_relu(x,0.1) # 这里的0.1是为了方便展示，理论上应为0.01甚至更小的值
plt.plot(x.numpy(),l_relu.numpy())
```

![](/files/-LokoRNAJ-2-uTyvJOKn)

## 2.正反向传播

<https://blog.csdn.net/jiang425776024/article/details/88205240>

<https://blog.csdn.net/jiang425776024/article/details/85040726>

只考虑3层的，多了太乱了，基本都是矩阵搞了：

![](/files/-LpsmagsN6_YIHaygcRk)

分别集3、4、2这几个神经元（圆圈）为：$$x\_1,x\_2,x\_3;y\_1,y\_2,y\_3,y\_4;z\_1,z\_2$$

其中第一层中间3x4条连接的线为权值，往往还有偏置b：(w13表示y1连接x3那条线，b1表示y1的偏置)

$$
\begin{aligned}
w\_{11},w\_{12},w\_{13} +b1\\
w\_{21},w\_{22},w\_{23} +b2\\
w\_{31},w\_{32},w\_{33} +b3\\
w\_{41},w\_{42},w\_{43} +b4
\end{aligned}
$$

于是：

$$
y\_1=
$$

## 3.存在的问题

* 1）梯度消失问题

如果激活函数**导数绝对值<1**，多次连乘后，误差项，进而**导致对W,b的梯度值接近0**，不幸的是，上面用的sigmoid就是这样的一个激活函数，不超过3/5层神经网络，上面那样的全连接网络后面梯度会接近0的。

ReLU一定程度上减少梯度消失问题，但不是绝对的。

* 2）饱和性

x趋于±无穷时，导数=0，x=c的时候**存在导数=0**。（上面说了要避免饱和性，梯度消失主要就是激活函数导数接近0，而饱和性的函数可能直接就是0，因此要避免这样的饱和性函数）

* 3）退化问题

神经网络的训练误差和测试误差会随着层数增加而增大，也就是说并不是层次越多越好，多了可能**过拟合**。解决技巧有残差网络等。

* 4）局部极小值

神经网络的优化目标不是一个凸优化问题，很可能存在无法预测的局部极小值，陷入其中很可能就无法跳出，造成效果不好。目前无好的解决办法。

* 5） 鞍点问题

Hessian矩阵**不正定**，不是局部极小值点，也就是说可能连局部极小值都找不到！。

以上问题都没有很好的解决办法，可见效果好坏通常还与初始迭代位置点优化，所有目前能做的就是**多次尝试**（暴力）。


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://im-qianuxn.gitbook.io/pytorch/ji-suan-ji/shen-du-xue-xi-li-lun/dnn.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
