人类大脑有数百亿个相互连接的神经元(如下图(a)所示),这些神经元通过树突从其他神经元接收信息,在细胞体内综合、并变换信息,通过轴突上的突触向其他神经元传递信息。我们在博文《最优化方法Python计算:无约束优化应用——逻辑回归模型》中讨论的逻辑回归模型(如下图(b)所示)与神经元十分相似,由输入端接收数据
x
=
(
x
1
x
2
⋮
x
n
)
\boldsymbol{x}=\begin{pmatrix} x_1\\x_2\\\vdots\\x_n \end{pmatrix}
x=
x1x2⋮xn
,作加权和
∑
i
=
1
n
w
i
x
i
\sum\limits_{i=1}^nw_ix_i
i=1∑nwixi加上偏移量
w
n
+
1
w_{n+1}
wn+1,即
∑
i
=
1
n
w
i
x
i
+
w
n
+
1
\sum\limits_{i=1}^nw_ix_i+w_{n+1}
i=1∑nwixi+wn+1,用逻辑函数将其映射到区间
(
0
,
1
)
(0,1)
(0,1)内,然后将如此变换所得的信息
y
y
y输出。

这启发人们将诸多逻辑回归模型分层连接起来,构成人工神经网络,创建出多层感应模型。下图展示了一个包括输入层、输出层和两个隐藏层(图中阴影部分)的人工神经网络。图中,黑点表示数据节点,圆圈表示人工神经元的处理节点。

