美文网首页深度学习
简单神经网络实现

简单神经网络实现

作者: 筱黎黎 | 来源:发表于2018-08-21 10:40 被阅读129次

训练一个神经网络

  • 我们搭建由一个输入层,一个隐藏层,一个输出层组成的简单的三层神经网络。
  • 输入层中节点数由数据的维度决定,也就是2个。
  • 输出层节点数则是由类的数量来决定,也是2个。(我们只有一个预测0和1的输出节点,所以我们只有两类输出,实际中,两个输出节点将更易于在后期进行扩展从而获得更多类别的输出)。
  • 以x,y坐标作为输入,输出的则是两种概率,一种是0(代表女),另一种是1(代表男)。


    三层神经网络示意图

隐藏层维度可以选择,隐藏层节点越多,实现的功能就越复杂,但是维度过高也是会有代价的。

  • 首先,更多的预测以及学习网络参数意味着更高的计算强度,更多的参数也会带来过拟合的风险,如何判断隐藏层的规模?
  • 另外,还需要为隐藏层选择激活函数(activation function)。激活函数会将输入转化成输出。非线性的激活函数可以帮助我们处理非线性的假设。通常选用的激活函数有tanh, sigmoid function, ReLUs
  • 这些函数有一个优点,就是通过原始的函数值便可以计算出它们的导数。例如tanh的导数就是1-tanh2x。这让我们可以在推算出tanh⁡x一次后就重复利用这个得到导数值。
  • 鉴于我们希望我们的网络输出的值为概率,所以我们将使用softmax作为输出层的激活函数,这个函数可以将原始的数值转化为概率

我们的网络是如何做出预测的呢?

神经网络是通过前向传播做出预测。如果该网络的输入x是二维的,那么我们可以通过以下方法来计算预测值y
z1=xW1+b1

a1=tanh(z1)

z2=a1W2+b2

a2=y=softmax(z2)

Zi表示第i层的输入,ai表示应用激活函数后的输出。Wi,bi表示需要我们通过训练数据来获取的神经网络参数,可以把它们当做网络层与层之间之间用于转化数据的矩阵。

每个神经元有两个单元组成。一个是权重和输入信号。另一个是非线性单元,叫做激励函数。信号e是激励信号。y = f(e) 是非线性单元的输出,即是神经元的输出。


为了训练神经网络,我们需要训练数据。训练数据由输入信号(x1和x2 )和期望输出z组成。网络的训练过程是一个迭代处理的过程。训练数据集用来在每次迭代过程中更新神经元的权重。每次学习过程由来自训练数据的输入信号开始。我们可以得出每一层的输出。下图说明信号在神经网络的传输路线。w(xm)n 是神经元xm 在第n层输入的连接权重。 yn 表示神经元n的输出。
#定义一些变量和参数,用于梯度下降算法
num_examples=len(X)
nn_input_dim=2#input layer dimensionality
nn_output_dim=2#output layer dimensionality

#grandient descent parameters
epsilon=0.01#learning rate for grandient descent学习率
reg_lambda=0.01#regularization strength正则化强度

网络如何做出预测

zi是第i层的输入,ai是该层应用激活函数后的输出i,Wi,bi是需要我们通过训练数据来获取的神经网络参数,你可以把它们当作在网络的层与层之间用于转化数据的矩阵。这些矩阵的维度可以通过上面的矩阵乘法看出来。如果我们在隐藏层上使用500个节点,那么就有 ,隐藏层的规模与可以用在隐藏层的节点数是呈正相关的。
  • 激活函数tanh图形


    tanh(x)

实现基本的三层神经网络

  • 定义损失函数, 研究参数是为了找到能够使我们的训练数据集错误率最小化的参数(W1,b1,W2,b2)。该如何定义错误呢?我们在这里用损失函数(loss function)来检测错误。

  • 通常对softmax的输出,我们会选择交叉熵损失函数(cross-entropy loss)(或者叫负对数似然)。如果我们有个训练示例,C个类别,那么预测值(hat{y})相对于真实的有标签数据的损失则可以通过如下方法来计算获得:

这个公式的功能就是对我们的训练示例进行求和,并加上预测值错误造成的损失。所以,标签值y与预测值

相差越大,损失就越大。

def calculate_loss(model):
    W1, b1, W2, b2 = model['W1'], model['b1'], model['W2'], model['b2']
    # Forward propagation to calculate our predictions
    z1 = X.dot(W1) + b1
    a1 = np.tanh(z1)
    z2 = a1.dot(W2) + b2
   
    #计算Softmax
    exp_scores = np.exp(z2)
    probs = exp_scores / np.sum(exp_scores, axis=1, keepdims=True)

    #计算损失函数 loss
    corect_logprobs = -np.log(probs[range(num_examples), y])#对Softmax取对数
    data_loss = np.sum(corect_logprobs)#损失函数为各输出值的的和

    # Add regulatization term to loss (optional)加入L2正则化项,lambda是正则化参数
    data_loss += reg_lambda/2 * (np.sum(np.square(W1)) + np.sum(np.square(W2)))
    return 1./num_examples * data_loss#?这一句什么意思?

