➤01 第一题参考
1.两种网络权系数学习公式
(1) 结构1
结构1网络是标准的分层(作业题中结构以是两层)前馈网络。可以根据 BP算法 ,利用误差反向传播关系写出各层权系数调整值算法公式。
下面给出课件中的对于具有层网络中,第
层的权系数
的调整公式:
其中 表示第
层的第
个神经元连接到第
层的第
个神经元的权系数。
▲ 具有h+1层的前馈网络结构示意图
公式中:
:是第
层中的第
个神经元的学习信号。它是从网络的输出层反向传播过来的。对于神经网络输出层的学习信号
就定义为误差:
:表示第
层神经元输出信息的导数;
:表示
层中第
个神经元的输出。
本质上讲,上面的权系数调整公示都符合统一的神经元学习算法公式:
即对于神经元线性加权的权系数的调整
与学习信号
,输入向量
的乘积成正比。
根据以上公式,可以写出结构1中网络各个权系数的修改公式。对于网络中的变量做如下约束:
是学习速率。
分别是神经网络中神经元1,2,3的输出;
- 输入节点4,5的输出分别是
由于结构1中的所有神经元的激励函数都是sigmoid函数:
对应的函数导数为:
这样,神经元的输出导数可以表示成:
- 输出层神经元权系数:
神经元1的学习信号:
那么它的三个神经元权向量的修正公式为:
注意:对于权系数,由于网络中规定的输入为-1,所以在修正公式前具有负号(-1)。对于后面的
也是一样的。
- 隐层神经元权系数:
隐层神经元2,3的学习信号分别为:
因此隐层神经元的各个权系数修正公式分别为:
(2) 结构2
相比于结构1,结构2不是一个严格的分层网络,因为它的输入层的信息直接越过隐层,到达输出层。
该网络只有两个神经元1,2。它们的输出分别记为:。对于输入层的神经元3,4的输出就是输入信号
。
神经元的传递函数采用双曲正切函数:
由于结构2的网络比较简单,可以直接根据公式(1-2)写出其中两个神经元1,2的各个权系数的修正公式:
- 神经元1:
学习信号:
四个权系数的修正公式为:
- 神经元2:
学习信号:
三个权系数修正公式:
2.使用编程语言实现上述基本算法
由于结构1属于典型的前馈网络,所以可以在标准的网络平台上实现该算法,比如MATLAB,TensorFlow,Keras,PaddlePaddle上等等。
对于结构2,由于它不属于标准的前馈网络,所以实现该算法,则需要通过C、Python等通用的编程语言来实现。
(1) 使用Python实现第一种结构算法
第一接驳算法的Python程序参见附录中:第一种结构(BP网络程序)
网络参数:
- 中间隐层结构2各节点,输出节点传递函数为线性函数。
- 使用学习速率:0.5。
下面是进行训练,网络误差曲线降低的过程。
▲ 训练误差收敛曲线
训练之后,对于异或问题的计算结构为:
样本 | S1 | S2 | S3 | S4 |
期望输出 | 0 | 1 | 1 | 0 |
神经网络输出 | 0.0404143 | 0.94139378 | 0.92436339 | 0.09499248 |
讨论1: 输入采用线性传递函数,相当于对于损失函数,不是使用均方差:
而是使用的对数似然函数:
讨论2: 如果输出的传递函数采用sigmoid函数,同时误差仍然采用均方差,上述网络在训练过程中对于XOR问题无法收敛。对于逻辑与则可以收敛到一个误差大约最小为0.05的结果。
(2) 使用Python 实现第二种结构
神经元1采用线性输出传递函数;神经元2采用双曲正切传递函数。
具体Python程序参见本文最后附录中的:第二种结构的程序
如下是在学习速率为0.5, 使用(-1,1)来表示异或逻辑样本是,网络训练误差收敛过程:
▲ 使用双极性训练网络,误差收敛曲线
网络输出结果:
样本 | x1 | x2 | x3 | x3 |
期望输出 | -1 | 1 | 1 | -1 |
实际输出 | -0.99503755 | 0.99212455 | 0.99503753 | -0.99503758 |
- 讨论1: 使用(0,1)来表示异或逻辑,上述训练过程不收敛。而使用(-1,1)逻辑来表示,则训练过程中很快就收敛了。
➤※ 作业1-1中的程序
1.第一种结构(BP网络)程序
#!/usr/local/bin/python
# -*- coding: gbk -*-
#============================================================
# HWDATA.PY -- by Dr. ZhuoQing 2020-11-17
#
# Note:
#============================================================
from headm import *
#------------------------------------------------------------
# Samples data construction
xor_x = array([[0,0],[1,0],[0,1],[1,1]]) # row->sample
xor_y = array([0, 1, 1, 0]).reshape(1, -1) # col->sample
xor_x0 = array([[-1,-1],[1,-1],[-1,1],[1,1]]) # row->sample
xor_y0 = array([-1, 1, 1, -1]).reshape(1, -1) # col->sample
#------------------------------------------------------------
def shuffledata(X, Y):
id = list(range(X.shape[0]))
random.shuffle(id)
return X[id], (Y.T[id]).T
#------------------------------------------------------------
# Define and initialization NN
def initialize_parameters(n_x, n_h, n_y):
random.seed(2)
W1 = random.randn(n_h, n_x) * 0.5 # dot(W1,X.T)
W2 = random.randn(n_y, n_h) * 0.5 # dot(W2,Z1)
b1 = zeros((n_h, 1)) # Column vector
b2 = zeros((n_y, 1)) # Column vector
parameters = {'W1':W1,
'b1':b1,
'W2':W2,
'b2':b2}
return parameters
#------------------------------------------------------------
# Forward propagattion
# X:row->sample;
# Z2:col->sample
def forward_propagate(X, parameters):
W1 = parameters['W1']
b1 = parameters['b1']
W2 = parameters['W2']
b2 = parameters['b2']
Z1 = dot(W1, X.T) + b1 # X:row-->sample; Z1:col-->sample
A1 = 1/(1+exp(-Z1))
Z2 = dot(W2, A1) + b2 # Z2:col-->sample
# A2 = 1/(1+exp(-Z2)) # A:col-->sample
A2 = Z2 # Linear output
cache = {'Z1':Z1,
'A1':A1,
'Z2':Z2,
'A2':A2}
return Z2, cache
#------------------------------------------------------------
# Calculate the cost
# A2,Y: col->sample
def calculate_cost(A2, Y, parameters):
err = A2 - Y
cost = dot(err, err.T) / Y.shape[1]
return cost
#------------------------------------------------------------
# Backward propagattion
def backward_propagate(parameters, cache, X, Y):
m = X.shape[0] # Number of the samples
W1 = parameters['W1']
W2 = parameters['W2']
A1 = cache['A1']
A2 = cache['A2']
dZ2 = (A2 - Y) #* (A2 * (1-A2))
dW2 = dot(dZ2, A1.T) / m
db2 = sum(dZ2, axis=1, keepdims=True) / m
dZ1 = dot(W2.T, dZ2) * (A1 * (1-A1))
dW1 = dot(dZ1, X) / m
db1 = sum(dZ1, axis=1, keepdims=True) / m
grads = {'dW1':dW1,
'db1':db1,
'dW2':dW2,
'db2':db2}
return grads
#------------------------------------------------------------
# Update the parameters
def update_parameters(parameters, grads, learning_rate):
W1 = parameters['W1']
b1 = parameters['b1']
W2 = parameters['W2']
b2 = parameters['b2']
dW1 = grads['dW1']
db1 = grads['db1']
dW2 = grads['dW2']
db2 = grads['db2']
W1 = W1 - learning_rate * dW1
W2 = W2 - learning_rate * dW2
b1 = b1 - learning_rate * db1
b2 = b2 - learning_rate * db2
parameters = {'W1':W1,
'b1':b1,
'W2':W2,
'b2':b2}
return parameters
#------------------------------------------------------------
# Define the training
def train(X, Y, num_iterations, learning_rate, print_cost=False):
# random.seed(3)
n_x = 2
n_y = 1
n_h = 3
lr = learning_rate
parameters = initialize_parameters(n_x, n_h, n_y)
W1 = parameters['W1']
b1 = parameters['b1']
W2 = parameters['W2']
b2 = parameters['b2']
XX,YY = shuffledata(X, Y)
costdim = []
for i in range(0, num_iterations):
A2, cache = forward_propagate(XX, parameters)
cost = calculate_cost(A2, YY, parameters)
grads = backward_propagate(parameters, cache, XX, YY)
parameters = update_parameters(parameters, grads, lr)
if print_cost and i % 50 == 0:
printf('Cost after iteration:%i: %f'%(i, cost))
costdim.append(cost[0][0])
if cost < 0.01:
break
# XX, YY = shuffledata(X, Y)
return parameters, costdim
#------------------------------------------------------------
parameter,costdim = train(xor_x, xor_y, 10000, 0.5, True)
A2, cache = forward_propagate(xor_x, parameter)
printf(A2, xor_y)
plt.plot(arange(len(costdim))*50, costdim)
plt.xlabel("Step(10)")
plt.ylabel("Cost")
plt.grid(True)
plt.tight_layout()
plt.show()
#------------------------------------------------------------
# END OF FILE : HWDATA.PY
#============================================================
2.第二种结构Python程序
#!/usr/local/bin/python
# -*- coding: gbk -*-
#============================================================
# HWXOR1.PY -- by Dr. ZhuoQing 2020-11-17
#
# Note:
#============================================================
from headm import *
#------------------------------------------------------------
# Samples data construction
xor_x = array([[0,0],[1,0],[0,1],[1,1]]) # row->sample
xor_y = array([0, 1, 1, 1]).reshape(1, -1) # col->sample
xor_x0 = array([[-1,-1],[1,-1],[-1,1],[1,1]]) # row->sample
xor_y0 = array([-1, 1, 1, -1]).reshape(1, -1) # col->sample
#------------------------------------------------------------
def shuffledata(X, Y):
id = list(range(X.shape[0]))
random.shuffle(id)
return X[id], (Y.T[id]).T
#------------------------------------------------------------
# Define and initialization NN
def initialize_parameters():
random.seed(2)
w10 = random.randn(1) * 0.1
w20 = random.randn(1) * 0.1
w13 = random.randn(1) * 0.1
w12 = random.randn(1) * 0.1
w14 = random.randn(1) * 0.1
w23 = random.randn(1) * 0.1
w24 = random.randn(1) * 0.1
parameters = {'w10':w10, 'w20':w20,
'w13':w13, 'w12':w12, 'w14':w14,
'w23':w23, 'w24':w24}
return parameters
#------------------------------------------------------------
# Forward propagattion
# X:row->sample;
# Z2:col->sample
def forward_propagate(X, parameters):
w10 = parameters['w10']
w20 = parameters['w20']
w13 = parameters['w13']
w12 = parameters['w12']
w14 = parameters['w14']
w23 = parameters['w23']
w24 = parameters['w24']
W2 = array([w23, w24])
W1 = array([w13, w14])
Z2 = dot(W2.T, X.T) - w20
# A2 = 1/(1+exp(-Z2))
A2 = (1-exp(-Z2)) / (1+exp(-Z2))
Z1 = dot(W1.T, X.T) + w12 * A2 - w10
A1 = Z1
cache = {'Z1':Z1,
'A1':A1,
'Z2':Z2,
'A2':A2}
return Z1, cache
#------------------------------------------------------------
# Calculate the cost
# A2,Y: col->sample
def calculate_cost(A2, Y, parameters):
err = A2 - Y
cost = dot(err, err.T) / Y.shape[1]
return cost
#------------------------------------------------------------
# Backward propagattion
def backward_propagate(parameters, cache, X, Y):
m = X.shape[0] # Number of the samples
w10 = parameters['w10']
w20 = parameters['w20']
w13 = parameters['w13']
w12 = parameters['w12']
w14 = parameters['w14']
w23 = parameters['w23']
w24 = parameters['w24']
A1 = cache['A1']
A2 = cache['A2']
dZ1 = A1 - Y
d10 = -1 * sum(dZ1, axis=1, keepdims=True) / m
d13 = dot(dZ1, X.T[0].T) / m
d12 = dot(dZ1, A2.T) / m
d14 = dot(dZ1, X.T[1].T) / m
dZ2 = w12 * dZ1 * (1 - power(A2, 2))
d23 = dot(dZ2, X.T[0].T) / m
d24 = dot(dZ2, X.T[1].T) / m
d20 = -1 * sum(dZ2, axis=1, keepdims=True) / m
grads = {'d10':d10, 'd20':d20,
'd13':d13, 'd12':d12, 'd14':d14,
'd23':d23, 'd24':d24}
return grads
#------------------------------------------------------------
# Update the parameters
def update_parameters(parameters, grads, learning_rate):
w10 = parameters['w10']
w20 = parameters['w20']
w13 = parameters['w13']
w12 = parameters['w12']
w14 = parameters['w14']
w23 = parameters['w23']
w24 = parameters['w24']
d10 = grads['d10']
d20 = grads['d20']
d13 = grads['d13']
d12 = grads['d12']
d14 = grads['d14']
d23 = grads['d23']
d24 = grads['d24']
w10 = w10 - learning_rate * d10
w20 = w20 - learning_rate * d20
w13 = w13 - learning_rate * d13
w12 = w12 - learning_rate * d12
w14 = w14 - learning_rate * d14
w23 = w23 - learning_rate * d23
w24 = w24 - learning_rate * d24
parameters = {'w10':w10, 'w20':w20,
'w13':w13, 'w12':w12, 'w14':w14,
'w23':w23, 'w24':w24}
return parameters
#------------------------------------------------------------
# Define the training
def train(X, Y, num_iterations, learning_rate, print_cost=False):
# random.seed(3)
lr = learning_rate
parameters = initialize_parameters()
XX,YY = X, Y #shuffledata(X, Y)
costdim = []
for i in range(0, num_iterations):
A2, cache = forward_propagate(XX, parameters)
cost = calculate_cost(A2, YY, parameters)
grads = backward_propagate(parameters, cache, XX, YY)
parameters = update_parameters(parameters, grads, lr)
if print_cost and i % 50 == 0:
printf('Cost after iteration:%i: %f'%(i, cost))
costdim.append(cost[0][0])
if cost < 0.01:
break
# XX, YY = shuffledata(X, Y)
return parameters, costdim
#------------------------------------------------------------
parameter,costdim = train(xor_x0, xor_y0, 1000, 0.5, True)
A2, cache = forward_propagate(xor_x0, parameter)
printf(A2, xor_y)
plt.plot(arange(len(costdim))*50, costdim)
plt.xlabel("Step(10)")
plt.ylabel("Cost")
plt.grid(True)
plt.tight_layout()
plt.show()
#------------------------------------------------------------
# END OF FILE : HWXOR1.PY
#============================================================