本文的目的是站在一个小白的角度,以一个简单的例子,让大家对神经网络有一个简单的认识。这个例子不是很严谨,但基本可以解释神经网络的工作流程,具有启发意义。
例子
假设我们现在有一条直线 y=w*x 上的1个点( x , y ),这个点的坐标是( 1,2 )。现在我们想知道当x=5的时候,y等于几。当然我知道大家都会这个小学生算术题,但是我们的计算机可没有上过小学,在不动用我们小学数学知识的情况下,如何让计算机通过学习的方式自己得出答案呢?
建模
![](https://img.haomeiwen.com/i3065733/d6292d2aaa5e7a39.jpeg)
如上图,我们将这个问题建成一个只有一个神经元的神经网络模型,其中一个 ( x , y ) 的坐标 ( 1 , 2 ) 就是我们的数据集,图中f(y)是激励函数(为了严谨所以这里加入它,不清楚可以不用管它),这里我们令f(y)=y就好了。我们假设初始状态令w=0,横坐标x就是这个神经元的输入,经过神经元之后我们会得到一个输出y_out,y 与 y_out 的差就是神经网络学到的与真实值之间的误差: loss=y - y_out。因为在这个例子里输出就是此时的权值w与x相乘的结果,如果loss大于0,很显然就是现在的w比真实系数小了,我们应该更新w,让w大一点。当我们更新完w之后再将数据x输入,再计算差值loss然后重复上述步骤,从而更新w,直至差值loss缩小到0或者我们可以接受的程度,这时我们就得到了想要的结果。
这里涉及一个问题,如何更新权值?这也是构建神经网络反向传播很重要的一步,很显然,我们应该根据得到的误差loss来更新权值,所以这里我们需要构建一个损失函数J(loss),J应当随着权值w的变化能够取得最小值(并且J的选取能够让此时的loss也最小)。所以我们的目的就是把权值w当作变量,根据J对w的导数(梯度方向)进行权值更新(因为这篇文章主要是讲神经网络的工作过程,所以损失函数具体怎么取这里不在赘述)。
代码实现
import matplotlib.pyplot as plt
import numpy as np
#准备数据集
train_x=np.array([[1]])
train_y=np.array([[2]])
#用这个列表装loss数据
LOSS=[]
#初始化权值
def initialize_with_zeros(dim):
w = np.zeros((dim, 1))
return w
#正向传播与反向传播
def propagate(w, X, Y):
#m是输入样本的个数
m=X.shape[1]
A=np.dot(X.T,w)
loss=Y-A
dw= -1 / m * np.dot(X,(Y-A))
LOSS.append(loss[0][0])
return dw
#x,y是输入的数据集,learning_rate是学习速率,num_iterations是学习的次数
def model(x, y, learning_rate, num_iterations):
w=initialize_with_zeros(x.shape[0])
for i in range(num_iterations):
dw = propagate(w, x, y)
w = w - learning_rate*dw
print(w)
model(train_x, train_y,0.03, 30)
#这里是可视化函数,将loss画出来
plt.plot(LOSS)
plt.show()
上面的代码就是前面模型的实现,得到的 loss 如图所示
![](https://img.haomeiwen.com/i3065733/21e35ac8b5b2cfd5.jpeg)
可以看到,误差loss随着迭代次数的增加而减小,这就说明我们的权值越来越接近真实值,上面的神经网络学到了东西。
上面的图是我们只有 (1 , 2) 这一个数据的时候得到的效果,接下来我们看看增加数据量的效果。
import matplotlib.pyplot as plt
import numpy as np
#准备数据集
train_x=np.array([[1,2,3,4]])
train_y=np.array([[2],[4],[6],[8]])
#用这个列表装loss数据
LOSS=[]
#初始化权值
def initialize_with_zeros(dim):
w = np.zeros((dim, 1))
return w
#正向传播与反向传播
def propagate(w, X, Y):
#m是输入样本的个数
m=X.shape[1]
A=np.dot(X.T,w)
loss=Y-A
dw= -1 / m * np.dot(X,(Y-A))
LOSS.append(loss[0][0])
return dw
#x,y是输入的数据集,learning_rate是学习速率,num_iterations是学习的次数
def model(x, y, learning_rate, num_iterations):
w=initialize_with_zeros(x.shape[0])
for i in range(num_iterations):
dw = propagate(w, x, y)
#更新权值
w = w - learning_rate*dw
print(w)
model(train_x, train_y,0.03, 100)
#这里是可视化函数,将loss画出来
plt.plot(LOSS)
plt.show()
注意,我们的模型是没有变的,只是将数据集从(1,2)这一个点变成了(1,2)(2,4)(3,6)(4,8)这四个点。然后我们来看一看效果。
![](https://img.haomeiwen.com/i3065733/81cf59d2765ced0c.jpeg)
可以看到,相比于只有一个点的情况,我们的收敛速度明显快了很多,在迭代了20次左右的时候就基本达到了较小的误差,所以有效的数据量对于神经网络是很重要的。
到现在,我们的逻辑已经很清晰了。神经网络的基本步骤有:
- 准备数据集
- 建模
- 参数初始化
- 数据输入
- 正向传播
- 计算损失函数/成本函数(多样本输入)
- 反向传播,更新权值
- 迭代
这个例子虽然比较浅显,但是也都具备了神经网络的基本框架,我们可以试想一下,这里我们输入的x,维度是1,那么如果我们要学习的是图片呢?比如一张32*32的图片就有1024那么大。。。。。。
注:
- 正常神经网络中是需要激活函数的,这里就简单令f(y)=y了
- 神经网络的一次迭代可以输入很多个样本的,代码中的运算用到简单的矩阵运算知识
- 神经网络中常用梯度下降法更新权值,梯度是根据成本函数对相应权值求导得来的(成本函数就是多个样本的损失函数取平均),代码中的损失函数为 J=(loss)^2,根据链式法则,对w的导数为-2loss*x,将常数舍去(因为他不影响结果),就是我们看到的
dw=1 / m * np.dot(X,(Y-A))
网友评论