记逻辑函数
sigmoid
(
x
)
=
1
1
+
e
−
x
=
φ
(
x
)
\text{sigmoid}(x)=\frac{1}{1+e^{-x}}=\varphi(x)
sigmoid(x)=1+e−x1=φ(x)。设多层感应模型的输入数据为
n
n
n维向量
x
=
(
x
1
x
2
⋮
x
n
)
\boldsymbol{x}=\begin{pmatrix} x_1\\x_2\\\vdots\\x_n \end{pmatrix}
x=
x1x2⋮xn
。不算输入层,模型连同输出层及隐藏层共有
l
l
l层。记
m
0
=
n
m_0=n
m0=n,第
i
i
i层(
0
<
i
≤
l
0<i\leq l
0<i≤l)含有
m
i
m_i
mi个神经元。于是,相邻的两层,第
i
−
1
i-1
i−1和第
i
i
i之间共有
(
m
i
−
1
+
1
)
m
i
(m_{i-1}+1)m_{i}
(mi−1+1)mi个待定参数。因此,模型具有
p
=
∑
i
=
1
l
(
m
i
−
1
+
1
)
m
i
p=\sum_{i=1}^l(m_{i-1}+1)m_i
p=i=1∑l(mi−1+1)mi
个待定参数,组织成
p
p
p维向量
w
=
(
w
1
w
2
⋮
w
p
)
\boldsymbol{w}=\begin{pmatrix} w_1\\w_2\\\vdots\\w_p \end{pmatrix}
w=
w1w2⋮wp
。设
k
0
=
0
k_0=0
k0=0,对
1
<
i
≤
l
1<i\leq l
1<i≤l,
k
i
=
∑
t
=
0
i
−
1
(
m
t
+
1
)
m
t
+
1
k_i=\sum\limits_{t=0}^{i-1}(m_{t}+1)m_{t+1}
ki=t=0∑i−1(mt+1)mt+1,记
(
m
i
−
1
−
1
)
×
m
i
(m_{i-1}-1)\times m_i
(mi−1−1)×mi矩阵
w
i
=
(
w
k
i
+
1
⋯
w
k
i
+
(
m
i
−
1
+
1
)
(
m
i
−
1
)
+
1
⋮
⋱
⋮
w
k
i
+
(
m
i
−
1
+
1
)
⋯
w
k
i
+
(
m
i
−
1
+
1
)
m
i
)
,
i
=
1
,
2
⋯
,
l
\boldsymbol{w}_i=\begin{pmatrix} w_{k_i+1}&\cdots&w_{k_i+(m_{i-1}+1)(m_i-1)+1}\\ \vdots&\ddots&\vdots\\ w_{k_i+(m_{i-1}+1)}&\cdots&w_{k_i+(m_{i-1}+1)m_i} \end{pmatrix}, i=1,2\cdots,l
wi=
wki+1⋮wki+(mi−1+1)⋯⋱⋯wki+(mi−1+1)(mi−1)+1⋮wki+(mi−1+1)mi
,i=1,2⋯,l
定义函数
F
(
w
;
x
)
=
φ
(
(
⋯
φ
⏟
l
(
(
x
⊤
,
1
)
w
1
)
,
1
)
,
⋯
)
,
1
)
w
l
)
.
F(\boldsymbol{w};\boldsymbol{x})=\underbrace{\varphi((\cdots\varphi}_l((\boldsymbol{x}^\top,1)\boldsymbol{w}_1),1),\cdots),1)\boldsymbol{w}_l).
F(w;x)=l
φ((⋯φ((x⊤,1)w1),1),⋯),1)wl).
该函数反映了数据从输入层到输出层的传输方向,称为前向传播函数,作为多层感应模型的拟合函数。按此定义,我们构建如下的多层感应模型类
import numpy as np #导入numpy
class NeuralNetwork(LogicModel): #神经网络模型
def __init__(self, hidden_layer_sizes = (100,)): #构造函数
self.layer_sizes = hidden_layer_sizes + (1,) #默认输出层含1个神经元
def w0len(self): #重载模型参数长度函数
p = 0
l = len(self.layer_sizes) #总层数
for i in range(l - 1): #逐层累加
m = self.layer_sizes[i]
n = self.layer_sizes[i + 1]
p += (m + 1) * n
return p
def F(self, w, x): #重载拟合函数
l = len(self.layer_sizes) #总层数
m, n = self.layer_sizes[0],self.layer_sizes[1]
k = (m + 1) * n #第0层参数个数
W = w[0:k].reshape(m + 1, n) #0层参数折叠为矩阵
z = LogicModel.F(self, W, x) #第1层的输入
for i in range(1, l - 1): #逐层计算
m = self.layer_sizes[i] #前层节点数
n = self.layer_sizes[i + 1] #后层节点数
W = w[k:k+(m+1)*n].reshape(m + 1,n) #本层参数矩阵
z = np.hstack((z, np.ones(z.shape[0]). #本层输入矩阵
reshape(z.shape[0], 1)))
z = super().F(W, z) #下一层输入
k += (m + 1) * n #下一层参数下标起点
y = z.flatten() #展平输出
return y
def fit(self, X, Y, w = None, hidden_layer_sizes = (100,)): #重载训练函数
if len(X.shape) == 1: #计算输入端节点数
k = 1
else:
k = X.shape[1]
self.layer_sizes=(k,) + self.layer_sizes #确定网络结构
RegressModel.fit(self, X, Y, w) #调用祖先训练函数
class NeuralNetworkRegressor(Regression, NeuralNetwork): #神经网络回归模型
def __init__(self, hidden_layer_sizes = (100,)):
super().__init__(hidden_layer_sizes) #执行父类构造函数
self.tagVal = identity #回归任务直接输出预测值
程序中,
- 第2~35行将表示神经网络模型的NeuralNetwork类定义为LogicModel的子类。与前面定义的线性回归模型、逻辑回归模型略有不同,事先要为模型确定网络结构:有少层,各层有多少个神经元。在NeuralNetwork中除了重载模型参数长度计算函数w0len、拟合函数F和训练函数fit外需要定义一个构造函数。事实上,Python系统为每一个类提供了一个缺省的构造函数__init__,完成内存分配等基础工作。开发者可根据需要重载构造函数以完成特殊的需求。具体而言,
- 第3~4行的__init__,重载NeuralNetwork的构造函数。传递给它的参数hidden_layer_sizes表示隐藏层结构,这是一个元组,缺省值为(100,),意味着只有1个隐藏层,隐藏层含100个神经元。函数计算神经网络的各层结构:在尾部添加仅含1个节点的输出层,赋予对象的layer_size属性。值得注意的是,此时网络的结构并未完全确定:输入端的节点数并未确定,这将在训练阶段有输入的数据来决定。
- 第5~12行重载了模型参数长度计算函数w0len。第7行根据模型的结构元组layer_sizes的长度确定层数l。第8~11行的for循环组成计算各层的参数个数:m为前层节点数(第9行),n为后层节点数(第10行),则第11行中(m+1)*n就是本层的参数个数,这是因为后层的每个节点的输入必须添加一个偏移量。第11行将算得的本层参数个数累加到总数p(第10行初始化为0)。
- 第13~28行重载拟合函数F,参数中w表示模型参数 w ∈ R p \boldsymbol{w}\in\text{R}^p w∈Rp,x表示自变量 ( x ⊤ , 1 ) (\boldsymbol{x}^\top,1) (x⊤,1)。第14行读取网络层数l。第15~18行计算第1隐藏层的输入:第15行读取第0层节点数m第1隐藏层节点数n。第16行计算第0层参数个数k(也是第1层参数下标起点)。第17行构造第0层的参数矩阵W。第18行计算 φ ( ( x ⊤ , 1 ) w 1 ) \varphi((\boldsymbol{x}^\top,1)\boldsymbol{w}_1) φ((x⊤,1)w1),作为第1隐藏层的输入z。第19~26行的for循环依次逐层构造本层参数矩阵 w i \boldsymbol{w}_i wi(第22行)和输入 ( z i ⊤ , 1 ) (\boldsymbol{z}_i^\top,1) (zi⊤,1)(第23~24行),第25行计算下一层的输入 φ ( ( z i ⊤ , 1 ) w i ) \varphi((\boldsymbol{z}_i^\top,1)\boldsymbol{w}_i) φ((zi⊤,1)wi)为z,第26行更新下一层参数下标起点k。完成循环,所得y因为是矩阵运算的结果,第27行将其扁平化为一维数组。
- 第29~35行重载训练函数fit。函数体内第30~33行的if-else分支语句根据表示训练用样本特征数据的参数X结构计算输入端节点数k,第34行将(k,)添加到对象表示网络结构的属性layer_sizes前端,完成网络结构的确定。第35行调用祖先RegressModel(见博文《最优化方法Python计算:无约束优化应用——线性回归模型》)类的fit函数完成训练。 - 第36~39行用NeuralNetwork与Regression(见博文《最优化方法Python计算:无约束优化应用——线性回归模型》)联合构造神经网络预测器类NeuralNetworkRegressor。其中,第37~39行定义该类的构造函数__init__:调用父类(NeuralNetwork)的构造函数,初始化网络结构layer_sizes,并用恒等函数identity(见博文《最优化方法Python计算:无约束优化应用——线性回归预测器》)设置作预测操作时计算标签值的函数tagVal,以适于回归预测。
理论上,只要给定足够多的隐藏层和层内所含神经元,多层感应模型能拟合任意函数。
例1 用MLPRegressor对象拟合函数 y = x 2 y=x^2 y=x2。
解:先构造训练数据:
import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import uniform
np.random.seed(2023)
x = uniform.rvs(-1, 2, 50)
y = (x**2)
plt.scatter(x, y)
plt.show()
第5行产生50个服从均匀分布
U
(
0
,
1
)
U(0,1)
U(0,1)的随机数值,赋予x。第6行计算x的平方赋予y。第7行绘制
(
x
,
y
)
(x,y)
(x,y)散点图。

