脸部的特征、单词的联想、声音的语调等这些都是相关的变量,我们可以用一个函数来表示这个关系。对于不同的函数我们有不同的近似模型,对我们自身能力建模可以吗?用神经网络,受人类大脑的启发,是万能函数的逼近器,这意味着可以学习任何函数。1989年证实了,任意决策区域可以通过仅仅只有内部单隐层和任意连续S形非线性特征的连续前馈神经网络来良好的近似。
让我们来建立一个简单的人工神经网络:
from numpy import *
# input data
input_data = array([[0,0,1],[1,1,1],[1,0,1],[0,1,1]]) # 给一些输入数据x
output_labels = array([[0,1,1,0]]).T # 一些相关的输出标签y
print(input_data)
print(output_labels)
存在一个函数表示x和y之间的映射,y=f(x),我们的目标是学习这个函数,这样就可以随机输入一些x值,预测对应的y值。函数可以通过神经网络即万能函数的逼近器来学习得到近似的结果。代码中x是由一个矩阵表示,每行是不同的数据点,每一列是不同的特征,随机取为0和1,y是由一个列向量表示,如下图:
如何学习这个函数,假设有个矩阵,使得input*matrix=output,该矩阵就是我们试图学习的函数的系数,称之为权值。
# weight matrix
synaptic_weghts = 2 * random.random((3,1))-1
print(synaptic_weghts)
print (activate(np.dot(input_data,synaptic_weghts))) # 预测值,输出输入数据与矩阵点积,即结果传递给Sigmoid函数,归一化为0-1之间的概率值
先随机初始化一个矩阵,结果为 [[-0.42594462] [-0.79605263] [ 0.21454577]],最后,我们希望这个矩阵具有理想值。计算预测值与真正输出的y之间的差异。
训练过程:
# training
for iteration in range(1000):
output = activate(np.dot(input_data,synaptic_weghts)) # 预测值
error = output_labels - output # 差异
print(error)
synaptic_weghts += np.dot(input_data.T,error * activate(output,True))
# testing
print(activate(np.dot(array([1,0,0]),synaptic_weghts))) # 输出[0.99929763]
我们知道梯度下降可以现实线性回归计算误差对权重的偏导数,就得到了一个梯度值。梯度下降算法就是寻找一个误差最小值。因此,我们增加梯度值来调整矩阵中的值,多次迭代训练,随着迭代误差将减少,最终我们的网络能够预测正确的输出标签。
神经网络可以视为是个大复合函数,由其他函数嵌套而成,每层都是一个这样的函数,把前一级函数的输出作为输入。
假如我们有一个数据集,输入和输出不是一对一关系,这样我们简单的AF神经网络就无法学习了。这样我们就需要把输入数据组合成一种新的表示,让其与输出具有一对一的关系,为此我们需要添加中间层。
如图,我们将第一层作为组合输入,第二层将使用第一层的输出作为输入,再将其映射到输出。所以我们用第一个权值矩阵乘以输入,然后用sigmoid函数作为激活函数将其激活,得到结果layer1并将其传递给下一层作为输入。
def activate(x,deriv=False):
if(deriv==True):
return x*(1-x)
return 1/(1+np.exp(-x))
# 2 weight value
synaptic_weight_0 = 2 * np.random.random((3,4))-1
synaptic_weight_1 = 2 * np.random.random((4,1))-1
print(synaptic_weight_0)
print(synaptic_weight_1)
# training
for iteration in range(60000):
# forward propagate through layers0,1,2
layer0 = input_data
layer1 = activate(np.dot(layer0,synaptic_weight_0)) # 所以我们用第一个权值矩阵乘以输入
layer2 = activate(np.dot(layer1,synaptic_weight_1))
#calculate erro for layer 2
layer2_erro = output_labels - layer2
if (iteration % 10000) == 0
print(str(np.mean(np.abs(layer2_erro))))
# use it to compute the gradient
layer2_gradient = 12_erro*activate(layer2,deriv=True)
# calculate erro for layer1
layer1_erro = layer2_gradient.dot(synaptic_weight_1.T)
# use it to compute its gradient
layer1_gradient = layer1_erro*activate(layer1,deriv=True)
# update the weights using the gradients
synaptic_weight_1 += layer1.T.dot(layer2_gradient)
synaptic_weight_0 += layer0.T.dot(layer1_gradient)
当我们计算预测值时,由于多个权值要更新,我们将递归计算反向上每一层的梯度误差 ,然后可以单独更新每个权值。我们称之为反向传播,在前向传播我们输入数据之后,我们将误差梯度反向传播更新我们的权值,这就是前馈神经网络。
循环网络是时序模型,是通过时间的反向传播。
当存在未标记的数据时,神经网络仍能够学习到函数吗?能够完成这个过程的神经网络叫做自组织神经网络,它首先对网络的权值进行随机初始化,将其看作二维神经元数组,每个神经元有一个具体的拓扑位置,并且包含与输入向量具有相同维度的权重向量连接节点之间的线仅仅代表它们相邻,并不代表之前的神经网络提到的那种联系。
接着从训练集中随机选择一个数据点,计算它与每个权值之间的欧氏距离,与之最近则是最相似,遍历其它节点来判断它们是否在它的半径范围内,并对它邻居节点的权值进行调整。反复执行该过程,是整个训练过程中一部分,对于每一个学习标签,这些节点通过自组织过程形成集群,临近的节点代表它们输入具有相似特征。我们甚至可以可视化,便于我们观察这些集群。
如果我们在上述基础上增加网络层数,输入数据量以及更多计算量时,这会被称作深度学习。 总而言之,神经网络只是一连串的矩阵运算,归根结底就是一个大的复合函数。由于在这些运算中会使用到非线性函数,比如sigmoid函数,因此它们能逼近任何线性或是非线性函数。如果数据没有标签,我们可以用自组织神经网络来学习得到带标签的集群。