从零开始构建简单人工神经网络:1个隐藏层

编译作者: 布加迪 2020-03-26 09:00:00

【51CTO.com快译】在上一篇文章《从零开始构建一个人工神经网络(上)》中,我们一开始讨论了什么是人工神经网络,接着介绍了如何使用Python从零开始构建一个简单的神经网络,只有1个输入层和1个输出层。这种神经网络名为Perceptron。然而,能够执行图像分类和股市分析等复杂任务的实际神经网络除了输入层和输出层外还有多个隐藏层。

我们在上篇中得出结论,Perceptron能够找到线性决策边界。我们使用Perceptron借助虚拟数据集来预测某人是否患有糖尿病。然而,Perceptron无法找到非线性决策边界。

我们在本文中将构建一个有1个输入层、1个隐藏层和1个输出层的神经网络。我们会看到,我们构建的神经网络能够找到非线性边界。

生成数据集

不妨先创造可供试用的数据集。幸好,scikit-learn有一些有用的数据集生成器,因此我们不需要自行编写代码。我们将使用make_moons函数。

  1. from sklearn import datasets  
  2. np.random.seed(0)  
  3. feature_set, labels = datasets.make_moons(300, noise=0.20)  
  4. plt.figure(figsize=(10,7))  
  5. plt.scatter(feature_set[:,0], feature_set[:,1], c=labels, cmap=plt.cm.Spectral) 

从零开始构建简单人工神经网络:1个隐藏层

图1

我们生成的数据集有两个类别,分别标为红点和蓝点。可以将蓝点视为男性患者,将红点视为女性患者,x轴和y轴是医学度量指标。

我们的目的是训练可根据x和y坐标预测正确类别(男性或女性)的机器学习分类器。请注意,数据不是线性可分离的,我们无法绘制将两个类别分开的直线。这意味着,除非你手动设计适用于特定数据集的非线性特征(比如多项式),否则线性分类器(比如没有任何隐藏层甚至没有逻辑回归的ANN)将无法拟合数据。

有1个隐藏层的神经网络

这是我们的简单网络:

从零开始构建简单人工神经网络:1个隐藏层

图2

我们有两个输入:x1和x2。有单单一个隐藏层,它有3个单元(节点):h1、h2和h3。最后,有两个输出:y1和y2。连接它们的箭头是权重。有两个权重矩阵:w和u。w权重连接输入层和隐藏层,u权重连接隐藏层和输出层。我们使用字母w和u,那样更容易关注要关注的计算。你还能看到我们将输出y1和y2与目标t1和t2进行了比较。

进行计算之前,我们需要介绍最后一个字母。让a成为激活前的线性组合。因此,我们有:

由于我们无法穷尽所有激活函数和所有损失函数,因此专注于两种最常见的函数。Sigmoid激活和L2范数损失。有了该新信息和新符号,输出y等于激活的线性组合。

因此,就输出层而言,我们有:

由于方法不同,我们将分别检查输出层和隐藏层的反向传播。

我想提醒诸位:

Sigmoid函数是:

导数是:

输出层的反向传播

为了获得更新规则:

我们必须计算

以单个权重uij为例。损失w.r.t. uij的偏导数等于:

其中i对应上一层(该变换的输入层),j对应下一层(该变换的输出层)。只要根据链式规则即可计算出偏导数。

关注L2-范数损失导数。

关注Sigmoid导数。

最后,三阶偏导数就是下面的导数:

所以,

替换上面表达式中的偏导数,我们得到:

因此,输出层的单个权重的更新规则由下式给出:

隐藏层的反向传播

与输出层的反向传播类似,wij将依赖:

关注链式规则。利用到目前为止我们可以利用Sigmoid激活和线性模型进行转换的结果,我们得到:

反向传播的实际问题来自该术语

那是由于没有“隐藏”目标。可以在下面看看权重w11的解决方案。查看计算过程时,建议先看一下上面显示的NN图。

从这里,我们可以计算

这就是我们想要的。最终的表达式是:

该方程的广义形式是:

反向传播的一般化

使用输出层和隐藏层的反向传播的结果,我们可以将它们放到一个公式中,在存在L2-范数损失和Sigmoid激活的情况下总结反向传播。

其中就隐藏层而言

实现有1个隐藏层的神经网络的代码

现在不妨实现我们刚使用Pytho从零开始的神经网络。我们将再次尝试对上面创建的非线性数据进行分类。

