神经网络是一个神经系统
计算机的神经网络是模仿大脑神经网络来的,但又有不同,大脑神经网络在收到外界刺激后,会将一些神经元相互连接起来,那么下一次在遇到相同刺激就可以根据上次经验做出相应行为,但计算机神经网络上,神经元一开始就已经连接好了,不能重新连接,在收到刺激后,通过调整每个神经元里的参数(或理解为权重)来记录此次行为(训练神经网络时会将刺激对应的行为也告诉神经网络),如下,小时候家长要给你喂糖吃时,你伸手他们就会给你糖。那么在计算机中,会给神经网络“想吃糖”“伸手”的信号,通过神经网络改变某些神经元的参数,使两者形成对应关系,计算机神经网络中,会先从“想吃糖”向“伸手”进行传递,之后从“伸手”向“想吃糖”进行反向传递,进行确认是否连接正确,正确则加强,不正确则调整优化。
例如,给你看一张照片,并告诉你这是猫,多看几种猫咪照片后,那么下一次再遇到“猫”照片时,你就知道这是猫咪了,计算机是同样的道理,给神经网络输入“猫”照片,给告诉他这是猫,再多次学习“猫”照片之后,他也能快速认识一张照片里是否有猫!
假如现在给你了如下数据,让你判断第五次小强去不去看电影?(1代表去)
我们可以很容易看出小强和如花有某种联系,可以大概判断第五次小强会去!
但下几次渣男变心了,这时再判断小强去不去就没那么明显了。
那么如何让计算机去判断小强去不去呢?
从上可以看出,如花,小倩,小明的决定都会对小强的行为有影响,可以理解为他们三人对小强作出决定的影响有一定权重,假如分别为w1,w2,w3,那么他小强去不去可以用公式z=如花 * w1 + 小倩 * w2 + 小明 * w3表达,如下:
下面是确定三个参数时,计算机的大致流程!
我们常说的模型,本质上就是数学公式,里面有很多未知的参数,而机器学习的目标就是通过大量数据不断试错来确定这些参数!
在学习代码之前,还需要预备两个基础知识:
1.sigmoid函数
2.梯度下降基本原理
首先是sigmoid函数,下面是函数公式以及图像
简而言之,他可以将一个数约束在【0,1】的范围,比如在上述的数据中,算出来的Z可能不属于【0,1】,与去(1)和不去(0)没有联系,因此,采用sigmoid函数可以使数据分布在【0,1】,进而可以预测是0还是1(可以理解为“去”的概率)
接下来是梯度下降,梯度下降涉及内容很广,这里只是就基本原理做简单讲解!
我们在计算出loss值后,就需要根据这个值对模型参数进行调整,假如此时在w1点,通过计算得到在w1处的斜率为dw,从图中可以看出,w得往斜率降低的地方移动,才能使loss逐渐减少,即往-dw方向移动,每次移动的步长设为λ(λ是一个步长,可以自己设定,后续优化模型时调整,也可以根据误差loss来确定,代表w从w1往-dw方向移动的距离,但不是直接移动,而是受斜率dw影响,因为斜率越大,代表此时函数越陡峭,误差也就越大,那么w就可以多移动一点,反之亦然),如此反复过后,loss值就会逐渐减小!
from numpy import random, dot, exp, array
# x是每次其他3个人的决定,y是小强的决定
X = array([[0, 0, 1], [1, 1, 1], [1, 0, 1], [0, 1, 1]])
y = array([[0, 1, 1, 0]]).T
# 设置随机权重
random.seed(1)
weights = random.random((3, 1)) * 2 - 1
for it in range(10000):
# 利用矩阵点乘一次性计算4个z出来
z = dot(X, weights)
# 使用Sigmoid函数,计算最终的output
output = 1 / (1 + exp(-z))
# 看看我们计算出来的和实际发生的有多大误差
error = y - output
# 计算斜率
slope = output * (1 - output)
# 计算增量
delta = error * slope
# 更新权重,针对每一个系数,要更新的值就是:每个样 和。
# print(weights)
weights = weights + dot(X.T, delta)
循环中,前面就是计算估计值,误差值,以及计算斜率,之后是计算误差受斜率的影响值,因为误差是一个数值,不能直接用于参数修改,还得考虑斜率,斜率越大,代表此时误差还很大,参数可以多修改一点,反之亦然。
delta是四行一列的矩阵,代表这四次训练中的误差,dot(X.T, delta)分解开就是每一个人的行为与误差的乘积,可以理解为这个人的行为对此次误差的贡献。
上面的代码是网上一位大佬写的,后面修改参数的梯度下降过程暂时不能完全理解,这里附上原作者的代码详解点击此处
下面是我根据前面对梯度下降的理解,自己写了一段代码,如有错误或建议,望指正!
for q in range(10000):
for i in range(4):
# 利用矩阵点乘一次性计算4个z出来
z = dot(X[i], weights)
# 使用Sigmoid函数,计算最终的output
output = 1 / (1 + exp(-z))
# 看看我们计算出来的和实际发生的有多大误差
error = output - y[i]
loss = error ** 2
# 计算斜率
dw1 = 2 * error * (output * (1 - output)) * X[i,0]
dw2 = 2 * error * (output * (1 - output)) * X[i,1]
dw3 = 2 * error * (output * (1 - output)) * X[i,2]
# 计算增量
weights[0] += (-abs(error) * dw1)
weights[1] += (-abs(error) * dw2)
weights[2] += (-abs(error) * dw3)
首先,我采用的是利用4次决定循环训练模型,到计算误差的前面都一样,从计算误差开始有改变:
loss最终的目标是趋于0最佳,因此我用error的平方表示,这里有三个参数z(w1 , w2 , w3 ),因此分别对三个参数求导dw1,dw2,dw3,之后根据公式wt = w1 + (-λ * dw)修改参数,其中,λ我不采用固定数值,而是采用误差值,这样,当误差大时,他移动的步长就大,反之则小。
下面是两段代码的运算结果:
基本可以看出,小强的决定主要受第一个人影响!