zoukankan      html  css  js  c++  java
  • 神经网络入门——14多层感知机

    实现隐藏层

    先修要求

    接下来我们会讲神经网络在多层感知器里面的数学部分。讲多层感知器我们会用到向量和矩阵。你可以通过下列讲解对此做个回顾:

    1. 可汗学院的 向量入门.
    2. 可汗学院的 矩阵入门.
    由来

    之前我们研究的是只有一个输出节点网络,代码也很直观。但是现在我们有多个输入单元和多个隐藏单元,它们的权重需要有两个索引 wij,其中 i表示输入单元,j 表示隐藏单元。

    例如在下面这个网络图中,输入单元被标注为 x1,x2x3,隐藏层节点是h1 和 h2

    对比上面的示意图,确保你了解了不同的权重在矩阵中与在神经网络中的对应关系。

    用 NumPy 来初始化这些权重,我们需要提供矩阵的形状(shape),如果特征是一个包含以下数据的二维数组:

    # Number of records and input units
    # 数据点数量以及每个数据点有多少输入节点
    n_records, n_inputs = features.shape
    # Number of hidden units
    # 隐藏层节点个数
    n_hidden = 2
    weights_input_to_hidden = np.random.normal(0, n_inputs**-0.5, size=(n_inputs, n_hidden))

    这样创建了一个名为 weights_input_to_hidden 的二维数组,维度是 n_inputs 乘 n_hidden。记住,输入到隐藏节点是所有输入乘以隐藏节点权重的和。所以对每一个隐藏层节点 h_jhj,我们需要计算:

     
     

    为了实现这点,我们需要运用矩阵乘法,如果你对线性代数的知识有些模糊,我们建议你看下之前先修部分的资料。这里你只需要了解矩阵与向量如何相乘。

    在这里,我们把输入(一个行向量)与权重相乘。要实现这个,要把输入点乘(内积)以权重矩阵的每一列。例如要计算到第一个隐藏节点 j = 1的输入,你需要把这个输入与权重矩阵的第一列做点乘:

     

    用输入与权重矩阵的第一列相乘得出到隐藏层第一个节点的输入

     

    代表指向 h1 的权重的线条被标成了红色,这样更好区分。

    为了定位权重,我们把输入节点的索引 i 和隐藏节点的索引 j 结合,得到:

    w11代表从 x1 到h1 的权重;

    w12代表从 x_1x1 到 h_2h2 的权重。

    下图包括了从输入层到隐藏层的所有权重,用 wij 表示:

     
     

    之前我们可以把权重写成数组,用wi 来索引。

    现在,权重被储存在矩阵中,由 wij 来索引。矩阵中的每一行对应从同一个输入节点发出的权重,每一列对应传入同一个隐藏节点的权重。这里我们有三个输入节点,两个隐藏节点,权重矩阵表示为:

     

    三个输入节点两个隐藏节点的权重矩阵

    针对第二个隐藏节点的输入,你需要计算输入与第二列的点积,以此类推。

    在 NumPy 中,你可以直接使用 np.dot

    hidden_inputs = np.dot(inputs, weights_input_to_hidden)

    你可以定义你的权重矩阵的维度是 n_hidden 乘 n_inputs 然后与列向量形式的输入相乘:

     
     

    注意:

    这里权重的索引在上图中做了改变,与之前图片并不匹配。这是因为,在矩阵标注时行索引永远在列索引之前,所以用之前的方法做标识会引起误导。你只需要了解这跟之前的权重矩阵是一样的,只是做了转换,之前的第一列现在是第一行,之前的第二列现在是第二行。如果用之前的标记,权重矩阵是下面这个样子的:

     

    用之前的标记标注的权重矩阵

     

    切记,上面标注方式是不正确的,这里只是为了让你更清楚这个矩阵如何跟之前神经网络的权重匹配。

     

    矩阵相乘最重要的是他们的维度相匹配。因为它们在点乘时需要有相同数量的元素。在第一个例子中,输入向量有三列,权重矩阵有三行;第二个例子中,权重矩阵有三列,输入向量有三行。如果维度不匹配,你会得到:

    # Same weights and features as above, but swapped the order
    hidden_inputs = np.dot(weights_input_to_hidden, features)
    ---------------------------------------------------------------------------
    ValueError                                Traceback (most recent call last)
    <ipython-input-11-1bfa0f615c45> in <module>()
    ----> 1 hidden_in = np.dot(weights_input_to_hidden, X)
    
    ValueError: shapes (3,2) and (3,) not aligned: 2 (dim 1) != 3 (dim 0)
    

      

    3x2 的矩阵跟 3 个元素的数组是没法相乘的。因为矩阵中的两列与数组中的元素个数并不匹配。能够相乘的矩阵如下:

     
     

    这里的规则是,如果是数组在左边,数组的元素个数必须与右边矩阵的行数一样。如果矩阵在左边,那么矩阵的列数,需要与右边向量的行数匹配。

     

    构建一个列向量

    看上面的介绍,你有时会需要一个列向量,尽管 NumPy 默认是行向量。你可以用 arr.T 来对数组进行转置,但对一维数组来说,转置还是行向量。所以你可以用 arr[:,None] 来创建一个列向量:

    print(features)
    > array([ 0.49671415, -0.1382643 ,  0.64768854])
    
    print(features.T)
    > array([ 0.49671415, -0.1382643 ,  0.64768854])
    
    print(features[:, None])
    > array([[ 0.49671415],
           [-0.1382643 ],
           [ 0.64768854]])

    当然,你可以创建一个二维数组,然后用 arr.T 得到列向量。

    np.array(features, ndmin=2)
    > array([[ 0.49671415, -0.1382643 ,  0.64768854]])
    
    np.array(features, ndmin=2).T
    > array([[ 0.49671415],
           [-0.1382643 ],
           [ 0.64768854]])

    我个人更倾向于保持所有向量为一维数组,这样可以更好认知。

     

    编程练习

    下面你要实现一个 4x3x2 网络的正向传播,用 sigmoid 作为两层的激活函数。

    要做的事情:

    • 计算隐藏层的输入
    • 计算隐藏层输出
    • 计算输出层的输入
    • 计算神经网络的输出
    import numpy as np
    
    def sigmoid(x):
        """
        Calculate sigmoid
        """
        return 1/(1+np.exp(-x))
    
    # Network size
    N_input = 4
    N_hidden = 3
    N_output = 2
    
    np.random.seed(42)
    # Make some fake data
    X = np.random.randn(4)
    
    weights_input_to_hidden = np.random.normal(0, scale=0.1, size=(N_input, N_hidden))
    weights_hidden_to_output = np.random.normal(0, scale=0.1, size=(N_hidden, N_output))
    
    
    # TODO: Make a forward pass through the network
    
    hidden_layer_in = np.dot(X, weights_input_to_hidden)
    hidden_layer_out = sigmoid(hidden_layer_in)
    
    print('Hidden-layer Output:')
    print(hidden_layer_out)
    
    output_layer_in = np.dot(hidden_layer_out, weights_hidden_to_output)
    output_layer_out = sigmoid(output_layer_in)
    
    print('Output-layer Output:')
    print(output_layer_out)
    

      

  • 相关阅读:
    (C/C++学习笔记) 五. 常变量(只读变量)和宏
    (C/C++学习笔记) 四. 运算符
    (C/C++学习笔记) 三. 作用域和可见性
    (C/C++学习笔记) 一. 基础知识
    计算机科学的基本术语及其英语表达
    模块与包
    Python的递归
    内置函数与匿名函数
    装饰器,迭代器,生成器分析
    命名关键字参数,函数对象,嵌套,名称空间与作用域,闭包
  • 原文地址:https://www.cnblogs.com/fuhang/p/8963129.html
Copyright © 2011-2022 走看看