原创 【零基础】浅层神经网络解析

2019-9-23 21:29 2755 24 4 分类: 机器人/ AI 文集: AI

回顾:

【零基础】AI神经元解析(含实例代码)


一、序言

  前两天写了关于单神经元的解析,这里再接再厉继续浅层神经网络的解析。浅层神经网络即是“层次较少”的神经网络,虽然层次少但其性能相对单神经元强大了不只一点。

  注:本文内容主要是对“床长”的系列教程进行总结,强烈推荐“床长”的人工智能系列教程(https://www.captainbed.net/)

二、浅层神经网络的构成

  回顾前面单神经元的构成,我们知道神经元包含4个关键函数:

  1)传播函数,由输入x、偏置w、阈值b计算出a

  2)激活函数,将a映射到0~1之间的结果y,可理解为(是、否)的概率

  3)反向传播函数,通过y、答案label计算出dw、db(用以更新w和b)

  4)损失函数,计算y与label间的误差


   直观上我们知道浅层神经网络自然是由数个神经元构成的,对于一个简单的两层神经网络其结构如下图所示:

 

  它包含了输入层(即X)、隐藏层、输出层,其中输入层不是神经元,所以说这是一个两层的神经网络。

  在实际实现时我们并不是挨个计算每一个经元的结果,最后再计算输出的结果。我们是一次计算出一层所有的神经元结果,再将每一层的结果作为输入计算下一层。而且第一层的传播函数并不与第二层传播函数分离,神经网络的传播函数包含了所有层的传播计算,反向传播函数也是包含了所有层的反向计算,所以从单神经元到神经网络代码的结构其实变化不大。

  下面我们直接上代码来解析,如果你看明白了前面单神经元的解析,那这里是非常好理解的。

  (文末附完整代码下载方式)

三、准备工作

  1)要处理的问题

  之前我们用单神经元要处理的问题是“从图片中识别出数字9”,即使使用单神经元也有93%的正确率,所以这里我们要增加问题的难度。将问题改为“从图片中识别出奇数”,代码上只需要很小的修改,将下面代码

  #将label不是9的数据全部转为0,将9转为1
  train_label = np.where(train_label==9,1,0)
  test_label = np.where(test_label==9,1,0)

  修改为:

  #找出图片中的奇数将label中13579置为1、02468置为0
  train_label = np.where((train_label%2)!=0,1,0)
  test_label = np.where((test_label%2)!=0,1,0)

  使用之前的单神经元代码执行后的结果为下图所示,可以看到预测效果大幅下降。

  2)要使用的网络结构

  首先要明确神经网络的层数,这里我们是一个简单的网络,所以只需要两层。其次是每一层神经元的个数,这里我们网络第一层设置4个神经元,第二层是输出层所以只要一个神经元。输入层跟以前一样,是784个输入(一张28x28图片的所有像素),网络结构如下图:

四、随机初始化参数

#初始化参数w和b
def initialize_parameters(input_num, hide_num, out_num):
  #input_num 输入层神经元个数
  #hide_num 隐藏层神经元个数
  #out_num 输出层神经元个数
  np.random.seed(2)
  #随机初始化第一层相关参数w、b
  W1 = np.random.rand(hide_num, input_num) * 0.01
  b1 = np.zeros(shape=(hide_num, 1))

  #随机初始化第二层相关参数w、b
  W2 = np.random.randn(out_num, hide_num) * 0.01
  b2 = np.zeros(shape=(out_num, 1))

  return W1,b1,W2,b2

   浅层神经网络与单神经元在初始化参数w、b的区别有以下几点:

  1)每一层神经元使用不同的w和b,所以有w1、w2、b1、b2,如果是三层网络则相应会有w3、b3.

  2)不同层神经元的w、b的数据形状是不一样的。比如我们输入的图片有784个像素,且第二层有4个神经元,所以第一层w的形状是(4,784)、b的形状是(4,1)。第二层神经元只有一个,来自第一层的输入只有4个参数,所以第二层w的形状是(1,4)、b的形状是(1,1)。

  3)w1和w2是随机生成的,之前单神经元结构中,w初始值为0,如果这里还使用全0的话,最终结果可能与单神经元一样,而且还乘以0.01确保初始值足够小。

五、传播函数

#向前传播函数
def forward(img, W1,b1,W2,b2):

  #第一层
  A1 = np.dot(W1, img) + b1
  Y1 = np.tanh(A1)#第一层和第二层使用不同的激活函数

  #第二层
  A2 = np.dot(W2, Y1) + b2
  Y2 = sigmoid(A2)
  return Y1,Y2

  传播函数与单神经元结构类似,不过需要注意的是,这里第一层使用的激活函数为tanh、第二层依旧使用的是sigmoid。他们的区别在于,sigmoid是将输出映射到0~1而tanh是将输出映射到-1~1。具体原因和区别以后再说(因为我也没搞清楚呢),这里只要知道有区别就行了。

 

 六、反向传播函数