Softmax公式 假设多分类问题,C=4,现行分类模型最后输出层包含四个输出值,分别是 经过Softmax处理后,数值转化成相对概率 Softmax将数值转化成概率,更有利于理解。 L2正则化 其中

是正则项,lambda是正则化参数。

实现一个用于计算输出的辅助函数

def predict(model, x):
    W1, b1, W2, b2 = model['W1'], model['b1'], model['W2'], model['b2']
    # Forward propagation
    z1 = x.dot(W1) + b1
    a1 = np.tanh(z1)
    z2 = a1.dot(W2) + b2
    exp_scores = np.exp(z2)
    probs = exp_scores / np.sum(exp_scores, axis=1, keepdims=True)
    return np.argmax(probs, axis=1) #返回最大值

训练神经网络的函数

  • 我们我们的目标是找到能最小化损失函数的参数值。我们可以使用梯度下降方法找到最小值。这里,我们使用批量梯度下降法,这种方法的学习速率是固定的,它的衍化版例如SGD(随机梯度下降stochastic gradient descent)或者最小批量梯度下降(minibatch gradient descent)通常在实际使用中会有更好的效果。作为输入,梯度下降法需要各参数对应损失函数的梯度,即

为了计算这些梯度,我们使用后向传播算法,这种方法通过输出计算梯度效率很高。(后向传播算法可参见http://galaxy.agh.edu.pl/~vlsi/AI/backp_t_en/backprop.html或者https://www.cnblogs.com/charlotte77/p/5629865.html))。

# This function learns parameters for the neural network and returns the model.
# - nn_hdim: Number of nodes in the hidden layer
# - num_passes: Number of passes through the training data for gradient descent
# - print_loss: If True, print the loss every 1000 iterations
num_example=len(X)
def build_model(nn_hdim, num_passes=20000, print_loss=False):
 
    # Initialize the parameters to random values. We need to learn these.
    np.random.seed(0)
    w1 = np.random.randn(nn_input_dim, nn_hdim) / np.sqrt(nn_input_dim)
    b1 = np.zeros((1, nn_hdim))
    w2 = np.random.randn(nn_hdim, nn_output_dim) / np.sqrt(nn_hdim)
    b2 = np.zeros((1, nn_output_dim))
 
    # This is what we return at the end
    model = {}
 
    # Gradient descent. For each batch...
    for i in range(0, num_passes):
 
        # Forward propagation
        z1 = X.dot(w1) + b1
        a1 = np.tanh(z1)
        z2 = a1.dot(w2) + b2
        exp_scores = np.exp(z2)
        probs = exp_scores / np.sum(exp_scores, axis=1, keepdims=True)
 
        # Backpropagation
        delta3 = probs
        delta3[range(num_example), y] -= 1
        dw2 = (a1.T).dot(delta3)
        db2 = np.sum(delta3, axis=0, keepdims=True)
        delta2 = delta3.dot(w2.T) * (1 - np.power(a1, 2))
        dw1 = np.dot(X.T, delta2)
        db1 = np.sum(delta2, axis=0)
 
        # Add regularization terms (b1 and b2 don't have regularization terms)
        dw2 += reg_lambda * w2
        dw1 += reg_lambda * w1
 
        # Gradient descent parameter update参数更新
        w1 += -epsilon * dw1
        b1 += -epsilon * db1
        w2 += -epsilon * dw2
        b2 += -epsilon * db2
 
        # Assign new parameters to the model
        model = { 'w1': w1, 'b1': b1, 'w2': w2, 'b2': b2}
 
        # Optionally print the loss.
        # This is expensive because it uses the whole dataset, so we don't want to do it too often.
        if print_loss and i % 1000 == 0:
            print ("Loss after iteration %i: %f" %(i, calculate_loss(model)))
 
    return model
# Build a model with a 3-dimensional hidden layer
model = build_model(3, print_loss=True)
 
# Plot the decision boundary
plot_decision_boundary(lambda x: predict(model, x))
plt.title("Decision Boundary for hidden layer size 3")
plt.show()

可以参考http://www.mamicode.com/info-detail-1567638.html

相关文章

网友评论

    本文标题:简单神经网络实现

    本文链接:https://www.haomeiwen.com/subject/aaoxiftx.html