Char6-神经网络neural networks
本章中主要讲解的内容包含:
神经模型的简介
感知机模型
全连接网络
神经网络介绍
常见的激活函数
输出层设计方案
误差类型
神经网络类型

机器学习的目的是找到一组良好的参数,使得其表示的数学模型能够很好地从训练数据集中学到映射关系
神经元模型
MP-神经模型
神经网络是由具有自适应性的简单单元组成的并行互连的网络。下图是经典的MP-神经元模型。
- 当前神经元接收来自
个其他的神经元传递过来的输入信号
- 这些信号带着自己的连接权重
一起过来
- 当前神经元的总输入:
- 将神经元的总输入和阈值
进行比较,再通过激活函数进行处理并输出

神经网络就是包含了多个参数的数学模型,这个模型就是若干个参数。
感知机
感知机简介
简单的两层神经网络,感知机是线性分类判别模型。
- 输入层接收来自外界的出入信号
,传递给输出层
- 输入信号有自己的权值
- 输出层是MP-神经元模型(也叫阈值逻辑单元)
- 感知机还有自己的偏置

上式的向量形式为
上面的表示感知机的净活性值,加上激活函数之后变成活性值:
激活函数可以是阶跃函数,也可以是符号函数;一般选用的符号函数

感知机模型
感知机模型就是上文中的

为了方便,直接将模型改成:
是一个n维空间中的超平面S,其中w是超平面的法向量,b是超平面的截距,这个超平面将特征空间划分成两部分,位于两部分的点分别被分为正负两类,所以超平面S称为分离超平面。
对于二分类的正确分类有:
- 正例输出
- 负例输出
那么,输入空间的某个点到
的距离为
叫函数间隔,除模长之后叫几何间隔,几何间隔可以认为是物理意义上的实际长度。
对于误分类点有:
- 输出
- 输出
那么总有:
因此误分类点到超平面的距离总是:
全部的误分类点到超平面的距离是
不考虑前面的系数,得到感知机的损失函数
感知机算法
1. 初始化参数w_0,b_0
2. 循环过程:
3. 在训练集中选取数据(x_i,y_i)
4. 计算感知机的输出a=sign(w^Tx_i+b)
5. 如果输出a和真实值y_i不等:
6. 更新w
7. 更新b
8.转至步骤2,直至训练集中没有误分类点
9. 输出w,b
过程解释:如果一个误分类点在超平面的一侧,调整两个参数,使得超平面向着该误分类点移动,以此来减少误分类点的和分离超平面的距离,直至超平面将该点正确分类。
全连接层
感知机模型的不可导限制了它的潜力,全连接层将不连续的阶跃函数换成了平滑连续的激活函数,通过堆叠多层网络实现。
每个输出节点和全部的输出相连接的网络层称之为全连接层
下图中3个输出,2个神经元,2个输出节点。

通过矩阵表示上述网络层的运算:

- 输入
的
为
,b是样本数量,
是输入节点数
- 权值矩阵W,其
为
,其中
是输出节点数
- 偏置b的
是
如果是2个样本参与运算,