#反向传播函数
def backward(img, label, W1,b1,W2,b2, Y1,Y2):
  m = img.shape[1]
  #第二层
  dZ2 = Y2 - label
  dW2 = np.dot(dZ2, Y1.T)/m
  db2 = np.sum(dZ2, axis=1, keepdims=True)/m
  #第一层
  dZ1 = np.multiply(np.dot(W2.T, dZ2), 1-np.power(Y1, 2))
  dW1 = np.dot(dZ1, img.T)/m
  db1 = np.sum(dZ1, axis=1, keepdims=True)/m

  return dW1,db1,dW2,db2

  与传播函数方向相反,这里是先计算第二层的反向传播再计算第一层的反向传播。需要注意的是,由于第一层使用的激活函数是tanh,所以其反向计算公式与第一层的公式不一样,因为使用不同激活函数其反向求导也就不一样了。

  另外np.sum中的两个参数axis=1、keepdims=True是为了确保db1的数据形式为(1,4),其中axis=1的意思是按行求和、keepdims=True的意思是保留矩阵的形状,不同参数的np.sum计算示意如下:

  np.sum(dZ1)/m                 0.0016664927232987162

  np.sum(dZ1, axis=1)/m            [0.00026393,0.00077922,0.0003274 ,0.00029595]

  np.sum(dZ1, axis=1, keepdims=True)/m   

                        [[0.00026393]
                        [0.00077922]
                        [0.0003274 ]
                        [0.00029595]]

七、梯度下降

#梯度下降 更新w、b参数
def update(W1,b1,W2,b2, dW1,db1,dW2,db2, learning_rate=1.2):
  W1 = W1 - learning_rate*dW1
  b1 = b1 - learning_rate*db1
  W2 = W2 - learning_rate*dW2
  b2 = b2 - learning_rate*db2

  return W1,b1,W2,b2

  梯度下降与单神经元的情况差不多。

八、损失函数

#损失函数
def costCal(Y2, label):
  m = label.shape[1]
  logprobs = np.multiply(np.log(Y2), label) + np.multiply((1-label), np.log(1-Y2))
  cost = -np.sum(logprobs)/m
  return cost

  损失函数与单神经元的情况也差不多,需要注意的是np.multiply就是将两个矩阵做对应元素的乘。

九、预测函数

#预测函数
def predict(W1,b1,W2,b2, img):
  Y1,Y2 = forward(img, W1,b1,W2,b2)
  predictions = np.round(Y2)#对结果四舍五入
  return predictions

  与单神经元的情况类似,预测函数其实就是做一次“向前传播”。

十、训练模型并预测

#训练模型
def model(img, label, hide_num, num_iterations = 1000, learning_rate=0.1, print_cost = False):
  np.random.seed(3)
  input_num = img.shape[0]
  out_num = label.shape[0]

  #初始化参数
  W1,b1,W2,b2 = initialize_parameters(input_num,hide_num,out_num)
  #循环若干次完成训练
  for i in range(0, num_iterations):
    #向前传播
    Y1,Y2 = forward(img, W1,b1,W2,b2)
    #计算本次成本
    cost = costCal(Y2, label)
    #反向传播,得到梯度
    dW1,db1,dW2,db2 = backward(img, label, W1,b1,W2,b2, Y1,Y2)
    #参数优化
    W1,b1,W2,b2 = update(W1,b1,W2,b2, dW1,db1,dW2,db2, learning_rate)
    # 将本次训练的成本打印出来
    if print_cost and i % 100 == 0:
    print ("在训练%i次后,成本是: %f" % (i, cost))

  return W1,b1,W2,b2

#调用训练模型

W1,b1,W2,b2 = model(train_img, train_label, 4, num_iterations=2000, learning_rate=1, print_cost=True)

#调用预测函数

predictions = predict(W1,b1,W2,b2, test_img)
print ('预测准确率是: %d' % float((np.dot(test_label, predictions.T) + np.dot(1 - test_label, 1 - predictions.T)) / float(test_label.size) * 100) + '%')

  需要注意的是这里的learning_rate=1,而单神经元时的learning_rate为0.005。

十一、总结回顾

  通过实现一个简单的二层神经网络我们发现,其实代码并没有修改很多,整体的结构也变化不大,其中最主要的变化在于第一层使用的激活函数变为tanh,由此导致反向传播的计算也有了较大的变化。

  运行后我们可以发现,预测的准确度较单神经元有了较大幅度的提升:

