今天完成神经网络的bp算法
其实从上周就开始看别人博客怎么实现,然后手动实现一下,自己动手确实可以加深印象
记录一下:
import math
import random
import numpy
def getDeviation(errOut, corOut):
x = 0
for i in range(len(errOut)):
x += (errOut[i] - corOut[i]) ** 2
return x / 2
class backpropagation:
def __init__(self, hideLen, studyRate):
inLen = len(inputs[0])
outLen = len(outputs[0])
# self.inToHide = numpy.ndarray((inLen, hideLen))
self.inToHide = numpy.zeros((inLen, hideLen))
# self.hideToOut = numpy.ndarray((hideLen, outLen))
self.hideToOut = numpy.zeros((hideLen, outLen))
self.b = numpy.zeros(hideLen)
for j in range(hideLen):
for i in range(inLen):
self.inToHide[i][j] = random.random()
for i in range(outLen):
self.hideToOut[j][i] = random.random() * 10
for y in range(100):
for i in range(len(outputs)):
for x in range(10):
tempHide = neural(inputs[i], self.inToHide, self.b)
tempOut = matrixMultiply([tempHide], self.hideToOut)[0]
bp(inputs[i], self.inToHide, tempHide, self.hideToOut, tempOut, outputs[i], studyRate, self.b)
tempHide = neural(inputs[i], self.inToHide, self.b)
tempOut = matrixMultiply([tempHide], self.hideToOut)[0]
print(tempOut)
print("-----------------------------")
print(self.inToHide)
print(self.hideToOut)
print(self.b)
print("-----------------------------")
def test(self, inp):
outs = numpy.ndarray((len(inp), len(inp[0])))
for i in range(len(inp)):
tempHide = neural(inp[i], self.inToHide, self.b)
outs[i] = matrixMultiply([tempHide], self.hideToOut)[0]
return outs
def neural(inp, inToHide, inherent):
tempHide = matrixMultiply([inp], inToHide)[0]
for i in range(len(inherent)):
tempHide[i] += inherent[i]
# 神经元固有值,也可以优化,暂时不动
sigmoid(tempHide)
return tempHide
def bp(inp, inToHide, hide, hideToOut, errOut, corOut, studyRate, b):
deviation = getDeviation(errOut, corOut)
if deviation < 0.00001:
return deviation
# print(deviation)
d_deviation_o = numpy.zeros(len(corOut))
for i in range(len(corOut)):
d_deviation_o[i] = errOut[i] - corOut[i]
d_ho_h = numpy.zeros(len(hide))
for i in range(len(hide)):
d_ho_h[i] = hide[i] * (1 - hide[i])
d_deviation_h = numpy.zeros(len(hide))
for i in range(len(hide)):
for j in range(len(corOut)):
d_deviation_h[i] += d_deviation_o[j] * hideToOut[i][j] * d_ho_h[j]
# 先修正inToHide
for i in range(len(inp)):
for j in range(len(hide)):
inToHide[i][j] -= d_deviation_h[j] * inp[i] * studyRate
b[j] -= d_deviation_h[j] * inp[i] * studyRate
# 再修正hideToOut
for i in range(len(hide)):
for j in range(len(corOut)):
hideToOut[i][j] -= d_deviation_o[j] * hide[i] * studyRate
return deviation
def matrixMultiply(leftMatrix, rightMatrix):
lXLen = len(leftMatrix)
lYlen = len(leftMatrix[0])
rXLen = len(rightMatrix)
rYLen = len(rightMatrix[0])
if lYlen != rXLen:
return None
outMatrix = numpy.zeros((lXLen, rYLen))
for i in range(lXLen):
for j in range(rYLen):
for k in range(lYlen):
outMatrix[i][j] += leftMatrix[i][k] * rightMatrix[k][j]
return outMatrix
def sigmoid(arr):
for i in range(len(arr)):
arr[i] = 1 / (1 + math.e ** -arr[i])
if __name__ == '__main__':
inputs = [[0, 0], [0, 1], [1, 0], [1, 1]]
outputs = [[0, 0], [0, 1], [0, 4], [0, 9]]
shit = backpropagation(4, 0.3)
print(shit.test([[1, 2]]))
'''
正向计算:
h1 = i1*a11 + i2*a21 + 0.5
ho1 = sigmoid(h1)
o1 = ho1 * b11 + ho2 * b21
o2 = ho1 * b12 + ho2 * b22
deviation = 1/2(O1 - o1)^2 + 1/2(O2 - o2)^2
计算偏导数,用于更新权值和固定值:
$(a, b)表示a对b的偏导数
$(deviation, o1) = (O1 - o1) * -1 = o1 - O1
$(deviation, o2) = (O2 - o2) * -1 = o2 - O2
$(o1, b11) = ho1
$(deviation, b11) = $(deviation, o1) * $(o1, b11) = (o1 - O1) * ho1
$(deviation, b12) = (o2 - O2) * ho1
$(deviation, b21) = (o1 - O1) * ho2
$(deviation, b22) = (o2 - O2) * ho2
$(o1, ho1) = b11
$(o2, ho1) = b12
$(deviation, ho1) = $(deviation, o1) * $(o1, ho1) + $(deviation, o2) * $(o2, ho1) = (o1 - O1) * b11 + (o2 - O2) * b12
$(deviation, ho2) = $(deviation, o1) * $(o1, ho2) + $(deviation, o2) * $(o2, ho2) = (o1 - O1) * b21 + (o2 - O2) * b22
$(ho1, h1) = ho1 - ho1^2
$(ho2, h2) = ho2 - ho2^2
$(deviation, h1) = [(o1 - O1) * b11 + (o2 - O2) * b12] * (ho1 - ho1^2)
$(deviation, h2) = [(o1 - O1) * b21 + (o2 - O2) * b22] * (ho2 - ho2^2)
更新w:
$(h1, a11) = i1
$(deviation, a11) = $(deviation, h1) * $(h1, a11) = [(o1 - O1) * b11 + (o2 - O2) * b12] * (ho1 - ho1^2) * i1
$(deviation, a21) = [(o1 - O1) * b11 + (o2 - O2) * b12] * (ho1 - ho1^2) * i2
$(deviation, a12) = [(o1 - O1) * b21 + (o2 - O2) * b22] * (ho2 - ho2^2) * i1
$(deviation, a22) = [(o1 - O1) * b21 + (o2 - O2) * b22] * (ho2 - ho2^2) * i2
更新b:
$(deviation, b1) = $(deviation, h) * $(h, b1) = $(deviation, h1)
'''
贴结果
[6.32587583e-07 6.33213280e-04]
[-0.00268672 1.00111571]
[3.99775448e-03 4.00182551e+00]
[-7.02548284e-04 8.99848403e+00]
[[-6.94880581 0.67494424 23.90272794 2.64975556]
[-0.34046229 -0.27877047 -0.04787937 -0.74671243]]
[[ 0.77230955 -5.19829496]
[-4.1884299 0.42527155]
[ 2.16351037 6.70760107]
[ 1.25660785 2.06724707]]
[-8.75129545 -1.08167547 22.65811574 0.99926829]
[[2.13356514 8.67763353]]
个人观点
效果不是很理想,需要进一步优化,调参数,一个是中间节点数,一个是学习速度,一个是循环次数
但是很开心,因为一种新的编程方法诞生,不用写if else,直接以矩阵运算作为程序
这对于无法用if else写的程序来说是必须的方法,比如图像识别,你无法构造if else的条件
c语言一类的程序的if else是可以转化为矩阵运算的,但是反过来很难
例子
if (x > 1)
return 22 * x
else
return 88
上面的if else可以用激活函数代替
有没有人能设计出这个矩阵和激活函数