用仅含一个隐藏层,隐藏层中包含3个神经元的多层感应器拟合
y
=
x
2
y=x^2
y=x2
import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import uniform
x = uniform.rvs(-1, 2, 50)
y = (x**2)
nnw = NeuralNetworkRegressor(hidden_layer_sizes = (3,))
nnw.fit(x, y)
yp = nnw.predict(x)
plt.scatter(x, yp)
plt.show()
score = nnw.score(x, y)
print('1隐藏层含3个神经元网络拟合评估分%.4f'%score)
前5行与前同。第6行创建含1个隐藏层,隐藏层含3个神经元的神经网络NeuralNetworkRegressor类对象nnw。第7行用x,y训练nnw。第8行调用nnw的predict函数,结果赋予yp。第9~10行绘制x上网络模型拟合的yp散点图。第11行调用nnw的score函数计算并输出测试评估。运行程序,绘制出下图并输出信息

训练中...,稍候
726次迭代后完成训练。
1隐藏层含3个神经元网络拟合评估分0.9934
用含两个隐藏层,分别包含7个、3个神经元的多层感应器拟合 y = x 2 y=x^2 y=x2
import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import uniform
random.seed(2023)
x = uniform.rvs(-1, 2, 50)
y = (x**2)
nnw = NeuralNetworkRegressor(hidden_layer_sizes = (7, 3))
nnw.fit(x, y)
yp = nnw.predict(x)
plt.scatter(x, yp)
plt.show()
score=nnw.score(x, y)
print('2隐藏层含各7,3个神经元网络拟合评估分%.4f' % score)
与上一段代码比较,仅第7行创建nnw的网络换成两个隐藏层,分别包含7个、3个神经元的多层感应器。运行程序,输出

训练中...,稍候
1967次迭代后完成训练。
2隐藏层含各3,7个神经元网络拟合评估分1.0000
比前一个显然拟合得更好,但也付出了计算时间的代价。
Say good bye, 2023.
写博不易,敬请支持:
如果阅读本文于您有所获,敬请点赞、评论、收藏,谢谢大家的支持!
本文探讨了人类大脑神经元的工作原理,并将其与逻辑回归模型进行类比,进一步阐述了人工神经网络的构造,特别是多层感应模型的结构、参数计算和前向传播过程。通过实例展示了如何用MLPRegressor拟合不同复杂度的函数。
1万+

被折叠的 条评论
为什么被折叠?