我们先为梯度下降定义一些有用的变量和参数,比如训练数据集大小、输入层和输出层的维度。

  1. num_examples = len(X) # training set size 
  2. nn_input_dim = 2 # input layer dimensionality 
  3. nn_output_dim = 2 # output layer dimensionality  

还定义梯度下降参数。

  1. epsilon = 0.01 # learning rate for gradient descent  
  2. reg_lambda = 0.01 # regularization strength  

首先,不妨实现上面定义的损失函数。我们使用该函数来评估模型的表现有多好:

  1. # Helper function to evaluate the total loss on the dataset  
  2. def calculate_loss(model, X, y):  
  3. num_examples = len(X) # training set size  
  4. W1, b1, W2, b2 = model['W1'], model['b1'], model['W2'], model['b2' 
  5. Forward propagation to calculate our predictions  
  6. z1 = X.dot(W1) + b1  
  7. a1 = np.tanh(z1)  
  8. z2 = a1.dot(W2) + b2  
  9. exp_scores = np.exp(z2)  
  10. probs = exp_scores / np.sum(exp_scores, axis=1, keepdims=True 
  11. # Calculating the loss  
  12. corect_logprobs = -np.log(probs[range(num_examples), y])  
  13. data_loss = np.sum(corect_logprobs)  
  14. Add regulatization term to loss (optional)  
  15. data_loss += Config.reg_lambda / 2 * (np.sum(np.square(W1)) + np.sum(np.square(W2)))  
  16. return 1. / num_examples * data_loss  

我们还实现了helper函数,计算网络的输出。它进行正向传播,返回概率最大的类别。

  1. def predict(model, x):  
  2. W1, b1, W2, b2 = model['W1'], model['b1'], model['W2'], model['b2' 
  3. Forward propagation  
  4. z1 = x.dot(W1) + b1  
  5. a1 = np.tanh(z1)  
  6. z2 = a1.dot(W2) + b2  
  7. exp_scores = np.exp(z2)  
  8. probs = exp_scores / np.sum(exp_scores, axis=1, keepdims=True 
  9. return np.argmax(probs, axis=1)  

最后是训练神经网络的函数。它使用我们在上面找到的反向传播导数实现了批梯度下降。

该函数学习神经网络的参数后返回模型。

nn_hdim:隐藏层中节点的数量。

num_passes:遍历梯度下降训练数据的次数。

print_loss:如果是True,每1000次迭代就打印输出损失。

  1. def build_model(X, y, nn_hdim, num_passes=20000, print_loss=False):  
  2. # Initialize the parameters to random values. We need to learn these.  
  3. num_examples = len(X)  
  4. np.random.seed(0)  
  5. W1 = np.random.randn(Config.nn_input_dim, nn_hdim) / np.sqrt(Config.nn_input_dim)  
  6. b1 = np.zeros((1, nn_hdim))  
  7. W2 = np.random.randn(nn_hdim, Config.nn_output_dim) / np.sqrt(nn_hdim)  
  8. b2 = np.zeros((1, Config.nn_output_dim))# This is what we return at the end  
  9. model = {}# Gradient descent. For each batch...  
  10. for i in range(0, num_passes):# Forward propagation  
  11. z1 = X.dot(W1) + b1  
  12. a1 = np.tanh(z1)  
  13. z2 = a1.dot(W2) + b2  
  14. exp_scores = np.exp(z2)  
  15. probs = exp_scores / np.sum(exp_scores, axis=1, keepdims=True)# Backpropagation  
  16. delta3 = probs  
  17. delta3[range(num_examples), y] -= 1  
  18. dW2 = (a1.T).dot(delta3)  
  19. db2 = np.sum(delta3, axis=0, keepdims=True 
  20. delta2 = delta3.dot(W2.T) * (1 - np.power(a1, 2))  
  21. dW1 = np.dot(X.T, delta2)  
  22. db1 = np.sum(delta2, axis=0)# Add regularization terms (b1 and b2 don't have regularization terms)  
  23. dW2 += Config.reg_lambda * W2  
  24. dW1 += Config.reg_lambda * W1# Gradient descent parameter update  
  25. W1 += -Config.epsilon * dW1  
  26. b1 += -Config.epsilon * db1  
  27. W2 += -Config.epsilon * dW2  
  28. b2 += -Config.epsilon * db2# Assign new parameters to the model  
  29. model = {'W1': W1, 'b1': b1, 'W2': W2, 'b2': b2}# Optionally print the loss.  
  30. # This is expensive because it uses the whole dataset, so we don't want to do it too often.  
  31. if print_loss and i % 1000 == 0:  
  32. print("Loss after iteration %i: %f" % (i, calculate_loss(model, X, y)))return model  

最后是主方法:

  1. def main():  
  2. X, y = generate_data()  
  3. model = build_model(X, y, 3, print_loss=True 
  4. visualize(X, y, model)  

每1000次迭代打印输出损失:

图3

隐藏层中节点数量是3时的分类

现在了解不同的隐藏层大小对结果有何影响。

  1. hidden_layer_dimensions = [1, 2, 3, 4, 5, 20, 50]  
  2. for i, nn_hdim in enumerate(hidden_layer_dimensions):  
  3. plt.subplot(5, 2, i+1)  
  4. plt.title('Hidden Layer size %d' % nn_hdim)  
  5. model = build_model(X, y,nn_hdim, 20000, print_loss=False 
  6. plot_decision_boundary(lambda x:predict(model,x), X, y)  
  7. plt.show()  

图4

我们可以看到,低维度的隐藏层很好地捕获了数据的总体趋势。较高维度易于过拟合。它们在“记忆”数据,而不是拟合总体形状。

如果我们在另外的测试集上评估模型,由于更好的泛化能力,隐藏层尺寸较小的模型可能会表现更好。我们可以通过更强的正则化来抵消过拟合,但是为隐藏层选择正确的尺寸是一种极为“经济”的解决方法。

你可以在该GitHub存储库中获取全部代码。

nageshsinghc4 / Artificial-Neural-Network-from-scratch-python

结论

我们在本文中介绍了如何使用Numpy Python,用数学导出有1个隐藏层的神经网络,并创建了有1个隐藏层的神经网络。

原文标题:Build an Artificial Neural Network From Scratch: Part 2,作者:Nagesh Singh Chauhan

【51CTO译稿,合作站点转载请注明原文译者和出处为51CTO.com】

神经网络 AI 人工智能
上一篇:物联网无人机如何为城市消毒 下一篇:探究谷歌用于构建量子机器学习模型的新框架:TensorFlow Quantum
评论
取消
暂无评论,快去成为第一个评论的人吧

更多资讯推荐

AI安全对抗中,只用一招轻松骗过五种神经网络

图像识别作为人工智能最成熟的应用领域,已经大规模落地并服务于人们的日常生活。但在大规模商业化的同时,也面临更多方面的威胁。

张鑫 ·  1天前
盘点人工智能十大经典应用领域、图解技术原理

本文通过案例分门别类地深入探讨人工智能的实际应用。案例甚多,此处所列举的仅是九牛一毛。本该按行业或业务对这些案例进行分类,但相反我选择按在行业或业务中最可能应用的顺序来分类。

Alex Castrounis ·  1天前
详解人工智能十大经典应用领域及其技术原理

本文通过案例分门别类地深入探讨人工智能的实际应用。案例甚多,此处所列举的仅是九牛一毛。本该按行业或业务对这些案例进行分类,但相反我选择按在行业或业务中最可能应用的顺序来分类。

华章科技 ·  1天前
目标驱动系统模式,能否成为实现人工通用智能(AGI)的关键?

组织开发AI方案时采取的一大核心模式,正是目标驱动型系统模式。与其他AI模式一样,这种形式的AI能够解决一系列原本需要人类认知能力才能处理的常见问题。

佚名 ·  1天前
后疫情时代的八大关键技术发展趋势

建立必要的基础架构以支持数字化世界并保持比较新的技术,这对于任何企业或国家在后疫情时代的世界中保持竞争力都至关重要。

Ahmed Banafa ·  2天前
从AI测温到安防机器人 智能安防会是新的“守门神”吗?

说起安防系统,很多人的脑海中会先冒出“监控摄像头”,“电子门禁”等字眼,而随着人工智能的加速发展,传统的安防系统短板也在逐渐暴露,越来越多的新功能开始被需要:人脸识别、车辆检测、夜间识别等等,而我们小时候幻想过的机器人站岗的场景,也正在逐渐变成现实……

王嘉陆 ·  2天前
用PyTorch实现一个简单的分类器

这篇文章我们先考虑在一个自己定义的简单数据集上实现分类,这样子可以最简单的了解一个神经网络的模型,如何用 pytorch 搭建起来。

佚名 ·  2天前
疫情期间,如何借AI之力持续提升客户忠诚度?

无论是保险公司Farmers Insurance,保险公司Tryg,还是通用汽车金融公司GM Financial,现在纷纷转向聊天机器人与AI技术,借此在疫情时期稳定客户群体。

佚名 ·  2天前
Copyright©2005-2020 51CTO.COM 版权所有 未经许可 请勿转载