0x00 感知器
感知器这个玩意其实蛮有意思,他能用来学习实现其他函数。一个感知器有3个部分组成:
输入权值和偏置项:学过机器学习的你一看可能就知道,这就是那个w和b。一个感知器可以接收多个输入,每个输入上都有一个权值
激活函数:比如机器学习中常用的sigmoid函数,一般记作f
输出
感知器的输出可以使用一个通用的函数来计算,如下:
y = f ( w x + b ) y=f(wx+b)
y = f ( w x + b )
看到这儿不要慌,下面我们通过一个简单的例子来简述感知器的训练过程。
0x01 感知器的训练
感知器的训练过程,其实就是设法通过不断地调整w和b的值,以求拟合我们输入和输出的数据。而调整的方式也很简单,如下:
w i ← w i + Δ w i b ← b + Δ b \begin{align*}
w_i&\gets w_i+\Delta w_i \\
b&\gets b+\Delta b
\end{align*}
w i b ← w i + Δ w i ← b + Δ b
其中:
Δ w i = η ( t − y ) x i Δ b = η ( t − y ) \begin{align*}
\Delta w_i&=\eta(t-y)x_i \\
\Delta b&=\eta(t-y)
\end{align*}
Δ w i Δ b = η ( t − y ) x i = η ( t − y )
上式中η \eta η 即为学习率,t即为true表示实际值,y即为预测值。
现在我们假设激活函数f为如下这个跃迁函数:
f ( z ) = { 1 z > 0 0 otherwise f(z)=\begin{equation}\begin{cases}1\qquad z>0\\ 0\qquad \text{otherwise}\end{cases}\end{equation}
f ( z ) = { 1 z > 0 0 otherwise
此后我们使用η = 0.2 \eta=0.2 η = 0.2 的学习率来训练一个感知器,以实现AND(与)运算的功能。我们以如下矩阵的形式来表示运算x 1 AND x 2 x_1 \text{ AND } x_2 x 1 AND x 2 的输入值:
x 1 AND x 2 → [ x 1 x 2 ] x_1 \text{ AND } x_2\rightarrow
\left[
\begin{matrix}
x_1 \\
x_2
\end{matrix}
\right]
x 1 AND x 2 → [ x 1 x 2 ]
首先我们假设初始值矩阵w和b如下:
W = [ 0 0 ] , b = 0 W=\left[
\begin{matrix}
0&0
\end{matrix}
\right],
b=0
W = [ 0 0 ] , b = 0
则当输入值为1 AND 1时有:
z = W x + b = [ 0 0 ] [ 1 1 ] + 0 = 0 y = f ( z ) = f ( 0 ) = 0 z=Wx+b=\left[
\begin{matrix}
0&0
\end{matrix}
\right]\left[
\begin{matrix}
1 \\
1
\end{matrix}
\right]+0=0\\
y=f(z)=f(0)=0
z = W x + b = [ 0 0 ] [ 1 1 ] + 0 = 0 y = f ( z ) = f ( 0 ) = 0
此时我们来计算变化后的W和b,众所周知1 AND 1=1,则有:
Δ w 1 = 0.2 × ( 1 − 0 ) × 1 = 0.2 Δ w 2 = 0.2 × ( 1 − 0 ) × 1 = 0.2 Δ b = 0.2 × ( 1 − 0 ) = 0.2 \Delta w_1=0.2\times (1-0)\times 1=0.2\\
\Delta w_2=0.2\times (1-0)\times 1=0.2\\
\Delta b=0.2\times (1-0)=0.2
Δ w 1 = 0.2 × ( 1 − 0 ) × 1 = 0.2 Δ w 2 = 0.2 × ( 1 − 0 ) × 1 = 0.2 Δ b = 0.2 × ( 1 − 0 ) = 0.2
由此,即可得出变化后的W和b分别为:
W = [ 0.2 0.2 ] , b = 0.2 W=\left[
\begin{matrix}
0.2&0.2
\end{matrix}
\right],
b=0.2
W = [ 0.2 0.2 ] , b = 0.2
此时对于输入1 AND 1,重新计算感知器的输出,我们会发现感知器已经可以输出正确的结果了。由此,我们继续训练我们的感知器,当输入值为0 AND 1时,依据新的W和b重新计算感知器的输出,有:
z = W x + b = [ 0.2 0.2 ] [ 0 1 ] + 0.2 = 0.4 y = f ( z ) = f ( 0.4 ) = 1 z=Wx+b=\left[
\begin{matrix}
0.2&0.2
\end{matrix}
\right]\left[
\begin{matrix}
0 \\
1
\end{matrix}
\right]+0.2=0.4\\
y=f(z)=f(0.4)=1
z = W x + b = [ 0.2 0.2 ] [ 0 1 ] + 0.2 = 0.4 y = f ( z ) = f ( 0.4 ) = 1
此时其返回了错误的结果,我们再来计算w和b的变化量,然后进行更新,则有:
Δ w 1 = 0.2 × ( 0 − 1 ) × 0 = 0 Δ w 2 = 0.2 × ( 0 − 1 ) × 1 = − 0.2 Δ b = 0.2 × ( 0 − 1 ) = − 0.2 \Delta w_1=0.2\times (0-1)\times 0=0\\
\Delta w_2=0.2\times (0-1)\times 1=-0.2\\
\Delta b=0.2\times (0-1)=-0.2
Δ w 1 = 0.2 × ( 0 − 1 ) × 0 = 0 Δ w 2 = 0.2 × ( 0 − 1 ) × 1 = − 0.2 Δ b = 0.2 × ( 0 − 1 ) = − 0.2
使用上面的变化量再对W和b进行更新可有:
W = [ 0.2 0 ] , b = 0 W=\left[
\begin{matrix}
0.2&0
\end{matrix}
\right],
b=0
W = [ 0.2 0 ] , b = 0
此时我们发现这组W和b已经可以完全适应输入1 AND 1和0 AND 1的情况了,我们再引入下一组训练数据1 AND 0,重新计算上述流程,并对W和b进行更新,在此我们不再写出相关计算步骤,而是直接给出更新后的W和b即为:
W = [ 0 0 ] , b = − 0.2 W=\left[
\begin{matrix}
0&0
\end{matrix}
\right],
b=-0.2
W = [ 0 0 ] , b = − 0.2
这组W和b适应了输入1 AND 0和0 AND 1的情况,却遗忘了1 AND 1的学习用例,于是我们不断地使用训练数据反复对模型进行训练,最终所得的结果如下:
W = [ 0.4 0.2 ] , b = − 0.4 W=\left[
\begin{matrix}
0.4&0.2
\end{matrix}
\right],
b=-0.4
W = [ 0.4 0.2 ] , b = − 0.4
在上述的W和b下,与运算所用的4组测试用例——1 AND 1, 0 AND 0, 0 AND 1, 1 AND 0——已经实现了完全匹配。
对于上述反复训练的过程,我们用python代码实现了出来,仅供参考:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 import numpy as npW = np.array([0 , 0 ]) b = 0 data = np.array([[0 , 0 ], [0 , 1 ], [1 , 0 ], [1 , 1 ]]) learn_rate = 0.2 def f (x ): if x > 0 : return 1 return 0 def y (x ): z = np.dot(W, x.T) + b return f(z) def all_matched (): for i in range (4 ): x = data[i] if y(x) != (x[0 ] & x[1 ]): return False , i return True , -1 def study (i ): x = data[i] error = (x[0 ] & x[1 ]) - y(x) delta_w1 = learn_rate * error * x[0 ] delta_w2 = learn_rate * error * x[1 ] delta_b = learn_rate * error global W, b W = np.array([W[0 ] + delta_w1, W[1 ] + delta_w2]) b = b + delta_b totally_matched, failed = all_matched() while not totally_matched: study(failed) totally_matched, failed = all_matched() print (W)print (b)