输出矩阵O的为
张量实现
定义好权值张量和偏置张量,利用批量矩阵相乘函数`tf.matmul()``
"""
输入X矩阵为𝑏=2个样本(2行,2个样本)
每个样本的输入特征长度为𝑑𝑖𝑛 = 784(784个属性特征)
输出节点数为𝑑𝑜𝑢𝑡 = 256
定义权值矩阵W的shape为[784,256],并采用正态分布初始化W;
偏置向量b的shape定义为[256]
在计算完X@W后相加即可,最终全连接层的输出O的shape为[2,256],即2个样本的特征,每个特征长度为 256。
"""
x = tf.random.normal([2,784])
w1 = tf.Variable(tf.random.truncated_normal([784, 256], stddev=0.1))
b1 = tf.Variable(tf.zeros([256]))
o1 = tf.matmul(x, w1) + b1
o1 = tf.nn.relu(o1)
层方式
通过layers.Dense(units, activation)
import tensorflow as tf
x = tf.random.normal([4, 28*28])
from tf.keras import layers
# 创建全连接层,指定输出节点数和激活函数
fc = layers.Denss(512, activation=tf.nn.relu) # 激活函数也可以不指定
h1 = fc(x) # 通过fc完成一次全连接的计算
fc.kernal # 获取权值矩阵
fc.bias # 获取Dense类的偏置
fc.trainable_variables # 返回的是待优化参数的列表
fc.variables # 返回所有的参数列表
神经网络
保证前一层的输出节点数与当前层的输入节点数匹配,即可堆叠出任意层数的网络。

张量实现
# 定义隐藏层1的张量
w1 = tf.Variable(tf.random.truncated_normal([784, 256], stddev=0.1))
b1 = tf.Variable(tf.zeros([256]))
# 定义隐藏层2的张量
w2 = tf.Variable(tf.random.truncated_normal([256, 128], stddev=0.1))
b2 = tf.Variable(tf.zeros([128]))
# 定义隐藏层3的张量
w3 = tf.Variable(tf.random.truncated_normal([128,64], stddev=0.1))
b3 = tf.Variable(tf.zeros([64]))
# 输出层张量
w4 = tf.Variable(tf.random.truncated_normal([64,10], stddev=0.1))
b4 = tf.Variable(tf.zeros([10]))
"""
计算时,只需要按照网络层的顺序,将上一层的输出送入当前层的输入即可,重复直至 最后一层,将输出层的输出作为网络的输出:
"""
with tf.GradienTape() as tape: # 必须将前向计算过程放入tf.GradienTape()环境中,利用 GradientTape 对象的 gradient()方法自动求解参数的梯 度,并利用 optimizers 对象更新参数
# x: [b, 28*28]
# 隐藏层 1 前向计算,[b, 28*28] => [b, 256]
h1 = x@w1 + tf.broadcast_to(b1, [x.shape[0],256])
h1 = tf.nn.relu(h1)
h2 = h1@w2 + b2
h2 = tf.nn.relu(h2)
h3 = h2@w3 + b3
h3 = tf.nn.relu(h3)
# 输出层前向计算,[b, 64] => [b, 10]
h4 = h3@w4 + b4
层方式
通过layer.Dense类来实现
# 方式1:将每个网络分别建立出来,并且指定激活函数
x = tf.random.normal([4,28*28])
fc1 = layers.Dense(256, activation=tf.nn.relu)
fc2 = layers.Dense(128, activation=tf.nn.relu)
fc3 = layers.Dense(64, activation=tf.nn.relu)
fc4 = layers.Dense(10, activation=None)
# 依次通过各个层
x = tf.random.normal([4,28*28])
h1 = fc1(x)
h2 = fc2(h1)
h3 = fc3(h2)
h4 = fc4(h3) # 通过输出层得到网络输出
# 通过Sequential容器来进行封装
x = tf.random.normal([4,28*28])
model = layers.Sequential({
layers.Dense(256, activation=tf.nn.relu), # 创建隐藏层 1
layers.Dense(128, activation=tf.nn.relu) , # 创建隐藏层 2
layers.Dense(64, activation=tf.nn.relu) , # 创建隐藏层 3
layers.Dense(10, activation=None) , # 创建输出层
})
out = model(x)
激活函数
Sigmoid
Sigmoid 函数也叫Logistic 函数,tf.nn.sigmoid(x)实现
在输入值较大或者较小的时候都是很容易出现梯度弥散现象。

ReLU
- 单边抑制
- 相对宽松的边界
- 通过
tf.nn.relu实现


LeakyReLU
ReLU 函数在𝑥 < 0时梯度值恒为 0,也可能会造成梯度弥散现象,为了克服这个问 题,LeakyReLU函数被提出。通过tf.nn.leaky_relu来实现

,上述函数退化为
-
,当能够获得较小的梯度值
imageTanh
Tanh函数能够将的输入压缩到[-1,1]之间,定义为tanh激活函数可通过Sigmoid函数缩放平移后实现。通过tf.nn.tanh()实现image
输出层设计
四种设计
根据输出值的区间来进行分类:
-
输出属于整个实数区间,如正弦函数曲线预测、年龄的预测、股票的走势预测等
-
输出值落在[0,1]之间,如图片的像素归一化到[0,1]之间
-
,输出值落在[0,1]之前,且所有的的输出值之和为1。通过添加Softmax函数来实现功能
-
输出值在[-1,1],使用
tf.tanh(x)来实现
image
softmax函数
与Dense层类似,Softmax函数还可以作为网络层来使用。通过类layers.Softmax(axis=-1)。
输入值较大,会出现溢出现象。同时实现Softmax函数和交叉熵损失函数,接口为tf.keras.losses.categorical_crossentropy(y_true, y_pred, from_logits=False)
-
y_true代表了one-hot编码后的真实标签 -
y_pred表示网络的预测值- 当
from_logits = True时,y_pred表示须为未经过Softmax函数的变量z - 当
from_logits = False时,y_pred表示为经过Softmax函数的输出。
- 当
z = tf.random.normao([2,10])
y_onehot = tf.constant([1,3])
y_onehot = tf.one_hot(y_onehot, depth=10)
# 输出层未使用Softmax函数,设置成True
loss = keras.losses.categorical_crossentropy(y_onehot,z,from_logits=True)
loss = tf.reduce_mean(loss)
# 可以利用 losses.CategoricalCrossentropy(from_logits)类方式同时实现 Softmax与交叉熵损失函数的计算
ctiteon = keras.losses.CategoricalCrossentropy(from_logits=True)
loss = criteon(y_onehot, z)
误差类型
均方差
均方差MSE,mean squared error:将输出向量和真实向量映射到笛卡尔坐标系上的两个点,计算两点之间的欧式距离(平方)
- MSE的值总是大于等于0;当其为0表示输出值等于真实标签
- 主要用于回归问题
o = tf.random.normal([2,10]) # 构造网络
y_onehot = tf.constant([1,3]) # 真实输出
y_onehot = tf.one_hot(y_onehot, depth=10)
loss = keras.losses.MSE(y_onehot, o) # 计算均方差,返回的是每个样本的均方差
loss = tf.reduce_mean(loss) # 计算batch均方差
# 通过类的方式实现
criteon = keras.losses.MeanSquaredError()
loss = criteon(y_onehot, o)
交叉熵
熵是用来衡量信息的不确定性。熵越大,代表不确定越大,信息量越大。
假设数据集中第
类样本占的比例是
,则
的信息熵定义为:
比如:某个事件发生的结果有3中情形,出现的概率分别是:
| 结果1 | 结果2 | 结果3 |
|---|---|---|
信息熵的计算如下:
交叉熵 Cross Entropy 的定义为
通过变换,交叉熵可以分解为 p 的熵𝐻(𝑝)与 p,q 的 KL 散度(Kullback-Leibler Divergence)的和
其中 KL 定义为
KL散度是衡量连个分布之间距离的指标。交叉熵和KL散度都是不对称的。
神经网络类型
- 卷积神经网络CNN
- 循环神经网络RNN
- 注意力网络Transformer
- 图神经网络GCN


