神经网络算法代码_如何从头开始构建属于你自己的神经网络

神经网络可以说是目前深度学习的主力军。只要有足够多的数据(大数据)和计算能力,就可以使用神经网络可以用来解决深度学习中的大多数问题。你可以使用Python或R语言创建神经网络并使用任何数据集方便的对其进行训练,并且具有很高的准确性。

为了便于理解,我们可以将神经网络视为一个黑匣子,就是给定输入的数据就能给你一个你想要的答案输。但是,这虽然听上去很容易,但了解这些算法的背后以及算法的工作原理却比较困难。

e1ddea09adb53fce65236ad4416486c2.png

程序员正在训练神经网络

在本文中,我们将探讨构建神经网络的一些细节。本文将使用Python编写神经网络的代码。还将使用Python的numpy库执行数值计算。本文将尽量避免一些复杂的数学算法细节(微积分),但是如果您想进一步了解这些知识,可能会继续在以后的文章中进行详细说明!

sa,让我们开始实验吧!

什么是神经网络?

在开始编写属于我们自己的神经网络代码之前,我们必须得先来了解一下神经网络究竟是什么东东。

9c35b0af45a86ace4cefbbdaa1fa74d7.png

神经网络

在上图中,我们可以看到一个非常随意的神经网络图。它具有一些彼此相连的彩色圆,并带有指向特定方向的箭头,而这些彩色圆圈有时被称为神经元

这些神经只不过是一些数学函数,当给定一些输入时就会产生输出,神经元的输出取决于神经元的输入和它的参数。我们可以通过更新这些参数以从神经网络中获得我们所需要的值。

这些神经元中的每一个都使用S形函数来定义,一个S型函数每得到一个输入就会给出一个介于0到1之间的输出。这些S型函数相互连接就可以形成一个完整的神经网络。

而此处的连接是指将一层S形单元的输出作为提供给下一层的S形函数的输入。这样我们的神经网络就可以为任何给定的输入产生输出。这个传递过程会一直持续到最后一层。最后一层会生成输出。神经网络为给定的输入产生输出的过程是正向传播。最后一层的输出也称为神经网络的预测。在本文的后面,我们将讨论如何评估预测。这些评价可以用来判断我们的神经网络是否需要改进。

在最后一层生成输出之后,我们会立即计算它的成本函数。成本函数会计算出神经网络离做出期望的预测的距离还有多远。成本函数的值会表示预测值和真实值之间的差。

我们的目标是使成本函数的值最小化,而让成本函数最小化的过程还需要一种算法,该算法可以不断的更新网络中参数的值,以使成本函数达到其最小值。

使用诸如梯度下降和随机梯度下降之类的算法来更新神经网络的参数。这些算法将会更新网络中每一层的权重和偏差值,具体取决于它将如何影响成本函数的最小化。可以通过反向传播来计算网络中每个输入神经元的权重和偏差对成本函数最小化的影响。

47476e16ebf9872c48f7b3758bb5a886.png

神 经 元

开始编写代码

介绍完了神经网络的主要基本思想,我们开始来把我们的想法变成具体的代码吧,第一步自然是导入我们所需的库。

import numpy as npimport matplotlib.pyplot as plt

说明一点,本文不会使用任何深度学习库。因此,本文将主要使用numpy库高效地执行数学运算。

建立神经网络的第一步将是初始化参数。我们需要为每一层中的每一个神经元初始化两个参数:

  1. 权重
  2. 偏向

这些权重和偏差将以矢量化形式声明。这意味着,我们不必为每一层中的每个神经元初始化权重和偏差,而是为每一层创建一个权重向量(或矩阵),并为偏差创建另一个向量。

这些权重和偏差矢量将与图层的输入进行组合。然后,我们将S形函数应用于该组合,并将其作为输入传输到下一层。

layer_dims 会保存每个图层的尺寸。我们将这些层的尺寸传递给 init_parms 函数,该函数将使用它们来初始化参数。这些参数将存储在名为params的字典中。因此,在params字典中,params ['W1'] 将表示第1层的权重矩阵。

def init_params(layer_dims): np.random.seed(3) params = {} L = len(layer_dims)  for l in range(1, L): params['W'+str(l)] = np.random.randn(layer_dims[l], layer_dims[l-1])*0.01 params['b'+str(l)] = np.zeros((layer_dims[l], 1))  return params

NB熬!我们现在已经初始化了权重和偏差,现在我们将定义S型函数。它将计算任何给定Z值的S型函数的值,并将该值存储为缓存。我们存储缓存值,因为我们需要它们来实现反向传播。这里的Z指的是是线性假设

注意,S型函数属于神经网络术语中的激活函数类别。激活函数的作用是塑造一个神经元的输出。

例如,S形函数接受具有离散值的输入,并给出介于零和一之间的值。其目的是将线性输出转换为非线性输出。使用不同类型的激活函数当然可以获得更好的性能,但是为了简单起见,本文将坚持仅仅只使用S型函数。

