Backpropagation is a method used in artificial neural networks to calculate a gradient that is needed in the calculation of the weights to be used in the network. It is commonly used to train deep neural networks, a term referring to neural networks with more than one hidden layer.
import math
import random
import string
import matplotlib.pyplot as plt
import numpy as np
random.seed(0)
rand(a, b)保证随机数在[a,b]范围内
def rand(a, b):
return (b-a)*random.random() + a
print(rand(6, 10))
9.377687406100193
生成I*J的矩阵。
def makeMatrix(I, J, fill=0.0):
m = []
for i in range(I):
m.append([fill]*J)
return m
m=makeMatrix(3, 5, 4.87)
print(m)
[[4.87, 4.87, 4.87, 4.87, 4.87], [4.87, 4.87, 4.87, 4.87, 4.87], [4.87, 4.87, 4.87, 4.87, 4.87]]
定义激活函数
def sigmoid(x):
return math.tanh(x)
def dsigmoid(y):
return 1.0 - y**2
画出来瞧瞧
numpy.arange() 参数的含义:起点,终点,间隔。
numpy.linspace():起点,终点,以及点个数。
Xaxis = np.arange(-10., 10., 0.2)
Yaxis = []
Zaxis = []
for i in Xaxis:
Yaxis.append(sigmoid(i))
Zaxis.append(dsigmoid(i))
plt.plot(Xaxis, Yaxis)
[]
plt.plot(Xaxis, Zaxis)
[]
一开始的神经网络权重为随机数
class neuralNetwork:
"""三层BP网络"""
def __init__(self, ni, nh, no):
# 输入层 隐藏层 输出层
self.ni = ni + 1
self.nh = nh
self.no = no
# 激活神经网络的所有节点(向量)
self.ai = [1.0]*self.ni
self.ah = [1.0]*self.nh
self.ao = [1.0]*self.no
# 权重矩阵
self.wi = makeMatrix(self.ni, self.nh)
self.wo = makeMatrix(self.nh, self.no)
# 设置随机值
for i in range(self.ni):
for j in range(self.nh):
self.wi[i][j] = rand(-0.2, 0.2)
for j in range(self.nh):
for k in range(self.no):
self.wo[j][k] = rand(-2.0, 2.0)
# 最后建立动量因子(矩阵)
self.ci = makeMatrix(self.ni, self.nh)
self.co = makeMatrix(self.nh, self.no)
def weights(self):
print('输入层权重:')
for i in range(self.ni):
print(self.wi[i])
print()
print('输出层权重:')
for j in range(self.nh):
print(self.wo[j])
def nodes(self):
print('各层')
print(self.ai)
print(self.ah)
print(self.ao)
n = neuralNetwork(2, 2, 1)
n.weights()
输入层权重:
[0.10318176117612099, -0.031771367667662004]
[-0.09643329988281467, 0.004509888547443414]
[-0.03802634501983429, 0.11351943561390904]
输出层权重:
[-0.7867490956842902]
[-0.09361218339057675]
有输入数据进行训练可以得到不一样的权重
def update(self, inputs):
if len(inputs) != self.ni - 1:
raise ValueError('与输入层节点数不符!')
# 激活输入层
for i in range(self.ni-1):
self.ai[i] = inputs[i]
# 激活隐藏层
for j in range(self.nh):
sum = 0.0
for i in range(self.ni):
sum = sum + self.ai[i] * self.wi[i][j]
self.ah[j] = sigmoid(sum)
# 激活输出层
for k in range(self.no):
sum = 0.0
for j in range(self.nh):
sum = sum + self.ah[j] * self.wo[j][k]
self.ao[k] = sigmoid(sum)
return self.ao[:]
neuralNetwork.update = update
data = [
[0, 0],
[0, 1],
[1, 0],
[1, 1]
]
for x in data:
print("===============================")
print("输入", x)
n.update(x)
n.nodes()
===============================
输入 [0, 0]
各层
[0, 0, 1.0]
[-0.03800802687973925, 0.11303430725900135]
[0.01931898850514613]
===============================
输入 [0, 1]
各层
[0, 1, 1.0]
[-0.13365514595070935, 0.11748427542797922]
[0.09387785467461307]
===============================
输入 [1, 0]
各层
[1, 0, 1.0]
[0.0650633725803233, 0.08156645286443749]
[-0.05875640766224714]
===============================
输入 [1, 1]
各层
[1, 1, 1.0]
[-0.031267687935803194, 0.08604465904035687]
[0.01654348731222915]
从上面的结果发现输出层的结果是很随机的。因此,需要结合训练数据的标签信息,计算真实的标签与输出层的误差,再反向传播回来改变权重。
dsigmoid(x)=1−x2 d s i g m o i d ( x ) = 1 − x 2
true label:y train result:r t r u e l a b e l : y t r a i n r e s u l t : r
e1=y−r e 1 = y − r
output_deltas=dsigmoid(r)∗e1=(1−r2)∗(y−r) o u t p u t _ d e l t a s = d s i g m o i d ( r ) ∗ e 1 = ( 1 − r 2 ) ∗ ( y − r )
e2=e1+output_deltas(k)∗wo(j,k) e 2 = e 1 + o u t p u t _ d e l t a s ( k ) ∗ w o ( j , k )
hidden_deltas[j]=dsigmoid(ah[j])∗e2 h i d d e n _ d e l t a s [ j ] = d s i g m o i d ( a h [ j ] ) ∗ e 2
动量可以存下上一次的change量,相当于一个余量。
def backPropagate(self,targets, N, M):
"""反向传播"""
if len(targets) != self.no:
raise ValueError('与输出节点个数不符!')
# 计算输出层的误差
output_deltas = [0.0] * self.no
for k in range(self.no):
error = targets[k] - self.ao[k]
output_deltas[k] = dsigmoid(self.ao[k]) * error
# 计算隐藏层的误差
hidden_deltas = [0.0] * self.nh
for j in range(self.nh):
error = 0.0
for k in range(self.no):
error = error + output_deltas[k] * self.wo[j][k]
hidden_deltas[j] = dsigmoid(self.ah[j]) * error
# 更新输出层权重
for j in range(self.nh):
for k in range(self.no):
change = output_deltas[k] * self.ah[j]
self.wo[j][k] = self.wo[j][k] + N*change + M*self.co[j][k]
self.co[j][k] = change
# 更新输入层权重
for i in range(self.ni):
for j in range(self.nh):
change = hidden_deltas[j] * self.ai[i]
self.wi[i][j] = self.wi[i][j] + N*change + M*self.ci[i][j]
self.ci[i][j] = change
# 计算误差
error = 0.0
for k in range(len(targets)):
error = error + 0.5*(targets[k]-self.ao[k])**2
return error
neuralNetwork.backPropagate = backPropagate
def train(self, patterns, epoch=10000, N=0.5, M=0.1):
# N:学习速率(learnning rate)
# M:动量因子(momentum factor)
for i in range(epoch):
error = 0.0
for p in patterns:
inputs = p[0]
targets = p[1]
self.update(inputs)
error = error + self.backPropagate(targets, N, M)
if i % 100 == 0:
print('误差 %-.5f' % error)
neuralNetwork.train = train
pat = [
[[0, 0], [0]],
[[0, 1], [1]],
[[1, 0], [1]],
[[1, 1], [0]]
]
n.train(pat)
误差 0.95942
误差 0.10487
误差 0.00415
误差 0.00179
误差 0.00112
误差 0.00082
误差 0.00064
误差 0.00355
误差 0.00046
误差 0.00039
误差 0.00034
误差 0.00031
误差 0.00085
误差 0.00027
误差 0.00024
误差 0.00022
误差 0.00049
误差 0.00022
误差 0.00018
误差 0.00017
误差 0.00018
误差 0.00075
误差 0.00017
误差 0.00014
误差 0.00013
误差 0.00018
误差 0.00047
误差 0.00014
误差 0.00012
误差 0.00012
误差 0.00013
误差 0.00020
误差 0.00023
误差 0.00010
误差 0.00011
误差 0.00009
误差 0.00012
误差 0.00011
误差 0.00017
误差 0.00009
误差 0.00009
误差 0.00007
误差 0.00010
误差 0.00022
误差 0.00009
误差 0.00008
误差 0.00008
误差 0.00007
误差 0.00009
误差 0.00011
误差 0.00010
误差 0.00009
误差 0.00009
误差 0.00007
误差 0.00006
误差 0.00007
误差 0.00008
误差 0.00013
误差 0.00006
误差 0.00006
误差 0.00006
误差 0.00006
误差 0.00005
误差 0.00008
误差 0.00006
误差 0.00010
误差 0.00009
误差 0.00006
误差 0.00005
误差 0.00005
误差 0.00006
误差 0.00005
误差 0.00006
误差 0.00010
误差 0.00007
误差 0.00005
误差 0.00004
误差 0.00004
误差 0.00005
误差 0.00005
误差 0.00004
误差 0.00006
误差 0.00008
误差 0.00007
误差 0.00005
误差 0.00004
误差 0.00004
误差 0.00004
误差 0.00005
误差 0.00006
误差 0.00005
误差 0.00004
误差 0.00004
误差 0.00004
误差 0.00004
误差 0.00004
误差 0.00004
误差 0.00004
误差 0.00004
误差 0.00004
def test(self, patterns):
for p in patterns:
print(p[0], '->', self.update(p[0]), 'true:', p[1])
neuralNetwork.test = test
n.test(pat)
[0, 0] -> [0.006383746849952502] true: [0]
[0, 1] -> [0.9947419206676759] true: [1]
[1, 0] -> [0.9947366857476139] true: [1]
[1, 1] -> [-0.004080859257171113] true: [0]