在训练0次后,成本是: 0.693817
在训练100次后,成本是: 0.251725
在训练200次后,成本是: 0.176756
在训练300次后,成本是: 0.110538
在训练400次后,成本是: 0.372297
在训练500次后,成本是: 0.128188
在训练600次后,成本是: 0.091792
在训练700次后,成本是: 0.075769
在训练800次后,成本是: 0.064764
在训练900次后,成本是: 0.055826
在训练1000次后,成本是: 0.132452
在训练1100次后,成本是: 0.102556
在训练1200次后,成本是: 0.131425
在训练1300次后,成本是: 0.086445
在训练1400次后,成本是: 0.178343
在训练1500次后,成本是: 0.077496
在训练1600次后,成本是: 0.093846
在训练1700次后,成本是: 0.071567
在训练1800次后,成本是: 0.070109
在训练1900次后,成本是: 0.060202
预测准确率是: 94%

  关注公众号“零基础爱学习”回复"AI5"可获得完整代码。后面我们还会继续更新“如何构建深度神经网络”,以及对目前还未明晰的问题解析。

作者: 布兰姥爷, 来源:面包板社区

链接: https://mbb.eet-china.com/blog/uid-me-3887969.html

版权声明:本文为博主原创,未经本人允许,禁止转载!

文章评论2条评论)

登录后参与讨论

测量无处不在 2019-10-11 10:45

人工神经网络(Artificial Neural Network,即ANN ),是20世纪80 年代以来人工智能领域兴起的研究热点。它从信息处理角度对人脑神经元网络进行抽象, 建立某种简单模型,按不同的连接方式组成不同的网络。在工程与学术界也常直接简称为神经网络或类神经网络。神经网络是一种运算模型,由大量的节点(或称神经元)之间相互联接构成。每个节点代表一种特定的输出函数,称为激励函数(activation function)。每两个节点间的连接都代表一个对于通过该连接信号的加权值,称之为权重,这相当于人工神经网络的记忆。网络的输出则依网络的连接方式,权重值和激励函数的不同而不同。而网络自身通常都是对自然界某种算法或者函数的逼近,也可能是对一种逻辑策略的表达。
最近十多年来,人工神经网络的研究工作不断深入,已经取得了很大的进展,其在模式识别、智能机器人、自动控制、预测估计、生物、医学、经济等领域已成功地解决了许多现代计算机难以解决的实际问题,表现出了良好的智能特性。

狗尾续貂,补充一下ANN的基本定义,概念辨析。

curton 2019-9-24 22:07

学习了
相关推荐阅读
布兰姥爷 2023-04-21 23:07
跟姥爷深度学习4 从数学计算看神经网络
一、前言我们前面简单的做了一个气温预测,经过反复调试,效果还不错。实际上在这个方向上我们还可以更进一步优化,但因为我们是学习嘛,主要还是看广度而不是深度。考虑到后面要开始学习卷积网络,我们必须把更基础...
布兰姥爷 2023-04-21 23:04
跟姥爷深度学习3 神经网络的调试实操
一、前言前面我们做了一次天气预测的模型,训练的结果都还好,网络好歹是“拟合”了,但预测数据不合预期让我一直耿耿于怀。所以我又花了很长时间来研究为什么,我的理论依据明明没有问题(今日平均温度与近一周平均...
布兰姥爷 2023-04-21 23:02
跟姥爷深度学习2 TensorFlow的基本用法
一、前言前面我们浅用TensorFlow做了个天气预测,虽然效果不咋样,但算是将整个流程跑通了。这一篇我们在之前基础上对TensorFlow的一些参数进行简单介绍,在接口文件的基础上了解各参数的简单含...
布兰姥爷 2023-04-11 22:22
跟姥爷深度学习1,浅用tensorflow做个天气预测
一、前言最近人工智能、深度学习又火了,我感觉还是有必要研究一下。三年前浅学了一下原理没深入研究框架,三年后感觉各种框架都成熟了,现成的教程也丰富了,所以我继续边学边写。原教程链接:https://ww...
布兰姥爷 2023-03-29 12:41
AI为啥要用显卡
一、前言GPT的发布让AI再次热了起来,与上次阿尔法狗不同的是,现在人人都可以跟聊上几句,给它出出难题,还能调戏下。同期英伟达发布了针对AI领域的全新GPU H100,有的童鞋会疑惑,这个英伟达不是做...
布兰姥爷 2019-11-04 21:09
【零基础】使用Tensorflow实现神经网络
一、序言  前面已经逐步从单神经元慢慢“爬”到了神经网络并把常见的优化都逐个解析了,再往前走就是一些实际应用问题,所以在开始实际应用之前还得把“框架”翻出来,因为后面要做的工作需要我们将精力集中在业务...
我要评论
2
24
关闭 站长推荐上一条 /2 下一条