#Z(线性假设)- Z=W*X+B#W-权重矩阵,b-偏差向量,X-输入def sigmoid(Z):A = 1/(1+np.exp(np.dot(-1, Z))) cache = (Z)  return A, cache

现在,让我们来开始编写代码以进行正向传播。前面本文已经讨论过,正向传播将采用上一层的值并将其作为下一层的输入。下面的函数将训练数据和参数作为输入,并将生成一层的输出,然后将其继续输出到下一层,依此类推。

A_prev 是第一层的输入 。我们将遍历网络的所有层并计算线性假设。之后,它将取Z值(线性假设)并将其赋予S型激活函数。缓存值会一路存储并累积在缓存中,最后,该函数将返回生成的值和存储的缓存。

现在来开始定义成本函数。

def cost_function(A, Y): m = Y.shape[1]  cost = (-1/m)*(np.dot(np.log(A), Y.T) + np.dot(log(1-A), 1-Y.T))   return cost

随着成本函数值的不断降低,我们的模型性能会变得更好。通过不断更新神经网络中每个层的参数值,可以使成本函数的值最小化。可以使用诸如梯度下降之类的算法以使成本函数最小化的方式来更新这些值。

梯度下降通过一些更新项来更新值。这些称为梯度的更新项是使用反向传播计算的,为网络中的每个神经元计算梯度值,它将会表示最终输出相对于特定神经元参数的变化。

def one_layer_backward(dA, cache): linear_cache, activation_cache = cache  Z = activation_cache dZ = dA*sigmoid(Z)*(1-sigmoid(Z)) # S型函数的导数  A_prev, W, b = linear_cache m = A_prev.shape[1]  dW = (1/m)*np.dot(dZ, A_prev.T) db = (1/m)*np.sum(dZ, axis=1, keepdims=True) dA_prev = np.dot(W.T, dZ)  return dA_prev, dW, db

上面的代码为一个单层进行了反向传播运算。它使用我们之前存储的缓存值来计算一层S型单元的梯度值。在激活缓存中,我们存储了该层的Z值。使用此值,我们将计算dZ,它是成本函数相对于给定神经元的线性输出的导数。

一旦计算了所有这些,就可以计算dWdbdA_prev,它们分别是成本函数相对于权重,偏差和先前激活的导数。本文直接在代码中使用了公式。如果您不熟悉微积分,那么乍一看似乎太复杂了。但是现在,可以试试把它与其他任何普通的数学公式一样来考虑。

之后,我们将使用此代码对整个神经网络实施反向传播。函数backprop就是用来完成这个的。在这里,我们创建了一个字典,用于将其渐变映射到每个图层。我们将向后遍历整个模型并计算梯度。

def backprop(AL, Y, caches): grads = {} L = len(caches) m = AL.shape[1] Y = Y.reshape(AL.shape)  dAL = -(np.divide(Y, AL) - np.divide(1-Y, 1-AL))  current_cache = caches[L-1] grads['dA'+str(L-1)], grads['dW'+str(L-1)], grads['db'+str(L-1)] = one_layer_backward(dAL, current_cache)  for l in reversed(range(L-1)):  current_cache = caches[l] dA_prev_temp, dW_temp, db_temp = one_layer_backward(grads["dA" + str(l+1)], current_cache) grads["dA" + str(l)] = dA_prev_temp grads["dW" + str(l + 1)] = dW_temp grads["db" + str(l + 1)] = db_temp  return grads

一旦我们遍历了所有层并计算出梯度,就会将这些值存储在梯度字典中并返回。

最后,使用这些渐变值,将更新每个层的参数。函数update_parameters会遍历所有层并更新参数之后就会返回它们。

def update_parameters(parameters, grads, learning_rate): L = len(parameters) // 2  for l in range(L): parameters['W'+str(l+1)] = parameters['W'+str(l+1)] -learning_rate*grads['W'+str(l+1)] parameters['b'+str(l+1)] = parameters['b'+str(l+1)] - learning_rate*grads['b'+str(l+1)]  return parameters

最后,是时候将所有函数全部组合在一起了。现在将创建一个称为train的函数来训练我们的神经网络。

def train(X, Y, layer_dims, epochs, lr): params = init_params(layer_dims) cost_history = []  for i in range(epochs): Y_hat, caches = forward_prop(X, params) cost = cost_function(Y_hat, Y) cost_history.append(cost) grads = backprop(Y_hat, Y, caches)  params = update_parameters(params, grads, lr)   return params, cost_history

此函数将在给定的时间段内逐步完成上述的所有函数。完成后,它将返回最终更新的参数和成本历史记录。成本历史记录(cost_history)可用于评估网络体系结构的整体性能。

ff5f96a350f14ba3380dac6ed8f1dc86.png

神经网络

写在最后

真的谢谢你能看到这里,由于本文看上去会比较复杂,所以我建议你可以尝试着打开Pycharm或是别的编译软件进行实战一下下,你可能就会收获更多有意义的想法,您的转发和点赞就是对作者最的帮助!

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值