神经网络是由神经元按照一定的连接结构组合而成的网络。神经网络可以看作一个函数,通过简单非线性函数的多次复合,实现输入空间到输出空间的复杂映射 。
前馈神经网络是最早发明的简单人工神经网络。整个网络中的信息单向传播,可以用一个有向无环路图表示,这种网络结构简单,易于实现。
目录
4.1 神经元
神经网络的基本组成单元为带有非线性激活函数的神经元。
在大脑中,神经网络由称为神经元的神经细胞组成,神经元的主要结构有细胞体、树突(用来接收信号)和轴突(用来传输信号)。一个神经元的轴突末梢和其他神经元的树突相接触,形成突触。神经元通过轴突和突触把产生的信号送到其他的神经元。信号就从树突上的突触进入本细胞,神经元利用一种未知的方法,把所有从树突突触上进来的信号进行相加,如果全部信号的总和超过某个阀值,就会激发神经元进入兴奋状态,产生神经冲动并传递给其他神经元。如果信号总和没有达到阀值,神经元就不会兴奋。图1展示的是一个生物神经元。
人工神经元模拟但简化了生物神经元,是神经网络的基本信息处理单位,其基本要素包括突触、求和单元和激活函数,结构见图2
4.1.1 净活性值
假设一个神经元接收的输入为,其权重向量为,神经元所获得的输入信号,即净活性值的计算方法为:
其中为偏置。
为了提高预测样本的效率,我们通常会将个样本归为一组进行成批地预测:
其中为个样本的特征矩阵,为个预测值组成的列向量。
使用pytorch计算一组输入的净活性值。代码实现如下:
import torch
X = torch.rand([2, 5]) # 2个特征数为5的样本
w = torch.rand([5, 1]) # 含有5个参数的权重向量
b = torch.rand([1, 1]) # 偏置项
z = torch.matmul(X, w) + b # 使用'torch.matmul'实现矩阵相乘
print("input X:\n", X)
print("weight w:\n", w, "\nbias b:", b)
print("output z:\n", z)
运行结果:
净活性值再经过一个非线性函数f(⋅)后,得到神经元的活性值。
注: 在pytorch中,可以使用torch.nn.Linear(features_in, features_out, bias=False)完成输入张量的上述变换。
【思考题】加权求和与仿射变换之间有什么区别和联系?
加权求和可简单看成对输入的信息的线性变换 ,从几何上来看,在变换前后原点是不发生改变的。仿射变换在图形学中也叫仿射映射,是指一个向量空间经过一次线性变换,再经过一次平移,变换为另一个向量空间,因此仿射变换在几何上没有原点保持不变这一特点。只有当仿射变换的平移项时,仿射变换才变为线性变换。
例如,平移就不是线性变换而是仿射变换。
以下是仿射变换的具体定义描述:
借用老师所发资料的描述:
NNDL 实验五 前馈神经网络(1)二分类任务_HBU_David的博客-CSDN博客
4.1.2 激活函数
激活函数通常为非线性函数,可以增强神经网络的表示能力和学习能力。常用的激活函数有S型函数和ReLU函数。
4.1.2.1 Sigmoid 型函数
Sigmoid 型函数是指一类S型曲线函数,为两端饱和函数。常用的 Sigmoid 型函数有 Logistic 函数和 Tanh 函数,其数学表达式为
Logistic 函数:
Tanh 函数:
Logistic函数和Tanh函数的代码实现和可视化如下:
import matplotlib.pyplot as plt
# Logistic函数
def logistic(z):
return 1.0 / (1.0 + torch.exp(-z))
# Tanh函数
def tanh(z):
return (torch.exp(z) - torch.exp(-z)) / (torch.exp(z) + torch.exp(-z))
# 在[-10,10]的范围内生成10000个输入值,用于绘制函数曲线
z = torch.linspace(-10, 10, 10000)
plt.figure()
plt.plot(z.tolist(), logistic(z).tolist(), color='red', label="Logistic Function")
plt.plot(z.tolist(), tanh(z).tolist(), color='blue', linestyle='--', label="Tanh Function")
ax = plt.gca() # 获取轴,默认有4个
# 隐藏两个轴,通过把颜色设置成none
ax.spines['top'].set_color('none')
ax.spines['right'].set_color('none')
# 调整坐标轴位置
ax.spines['left'].set_position(('data',0))
ax.spines['bottom'].set_position(('data',0))
plt.legend(loc='lower right', fontsize='large')
plt.savefig('fw-logistic-tanh.pdf')
plt.show()
运行结果:
4.1.2.2 ReLU型函数
常见的ReLU函数有ReLU和带泄露的ReLU(Leaky ReLU),数学表达式分别为:
其中λ为超参数。
可视化ReLU和带泄露的ReLU的函数的代码实现和可视化如下:
# ReLU
def relu(z):
return torch.maximum(z, torch.tensor(0.))
# 带泄露的ReLU
def leaky_relu(z, negative_slope=0.1):
a1 = (torch.tensor((z > 0), dtype=torch.float32) * z)
a2 = (torch.tensor((z <= 0), dtype=torch.float32) * (negative_slope * z))
return a1 + a2
# 在[-10,10]的范围内生成一系列的输入值,用于绘制relu、leaky_relu的函数曲线
z = torch.linspace(-10, 10, 10000)
plt.figure()
plt.plot(z.tolist(), relu(z).tolist(), color="red", label="ReLU Function")
plt.plot(z.tolist(), leaky_relu(z).tolist(), color="blue", linestyle="--", label="LeakyReLU Function")
ax = plt.gca()
ax.spines['top'].set_color('none')
ax.spines['right'].set_color('none')
ax.spines['left'].set_position(('data', 0))
ax.spines['bottom'].set_position(('data', 0))
plt.legend(loc='upper left', fontsize='large')
plt.savefig('fw-relu-leakyrelu.pdf')
plt.show()
运行结果:
《神经网络与深度学习》4.1节中提到的其他激活函数:
1.Hard-Logistic函数和Hard-Tanh函数
Logistic函数和Tanh函数都是Sigmoid型函数,具有饱和性,但是计算开销较大。Hard_Logistic和Hard_Tanh是前面两种Sigmoid函数的Hard版,解决了两端饱和性问题但依然没解决指数运算量大的问题。比前者们更易进行拟合,两端饱和部分被一阶泰勒展开函数进行线性化处理后在进行梯度计算的时候明显的收敛速度加快。而关于函数是否零中心化此二者与其非Hard版本保持一致,并且继承其前者的其他优点。
2.ELU
ELU(Exponential Linear Unit,指数线性单元)是一个近似的零中心化的非线性函数,其定义为
其中γ≥0是一个超参数,决定x≤0时的饱和曲线,并调整输出均值在0附近。
3.Softplus
Softplus函数可以看作Rectifier函数的平滑版本,其定义为:Softplus(x)=log(1+exp(x)). Softplus函数其导数刚好是Logistic函数.Softplus函数虽然也具有单侧抑制、宽兴奋边界的特性,却没有稀疏激活性。